The KK Memory Space and Bank Registers
The KimKlone adds six new registers to the 6502 programming model, and four of them — Bank Registers K0, K1, K2 and K3 — support the KK's 16 megabyte addressing capability. The bank registers reside in a register file built with 74HC670's. An extra read port from the register file is what drives the high 8 bits of the 24-bit address sent to memory. The high 8 address lines coordinate exactly with the low 16 address lines supplied straight from the 65C02.
One Bank Register at a time is selected to drive the upper address bus, and this selection can be updated on any bus cycle. Of course the low address bits (from the 65C02) also update on a cycle-by-cycle basis, and the combined result is a complete 24-bit address for every cycle. It's important to be clear that during execution of a single instruction two different Bank Registers may be sequentially selected (eg: for code access and for data access).
The programmer sees memory as a linear 16 MB space composed of 256 "banks," each of which is 64KB in size. Because there are four Bank Registers, as many as four different banks can be made available simultaneously. Any Bank Register can indicate any of the 256 banks in the overall 16MB map. Each Bank Register typically gets used in an associated role; eg, for fetching code or accessing data.
Loading the Bank Registers
Before the Bank Registers can be used to generate 24-bit addresses there needs to be some way to load the Bank Registers themselves. Several of the 65C02's previously undefined opcodes are appropriated for this purpose. In fact, there are several addressing modes by which Bank Registers can be loaded from memory. Bank Registers may also be pushed/popped to and from the stack.
The register I call K0 is what drives the high address lines during all code fetch cycles. K0 is also the default for data accesses. Obviously, then, it's the K0 that almost always drives the high address lines. However, K0 relenquishes control when a "Far" access is specified. K0 is also ignored during bus cycles for stack and Zero-Page accesses. These go to bank 00h, regardless of the Bank Registers.
K1 and K2
To reach for data independently of the K0, a program can use "Far" memory operations. These are just the usual 65xx reads and writes, such as LDA or STX, but with an added specification (explained below) which calls for K1 or K2. Read-Modify-Write operations such as INC and DEC can also be Far.
As always, microcode tracks the sequence. On the exact cycle when the 65C02 will read or write the data, K1 or K2 will jump in for the data access only and temporarily preempt the K0 on the high address lines. Then K0 immediately resumes control and the subsequent instruction bytes are fetched as if nothing had happened. Later we'll see why it's pivotal that a single instruction can activate the alternate bank, do the access, then put things back as they were.
There are two ways to specify a Far memory operation. The general means (and the most flexible) is to use either the K1 prefix or the K2 prefix, known by the mnemonics K1_ and K2_. A prefix is a one-byte code which executes in one cycle. It is placed ahead of a standard 65xx op-code; together the prefix and its target perform as a single instruction. In other words the prefix is a modifier. Prefixes are applicable to nearly all the 65C02's instructions and addressing modes; basically "anything goes" that's reasonable. Only a few questionable operations (eg: LDA Immediate Far) aren't implemented.
The other type of Far memory specification does not use a prefix. Instead, the prefix and the target op-code are both represented by a single, "2 in 1" op-code byte, thus eliminating one byte and one cycle of overhead. Due to limitations in op-code space, only a handful of instructions are available using this type of specification. These include high-utility operations such as LDA and STA using Absolute and Indirect-Y address modes.
The last of the new 8-bit registers, and the alter-ego of K0, is K3. K3 is used when the program needs to make a Far Jump or Far Call to a new location. Here's the drill: First, K3 is loaded with the high eight bits of the destination address; then a JMP_K3 or JSR_K3 instruction is executed. At the appropriate instant K0 and K3 undergo Register Renaming, in effect exchanging contents with one another.
Code at the new location may discard the value in K3 (the former K0) or preserve and make use of it — to reach back to the calling code for an in-line parameter, perhaps, or perhaps to effect a speedy return using RTS_K3. (Of course if you wish to nest the far calls it'll be necessary to push and later pop K3.)
K3 has one final trick
up its sleeve. Besides being your ticket to Far jumping, it has its own
prefix instruction and can be used in the same way as K1 and K2.
The next section presents
an overview of the memory addressing
|< Previous Page KK Index Next Page >|
Servicing the unserviceable