/* stack.c -- F18 circular hardware stacks. * * The two decompositions (T/S + 8-ring, R + 8-ring) are exactly equivalent to * flat circular buffers of depth 10 and 9 respectively. The argument, since * the ISA is specified in terms of the decomposition and the differential * test in tests/test_stack.c is written against the flat form: * * Data stack, 10 deep. Read the stack top to bottom as * * T, S, ring[(head-1) mod 8], ring[(head-2) mod 8], ..., ring[head mod 8] * * -- that is, ring[(head-1) mod 8] sits immediately below S, and head names * the oldest slot. push(x) does ring[head]=S; S=T; T=x; head=(head+1) mod 8, * which appends at the top and rotates the oldest entry into the ring. * pop() takes T, promotes S, and pulls ring[(head-1) mod 8] up into S while * stepping head back one -- so the element that was third becomes second and * the ring is re-seated one position earlier. That is a 10-slot circular * buffer whose slot 0 is T and slot 1 is S, and the head arithmetic is * bookkeeping for which ring slot is oldest. * * Return stack, 9 deep, same argument with one register instead of two: the * stack reads R, ring[(head-1) mod 8], ..., ring[head mod 8]. * * "No overflow or underflow; pushing past the bottom silently overwrites the * oldest entry" (D-2) is not an extra rule here -- it is what a fixed-depth * circular buffer with no bounds check does on its own, once the pointer is * allowed to wrap. Nothing below tests head against anything. */ #include "v4/stack.h" void v4_dstack_reset(v4_dstack *st) { st->t = 0; st->s = 0; st->head = 0; st->depth = 0; for (unsigned i = 0; i < V4_DATA_RING; i++) st->ring[i] = 0; v4_guard_fill(st->guard_head, V4_DATA_BOUND, V4_GUARD_PATTERN_HEAD); v4_guard_fill(st->guard_tail, V4_DATA_BOUND, V4_GUARD_PATTERN_TAIL); } int v4_dstack_guards_intact(const v4_dstack *st) { return v4_guard_intact(st->guard_head, V4_DATA_BOUND, V4_GUARD_PATTERN_HEAD) && v4_guard_intact(st->guard_tail, V4_DATA_BOUND, V4_GUARD_PATTERN_TAIL); } void v4_dstack_push(v4_dstack *st, v4_cell x) { st->ring[st->head] = st->s; st->s = st->t; st->t = x; st->head = (st->head + 1u) % V4_DATA_RING; if (st->depth < V4_DATA_DEPTH) st->depth++; } void v4_dstack_clear(v4_dstack *st) { st->depth = 0; } void v4_rstack_clear(v4_rstack *st) { st->depth = 0; } v4_cell v4_dstack_pop(v4_dstack *st) { v4_cell x = st->t; st->t = st->s; st->head = (st->head + V4_DATA_RING - 1u) % V4_DATA_RING; st->s = st->ring[st->head]; if (st->depth > 0) st->depth--; return x; } v4_cell v4_dstack_peek(const v4_dstack *st) { return st->t; } v4_cell v4_dstack_peek2(const v4_dstack *st) { return st->s; } void v4_rstack_reset(v4_rstack *st) { st->r = 0; st->head = 0; st->depth = 0; for (unsigned i = 0; i < V4_RET_RING; i++) st->ring[i] = 0; v4_guard_fill(st->guard_head, V4_RET_BOUND, V4_GUARD_PATTERN_HEAD); v4_guard_fill(st->guard_tail, V4_RET_BOUND, V4_GUARD_PATTERN_TAIL); } int v4_rstack_guards_intact(const v4_rstack *st) { return v4_guard_intact(st->guard_head, V4_RET_BOUND, V4_GUARD_PATTERN_HEAD) && v4_guard_intact(st->guard_tail, V4_RET_BOUND, V4_GUARD_PATTERN_TAIL); } void v4_rstack_push(v4_rstack *st, v4_cell x) { st->ring[st->head] = st->r; st->r = x; st->head = (st->head + 1u) % V4_RET_RING; if (st->depth < V4_RET_DEPTH) st->depth++; } v4_cell v4_rstack_pop(v4_rstack *st) { v4_cell x = st->r; st->head = (st->head + V4_RET_RING - 1u) % V4_RET_RING; st->r = st->ring[st->head]; if (st->depth > 0) st->depth--; return x; } v4_cell v4_rstack_peek(const v4_rstack *st) { return st->r; }