BMOW title
Floppy Emu banner

Success?

I think I’ve succeeded at cramming a decently useful CPU into this 128 macrocell device! I threw away my first design and started over from scratch, abandoning almost all the 6502-related elements, and working closer to a minimal instruction set design. I also changed the Verilog structure to explicitly specify the internal datapaths between CPU registers, rather than the more behavior-oriented design I tried originally.

The major caveat is that none of this is tested it yet. No testing whatsoever. It’s virtually certain that the design contains many mistakes, some of which may cause it to fit into fewer macrocells than it would otherwise. As of now, the design occupies 121 of 128 macrocells. Due to routability contraints, however, I can’t really make use of the last seven.

My primary goals were to making a working 8-bit CPU, with a stack, index register, and indexed addressing mode. I’ve accomplished that, but a lot of other nice stuff had to be tossed out. Here are the features that the CPLD CPU supports, and doesn’t support:

Addressing Modes

Supported: immediate, absolute, absolute with index
Not supported: indirect, indirect with index, read-modify-write

Indirect addressing would be nice, but I’m not going to lose sleep over its absence. Self-modifying code can be used as a sort of poor-man’s indirect addressing where needed.

Program Flow

Supported: jump, branch if carry set, branch if zero flag set, call, return
Not Supported: indirect jump, branch if carry not set, branch if zero flag not set, negative flag, overflow flag

The overflow flag is rarely used, and a subroutine can be written to do the same thing if needed. The negative flag would be more useful, but not critical. Branch on flag not set would be very useful, but can always be avoided by modifying the branch test.

Math and Logical Operations

Supported: add A, sub A, compare A, nor A, load/store/push/pull A, load/store/push/pull X, increment/decrement X
Not supported: add/subtract with carry-in, compare X, and, or, xor, shift, rotate, test, register-to-register transfers, direct set/clear of flags

I decided the lack of a carry-in wasn’t a big deal. You can always test the carry out, and manually add 1 to the next stage of a multi-byte addition or subtraction.

Having NOR as the only logical operation seems strange, but is surprisingly powerful:

not A = A nor 0
A or B = (A nor B) nor 0
A and B = (A nor 0) nor (B nor 0)

For the common task of AND-ing a number with an immediate value to check if a particular bit is set, this can be done with NOR in a single step if you use the bitwise-complement of the immediate value, and also reverse the sense of the test:

NOR #$7F
BZ highBitIsOne

Other missing operations can be easily simulated:

clear carry = ADD #0
set carry = SUB #0
left shift = STA temp, ADD temp
transfer A to X = PHA, PLX
transfer X to A = PHX, PLA

Of all the missing functions, the only ones I really wish I could squeeze in are the branch if not set, and compare X. Not having compare X means that any loop over X has to start at some number and go down to zero, instead of start at zero and go up. Most of the time that’s probably OK. In an emergency, compare X could be simulated as:

PHA, PHX, PLA, CMP, PLA

But that’s pretty ugly, and it also assumes that PLA doesn’t modify the flags (still undecided).

I will post the Verilog code once it’s tidied up a bit more, and I’m confident I’ve squeezed it as much as possible.

Be the first to comment! 

No comments yet. Be the first.

Leave a reply. For customer support issues, please use the Customer Support link instead of writing comments.