-
Notifications
You must be signed in to change notification settings - Fork 0
Sequences
SequenceExample(
in Clk,
out reg [4] A@(Clk) = 0,
out reg [4] B@(Clk) = 9)
{
@(Clk)
{
A <= 1;
A <= 2;
//parallel
{
A <= 3;
B <= 5;
}
//parallel
{
@(clk)
{
A <= 4;
A <= 5;
}
B <= B + 1;
}
A <= 0;
B <= 0;
}
}
// __ __ __ __ __ __ __
//Clk ______/ \__/ \__/ \__/ \__/ \__/ \__/ \_
//A 0 1 2 3 4 5 0
//B 9 5 6 7 0
SequenceExample(
in Clk,
out reg A@(Clk) = 0,
out reg B@(Clk) = 0,
out reg C@(Clk) = 0,
out reg [8] D@(Clk) = 0)
{
reg [4] counter@(Clk) = 0;
counter <= counter+1;
@(Clk)
{
{A <= 1; B <= 1;}
@(counter==3);
{A<=0; C<=1}
@(counter==6)
{
B <= 0;
C <= 0;
}
A <= 1;
{
D <= D+1;
@(counter==11)
{
D <= 0;
}
}
A <= 0;
}
}
// __ __ __ __ __ __ __ __ __ __ __ __
//Clk ______/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \_
//counter |0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |10 |11 |12
//A |0 |1 |0 |1 |1
//B |0 |1 |0
//C |0 |1 |0
//D |0 |1 |2 |3 |0
A sequence can be described using the sequence construct.
Sequencer(
in Clk,
out reg A@(Clk),
out reg B@(Clk),
out reg C@(Clk),
out reg D@(Clk),
out reg E@(Clk),
out Q)
{
//Default is 0
Q = 0;
sequence@(Clk) //Positive edge of Clk
{
//Step 1
A <= 1;
B <= 0;
C <= 0;
D <= 0;
E <= 0;
@(/*No condition*/); //Wait for Clk pulse
//Step 2
A <= 0;
B <= 1;
@(); //Wait for Clk pulse
//Step 3
B <= 0;
C <= 1;
D <= 1;
Q = 1; //Assign to 1 during this state
@(); //Wait for Clk pulse
//Step 4
C <= 0;
E <= 1;
}
}
A sequence is defined along with a clock. This clock controls the state machine, and all operations are synchronous to it.
The @
symbol specifies the condition to move onto the next state. If no condition is specified, the sequence moves to the next state on the next clock edge.
If no wait condition after the final step is specified, it will automatically transition back to the first step on the next clock. (Equivalent to a final @();
). If a wait condition is explicitly stated (and followed by no other code), the automatic clock will not be inserted, and the explicit condition will be used instead.
The timing diagram produced by the code looks like this:
Step 1 2 3 4 1
__ __ __ __ __
Clk _/ \__/ \__/ \__/ \__/ \__
|______ | | | ____
A UU \_________________/
| | _____ | |
B UU______/ \________________
| | | _____ |
C UU____________/ \__________
| | | ___________
D UU____________/ \____
| | | | _____
E UU__________________/ \____
| | |_____| |
Q _____________/ \___________
Signals are shown initialized to U
because they have no initial value so their value is unknown. Q
has been given a default value of 0
.
In the first step all signals are initialized, with A
being set HIGH
and all other signals set LOW
.
In the second step, A
is set LOW
and B
is set HIGH
. The other signals remain unchanged.
On the third step, B
is set LOW
, and C
and D
are set HIGH
. Q
is also assigned HIGH
here. Q
is not a register so the value of Q
is only combinational. That means it is only set HIGH
during this state. Since the default is listed before, this assignment takes precedence and overrides it.
On the forth step, C
is set back LOW
and E
is set HIGH
. Q
is not specified and therefore Q
returns to the default value.
At the end of the sequence, it repeats. Therefore all signals are returned to LOW
, except for A
which is set to HIGH
.
This is the equivalent Verilog code that would produce the same output waveform. The state machine must be created manually.
module Sequencer(
input Clk,
output reg A,
output reg B,
output reg C,
output reg D,
output reg E,
output Q)
{
reg [1:0] state;
// Q = 1 when (state == 3), otherwise Q = 0
//State is incremented at the same time the outputs are updated. Therefore it is 1 ahead.
assign Q = (state == 3 ? 1 : 0);
always @(posedge Clk)
begin
state <= state + 1;
case (state)
0: //Step 1
begin
A <= 1;
B <= 0;
C <= 0;
D <= 0;
E <= 0;
end
1: //Step 2
begin
A <= 0;
B <= 1;
end
2: //Step 3
begin
B <= 0;
C <= 1;
D <= 1;
end
3: //Step 4
begin
C <= 0;
E <= 1;
end
endcase
end
end
wire [4] burstLen;
wire [32] addr;
wire [32] data [8];
wire transfer;
sequence@(Clk)
{
@(transfer);
AWaddr <= addr;
AWvalid <= 1;
AWlen <= burstLen-1;
//Fork to handle address and data asynchronously
fork
{
//Write Address
@(AWready);
AWaddr <= 32x00000000;
AWvalid <= 0;
}
//Write Data
{
@();
for (int i=0; i<burstLen; i++) //int? reg? var?
{
//Post data
Wdata <= data[i];
Wvalid <= 1;
//Assert last on last transfer
if (i==burstLen-1) { Wlast <= 1; }
//Wait for acknowledge and loop around for next transfer
@(Wready);
}
//Reset signals
Wdata <= 32x00000000;
Wvalid <= 0;
Wlast <= 0;
}
join;
Bready <= 1;
//Write Response
@(Bvalid);
Bready <= 0;
}
wire [4] burstLen;
wire [32] addr;
wire [32] data [8];
wire transfer;
reg addrDone;
reg dataDone;
reg sync;
sequence@(Clk)
{
sync <= 1;
@(transfer);
AWaddr <= addr;
AWvalid <= 1;
AWlen <= burstLen-1;
sync <= 0; //Signal to begin address and data
//Wait for address and data to complete
@(addrDone && dataDone);
sync <= 1;
Bready <= 1;
//Write Response
@(Bvalid);
Bready <= 0;
}
sequence@(Clk)
{
addrDone <= 0;
@(!sync && AWready);
//Write Address
AWaddr <= 32x00000000;
AWvalid <= 0;
//Signal sync
addrDone <= 1;
//Wait for sync
@(sync);
}
sequence@(Clk)
{
dataDone <= 0;
@(!sync);
//Write Data
for (int i=0; i<burstLen; i++)
{
//Post data
Wdata <= data[i];
Wvalid <= 1;
//Assert last on last transfer
if (i==burstLen-1) { Wlast <= 1; }
//Wait for acknowledge and loop around for next transfer
@(Wready);
}
//Reset signals
Wdata <= 32x00000000;
Wvalid <= 0;
Wlast <= 0;
//Signal sync
dataDone <= 1;
//Wait for sync
@(sync);
}
sequence@(Clk) //Positive edge of Clk
{
State1:
A <= 1;
B <= 0;
C <= 0;
D <= 0;
E <= 0;
@(); //Wait for Clk pulse
State2:
A <= 0;
B <= 1;
@(cond1) goto State1;
@(cond2) goto State4;
State3:
B <= 0;
C <= 1;
D <= 1;
Q = 1; //Assign to 1 during this state
@(cond1) goto State1;
@(cond2) goto State2;
@(); //Default transition on next clock
State4:
C <= 0;
E <= 1;
}
sequence@(Clk) //Positive edge of Clk
{
@State1:
A <= 1;
B <= 0;
C <= 0;
D <= 0;
E <= 0;
goto State2; //Wait for Clk pulse
@State2:
A <= 0;
B <= 1;
if (cond1) { goto State1; }
if (cond2) { goto State4; }
@State3:
B <= 0;
C <= 1;
D <= 1;
Q = 1; //Assign to 1 during this state
goto State4; //Default transition on next clock. Must be placed due to overriding rule
if (cond1) { goto State1; }
if (cond2) { goto State2; }
@State4
C <= 0;
E <= 1;
goto State1;
}
reg [3] state@(Clk);
wire [3] nextState;
state <= nextState;
Q = 0;
//Next state & Combinational
switch (state)
{
0:
nextState = 1;
1:
nextState = 2;
2:
nextState = 2;
if (cond1) { nextState = 1; }
if (cond2) { nextState = 3; }
3:
Q = 1; //Assign to 1 during this state
nextState = 4;
if (cond1) { nextState = 1; }
if (cond2) { nextState = 2; }
4:
nextState = 1;
}
switch (nextState)
{
0:
//Nothing
1:
A <= 1;
B <= 0;
C <= 0;
D <= 0;
E <= 0;
2:
A <= 0;
B <= 1;
3:
B <= 0;
C <= 1;
D <= 1;
4:
C <= 0;
E <= 1;
}
WIP
sequence@(Clk)
{
sig1 <= 0;
sig2 <= 0;
@(cond1);
once
{
sig1 <= sig1 + 1;
}
sig2 <= sig2 + 1;
@(cond2);
}
sequence@(Clk)
{
Init:
A <= 0;
B <= 0;
C <= 0;
@(cond1);
State1:
A <= 1;
B <= 1;
C <= 1;
@(cond2) goto Init,
@(cond3);
State2:
A <= 1;
B <= 1;
C <= 1;
@(cond4) goto Init,
@(cond5) goto State1,
@(false);
State3:
A <= 1;
B <= 1;
C <= 1;
@(cond6);
}
sequence@(Clk)
{
Init:
A <= 0;
B <= 0;
C <= 0;
@(cond1);
State1:
A <= 1;
B <= 1;
C <= 1;
if (cond2)
{
goto Init;
}
@(cond3); //What happens if omitted?
State2:
A <= 1;
B <= 1;
C <= 1;
if (cond4) { goto Init; }
if (cond5) { goto State1; }
goto State2; //Overriding?
State3:
A <= 1;
B <= 1;
C <= 1;
@(cond6);
}