When implementing Verilog tasks in modules, the best approach is to group tasks that have the same output signals into separate modules. If different modules control the same signal, then explicit arbitration logic is required to specify which module is controlling the signal at a given time. To put tasks in a separate module, you will require start and completion handshaking signals.

Behavioural:

task update_a_and_b;

begin

a = y;

wait (z != 0) b = z;

end

endtask

...

y = x + w;

update_a_and_b; // calls the task

x = a + b;

@(posedge clock);

x = b;

if (y == x) update_a_and_b;

@(posedge clock);

command1;

Care must be taken when translating this into synthesizable Verilog, to preserve correct timing:

module update_a_and_b(do_update_a_and_b, clock, reset, a, z, done_update_a_and_b, b_temp, x_temp);

input do_update_a_and_b; // this signal should go high for only one clock cycle

input clock;

input reset; // reset this module when reset goes high

input [7:0] a;

input [7:0] z;

output done_update_a_and_b;

output [7:0] b_temp;

output [7:0] x_temp;

reg done_update_a_and_b;

reg [7:0] b_temp;

reg [7:0] x_temp;

reg state;

always @(posedge refclk or posedge reset)

if (reset)

begin

state <= 0;

done_update_a_and_b = 0;

b_temp = 0;

x_temp = 0;

end

else if (do_update_a_and_b && (state == 0))

begin

done_update_a_and_b = 0;

if (z != 0)

begin

b_temp = z;

x_temp = a+b_temp; // x value is update inside this module, as it must occur immediately when z != 0

done_update_a_and_b = 1;

// stay in state 0, we've finished

end

else state <= 1;

end

else

begin

case (state)

0 : done_update_a_and_b = 0; // do nothing, this is the idle state

1 : if (z != 0)

begin

b_temp = z;

x_temp = a+b_temp; // x value is update inside this module, as it must occur immediately when z != 0

done_update_a_and_b = 1;

state <= 0;

// stay in state 0, we've finished

end

endcase

end

endmodule

...

reg [2:0] top_state;

...

case (top_state)

0 : begin

y = x + w;

a = y; // this must happen immediately

if (z != 0) // we have to update x and b immediately if z != 0

begin

b = z;

x = a + b;

top_state <= 2;

end

else

begin

do_update_a_and_b = 1; // call the task

top_state <= 1;

end

end

1 : begin

do_update_a_and_b = 0; // stays high for only one cycle

if (done_update_a_and_b)

begin

// we assume the values of x and b weren't needed on the previous cycle, otherwise additional circuitry is needed

// or x_temp and b_temp values need to be used on that cycle - it's very difficult to coordinate this correctly

// in the general case

x = x_temp;

b = b_temp;

top_state <= 2;

end

end

2 : begin

x = b;

if (y == x)

begin

a = y; // this must happen immediately

if (z != 0) // we have to update x and b immediately if z != 0

begin

b = z;

x = a + b;

top_state <= 4;

end

else

begin

do_update_a_and_b = 1; // call the task

top_state <= 3;

end

end

else top_state <= 4;

end

3 : begin

do_update_a_and_b = 0; // stays high for only one cycle

if (done_update_a_and_b)

begin

// we assume the values of x and b weren't needed on the previous cycle, otherwise additional circuitry is needed

// or x_temp and b_temp values need to be used on that cycle - it's very difficult to coordinate this correctly

// in the general case

x = x_temp;

b = b_temp;

top_state <= 4;

end

end

4: command1;

endcase

Now if we didn't care about having a couple of additional cycle delays between updates (i.e. assuming nothing depends on the variable values immediately, and nothing else is changing variable values), we could implement this in a far simpler fashion:

module update_a_and_b(do_update_a_and_b, clock, reset, a, z, done_update_and_b, b_temp, x_temp);

input do_update_a_and_b; // this signal should go high for only one clock cycle

input clock;

input reset; // reset this module when reset goes high

input [7:0] a;

input [7:0] z;

output done_update_and_b;

output [7:0] b_temp;

output [7:0] x_temp;

reg done_update_and_b;

reg [7:0] b_temp;

reg [7:0] x_temp;

reg state;

always @(posedge refclk or posedge reset)

if (reset)

begin

state <= 0;

done_update_and_b = 0;

b_temp = 0;

x_temp = 0;

end

else if (do_update_a_and_b && (state == 0))

begin

state <= 1;

done_update_a_and_b = 0;

end

else

begin

case (state)

0 : done_update_and_b = 0; // do nothing, this is the idle state

1 : if (z != 0)

begin

b_temp = z;

x_temp = a+b_temp; // x value is update inside this module, as it must occur immediately when z != 0

done_update_and_b = 1;

state <= 0;

// stay in state 0, we've finished

end

endcase

end

endmodule

...

reg [2:0] top_state;

...

case (top_state)

0 : begin

y = x + w;

do_update_a_and_b = 1; // call the task

top_state <= 1;

end

1 : begin

do_update_a_and_b = 0; // stays high for only one cycle

if (done_update_and_b)

begin

x = x_temp;

b = b_temp;

top_state <= 2;

end

end

2 : begin

x = b;

if (y == x)

begin

do_update_a_and_b = 1; // call the task

top_state <= 3;

end

else top_state <= 4;

end

3 : begin

do_update_a_and_b = 0; // stays high for only one cycle

if (done_update_and_b)

begin

x = x_temp;

b = b_temp;

top_state <= 4;

end

end

4: command1;

endcase

Note: in general commandi refers to a block of commands. It is assumed there is an

appropriate clock for the case statement state machines.

Care is required in setting appropriate reset states, initialization, and completion of use of a

state machine:

o Is there a signal to tell the state machine to begin?

o Does a done signal go high, signalling the state machine has finished?

o When it is not in operation, does the state machine idle correctly? Does it change signal values shared with other code? Does it set outputs from it to appropriate idling values?

o Is the state machine reset to the idle state by a reset signal?

o Ensure that you initialize all registers.

o Ensure that your state register has the correct bit width - if it is too small, assigning a larger state value will just return it to an earlier state.

## Post a Comment

Your comments will be moderated before it can appear here.