CodiodeCodiode
Home
Problem Solving
Skill Tracks
My Assignments
Contests
Leaderboard
Community
Settings
Codiode/Problems/Memory Design

Stack Overflow and Underflow Protection

MediumVerilog / SystemVerilogBuild

Hardware accelerators and embedded processors rely on stacks to manage local variables, state contexts, and return addresses. A hardware stack must protect its contents from invalid operations; pushing to a full stack destroys valid data, while popping from an empty stack returns undefined garbage.

The safe_stack module maintains an internal 4-deep by 8-bit memory array and a stack pointer. It processes push and pop commands to store and retrieve data. When a push is requested but the stack is at maximum capacity, the module ignores the write and asserts an overflow flag. When a pop is requested but the stack contains no data, the module ignores the read and asserts an underflow flag. Simultaneous push and pop requests cancel each other out, resulting in no memory changes and no error flags.

Timing and Reset Rules

  • Clock edge: posedge clk
  • Reset type: Asynchronous active-low rst_n
  • Reset state: empty=1, full=0, overflow=0, underflow=0, rdata=8'h00. The internal pointer resets to 0.
  • Priority rules: If push and pop are asserted simultaneously, they cancel out. The pointer remains unchanged, memory is not written, and no error flags assert. An active rst_n takes priority over any memory operation.
  • Registered outputs: overflow and underflow are registered and assert for exactly one clock cycle immediately following the invalid request. rdata is registered and updates on the clock edge of a valid pop operation.

Worked Trace

Cycle 1: rst_n=0 → empty=1, full=0, overflow=0, underflow=0, rdata=8'h00 Cycle 2: rst_n=1, pop=1 → empty=1, underflow=0 (Invalid pop requested) Cycle 3: push=1, wdata=8'hAA → empty=0, underflow=1 (Underflow asserts for 1 cycle) Cycle 4: push=1, wdata=8'hBB → empty=0, full=0, underflow=0 Cycle 5: push=1, wdata=8'hCC → empty=0, full=0 Cycle 6: push=1, wdata=8'hDD → empty=0, full=1 (Stack is now full) Cycle 7: push=1, wdata=8'hEE → empty=0, full=1, overflow=0 (Invalid push requested) Cycle 8: pop=1 → empty=0, full=0, overflow=1, rdata=8'h00 (Overflow asserts for 1 cycle, valid pop requested) Cycle 9: push=0, pop=0 → empty=0, full=0, overflow=0, rdata=8'hDD (rdata updates from pop)

{ "signal": [
  { "name": "clk",       "wave": "p........" },
  { "name": "rst_n",     "wave": "01......." },
  { "name": "push",      "wave": "001111100" },
  { "name": "pop",       "wave": "010000010" },
  { "name": "wdata",     "wave": "x.====x..", "data": ["AA", "BB", "CC", "DD", "EE"] },
  {},
  { "name": "empty",     "wave": "1.0......" },
  { "name": "full",      "wave": "0.....1.0" },
  { "name": "overflow",  "wave": "0......10" },
  { "name": "underflow", "wave": "0.10....." },
  { "name": "rdata",     "wave": "2.......2", "data": ["00", "DD"] }
], "head": { "text": "Underflow and overflow flag generation with registered read data." } }

Port Table

| Signal | Direction | Width | Description | |--------|-----------|-------|-------------| | clk | input | 1 | Positive-edge triggered clock | | rst_n | input | 1 | Asynchronous active-low reset | | push | input | 1 | Push command; writes wdata to stack if not full | | pop | input | 1 | Pop command; reads top of stack to rdata if not empty | | wdata | input | 8 | Data to be pushed onto the stack | | rdata | output | 8 | Data popped from the stack; updates on valid pop; resets to 0 | | full | output | 1 | Asserted when stack contains exactly 4 elements | | empty | output | 1 | Asserted when stack contains 0 elements | | overflow | output | 1 | Registered flag; asserts for 1 cycle after a push to a full stack | | underflow | output | 1 | Registered flag; asserts for 1 cycle after a pop from an empty stack |

Constraints

  • Internal memory must be exactly 4 entries deep and 8 bits wide.
  • overflow and underflow must be exactly one clock cycle wide.
  • rdata must hold its value until the next valid pop or a reset.
  • Simultaneous push and pop must be treated as a no-op (no memory change, no pointer change, no error flags).

Topics

Sequential LogicState ManagementMemory Design

Solve this problem

Write the module in Verilog, SystemVerilog or VHDL. Your submission is compiled and simulated against a real testbench — you get the waveform back, not a stored answer.

This problem is part of Codiode Pro. The statement above is free to read.

Sign in to solveSee what Pro unlocks

The circuit builder and code editor need a desktop screen. On a phone, read the problem here and open it on a laptop to solve.

Related problems

  • Shift Register Based FIFOMedium
  • Asymmetric Data Width FIFOHard
  • True Dual Port RAM 2RWHard
  • Circular Buffer with OverwriteMedium
  • Synchronous Single Port RAMEasy
  • Circular Buffer Pointer MathMedium
  • Combinational ROM InitializationEasy
  • Read First Single Port RAMMedium

Browse all problems · Learning tracks