I thought I would start to describe various aspects of the design and then ask questions as they come up. I’m thinking this combined approach might be valuable to other hardware newbs like myself. My journey here started nearly at ground zero so it’s baby steps all the way. For folks that know what they are doing: please bare with us and feel free to comment on the good and the ugly. I fully expect that there will be significant shortcomings to address as we go.
Now, given the objective is to learn, I set myself some design guidlines at the start:
1) Don’t use a chip unless I understand what is going on inside – which pretty much restricts me to simple ICs (muxes, decoders, latches, etc.). Keep away from higher-density ICs like 74181 sor 74182s,
2) Do as much as possible in discrete logic even at the cost of slower performance (i.e. no lookup ROMs for the ALU, keep control ROMs to a minimum),
3) The result needs to be a fully functional processor accurate enough to be genuingly called a 6502. The practical “acid test” is to be able to run a game I wrote for the C64 back in 1983 (amazingly, I was able to download a copy from the web 30 years after I had written it! I even found an original, unopened shrink-wrap copy in an eBay store – cassette and all. Wow).
Before we get going, I’ll just mention a couple of resources I found useful as a complete neophyte (I certainly needed “paint by numbers” at the start). For digital logic basics, try
http://www.robotbrigade.com/digitalLogic.php. For CPU design basics, Donn Stewart’s
http://www.cpuville.com is great.
Ok, first up, a block diagram:
Attachment:
6502 Block Diagram.png [ 104.69 KiB | Viewed 21078 times ]
Busses are on the sides, 8-bit wide registers in the middle. The W Bus on the left is used to write to registers and the R bus on the right to read from them. Outputs from registers to the “R” bus are tri-state (74HC574s with Output Enable signals). For a memory write, data flows from a register to the R Bus and from there to the external Data Bus on its way to memory. Similarly, reads go from memory through the Data Bus and W Bus to a destination register. Transfers between registers travel through the ALU to get from R Bus to W Bus. The ALU takes its second operand from memory through the B register (the B register is required only to spread the long journey from memory through ALU over two cycles).
For addressing, PCL/PCH together make up the program counter. Similarly, DPL/DPH make up the “Data Pointer” which is used to resolve target addresses. Both PC and DP can be output to the internal Address High (ADH) and Address Low (ADL) busses, and from there to the external Address Bus. The stack pointer SP can be output to ADL and is paired with an “$01” in ADH for Page 1 Stack Addressing. The ADH can also generate “$00” for Zero-page addressing and “$FF” to fetch interrupt vectors high in memory. Similarly, the box labelled “$FA, $FC, $FE, $FF” refers to contants that can be placed on the R Bus and loaded into DPL as the low-byte of interrupt vector addresses. The “$FF” constant is also used to initialize the SP register on Reset. Finally, the T register can be used directly as the low-byte of a target address, which saves a cycle during Indirect Addressing operations.
The INC16 circuit is capable of 16-bit increment/decrement operations in parallel with the ALU. It takes its input from ADL/ADH and is used to increment PC, as wel as to manipulate SP for stack push and pull operations. Another parallel data path allows the DPH and I registers to be loaded directly from memory (in addition to the normal path throught the W Bus). Both these “parallel” capabilities were necessary only to try to match 6502 cycle counts on specific instructions.
To illustrate how I'm using this machinery, below is the microcode for an LDA absolute instruction:
(“*” denotes dereferincing an address, “+=” denotes an INC16 operation, “:=” denotes a data transfer)
I := *PC; PC += 1 : Fetch Opcode : Output enable the PC onto the address bus. Load IR from the W Bus. Load PC from the INC16 S Bus.
DPl := *PC; PC += 1 : Fetch ADL : Output enable the PC onto the address bus. Load DPL from the W Bus. Load PC from the INC16 S Bus.
DPh := *PC; PC += 1 : Fetch ADH : Output enable the PC onto the address bus. Load DPH from the W Bus. Load PC from the INC16 S Bus.
A := *DP; SETF(NZ); END : Load A : Output enable DP on to the address bus. Load A from the W Bus. Set N and Z flags. End the sequence.
Now for some questions:
• 6502 block diagrams depict bi-directional connections from registers to various internal busses. Although I get the advantages of a bi-directional bus, having two independant buses allows me to read from and write to a given register in the same cycle (i.e., when incrementing a register, for example). Does the 6502 have bi-directional buses internally or is it just a short-hand? If bi-directional, how are register increments accomplished in one cycle?
• I often see a Memory Address Register (MAR) connnected directly to the address bus in various CPU designs. I have to confess I don’t really understand why they are needed. So far as I can tell, the extra cycle(s) required to move an address to the MAR can be avoided by using tri-state buffers on the outputs of various registers and using them directly. I have to believe I am missing something here. Why move the contents of the PC to a MAR when one can output-enable the PC register directly onto the address bus?
• I could think of no way to generate constants on the R Bus other than by wiring specific values behind a dedicated tri-state buffer (74HC541). Seems like a heavy handed approach. How do folks normally accomplish this?
• I understand that it can be fatal to have IC outputs connected together while not in a high impedance state. Control logic can regulate this on a bus but how does one avoid the inevitable collisions at the point of transition – when one register is “coming up” while another is “going down”?
• Does anything here look like it's going to land me in hot water come implementation?
Ok, that's it for now. Thanks in advance for your comments and thoughts.
Best,
Drass.