1
\$\begingroup\$

I'm trying to program an 8 level stack register for a Program Counter. It is working well enough, but for some reason, when I test it, some combinations of inputs produce unexpected results. This is leading me to believe that I don't really understand the underlying logic behind the "if(condition1 && condition2)" statement or the always@ statement (Statement? I'm not really sure how to call it). I don't care if it is synthesizable. I just feel that I'm missing something.

Here is the code:

 module Stack(
 // Buses
 inout [12:0] BUS_Stack, // Bus used to exchange data between Stack and PC
 // Inputs
 input logic WE_Stack, // Write Enable. WE = 1 Stack sends data to PC
 input logic RE_Stack // Read Enable. RE = 1 Receives data from PC
 );
 // Internal variables
 integer i; // Variable used for "for loops"
 reg [12:0] Stack [0:7]; // Stack matrix. A registry is used for it to have "memory"
 logic [12:0] Data_To_PC; // Internal variable that manages the writing process to BUS_Stack
 parameter Height = 7; // Constant for the number of layers that the stack has. Given in (N-1) bits
 // The bus between PC and Stack is set to Z when WE_Stack = 0;
 assign BUS_Stack = (WE_Stack && !RE_Stack) ? Data_To_PC : 13'bz;
 always @(BUS_Stack or WE_Stack == 1'b1 or RE_Stack)
 begin
 // Receive data from PC
 if (!WE_Stack && RE_Stack)
 begin
 // Downward PUSH to all elements in the Stack register
 for (i = Height; i > 0 ; i = i - 1) Stack [i][12:0] = Stack [i-1][12:0];
 // First Stack address <- Bus
 Stack [0][12:0] = BUS_Stack;
 end
 // Send data to PC
 else if (WE_Stack && !RE_Stack)
 begin
 // Stack's first row is asigned to the Bus
 Datos_A_PC = Stack [0][12:0];
 // Upwards PUSH to all elements inside the stack register
 for (i = 0; i < Height ; i = i + 1) Stack [i][12:0] = Stack [i+1][12:0];
 Stack[Height][12:0] = 13'bx;
 end
 end
endmodule

Here is the testbench I'm using:

//----------------------------TESTBENCH--------------------------------
module testbench();
 // Inputs and Outputs
 logic WE_Stack, RE_Stack;
 logic [12:0] PC;
 wire [12:0] BUS_Stack;
 // Connection to module
 Stack STK (.WE_Stack(WE_Stack), .BUS_Stack(BUS_Stack), .RE_Stack(RE_Stack));
 // Assign statement used to simulate the Stack bus receiving data
 assign BUS_Stack = (!WE_Stack && RE_Stack) ? PC : 13'bz;
 initial
 begin
 $monitor("WE_Stack: %b \t RE_Stack: %b", WE_Stack, RE_Stack);
 #1 WE_Stack = 0; RE_Stack = 1;
 #1 PC = 13'd7;
 #1 PC = 13'd21;
 #1 PC = 13'd1;
 #1 PC = 13'd144;
 #1 PC = 13'd5;
 #3 WE_Stack = 1; RE_Stack = 0;
 #1 WE_Stack = 1; RE_Stack = 1;
 #1 WE_Stack = 1; RE_Stack = 0;
 #1 WE_Stack = 0; RE_Stack = 0;
 #1 PC = 13'd4;
 #1 PC = 13'd68;
 end
 initial
 begin
 #120 $finish;
 $dumpfile("dump.vcd");
 $dumpvars(1);
 end
endmodule

The problem appears after the line

#3 WE_Stack = 1; RE_Stack = 0;

The program is supposed to write to PC only once, but when simulated, it produces about 7 write operations to the PC.

asked May 20, 2018 at 7:09
\$\endgroup\$
6
  • 1
    \$\begingroup\$ Computers normally work using a clock. I do not see a clock anywhere. I suggest you have a look at some existing Verilog code. \$\endgroup\$ Commented May 20, 2018 at 7:35
  • \$\begingroup\$ Yeah... I tried to structure this as a block of combinational logic. I'm experimenting a bit with that, but still, my problem is that I think this should produce the required behaviour \$\endgroup\$ Commented May 20, 2018 at 7:48
  • \$\begingroup\$ I suspect it's your use of always @(... WE_Stack == 1'b1). The always block acts when any of it's inputs changes, but not to a specific value. Add the check inside the always block \$\endgroup\$ Commented May 20, 2018 at 8:14
  • \$\begingroup\$ I tried changing it, but to no avail. Any comments about the if statements? At least I know the for loops are working correctly \$\endgroup\$ Commented May 20, 2018 at 8:22
  • \$\begingroup\$ "I tried to structure this as a block of combinational logic" I have no idea what you are trying to build but normally a stack is a structure with a memory remembering past states. You can not build a memory from combinatorial logic. You need register or latches. The latter can be made with conditional statements but they do not official count as 'combinatorial'. Also latches are very much frowned up and should not be used except in extreme rare cases. \$\endgroup\$ Commented May 20, 2018 at 10:34

2 Answers 2

1
\$\begingroup\$

You aren't clocking the stack. That means that every simulation instant that the always block is triggered will cause a write. You are triggering the always whenever write is high, and that occurs for 3 time units, so I'd expect that statement to cause 3 writes. I don't know why you see 7, but more than 1 makes sense.

It's almost always better to use always @* instead of an old-fashioned sensitivity list.

Try putting a semicolon after the pound delays. I forget what a pound delays on the lhs of an assignment does.

answered May 20, 2018 at 15:19
\$\endgroup\$
1
\$\begingroup\$

Thanks for the help everyone. After a little debbugging i found out that the bit of code causing all the trouble was the "assign". The assign statement updates as soon as the for loop ends. So, if a write to the BUS is registered, the program exits the for loop but quickly re-enters it after the BUS is updated with data. The program becomes an endless cycle in which the for loop changes the data in the BUS and because the BUS is changed it executes itself all over again.

answered May 26, 2018 at 2:07
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.