2
\$\begingroup\$

I am providing input to an SPI interface. The input signal is a concatenation of several different signals. What I would like to do in simulation is have continuous concatenation of the different signals into one final string that will be sent to the SPI:

logic [7:0] foo;      // Signal 1
logic [7:0] bar;      // Signal 2
logic [15:0] combine; // Final signal
assign combine = {foo, bar};

task SendSPI;
begin
     foo = 8'hFF;
     bar = 8'h00;
     SendToSpi(combine); // Want it to send 16'hFF00;
endtask;

The above code compiles and runs on the simulator (Cadence NC sim), but the value of combine is undefined (xxxx). I know I can get around this by having a concatenation task:

task CombineSignal;
begin
     combine = {foo, bar};
endtask;

and I would call that task everytime I wanted to concatenate, but having continuous assignment work would be really nice! Does anyone know if continuous assignment is possible in a situation like this?

\$\endgroup\$
2
  • \$\begingroup\$ Does combine[15:8] = foo; combine[7:0] = bar; work? \$\endgroup\$
    – Samuel
    Sep 23, 2013 at 18:50
  • \$\begingroup\$ Have you tried declaring the variable type as wire or reg instead of logic? \$\endgroup\$
    – Iancovici
    Sep 23, 2013 at 18:58

2 Answers 2

3
\$\begingroup\$

I figured out what was going on. The assign combine statement needs time to pass before it takes a new value.

logic [7:0] foo;      // Signal 1
logic [7:0] bar;      // Signal 2
logic [15:0] combine; // Final signal
assign combine = {foo, bar};

task SendSPI;
    begin
         foo = 8'hFF;
         bar = 8'h00;

         SendToSpi(combine); // combine is undefined.

         @(negedge clk);     // let some simulator time pass.

         SendToSpi(combine); // combine now equals 16'hFF00
    endtask;
\$\endgroup\$
1
  • \$\begingroup\$ No, the assign statement doesn't need time to pass, it's your task call that needs time. \$\endgroup\$
    – Alain
    Nov 3, 2013 at 16:15
1
\$\begingroup\$

You must understand how Verilog simulators schedule events.

If procedural statements appear in different procedural blocks, there is no guarantee for the order of their execution. For example:

initial
  begin
    a = 0;
    b = 1;
  end

always a = b;

always b = a;

The above code can result in both a and b being 1's, as well as 0's.

However, procedural statements appearing in the same procedural block are guaranteed to execute sequentially:

initial
  begin
    a = 0;
    b = 1;
  end

always 
  begin
    a = b;
    b = a;
  end

The above code will result in both a and b being 1's.

The problem with your initial code is that the concatenation operation is outside of the body of the task, therefore there is no way the scheduler can execute it between the statements in the body of the task (because they are executed sequentially, without outside interruption).

However, once you add a sequential construct (@(negedge clk)), the simulator advances to the next time slot which allows for the concatenation assignment to be executed.

Although the code you provided works for you, it is very bad practice to write Verilog this way. Why don't do this:

logic [7:0] foo;      // Signal 1
logic [7:0] bar;      // Signal 2

task SendSPI;
begin
     foo = 8'hFF;
     bar = 8'h00;
     SendToSpi({foo, bar}); // Will send 16'hFF00;
endtask;
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.