Correcting memory map, better explaining the scratchpad, and adding a section about the write queue
This commit is contained in:
parent
b5a40c7895
commit
bd07b7ef5f
91
memorymap.md
91
memorymap.md
@ -7,7 +7,7 @@
|
||||
1F800000h 9F800000h -- 1K Scratchpad (D-Cache used as Fast RAM)
|
||||
1F801000h 9F801000h BF801000h 8K I/O Ports
|
||||
1F802000h 9F802000h BF802000h 8K Expansion Region 2 (I/O Ports)
|
||||
1FA00000h 9FA00000h BFA00000h 2048K Expansion Region 3 (whatever purpose)
|
||||
1FA00000h 9FA00000h BFA00000h 2048K Expansion Region 3 (SRAM BIOS region for DTL cards)
|
||||
1FC00000h 9FC00000h BFC00000h 512K BIOS ROM (Kernel) (4096K max)
|
||||
FFFE0000h (KSEG2) 0.5K I/O Ports (Cache Control)
|
||||
```
|
||||
@ -25,11 +25,11 @@ Additionally, there are a number of memory mirrors.<br/>
|
||||
|
||||
#### KUSEG,KSEG0,KSEG1,KSEG2 Memory Regions
|
||||
```
|
||||
Address Name Size Privilege Code-Cache Data-Cache
|
||||
00000000h KUSEG 2048M Kernel/User Yes (Scratchpad)
|
||||
80000000h KSEG0 512M Kernel Yes (Scratchpad)
|
||||
A0000000h KSEG1 512M Kernel No No
|
||||
C0000000h KSEG2 1024M Kernel (No code) No
|
||||
Address Name i-Cache Write-Queue
|
||||
00000000h KUSEG Yes Yes
|
||||
80000000h KSEG0 Yes Yes
|
||||
A0000000h KSEG1 No No
|
||||
C0000000h KSEG2 (No code) No
|
||||
```
|
||||
Kernel Memory: KSEG1 is the normal physical memory (uncached), KSEG0 is a
|
||||
mirror thereof (but with cache enabled). KSEG2 is usually intended to contain
|
||||
@ -39,22 +39,29 @@ processors), the PSX doesn't support virtual memory, and KUSEG simply contains
|
||||
a mirror of KSEG0/KSEG1 (in the first 512MB) (trying to access memory in the
|
||||
remaining 1.5GB causes an exception).<br/>
|
||||
|
||||
#### Code Cache
|
||||
Works in the cached regions (KUSEG and KSEG0).<br/>
|
||||
#### i-Cache
|
||||
The i-Cache can hold 4096 bytes, or 1024 instructions.<br/>
|
||||
It is only active in the cached regions (KUSEG and KSEG0).<br/>
|
||||
There are reportedly some restrictions... not sure there... eventually it is
|
||||
using the LSBs of the address as cache-line number... so, for example, it
|
||||
couldn't simultaneously memorize opcodes at BOTH address 80001234h, AND at
|
||||
address 800F1234h (?)<br/>
|
||||
|
||||
#### Data Cache aka Scratchpad
|
||||
The MIPS CPU usually have a Data Cache, but, in the PSX, Sony has misused it as
|
||||
"Scratchpad", that is, the "Data Cache" is mapped to a fixed memory location at
|
||||
1F800000h..1F8003FFh (ie. it's used as Fast RAM, rather than as cache).<br/>
|
||||
There \<might\> be a way to disable that behaviour (via Port FFFE0130h or
|
||||
#### Scratchpad
|
||||
MIPS CPUs usually have a d-Cache, but, in the PSX, Sony has assigned it as
|
||||
what's referenced as the "Scratchpad", mapped to a fixed memory location at
|
||||
1F800000h..1F8003FFh, ie. it's used as Fast RAM, rather than as cache.<br/>
|
||||
There \<might\> be a way to disable that behavior (via Port FFFE0130h or
|
||||
so), but, the Kernel is accessing I/O ports via KUSEG, so activating Data Cache
|
||||
would cause the Kernel to access cached I/O ports.<br/>
|
||||
Not tested yet, but most probably the Scratchpad can be used only for Data (ie.
|
||||
NOT for program Code?).<br/>
|
||||
The purpose of the scratchpad is to have a more flexible cache system available
|
||||
to the programmer. Neither the kernel nor the Sony libraries will try to make use
|
||||
of it, so it is therefore completely up for grabs to the programmer. A good example
|
||||
would be if you were to write a piece of code that's doing a lot of CRC computation,
|
||||
to use the 1KB scratchpad to initially load the CRC lookup tables, which incidentally,
|
||||
is exactly 1KB large. Doing this will relieve SDRAM page changes overhead while reading
|
||||
the data to checksum linearly, while also keeping the whole CRC code in the i-Cache,
|
||||
hence being more optimal than what you'd get with an automatic d-Cache system.
|
||||
|
||||
#### Memory Mirrors
|
||||
As described above, the 512Mbyte KUSEG, KSEG0, and KSEG1 regions are mirrors of
|
||||
@ -78,6 +85,60 @@ The Scratchpad is mirrored only in KUSEG and KSEG0, but not in KSEG1.<br/>
|
||||
(unless RAM/BIOS/Expansion mirrors are mapped to "unused" area)
|
||||
```
|
||||
|
||||
#### Write queue
|
||||
The MIPS CPU has a 4-words deep pass-through write queue, in order to relieve
|
||||
some bus contention when writing to memory. If reading the same memory location
|
||||
that just got written into the write queue, it will first be flushed before
|
||||
being read back from memory.<br/>
|
||||
It is important to realize that the write queue's mechanism is only viable for
|
||||
normal memory attached to the main CPU, and that any hardware register state machine
|
||||
will get messed up by it.<br/>
|
||||
The typical example is the typical JEDEC standard to access flash, which usually does
|
||||
the following sequence to read the ID of a flash chip:
|
||||
```C
|
||||
base[0xAAA] = 0xAA;
|
||||
base[0x555] = 0x55;
|
||||
base[0xAAA] = 0x90;
|
||||
uint8_t mnfctrID = base[0x000];
|
||||
uint8_t deviceId = base[0x002];
|
||||
```
|
||||
|
||||
In this example above, if `base` is located in a memory segment that has the write queue
|
||||
enabled, even if the low level assembly code will do the first 3 stores before doing 2 loads,
|
||||
the physical signals sent to that device through the CPU bus will be seen in the sequence:
|
||||
```
|
||||
store(0xaaa, 0xaa)
|
||||
load(0x000)
|
||||
store(0x555, 0x55)
|
||||
load(0x002)
|
||||
store(0xaaa, 0x90)
|
||||
```
|
||||
|
||||
Therefore, using KSEG1 that disables the write queue is the only way to ensure that the
|
||||
operations are done in the proper way.
|
||||
|
||||
The above is valid for most of the hardware connected to the main CPU, such as the CDROM
|
||||
controller, exp1, exp2, the SPU, or the GPU. Therefore, using BF80180xh to access the
|
||||
CDROM registers is more correct than using 1F80180xh.
|
||||
|
||||
It is noteworthy that the Sony code will still incorrectly use KUSEG as the memory map
|
||||
for all hardware registers, and they then spend a lot of time writing 4 dummy values
|
||||
somewhere, in order to ensure the write queue has been flushed.
|
||||
|
||||
The SN debugger in contrast is properly using the KSEG1 memory map for all the hardware
|
||||
registers, nullifying the need to flush the write queue when accessing it.
|
||||
|
||||
It's also noteworthy that doing ANY KSEG1 access (read OR write) will automatically stall
|
||||
the CPU in order to flush the whole write queue before proceeding with the operation.
|
||||
Therefore, all BIOS ROM operations will naturally and effectively have the write queue
|
||||
disabled, as this code requires the CPU to read from KSEG1 constantly.
|
||||
|
||||
This also means that if using KUSEG for the hardware registers, another method to flush
|
||||
the write queue, albeit potentially slightly less efficient, would be to simply read
|
||||
the first byte located at BFC00000h. The latter is what is effectively described as the
|
||||
official method to flush the write queue in the MIPS handbook. This could be potentially
|
||||
useful to flush the write queue all at once, instead of flushing it word by word.
|
||||
|
||||
#### More Memory Info
|
||||
For Info on Exception vectors, Unused/Garbage memory locations, I/O Ports,
|
||||
Expansion ROM Headers, and Memory Waitstate Control, etc. see:<br/>
|
||||
|
Loading…
Reference in New Issue
Block a user