Memory map
The memory map is currently:
| A3 | A2 | A1 | A0 | Write | Read |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | Write A[7:0] | Read A[7:0] |
| 0 | 0 | 0 | 1 | Write A[15:8] | Read A[15:8] |
| 0 | 0 | 1 | 0 | Write A[23:16] | Read A[23:16] |
| 0 | 0 | 1 | 1 | Write A[31:24] | Read A[31:24] |
| 0 | 1 | 0 | 0 | Write LCD Row +0 | Read IRQ status |
| 0 | 1 | 0 | 1 | Write LCD Row +256 | Clear IRQ status |
| 0 | 1 | 1 | 0 | Write D[15:8] | Read D[15:8] |
| 0 | 1 | 1 | 1 | Write IRQ mask | Read IRQ mask |
| 1 | 0 | 0 | 0 | Write to SRAM | Read from SRAM |
| 1 | 0 | 0 | 1 | Write to SDRAM | Read from SDRAM |
| 1 | 0 | 1 | 0 | Write to SPI | Read from SPI |
| 1 | 0 | 1 | 1 | Write to voice generator | Read from voice generator |
| 1 | 1 | 0 | 0 | Write to MMU + 0 | Read keys |
| 1 | 1 | 0 | 1 | Write to MMU + 256 | Read rotary encoder |
| 1 | 1 | 1 | 0 | Add to address | Unused |
| 1 | 1 | 1 | 1 | Write to CLUT | Unused |
Not all read operations are currently used - the two that aren't are reserved for future expansion (maybe a version number)
The first 8 addresses are for registers, and the last 8 addresses are for operations.
Notes on some of the registers
Here are some notes on the registers (address 4'b0xxx).
A[31:0]
These are an internal memory address range - SRAM requires 19 bits, and SDRAM requres 25 bits. The unused bits are ignored.
The row and D[15:8] can influence the address (see later).
D[15:8]
D[15:8] is used to provide additional bits for the SDRAM interface (which will only be 16-bit), so to write a value, you initially write to D[15:8], and then write to SDRAM - this combines the bits together. To read a value, you read from SDRAM, and then read D[15:8]
Row
The display is implemented as an 8-bit indexed colour display, so each pixel consumes one byte.
Since there are 320 rows, two addresses are used for the rows - the first takes the data bus input, and sets the row to that value; the second takes the data bus input and adds 256 to it.
At the same time as the row command is issued, D[15:8] is stored at the low 8-bits.
This means that to fill a rectangle, all that needs to happen is that D[15:8] is written to in order to indicate the first column, and then the first row is set. The required number of pixels are written, and then the second row is set. This automatically reverts the address back to the start column.
Notes on the operations
Here are some notes on the operations (address 4'b1xxx).
Add to address
This takes the current data bus value, and sign extend adds it to the current address. So, if you write the value 0x01, then the address is incremented; using 0xff will decrement it.
CLUT
The colour lookup table (CLUT) uses A[7:0] as the blue component, A[15:8] as green, and A[23:16] as red. The written date is the palette number to select.
Example code
Here is some example code for performing some of the operations.
Writing to an SDRAM address
void writeSD(long addr, short value)
{
fpga_write(0x0, (addr >> 0));
fpga_write(0x1, (addr >> 8));
fpga_write(0x2, (addr >> 16));
fpga_write(0x3, (addr >> 24));
fpga_write(0x6, (value >> 8)); // Set D[15:8]
fpga_write(0x9, (value >> 0)); // Write to memory
}
Note that the address is the number of short ints, rather than bytes. Also note that this is the logical address, rather than the physical (unless the MMU has been configured to be a linear set of numbers).
Copying data to SDRAM
void copyToSD(long addr, short* from, short shorts)
{
fpga_write(0x0, (addr >> 0));
fpga_write(0x1, (addr >> 8));
fpga_write(0x2, (addr >> 16));
fpga_write(0x3, (addr >> 24));
while(shorts > 0)
{
fpga_write(0x6, (*from >> 8))
fpga_write(0x0, (*from >> 0));
fpga_write(0xe, 1); // Increment address
shorts--;
}
}
Setting CLUT value
void setCLUT(BYTE red, BYTE green, BYTE blue, BYTE col)
{
fpga_write(0x2, red);
fpga_wirte(0x1, green);
fpga_write(0x0, blue);
fpga_write(0xf, col);
}
Example rectangle fill
Example code to do a rectangle fill would be:
void fillrect(int x0, int y0, int w, int h, int col)
{
fpga_write(0x6, x0); // Write D[15:8] (column)
while(h)
{
int x;
if(y0 < 256)
fpga_write(0x4, y0); // Write to row y0 + 0;
else
fpga_write(0x5, y0 & 0xff); // Write to row y0 + 256;
for(x = w; x > 0; --x)
{
fpga_write(0x8, col); // Write to SRAM
fpga_write(0xe, 1); // Increment address
}
--h;
y0++;
}
}
