0
votes

I am working on a school project for a 2-stage pipeline processor in Verilog HDL and have run into an issue that has stumped me for a few days. I will add small code snippets and a picture of the signals I am getting through ModelSim through my description. I am simply taking the output from my ALU:

ALU #(BUS_WIDTH(BUS_WIDTH)) alu (
    .A(Amux),
    .B(Bmux),
    .sel(ALUsel),
    .Dout(ALUout)
);

I am then passing it directly to the buffer between my stages in the same file in the following manner (other signals and data being buffered removed for ease of reading):

Buffer #(.BUS_WIDTH(BUS_WIDTH)) buff(
    .clk(clk),
    .reset(reset),
    .aluA(ALUout),
    .aluB(ALUoutM),
);

The inside of the buffer module looks like the following (I am again removing everything else being buffered for ease of reading:

module Buffer(
    input clk,
    input reset,
    input [31:0] aluA,
    output reg [31:0] aluB
);

    always @(posedge clk)
    begin
        if (~reset)
        begin
            aluB <= 32'h00000000;
        end else
        begin
            aluB <= aluA;
        end
    end
endmodule

The following image is what I am having issues with:enter image description here

This is happening a few cycles after the testbench has been started and the previous cycles run successfully. Looking at the image, the top signal is the ALUout and the second signal is ALUoutM. My desired outcome is for my ALUoutM signal to match my ALUout signal from the previous clock cycle (I have verified that a full clock cycle is the period between the signal changes in the image). As previously stated, this desired outcome is seen in all cycles previous to this one. Between the first and second cycle, the outcome isn't as desired, but then goes back to being correct. I have triple checked and verified that my ALUoutM isn't being driven by any other signals. I am mostly trying to figure out if I am making a beginner mistake with verilog that I am unaware of. Thank you for any help.

ADDITION

Per the comments of Oldfart (I love that name), I was able to add the signals of the buffer into my simulator also, but it is displaying the exact same behavior as the input signals are. In the following image, you'll notice a correct behavior for the first 4 clock cycles and then a random value of 0x00000000 coming out of the buffer. Then it is correct for one more clock cycle before completely flying off the rails.

enter image description here

1
Why is aluB in Buffer an input?Unn
@Unn It actually isn't. That is a typo. I double checked my code and it is indeed an output. Thanks for pointing that out.Cody Berry
The normal debug procedure in this case is to also put alu and aluB from your Buffer module in the waveform display and trace where things go wrong. Why? Because I don't believe in "triple checking" even if I do it myself. It is just too easy to overlooks a case.Oldfart
@Oldfart Are you saying to do that in the testbench file that I am getting these same signals from? How would I add them to the output since they're from another module? ALUout is directly plugged into the aluA port of Buffer and ALUoutM is plugged into the aluB port of Buffer. Since that is the case, I am understanding you to mean that I should grab both the ports themselves? How would I do this?Cody Berry
Most simulators have an hierarchy window which you can expand like the file system on your computer. Select a module and your 'signals' window will update with the signals in the module. Select and drag the signals to the waveform window. Most simulators you need to re-start to update the waveform unless you previously enabled some 'log all signals' option.Oldfart

1 Answers

0
votes

Okay, thanks to Oldfart (still love that name) for giving me advice on the issue. After talking about it all with the professor and a teaching assistant, I changed all of my MUXes to trigger on an

always @ ( * )

signal which I hadn't thought to be the issue when posting the question. I was previously creating them as

always @ (sel or input_a or input_b or ... or input_N)

This wasn't immediately propagating my data through like a MUX would be expected. I believe this is because all of the inputs do not get to the MUX at the same time, thus causing the value of the output to potentially change the same number of times as the number of signals that changed (unless you're lucky enough to have every signal reach at the same time). This potentially gives you the incorrect signal many times until all of the inputs have propagated to the MUX. In short, who knows what values you end up clocking if you're doing it the way I was originally doing it.

This along with "registering" my outputs to my modules solved my issue. For anyone unsure what I mean, when I declare my outputs, I do so as

output reg [(width - 1):0] output_x

as opposed to

output [(width - 1):0] output_x

I am not 100% sure why this one helped, but when I went back and did this, it made the entire processor give me much nicer signals that acted as I expected. I believe this is because it causes all of the outputs to "latch". If someone could elaborate on why this helps, I would greatly appreciate it.