0
\$\begingroup\$

I have a Verilog module acting as a register file (a slew of registers and some access ports) with a control signal coming from another module that controls when the write to one of the registers happens.

The idea is that I raise a control pin and the specified register is set to the value on one of the module's data inputs as follows:

module RegisterFile(
input CLK,
input [4:0] RegA_Name,
input [4:0] RegB_Name,
input [4:0] RegC_Name,
input [31:0] RegA_In,
input [31:0] RegC_In,
input RegA_WrtEn,
input RegC_WrtEn,
output reg [31:0] RegA_Out,
output reg [31:0] RegB_Out
);

reg [31:0] r [31:0];

integer i;
initial begin
    for(i = 0; i < 32; i = i + 1'b1)
        r[i] = 0;
end


always@(posedge CLK) begin

    RegA_Out <= r[RegA_Name];
    RegB_Out <= r[RegB_Name];

    if(RegA_WrtEn) begin
        r[RegA_Name] <= RegA_In;
    end

    if(RegC_WrtEn) begin
        r[RegC_Name] <= RegC_In;
    end
end

I'm aiming for the register contents to get set and for that content to appear on the output on the same clock cycle that write enable gets set high.

I see the behavior that I'm shooting for when testing the module from a testbench, but when I wire it to the module that's actually going to be controlling it and test that, the write happens not on the clock cycle that write enable is set high, but two clock cycles after (depicted in the waveform below). Why might this be? How can I edit my code to achieve the behavior I'm shooting for, or something close to it?

enter image description here

\$\endgroup\$
3
  • 1
    \$\begingroup\$ There's no clock signal on timing diagram, all conclusions may be guesses only. Please add clock so that we can see timing. \$\endgroup\$ – Anonymous May 6 '17 at 7:25
  • \$\begingroup\$ Your code is doing exactly what you have programmed it to do. \$\endgroup\$ – Tom Carpenter May 6 '17 at 17:04
  • \$\begingroup\$ This is a "read before write" configuration. You may prefer "write before read" and allow flow-through updates (this is a classical issue with pipelined CPUs, with register bypassing...) \$\endgroup\$ – TEMLIB May 6 '17 at 17:36
1
\$\begingroup\$

Your code is doing exactly what you have described in your HDL.

At every positive clock edge (always @ (posedge CLK) begin), do the following:

  1. Update the output registers to show the value of r that was latched into the register on the previous clock cycle (RegA_Out <= r[RegA_Name];)
  2. If the write enable signals are high (if (RegA_WrtEn)), then update the value of r to the incoming data.

As a result it takes two positive/rising clock edges after the WrtEn is asserted for the data to appear at the output. This is exactly what you are seeing in your simulation.

I've numbered the clock cycles in your simulation output:

Numbered Sim Output

  • On clock cycle 1, you assert the WrtEn and RegA_In signals.
  • On the next rising edge, cycle 2, the first data word is latched into the r register (you would see this if you probed it).
  • Next, on cycle 3, the data in the r register is latched onto the RegA_Out register, and the second data word is latched into the r register.
  • Finally, on cycle 4, the second data word is read from the r register and latched onto the RegA_Out register.
\$\endgroup\$
1
  • \$\begingroup\$ Depending on your goals, it may be that having an output register which created an extra pipeline stage may not be what is desired, and what you really want could just be the direct output of the internal register. Of course, the more logic to combine in between registers, the slower the maximum speed; the tradeoff to keeping register-register paths short is that your design then has to accommodate longer pipelines. \$\endgroup\$ – Chris Stratton Jul 29 '19 at 14:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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