Close

OPC5 - pi and enhancements

A project log for OPC-5 - a CPU for FPGA, in one page

A 16-bit CPU, with 16 registers, described in 66 lines of code - with HDL, emulators and a macro assembler.

ed-sEd S 07/16/2017 at 18:480 Comments

Yes, we can compute digits of pi! See below. First, a few enhancements:

We've had three predicate bits for a while now, and we've used them to offer predication on two processor status bits: the carry bit, and the zero bit, and to have predication on both bit is set and bit is clear. We've decided to rejig that: add a sign bit too, and remove the 'combination' predication. So now, any instruction can be predicated on any one of the three bits, in either sense, or be unconditional, or not execute.

After some to-and-fro to decide exactly how it should work, we've also added maskable interrupts and software interrupts, and a return-from-interrupt instruction. We keep discussing the possibilities of shadow registers, register windows, or multiple register banks, but at present we still just have the one logical file of 16 registers. (In the implementation, neither r0 or r15 is ever read, one because it must always readback as zero, and the other because it must read as the PC, which needs to be a register of its own to allow for increment.) Oh, we do have shadows for the PC and PSR, so the interrupt state can return to the main code without ever using complex push or pop operations, which this machine doesn't do.)

Now, for pi, we started with a 65Org16 program which was itself a quick port of the 65816 pi spigot written by Bruce Clark. We ported it to OPC5ls more or less mechanically - with the main difference that we could use registers instead of memory, and didn't need to juggle values. Here's a typical code fragment:

div:                   # uses y as loop counter
mov r10, r1 # sta r mov r3, r0, 16 # ldy #16
mov r1, r0, 0 # lda #0
add r11, r11 # asl q
d1: adc r1, r1 # rol
cmp r1, r10 # cmp r
nc.mov pc, r0, d2 # bcc d2
sbc r1, r10 # sbc r
d2: adc r11, r11 # rol
mov r3, r3, -1 # dey, don't affect the carry flag
nz.mov pc, r0, d1 # bne d1
RTS()

Interestingly, where the 6502 takes 72000 cycles to compute 6 digits with this approach, our transliterated approach takes 85000 - but recoding into more idiomatic code for our OPC5ls machine gets it down to just 40000 cycles. That's nice! In fact even with two-cycle memory, because there are cycles which don't access memory, it only takes 65000 cycles, so that's a hopeful indicator should we fit an 8-bit memory system to this 16-bit CPU.

Discussions