|
|
External Memory Map (Accessed with MOVX)
Status Codes
- Working - A reasonable number of tests have been done and this
feature appears to be working properly.
- Looking Good... - Working in initial tests, but not enough tests have
been done to know if it really works well.
- Untested - It's implemented and ought to work, but no tests
have been done yet to see if it's actually working
- Unimplemented - Some piece of hardware is still missing to allow
this feature to work... but since it's on this list, at least some
of the hardware is in place.
- Missing - None of the hardware exists yet. These appear on a
list at the bottom, because their functionality is not yet well
defined enough to be added to the register list.
Address |
Allocation |
Description |
0x0000 - 0x4FFF |
Static |
Static variables (20k) available for the application level code |
0x5000 - 0x7FFF |
Dynamic |
Three pages (8k) of space available for the application to use
dynamic memory (mapping pages obtained from malloc_blocks ) |
0x8000 - 0x8FFF |
Static |
Variables for FAT32, IDE, Playback, Memory Manager |
0x9000 - 0x9FFF |
Dynamic |
Playback DMA buffer |
0xA000 - 0xAFFF |
Dynamic |
IDE DMA buffer |
0xB000 - 0xBFFF |
Dynamic |
FAT32 buffer |
0xC000 - 0xCFFF |
None |
Unused |
0xD000 - 0xDFFF |
Static |
FAT32 cached FAT sector list |
0xE000 - 0xEFFF |
Dynamic |
Memory manager buffer (typically maps blocks 0-31, which contain
allocation and usage data for all other blocks) |
Name |
Data Type* |
Address |
Status |
Description |
PAGE_0 |
memory |
0x0000 to 0x0FFF |
Working |
DRAM Memory, may be mapped to any 4k range within the SIMM |
PAGE_1 |
memory |
0x1000 to 0x1FFF |
Working |
DRAM Memory, may be mapped to any 4k range within the SIMM |
PAGE_2 |
memory |
0x2000 to 0x2FFF |
Working |
DRAM Memory, may be mapped to any 4k range within the SIMM |
PAGE_3 |
memory |
0x3000 to 0x3FFF |
Working |
DRAM Memory, may be mapped to any 4k range within the SIMM |
PAGE_4 |
memory |
0x4000 to 0x4FFF |
Working |
DRAM Memory, may be mapped to any 4k range within the SIMM |
PAGE_5 |
memory |
0x5000 to 0x5FFF |
Working |
DRAM Memory, may be mapped to any 4k range within the SIMM |
PAGE_6 |
memory |
0x6000 to 0x6FFF |
Working |
DRAM Memory, may be mapped to any 4k range within the SIMM |
PAGE_7 |
memory |
0x7000 to 0x7FFF |
Working |
DRAM Memory, may be mapped to any 4k range within the SIMM |
PAGE_8 |
memory |
0x8000 to 0x8FFF |
Working |
DRAM Memory, may be mapped to any 4k range within the SIMM
This page is reserved for misc static data structures used by
library routines. File descriptor tables, IDE and playback
pending request queues, etc.
|
PAGE_9 |
memory |
0x9000 to 0x9FFF |
Working |
DRAM Memory, may be mapped to any 4k range within the SIMM
This page is reserved for playback. The playback code maps the
currently playing block here, until the DMA transfer to the MP3
decoder is complete.
|
PAGE_A |
memory |
0xA000 to 0xAFFF |
Working |
DRAM Memory, may be mapped to any 4k range within the SIMM
This page is reserved for use by the the IDE driver. The IDE
driver maps blocks here for DMA transfers.
|
PAGE_B |
memory |
0xB000 to 0xBFFF |
Working |
DRAM Memory, may be mapped to any 4k range within the SIMM
This page is reserved for use by the the FAT32 filesystem.
Typically, the FAT32 code will map blocks containing FAT
sectors when tring to figure out what clusters compose a
file, and to copy the data from the cached clusters when
the application reads the file.
|
PAGE_C |
memory |
0xC000 to 0xCFFF |
Working |
DRAM Memory, may be mapped to any 4k range within the SIMM
This page isn't currently being used.
|
PAGE_D |
memory |
0xD000 to 0xDFFF |
Working |
DRAM Memory, may be mapped to any 4k range within the SIMM
This page is reserved for use by the FAT32 filesystem.
This page holds an array of block numbers which are being used
to cache FAT sector groups.
|
PAGE_E |
memory |
0xE000 to 0xEFFF |
Working |
DRAM Memory, may be mapped to any 4k range within the SIMM
This page is reserved for use by the memory manager (malloc, et all).
The memory manager will usually map one of the first 32 blocks,
which contain a linked list and misc data about all of the
4k blocks (16 bytes per block).
|
DRAM_PAGE_CFG |
16 bit INT (15) |
0xFF00 to 0xFF1D |
Working |
These fifteen integers control which of the 4k pages
of the DRAM is seen in each of the 4k pages in the
processor's 4k pages (PAGE_X above). Each of the
supported SIMM sizes provides the following blocks:
- 4 MByte SIMM
- 8 MByte SIMM
- 16 MByte SIMM
- 0 to 1023
- 2048 to 3071
- 4096 to 5119
- 6144 to 7167
- 32 MByte SIMM
4 and 8 meg SIMM sizes will repeat (duplicate) 4 times though
the remaining blocks. A 4 meg SIMM, for example, would appear
to have memory at block 2048, but writing there would overwrite
the contents of block 0.
|
DMA_IDE_DEST |
16 bit INT |
0xFF22 to 0xFF23 |
Working |
Destination address for DMA transfer from the IDE
interface to the DRAM. The 16 bit address must be between
0000 to EFFE. The page(s) where the DMA will write data
must remain mapped (DRAM_PAGE_CFG) during the entire transfer.
Only even addresses should be used. This register is incremented
by the hardware as the DMA transfer takes place |
DMA_IDE_COUNT |
16 bit INT |
0xFF24 to 0xFF25 |
Working |
Specifies the number of 16 bit words to transfer from
the IDE interface to DRAM. To transfer a 512 byte sector,
this would be initialized to 256.
This register is decremented
as the transfer takes place and it will read zero when
the transfer is complete. An interrupt may also be
generated upon completion.
|
DMA_MP3_SRC |
16 bit INT |
0xFF28 to 0xFF29 |
Working |
Source address for DMA transfer from the DRAM
to the STA013 MP3 decoder chip. The hardware automatically
transfers the data as the STA013 is ready for it.
This register is incremented
by the hardware as the DMA transfer takes place. The
page(s) containing this memory need to remain mapped
during the transfer. |
DMA_MP3_COUNT |
16 bit INT |
0xFF2A to 0xFF2B |
Working |
Specifies the number of 16 bit words to transfer from
DRAM to the STA013 MP3 decoder chip. This register is decremented
as the transfer takes place and it will read zero when
the transfer is complete. An interrupt may also be
generated upon completion. |
MEMCPY_DEST |
16 bit INT |
0xFF30 to 0xFF31 |
unimplemented |
Don't use the fast hardware memcpy yet! |
MEMCPY_SRC |
16 bit INT |
0xFF32 to 0xFF33 |
unimplemented |
Don't use the fast hardware memcpy yet! |
MEMCPY_COUNT |
16 bit INT |
0xFF34 to 0xFF35 |
unimplemented |
Don't use the fast hardware memcpy yet! |
IDE_RESET_BIT |
1 bit |
0xFF40 |
Working |
The LSB at this location controls the IDE reset pin.
Write 0 to reset the IDE devices, or write 1 for normal
operation. This bit is initialized to zero when the
FPGA is configured, and must be written as 1 to allow
the IDE devices to operate. The upper 7 bits will read
random data, and should always be written as zeros. |
IDE_DATA_BUF_LSB |
8 bit BYTE |
0xFF42 |
untested |
Reading this regsiter will return the lower 8 bits
of data from the previous IDE interface read. Writing
will store the lower 8 bits to be written on the next
IDE write. Only the buffers within the FPGA are accessed,
no IDE activity is generated by accessing this register.
Separate buffers are used within the FPGA,
so a write to this register followed by a read will not
necessarily return the same byte. This register will
not normally be needed, as reads and writes to the IDE
port at even addresses will read/write the lower byte
of the IDE devices.
|
IDE_DATA_BUF_MSB |
8 bit BYTE |
0xFF43 |
Working |
Reading this regsiter will return the upper 8 bits
of data from the previous IDE interface read. Writing
will store the upper 8 bits to be written on the next
IDE write. Only the buffers within the FPGA are accessed,
no IDE activity is generated by accessing this register.
Separate buffers are used within the FPGA,
so a write to this register followed by a read will not
necessarily return the same byte. This register will
normally be used when transfering data without DMA,
where it would be written before a write to the IDE
port or read after a read from the IDE port.
|
IRQ_IDENT |
8 bit BYTE |
0xFF50 |
Working |
This read-only register tells which interrupts are
currently pending. Reading it does not clear an interrupt.
This register should be read at the beginning on the
interrupt service routine to determine which actual
interrupt occured.
- Bit 0: DMA transfer from IDE interface completed
- Bit 1: DMA transfer to MP3 decoder completed
- Bit 2: memcpy operation completed
Unused bits will always read as zeros. If more interrupts
are added in the future, these bits will be defined. |
IRQ_MASK |
8 bit BYTE |
0xFF51 |
Untested |
This write-only register configure which bits in the
interrupt register can assert the 8051's INT0 pin. The
bits are set by completion of a DMA transfer, and cleared
by writing to the "ack" registers, regardless of what is
written here. This register allows the individual interrupt
to be masked from asserting INT0, but they otherwise
function in exactly the same way.
- Bit 0: DMA transfer from IDE interface
- Bit 1: DMA transfer to MP3 decoder
- Bit 2: memcpy operation
|
DMA_IDE_GO |
Flag |
0xFF58 |
Working |
Writing to this location causes a DMA transfer from
the IDE interface to DRAM memory to begin. DMA_IDE_DEST,
DMA_IDE_COUNT, and the corresponding page select in
DRAM_PAGE_CFG need to be set up, and it also helps if
the drive is ready to transfer data from a command
written via IDE_PORT. Data is transfered directly from
the drive to DRAM. The drive "sees" PIO style access.
Data transfer speed should be approx 2.4 Mbytes/sec. |
DMA_MP3_GO |
Flag |
0xFF59 |
Working
|
Writing to this location causes a DMA transfer from
the DRAM to MP3 decoder chip. DMA_MP3_SRC and DMA_MP3_COUNT
need to be set up before writing here. |
MEMCPY_GO |
Flag |
0xFF5A |
Unimplemented (may crash if used) |
Don't use the hardware memcpy yet... just do it in
code for now. |
IRQ_DMA_IDE_ACK |
Flag |
0xFF5C |
Working |
Writing to this location causes bit 0 in IRQ_IDENT to
be cleared. This must be done in the interrupt service
routine if bit 0 is set. |
IRQ_DMA_MP3_ACK |
Flag |
0xFF5D |
Working |
Writing to this location causes bit 1 in IRQ_IDENT to
be cleared. This must be done in the interrupt service
routine if bit 1 is set. |
IRQ_MEMCPY_ACK |
Flag |
0xFF5E |
Untested |
Writing to this location causes bit 2 in IRQ_IDENT to
be cleared. This must be done in the interrupt service
routine if bit 2 is set. |
IDE_PORT |
8 bit Bytes (see desc) |
0xFF60 to 0xFF7F |
Working |
This area provides read/write access to the IDE interface.
All reads within this range cause an IDE read cycle, and all
writes cause an IDE write cycle. Access to the even addresses
within this range read/write the lower 8 bits of the IDE port,
and the upper 8 bits are from IDE_DATA_BUF_MSB are used.
Likewise, access to the odd locations read/write the upper 8
bits and IDE_DATA_BUF_LSB is used for the lower 8 bits. The
first 16 bytes access the IDE interface via CS0, and the second
16 access it via CS1.
Normally only some of the even addresses will be used,
because the upper data byte of the IDE interface are only used for
data transfer, not commands. Most IDE registers are accessed with
CS0, only "control" and "alt_status" use CS1. Here's the list of registers
that would normally be used.
- 0xFF60 - Data read/write (use with IDE_DATA_BUF_MSB)
- 0xFF62 - Error Code (read)
- 0xFF64 - Sector Count (write)
- 0xFF66 - Sector (write)
- 0xFF68 - Cylinder, LSB (write)
- 0xFF6A - Cylinder, MSB (write)
- 0xFF6C - Head (write)
- 0xFF6E - Status (read), Command (write)
- 0xFF7C - Control (write)
- 0xFF7C - Alt Status (read)
|
Ethernet
(Tom did some work on an ethernet add-on
a couple years ago,
but that project is more or less dead now. These
addresses could be reclaimed for something else if
anyone wants them.)
|
TBD |
0xFF80 to 0xFF8F |
Unimplemented |
This area is reserved for Tom's Ethernet project.
The tenative register list for a Cirrus CS8900A chip is:
- FF80 - Receive/Transmit Data (port 0)
- FF82 - Receive/Transmit Data (port 1)
- FF84 - Transmit Command (TxCMD)
- FF86 - Transmit Length (TxLength)
- FF88 - Interrupt Status Queue
- FF8A - PacketPage Pointer
- FF8C - PacketPage Data (Port 0)
- FF8E - PacketPage Data (Port 1)
|
DRAM_WR_DIS |
Flag |
0xFFC0 |
Working |
Writing to this location disables writing to the DRAM memory.
This is done by the Flash ROM programming code within PAULMON2_MP3,
so that the DRAM doesn't "hear" the writes to the
flash memory. The code with PM2 also enables DRAM writing after
the flash programming. |
DRAM_WR_EN |
Flag |
0xFFC1 |
Working |
Writing to this location enables writing to the DRAM memory.
The FPGA is initialized with DRAM writing enabled, so it is not
necessary to write here unless DRAM writing has been disabled. |
* Data Type: "16 bit INT" types are also stored
as "little endian", where the LSB is stored at the first
location and MSB are the second. "Flag" types are special
locations that cause an action when written. They do not
have data associated with them, so any byte may be written
(whatever's in the accumulator at the moment?).
Missing Stuff
- Tri-state all the IDE interface pins when the PC power
sense pin is pulled low. There needs to be a way for the
firmware to know this has happened.
- Interrupt mask. Right now there's no way to mask
the individual interrupt sources. The current firmware
(0.5.0) does polling by reading IRQ_IDENT and ignores the
interrupt pin.
TODO: add memory map for code space.... explain bank swap, normal
code goes in bank 0, how to properly call to and return from code in
bank 1, how to get code to download to the correct bank, and
possibly other issues I missed in this list.
TODO: explain how the DMA works. General process: do setup for
that source has data, make sure pages are properly mapped,
set up DMA parms, write to go flag, when interrupt happens it's
done, clear interrupt with ack flag. All DMA channels are
separate and can be used concurrently (sending data to MP3 decoder
while also transfering sectors from the drive). DRAM is still
accessible during DMA transfers, and it's ok to remap pages
that aren't involved in the transfer.
IDE Port, 16 Bit Access
Here's a copy of a message I wrote to help clarify issues
associated with accessing the IDE port in 16 bit PIO mode.
Accessing 16 bit data from the IDE port is tricky. Usually you
would read IDE_DATA (0xFF60) first to get the LSB. Reading this
register causes all 16 bits to be read into the FPGA's 16-bit
buffer for the IDE port, so the upper 8 bits may be read using
the IDE_DATA_BUF_MSB (0xFF43) register.
The tricky part is that any 16 bit access to or from the IDE
drive or the DRAM will reuse the buffer and overwrite its
contents. So, if you have code like this:
xdata unsigned char my_lsb, my_msb;
my_lsb = read_fpga_reg(0xFF60);
my_msb = read_fpga_reg(0xFF43);
It will not work. The first line reads the IDE_DATA port, and
then the byte is stored in variable "my_lsb", which is in xdata
memory (DRAM), so the writing operation to my_lsb will destroy
the contents of the 16 bit buffer that is read in the next line.
If you replace this code with something like:
data unsigned char my_lsb, my_msb;
my_lsb = read_fpga_reg(0xFF60);
my_msb = read_fpga_reg(0xFF43);
Now the two bytes are allocated in the 8051's internal memory,
so the write operation to "my_lsb" will not destroy the 16-bit
buffer contents. However, this _still_ won't work, because
an interrupt could occur anytime between the two MOVX instructions
that will ultimately be executed within the two calls to
read_fpga_reg, and nearly all of the interrupt routines will
access the DRAM memory. So if you disable interrupts, like this:
data unsigned char my_lsb, my_msb;
EA = 0;
my_lsb = read_fpga_reg(0xFF60);
my_msb = read_fpga_reg(0xFF43);
EA = 1;
It probably work, but it will still fail if there is a DMA
transfer underway, as these DMA transfers also access DRAM and
reuse that 16-bit buffer.
I don't currently have a reasonable way to work around the
DMA access... so this is a pretty serious limitation which will
need to be addressed in the hardware to enable you to make
use of 16 bit PIO access to the IDE interface.
One thing that might make you life a bit easier is using some
C syntax to directly access the registers, instead of having
to call assembly language helper functions. You can declare
the FPGA registers like this:
volatile xdata unsigned char at 0xFF60 reg_ide_data;
volatile xdata unsigned char at 0xFF43 reg_ide_buf_msb;
and then you can access them just like C variables. Be sure
to use the "volatile" keyword, so that the C compiler doesn't
try to optimize out your accesses to the registers.
Flash ROM (Code) Memory Allocation
There are two banks of 56k (the first 8k is always consumed
by the image of the monitor in the 87C52's internal EPROM).
Here's how the flash rom memory is allocated today (June 4, 2002):
Bank | Begin | End | Usage |
0 | 2000 | 2FFF | Interrupt Routines |
0 | 3000 | DFFF | C Code |
0 | E000 | ECFF | Utility Programs (non-essential) |
0 | ED00 | EFFF | Utility Programs (the 'X', 'Y' erase and auto-start) |
0 | F000 | FFFF | Firmware Rev is 0.1.3 (which is run if there is no simm) |
1 | 2000 | 2FFF | Interrupt Routines (must be in both banks) |
1 | 3000 | 7FFF | Device Drivers |
1 | 8000 | 8FFF | Non-Volatile Params |
1 | 9000 | 9FFF | STA013 Config Data |
1 | A000 | CEFF | FPGA Config For 0.6.x |
1 | CF00 | CFFF | Unused (256 bytes) |
1 | D000 | FEFF | FPGA Config For 0.1.3 |
1 | FF00 | FFFF | Helper code for the 'X' and 'Y' erase |
|