I am facing an issue with the post-synthesis implementation of a special Serial-In-Serial-Out kind of buffer. It receives inputs and stores them in registers and can later output the stored inputs.
- When
iReset
is HIGH, the contents of the buffer are cleared. - When
iValid
is HIGH, the values of the registers in the buffer are shifted andbuffer[0]
receivesiResidual
. - When
oEnable
is HIGH, the buffer outputs the values of the last register tooResidual
(in this casebuffer[2]
) and the values are shifted accordingly. - When
oValid
is HIGH, it means thatoResidual
is a valid output.
Here is the full code:
module ResidualBuffer (
input iClock,
input iValid,
input iReset,
input oEnable,
input signed [15:0] iResidual,
output signed [15:0] oResidual,
output oValid,
output signed [15:0] bufferReg0,
output signed [15:0] bufferReg1,
output signed [15:0] bufferReg2
);
parameter blkSize = 3;
reg signed [15:0] buffer [0 : blkSize - 1];
integer i;
reg signed [15:0] oResidualReg;
assign oResidual = oResidualReg;
reg signed [blkSize : 0] oValidReg = -2; // for blkSize = 3, oValidReg = 4'b1110
assign oValid = oValidReg[0];
assign bufferReg0 = buffer[0];
assign bufferReg1 = buffer[1];
assign bufferReg2 = buffer[2];
always @(posedge iClock or posedge iReset) begin
if (iReset) begin
for (i = 0; i < blkSize; i = i + 1) begin
buffer[i] <= 0;
end
oResidualReg <= 0;
oValidReg <= -2;
end else if (iValid) begin
for (i = 1; i < blkSize; i = i + 1) begin
buffer[i] <= buffer[i - 1];
end
buffer[0] <= iResidual;
oResidualReg <= oResidualReg;
oValidReg <= oValidReg;
end else if (oEnable) begin
oValidReg <= oValidReg>>1;
oResidualReg <= buffer[blkSize - 1];
for (i = 1; i < blkSize; i = i + 1) begin
buffer[i] <= buffer[i - 1];
end
end
end
endmodule
The behavioural simulation is working as expected:
The post-synthesis simulation is different and confusing:
The problems I am facing are:
- When
iValid
is LOW,buffer[0]
continues to receiveiResidual
and the values in the registers are shifted and I don't understand why. - When
oEnable
is HIGH, it is reflected only in the next clock cycle. However this is not the case foriValid
as explained in (1) and I don't understand why.
~Edit: For those who want to look at the testbench I used
`timescale 1ns / 100ps
module ResidualBufferTB;
reg iClock;
reg iValid;
reg iReset;
reg oEnable;
reg signed [15:0] iResidual;
wire signed [15:0] oResidual;
wire oValid;
wire signed [15:0] bufferReg0;
wire signed [15:0] bufferReg1;
wire signed [15:0] bufferReg2;
ResidualBuffer #(.blkSize(3)) DUT (
.iClock(iClock),
.iValid(iValid),
.iReset(iReset),
.oEnable(oEnable),
.iResidual(iResidual),
.oResidual(oResidual),
.oValid(oValid),
.bufferReg0(bufferReg0),
.bufferReg1(bufferReg1),
.bufferReg2(bufferReg2)
);
always begin
#0 iClock = 0;
#125 iClock = 1;
#125 iClock = 0;
end
initial begin
iReset = 1; iValid = 0; oEnable = 0;
#125 iReset = 0;
#250 iValid = 1; iResidual = 20;
#250 iResidual = -123;
#250 iResidual = 31;
#250 iValid = 0; iResidual = 0;
#250
#250 oEnable = 1;
#1250
$stop;
end
endmodule