For a long time I've thought that designing a CPU would be quite interesting. Every so often I try, usually with some lofty aim to make an architecture which is really elegant. So I spend ages designing it on paper, and eventually give up because I can't quite get it to work within those parameters.
So this time I decided the only requirements would be that it would be a largely 8 bit processor, and it would work, even if it wasn't particularly nice to use, or elegant, or efficient.
So this is what I ended up with. (As I'm a Z80 person, there are a few similarities with that CPU).
An 8 bit data bus and a 16 bit address bus – but I'm tempted to include banked memory later. Memory mapped IO only at the moment. As yet, no interrupt handling, but I think that will have to be added at some point. There are control lines to indicate whether a memory operation is for instructions, data or the stack, so in theory each of these could be in separate, isolated areas of memory.
8 8-bit registers, r0..r7, which can also be used as 4 16-bit registers, w0..w3. Separate 16-bit programme counter and stack pointer. A separate flags register with four flags: zero, carry, overflow and negative.
The instruction set is comprised of these instructions:
- nop
- ld r0,f
- ld r,r0
- ccf
- scf
- jp/call w3
- jp/call <nnnn>
- jr ±<nn>
- ret
- add/adc/sub/sbc/and/or/xor/cp r0,<nn>
- inc/dec/not/neg r0
- jp/call <c>,<nnnn>
- jr <c>,±<nn>
- ret <c>
- add/adc/sub/sbc/and/or/xor/cp r0,r<r>
- ld r<r>,<nn>
- ld r0,(<nnnn>)
- ld r0,r<s>
- sll/srl/sla/sra/rol/ror/rcl/rcr r0
- ld (<nnnn>),r0
- ld r<s>,r0
- ld r0,(w<w>+<nn>)
- ld (w<w>+<nn>),r0
- ld r0,(w<w>)
- ld (w<w>),r0
- ld w<w>,<nnnn>
- ld sp,w<w>
- ld w<w>,sp
- push/pop/inc/dec w<w>
Where:
- r<r> = r0..r7
- r<s> = r1..r7
- w<w> = w0..w3
- <c> = z/nz/c/nc/o/no/n/nn
- <nn> = 8 bit number
- <nnnn> = 16 bit number
This leaves 54 opcodes currently unused, so there's plenty of room for expansion at the moment.
r0 is used as the accumulator. You can jump/call using the w3 register or a direct value only — there's no ability to use the other w registers for jumps/calls.
Unlike on the Z80, the 16 bit inc and dec instructions also affect the zero flag. But we have no instruction for move data directly between registers — everything currently has to go via r0, which is a bit of a pain. You can also only load values from memory into r0.
I'd already written a Z80 assembler in JavaScript a few years ago (https://github.com/jamesots/maz), so I've been able to modify it to compile AUG1 code instead. I haven't added any way to utilise the memory regions, and if I added banked memory I'd have to think of some way to handle that in a compiler too. I'd probably need some kind of executable format which would include instructions for where to load data – at the moment I'm just loading a contiguous block of data at 0. (Well, compiling it into the FPGA bitstream currently.)
The VHDL implementation is currently very crude, and most instructions take quite a few clock cycles to complete. However, since my FPGA board runs at 125MHz it's still much faster than it needs to be.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.