Close

RPN calculator

A project log for Bit-serial CPU based on crossbar switch

256 switches and few shift registers to implement a working 16 or 32-bit integer arithmetic calculator (+, -, *, /, isqrt, BCD / bin conv..)

zpekiczpekic 04/11/2022 at 03:530 Comments

The RPN calculator is an incarnation of the serial cross-bar switch CPU. Its structure is essentially the same like the simplified model:

but will following changes:

The system includes a component that displays the values of RPN calculator registers and flags for debugging and visualization:

16-bit mode, running at 64Hz frequency, trace input and trace output enabled (matrix is for "rotate registers" instruction):

32-bit mode, running at 1.6MHz, with no tracing input or output (matrix shows digit entry instruction)

As far as operations supported they can be seen in the implementation VHDL of the system:

-----------------------------------------------------------------
-- Calculator commands, each is a single ASCII char
-----------------------------------------------------------------
type table_32x8 is array(0 to 31) of std_logic_vector(7 downto 0);
constant kypd2ascii: table_32x8 := (
	-- no "shift", entering hex digits into TOS
	c('0'),
	c('1'),
	c('2'),
	c('3'),
	c('4'),
	c('5'),
	c('6'),
	c('7'),
	c('8'),
	c('9'),
	c('A'),
	c('B'),
	c('C'),
	c('D'),
	c('E'),
	c('F'),
	-- with "shift", entering a command (TOS = R0, top of stack, NOS = R1, next on stack)
	c('Z'),	-- 0 == TOS <= 0, reset flags, clear error
	c('U'),	-- 1 == dUp(licate) NOS <= TOS, push all regs down, R7 lost)
	c('$'),	-- 2 == BCD to binary (unsigned) (TOS changes, R7 destroyed)
	c('#'),	-- 3 == binary to BCD (unsigned) (TOS changes, R7 destroyed)
	c('R'),	-- 4 == rotate registers (R7 <= TOS, ... TOS <= NOS etc.)
	c('<'),	-- 5 == shift (logical) TOS up
	c('>'),	-- 6 == shift (logical) TOS down
	c('N'),	-- 7 == nuke all (all registers <= 0), reset flags, clear error
	c('Q'),	-- 8 == integer square root (TOS assumed positive / unsigned)
	X"00",	-- 9 == not used
	c('+'),	-- A == add (signed) (TOS <= TOS + NOS, pop regs, R7 <= 0)
	c('-'),	-- B == subtract (signed) (TOS <= TOS - NOS, pop regs, R7 <= 0)
	c('*'),	-- C == multiply (unsigned) (TOS/NOS <= TOS * NOS, R7 lost)
	c('/'),	-- D == divide	(unsigned TOS is div, NOS is mod after TOS/NOS, R7 lost)
	X"0D",	-- E == enter (TOS = 0, push other regs down, R7 lost)
	c('S')  -- F == swap (TOS <=> NOS)
);

These commands can be entered either through HEXPAD on the Anvyl board, or through serial UART (connected to terminal emulator app on the host PC, such as TeraTerm for example):

key <= rx_ready or kypd_keypressed;
input_clear <= '1' when (hc_status = status_done) else reset;

on_key: process(key, kypd_hex, kypd_shift, rx_char, input_clear)
begin
    if (input_clear = '1') then
        input <= X"00";
    else
        if (rising_edge(key)) then
            if (kypd_keypressed = '1') then
                input <= kypd2ascii(to_integer(unsigned(kypd_shift & kypd_hex)));
            else
                input <= rx_char;
            end if;
        end if;
    end if;
end process;

Given that a subset of ASCII 8-bit chars represent 8-bit instructions for the RPN calculator (CPU), entering a stream of letters results in expected calculations. For example:

Discussions