With hardware selection and fabrication method decisions out of the way, the next step was to establish a
memory map.
A computer's memory map is analogous to the floor plan of a building and always involves tradeoffs of one sort or another.
As POC V1 is a simple design, I devised a simple memory map that is characteristic of many 6502-based systems:
RAM $000000–$00CFFF (52 KB)
I/O $00D000–$00D7FF (2 KB)
Unused $00D800-$00DFFF (2 KB)
ROM $00E000–$00FFFF (8 KB)
The W65C816S is able to address far more RAM than its eight bit
cousins, up to 24 bits worth or 16 megabytes (MB).
However, the '816 has only 16 address bus lines,
A0-A15, just like its eight bit cousins, and multiplexes the
A16-A23 address bits on to the data bus (
D0-D7)
when the Ø2 clock is in the low part of its cycle.
Hence it is necessary to use additional hardware to take advantage of the extended addressing capability.
Aside from adding complexity, implementing 24 bit addressing causes circuit timing to become critical at high Ø2 clock
rates—achieving satisfactory results can be difficult with
discrete logic.
Keeping the simplicity requirement in mind, I decided to stick with 16
bit addressing and hence a 64 KB address space. I know 64 KB
doesn't sound like much in this day and age of servers with 64 gigabytes
of RAM. However, you'd be surprised how much can be packed into
that space with some adroit programming. Also, consider that the
first IBM PC only had 64 KB of memory.
In 6502-based designs, it is customary to place ROM at the top of the memory map because
following reset, that's where the MPU will go to in search of code to
execute, specifically the reset vector at
$00FFFC-$00FFFD. The '816 is no different in this respect. As it is desirable to maximize the amount of contiguous
RAM available for code and data, placing the I/O block
right below the ROM is also customary, although some designers deviate from this practice.
The result is the above map, which makes available 52K of contiguous RAM. This
memory map is established entirely by the use of basic logic gates (the 74AC
glue logic)—there are no
programmable logic devices involved.
A characteristic of the 6502
family is that it uses memory-mapped
input/output
(I/O), which simply means the MPU makes no distinction between
addressing memory and addressing I/O devices—also, there are no special
input/output instructions. This characteristic of the '816 means
that I/O decoding hardware is
required in all but the simplest of systems.
A customary choice
for
this task is the 74xx138 3-of-8
decoder (74AC138, in this case), which can work with up to eight
devices. In order to avoid having to use too many gates to address the I/O block,
I allocated one page (256 bytes) to each device. The unused address space following the I/O block
reflects this decision.
One of the sometimes-maddening limitations of the 6502 and its eight bit brethren is its fixed
hardware stack
location,
which tends to make things awkward for anyone attempting to design a
system that can run more that one process at a time. This
not-so-little annoyance was addressed in the '816 by giving it a 16 bit
stack
pointer, which allows the stack to be located anywhere in the range
$000000-
$00FFFF, a characteristic that also allows the MPU to function without having to account for the
A16-A23 address bus component.
In my design, I took advantage of the 16 bit stack pointer and initially placed the top of the stack at
$00CFFF,
as that is as high in RAM as it could go (the stack, of course, expands downward).
I later moved the top of the stack down to
$00CDFF so I could relocate the TIA-232
buffers
to better use contiguous RAM.
In addition to its 16 bit stack pointer, the '816 has another handy feature,
which the ability to locate page zero anywhere in the first 64K of memory.
For those who aren't familiar with the 6502 family, page zero (or zero page or direct page,
often abbreviated to ZP), the first 256 bytes in memory, is significant because the MPU doesn't have to form a full
16 or 24 bit address when reading or writing on a ZP location—the most
significant byte(s) of the address is(are) implied.
Hence clock cycles are conserved and most instructions that act on ZP addresses execute,
on average, 25 to 30 percent faster than those acting on absolute addresses (absolute
meaning any address that cannot be expressed in eight bits).
As only one byte is used to address a ZP location, no more
than 256 such locations are possible, and some machine instructions
will only work on ZP locations. Unsuprisingly, contention
for ZP space is common in 6502 systems.
For example, the
Commodore 64's kernel and BASIC interpreter together used 251 of
the available ZP locations, leaving a mere five for the hapless programmer.
The '816 addresses(!) this problem by allowing the programmer to locate ZP anywhere
s/he desires within the range
$000000-
$00FFFF.
Hence functions (subroutines) can be allocated an ephemeral ZP (and an ephemeral stack
as well), thus encouraging more use of the fast ZP instructions.
Be all that as it may, I was more interested in simplicity, so I decided to leave ZP where it
normally would appear following reset, which is in the range
$00000-$0000FF.
I could always relocate it under program control if I later decided doing so was advantageous.
As I mentioned above, I/O decoding is performed by a 74AC138
, which is able to support up to eight I/O devices. However, only two were wired
into the initial design:
DUART: $00D000
RTC: $00D100
My original plan was to use POC V1 only to develop firmware and a
machine language monitor, as well as debug hardware-level issues.
However, after getting POC V1 up and running, I decided to work out a
way to add a SCSI-SE (single-ended) port to it, which I'll describe on
a later page.
Hence I later modified V1 to make additional I/O addresses available to the SCSI
hardware.
This arrangement, as well as the HBA's general design, will be discussed later on.
Previous Page Home Next Page