1

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.

Eddysanoli
  • 121
  • 1
  • 6
  • 1
    Computers normally work using a clock. I do not see a clock anywhere. I suggest you have a look at some existing Verilog code. – Oldfart May 20 '18 at 07:35
  • 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 – Eddysanoli May 20 '18 at 07:48
  • 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 – awjlogan May 20 '18 at 08:14
  • I tried changing it, but to no avail. Any comments about the if statements? At least I know the for loops are working correctly – Eddysanoli May 20 '18 at 08:22
  • *"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. – Oldfart May 20 '18 at 10:34
  • Sorry, I meant asynchronous – Eddysanoli May 26 '18 at 01:58

2 Answers2

1

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.

Matt
  • 606
  • 1
  • 4
  • 6
1

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.

Eddysanoli
  • 121
  • 1
  • 6