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:
- switch matrix is 16*16, which then requires 2 MT8816 ICs on the breadboard
- there are 8 general purpose registers (0 - 7) that can be viewed as a stack (TopOfStack = R0, NextOnStack = R1 etc.), or random access
- there are 2 special registers that can be loaded with parallel values (0xC and 0xD), they are used for constants
- all registers can be 16 or 32 bit wide - calculations can be also 16 or 32 (e.g. it is possible to multiply 2 32-bit integers for 64-bit result)
- 2-input AND is also added to the ALU
- DELAY and CARRY flags are present, but new ones added: ADJUST (for decimal adjust operations) and ZERO - this is actually 16 flags, one per row, meaning each register has own zero flag (only TOS and NOS are used)
- 2 rows (0xE, 0xF) and 2 columns (0xA, 0xB) are not used, so either more operations and/or registers could be added
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:
- Entering 99999999 into TOS
- Converting from BCD to binary
- Enter to clear TOS
- Enter 3
- Divide
- Convert from binary to BCD for correct result
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.