Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionLast revisionBoth sides next revision | ||
memory_map [2021/08/25 17:05] – pulkomandy | memory_map [2022/08/19 08:48] – [IO registers] pulkomandy | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | {{: | ||
+ | |||
^ Start | ^ Start | ||
| 0x000000 | | 0x000000 | ||
Line 4: | Line 6: | ||
| 0x003000 | | 0x003000 | ||
| 0x003D00 | | 0x003D00 | ||
- | | 0x003e00 | + | | 0x003E00 |
External memory starts at 0x4000. It can be mapped to the internal ROM and the two possible chips in the cartridges. | External memory starts at 0x4000. It can be mapped to the internal ROM and the two possible chips in the cartridges. | ||
Line 11: | Line 13: | ||
====== IO registers ====== | ====== IO registers ====== | ||
+ | |||
+ | {{: | ||
^ Address | ^ Address | ||
Line 23: | Line 27: | ||
| 5/A/F | IOx mask | | | 5/A/F | IOx mask | | ||
- | IO special functions and usage: | + | Each IO port is configured by 4 registers. |
- | * IOA15: act | + | The direction register is 0 for input pins, 1 for output pins. |
- | * IOA14-0: 15 bit RGB | + | |
- | * IOA15: SCK | + | |
- | * IOA14: SDA | + | |
- | * IOA13: SWS | + | |
- | * IOA12: CKV | + | |
- | * IOA11: FM | + | |
- | * IOA10: FP | + | |
- | * IOA9: LP | + | |
- | * IOA8: CP | + | |
- | * IOA7-0: D7-0 | + | |
- | * IOC15: SPI clock | + | |
- | * IOC14: RX | + | |
- | * IOC13: TX | + | |
- | * IOC12: SPI SSB | + | |
- | * IOC11: TFT Clock | + | |
- | * IOC10: timebase | + | |
- | * IOC9: TAPWM | + | |
- | * IOC8: VSYNC | + | |
- | * IOC7: HSYNC | + | |
- | * IOC1: timebase 2 / external clock 1 input | + | |
- | * IOC0: TBPWM / external clock 2 input | + | |
- | ===== Cartridge banks selection | + | ===== Global configuration register |
- | These IO pins allow to map either | + | * Bit 0: IOA special functions select |
+ | * Bit 1: IOB special functions select | ||
+ | |||
+ | These two bits allow to select one of two special functions for the IOA and IOB registers. Then each pin in that IO register can be switched between normal GPIO and special function using the MASK register. | ||
+ | |||
+ | For IOA, special = 0 selects the TFT display interface, special = 1 selects the STN LCD interface and I2S audio output. | ||
+ | |||
+ | For IOB, only special = 0 is documented and it selects the CSB0, CSB1, CSB2 chip select | ||
+ | |||
+ | * Bit 2: IOA Wakeup enable | ||
+ | * Bit 3: IOB Wakeup enable | ||
+ | * Bit 4: IOC Wakeup enable | ||
+ | |||
+ | These bits enable system wakeup from sleep mode from activity on the corresponding IO ports. A typical setup on the V.Smile is to enable wakeup on port B to detect when the ON button is pressed. | ||
+ | ===== Input pins configuration ===== | ||
+ | |||
+ | If the attribute bit for a pin is 0, the data bit can be used to set a pull up or pull down resistor on the pin. | ||
+ | |||
+ | If the attribute bit is 1, the pin is floating without pull up or pull down. | ||
+ | |||
+ | It is possible to read both the internal buffer and the actual state of the pin. | ||
+ | |||
+ | ===== Output pins configuration ===== | ||
+ | |||
+ | If the attribute bit for a pin is 0, the output is inverted. Writing 1 to the data bit results in a logic 0 output. If the data bit is set to 0, the result is a logic 1 output. | ||
+ | |||
+ | If the attribute bit is 1, there is no inversion, and the data bit is output as is. | ||
- | * IOB2: CSB3 | ||
- | * IOB1: CSB2 | ||
- | * IOB0: CSB0 | ||
====== Timers ====== | ====== Timers ====== | ||
- | 3D10 Timebase setup TMB2 freq TMB1 freq | + | {{: |
- | 00 TMB2 128Hz TMB1 8Hz | + | |
- | 01 256Hz 16Hz | + | |
- | 10 512Hz 32Hz | + | |
- | 11 1024Hz 64Hz | + | |
- | 3D11 Timebase clear | + | |
- | 3D12 TimerA Data | + | |
- | 3D13 TimerA Control output_pulse_ctrl source B select bits source A select bits | + | |
- | 3D14 TimerA ON on/ | + | |
- | 3D15 TimerA IRQCLR clear | + | |
- | 3D16 TimerA DATA | + | |
- | 3D17 TimerB Control output_pulse_ctrl source C select bits | + | |
- | 3D18 TimerB ON on/ | + | |
- | 3D19 TimerB IRQCLR clear | + | |
- | 3D1C Line counter | + | |
+ | ^ Address ^ Contents | ||
+ | | 3D10 | Timebase setup | ||
+ | | 3D11 | Timebase clear | ||
+ | | 3D12 | TimerA Data | ||
+ | | 3D13 | TimerA Control: output_pulse_ctrl (bits 9-6), source B select bits (5-3), source A select bits (2-0) | | ||
+ | | 3D14 | TimerA enable (bit 0) | | ||
+ | | 3D15 | TimerA IRQ clear (bit 0) | | ||
+ | | 3D16 | TimerA DATA | | ||
+ | | 3D17 | TimerB Control: output_pulse_ctrl (bits 9-6), source C select bits (bits 2-0) | | ||
+ | | 3D18 | TimerB enable (bit0) | ||
+ | | 3D19 | TimerB IRQ clear (bit0) | ||
+ | | 3D1C | Scanline counter | ||
+ | |||
+ | Timebase setup values: | ||
+ | * Bits 3-2: TMB2 frequency | ||
+ | * 00 - 128 Hz | ||
+ | * 01 - 256 Hz | ||
+ | * 10 - 512 Hz | ||
+ | * 11 - 1024 Hz | ||
+ | * Bits 1-0: TMB1 frequency | ||
+ | * 00 - 8 Hz | ||
+ | * 01 - 16 Hz | ||
+ | * 10 - 32 Hz | ||
+ | * 11 - 64 Hz | ||
+ | |||
+ | ===== Timer A ===== | ||
+ | |||
+ | Timer A ticks on the rising edge of the AND of sources A and B (so one source can be used to mask the other). | ||
+ | |||
+ | The counter is incremented at each tick until it reaches FFFF and overflows. | ||
+ | |||
+ | Reading the data register allows to know the current timer value. | ||
+ | |||
+ | When the timer overflows, several things happen: | ||
+ | |||
+ | * An interrupt is triggered (if activated) | ||
+ | * The FTAOUT pin is toggled | ||
+ | * The counter is reloaded to the last value written to the data register | ||
+ | * The 4 bit counter for PWM generation is incremented | ||
+ | |||
+ | ==== Control register bits 2-0: Source A ==== | ||
+ | |||
+ | * 00x: Timer disabled | ||
+ | * 010: 32768Hz | ||
+ | * 011: 8192Hz | ||
+ | * 100: 4096Hz | ||
+ | * 101: 1 (use source B only) | ||
+ | * 110: Timer disabled | ||
+ | * 111: EXT1 | ||
+ | |||
+ | ==== Control register bits 5-3: Source B ==== | ||
+ | |||
+ | * 000: 2048Hz | ||
+ | * 001: 1024Hz | ||
+ | * 010: 256Hz | ||
+ | * 011: TMB1 | ||
+ | * 100: 4Hz | ||
+ | * 101: 2Hz | ||
+ | * 110: 1 (use source A only) | ||
+ | * 111: EXT2 | ||
+ | |||
+ | ==== Control register bits 9-6: output pulse control ==== | ||
+ | |||
+ | {{: | ||
+ | |||
+ | This configure the pulse width from 0 to 15 timer ticks. A new pulse starts every 16 ticks. | ||
====== Misc. peripherals ====== | ====== Misc. peripherals ====== | ||
- | 3D20 System Control Watchdog sleep LVR OE LV en #2V out LVD volt select #32K clk # | + | ^ Address ^ Contents |
- | 3D21 INT Ctrl ADC Ext2 TimerA TimerB Ext1 UART Key Chg 4096Hz 2048Hz 1024Hz 4Hz TMB2 TMB1 | + | | 3D20 | System Control |
- | interrupt vector FFFB FFFD FFFA FFFA FFFD FFFB FFFF FFFE FFFE FFFE FFFF FFFF FFFF | + | | 3D21 | Interrupts control | |
- | 3D22 INT clear ADC Ext2 TimerA TimerB Ext1 UART Key Chg 4096Hz 2048Hz 1024Hz 4Hz TMB2 TMB1 | + | | 3D22 | Interrupt status (read)/ clear (write) | |
- | read status SPI ADC Ext2 TimerA TimerB Ext1 UART Key Chg 4096Hz 2048Hz 1024Hz 4Hz TMB2 TMB1 | + | | 3D23 | External Memory Control |
- | 3D23 Ext Memory Ctrl Ram Decode Control Addr Decode Ctrl Bus Arbitrer Control Wait State Number CKOEN | + | | 3D24 | Watchdog |
- | 3D24 Watchdog clear 5 5 A A | + | | 3D25 | ADC Control |
- | 3D25 ADC Control int status req auto req int_en VRT_En CH_Sel CLK_Sel CSB ADE | + | | 3D27 | ADC data | |
- | 3D27 ADC DATA rdy adc data | + | | 3D28 | Sleep Mode (write AA55) | |
- | 3D28 Sleep Mode A A 5 5 | + | | 3D29 | Wakeup Source |
- | 3D29 Wakeup | + | | 3D2A | Wakeup Time | |
- | 3D2A Wakeup | + | | 3D2B | TV System (read only, bit0 indicaters NTSC or PAL) | |
- | 3D2B TV System read only NTSC/ | + | | 3D2C | Pseudo Random1 |
- | 3D2C Pseudo | + | | 3D2D | Pseudo Random2 |
- | 3D2D Pseudo Random2 same, | + | | 3D2E | FIQ Sel |
- | 3D2E FIQ Sel fiq_sel | + | | 3D2F | DS register (sets or gets data segment value of CPU status register) | |
- | 000 PPU 010 TimerA 100 UART(SPI) 110 ADC | + | |
- | 001 SPU 011 TimerB 101 External 111 None | + | ===== System control ===== |
- | 3D2F DataSegment Access DS | + | |
+ | * Bit 15: enable watchdog | ||
+ | * Bit 14: enable | ||
+ | * Bit 9: Low-voltage regulator output enable | ||
+ | * Bit 8: Low-voltage regulator enable | ||
+ | * Bit 7: #2V out | ||
+ | * Bits 6-5: Low-voltage regulator voltage | ||
+ | * Bit 4: 32KHz clock | ||
+ | * Bit 2: Video DAC enable | ||
+ | * Bit 1: Audio DAC enable | ||
+ | |||
+ | ===== Interrupts ===== | ||
+ | |||
+ | The three interrupt registers have the same layout: | ||
+ | |||
+ | * Bit 13: ADC (interrupt vector | ||
+ | * Bit 12: External interrupt 2 (FFFD) | ||
+ | * Bit 11: Timer A (FFFA) | ||
+ | * Bit 10: Timer B (FFFA) | ||
+ | * Bit 9: External interrupt 1 (FFFD) | ||
+ | * Bit 8: UART (FFFB) | ||
+ | * Bit 7: Key change (FFFF) | ||
+ | * Bit 6: 4096Hz (FFFE) | ||
+ | * Bit 5: 2048Hz (FFFE) | ||
+ | * Bit 4: 1024Hz (FFFE) | ||
+ | * Bit 3: 4Hz (FFFF) | ||
+ | * Bit 1: TMB1 (FFFF) | ||
+ | * Bit 0: TMB2 (FFFF) | ||
+ | |||
+ | There are interrupts coming from devices, which have separate enable bits in each of the devices. | ||
+ | |||
+ | The complete list of interrupt vectors is: | ||
+ | |||
+ | ^ Vector address ^ Name ^Triggered by ^ | ||
+ | | FFF5 | BREAK |'' | ||
+ | | FFF6 | FIQ | ||
+ | | FFF7 | RESET |Console startup/ | ||
+ | | FFF8 | IRQ0 |PPU | | ||
+ | | FFF9 | IRQ1 |SPU | | ||
+ | | FFFA | IRQ2 |Timers A and B | | ||
+ | | FFFB | IRQ3 |UART, SPI, SIO, I2C | | ||
+ | | FFFC | IRQ4 |SPU beat and envelope | ||
+ | | FFFD | IRQ5 |External interrupts | ||
+ | | FFFE | IRQ6 |1024, 2048 or 4096Hz | ||
+ | | FFFF | IRQ7 |4Hz ticker, Timebase 1, Timebase 2, Low voltage detect, Key change | | ||
+ | |||
+ | As the vector addresses are only 16-bit, they can only point to the first segment (0x0000 - 0xFFFF). | ||
+ | ===== External bus configuration ===== | ||
+ | |||
+ | * Bits 11-8: External RAM decode control | ||
+ | * 0xxx - No mapping | ||
+ | * 1000 - Map '' | ||
+ | * 1001 - Map '' | ||
+ | * 1010 - Map '' | ||
+ | * 1011 - Map '' | ||
+ | * 1100 - Map '' | ||
+ | * 1101 - Map '' | ||
+ | * 1110 - Map '' | ||
+ | * 1111 - Map '' | ||
+ | * Bits 7-6: ROM address decode control | ||
+ | * 00 - Map entire range to ROMCSB | ||
+ | * 01 - Map '' | ||
+ | * 1x - Map '' | ||
+ | * Bits 5-3: Bus arbitration priority control | ||
+ | * 101 - 1. Audio, 2. PPU, 3. CPU | ||
+ | * 111 - 1. PPU, 2. Audio, 3. CPU | ||
+ | * Bits 2-1: Number | ||
+ | * Bit 0: CKOEN | ||
+ | |||
+ | External RAM mapping overrides any ROM mapping. | ||
+ | |||
+ | ==== ADC ==== | ||
+ | |||
+ | Control | ||
+ | |||
+ | * Bit 13: interrupt | ||
+ | * Bit 12: request conversion | ||
+ | * Bit 10: auto request | ||
+ | * Bit 9: interrupt enable | ||
+ | * Bit 8: VRT enable | ||
+ | * Bits 5-4: select channel | ||
+ | * Bits 3-2: clock select | ||
+ | * Bit 1: CSB | ||
+ | * Bit 0: ADE | ||
+ | |||
+ | ==== Sleep/Wakeup ==== | ||
+ | |||
+ | Wakeup | ||
+ | |||
+ | * Wakeup | ||
+ | * Wakeup time: number | ||
+ | * Sleep: write AA55 here to start sleeping. CPU will be halted until the next wakeup event. | ||
+ | |||
+ | ==== Pseudo | ||
+ | |||
+ | There are two generators using the formula | ||
+ | |||
+ | The first one has a default seed = 001_0100_0001_1000 | ||
+ | The second one has a default seed = 001_0110_0101_1000 | ||
+ | |||
+ | You can write the registers | ||
+ | |||
+ | ==== FIQ ==== | ||
+ | |||
+ | There can only be a single | ||
+ | |||
+ | | ||
+ | * 001: SPU | ||
+ | | ||
+ | * 011: TimerB | ||
+ | | ||
+ | * 101: External | ||
+ | * 110: ADC | ||
+ | | ||
+ | |||
+ | ==== DS register ==== | ||
+ | This allows direct read and write access to the DS (Data Segment) register. Normally in the uN'SP architecture, | ||
====== UART ====== | ====== UART ====== | ||
- | 3D30 UART Control TxEn RxEn Mode MulPro 9th bit TxIntEn RxIntEn | + | {{:sunplus:sunplus_uart.png? |
- | 3D31 UART Status rxbf txbusy bit9 overrun frame parity txrdy rxrdy | + | |
- | 3D32 UART Reset reset | + | |
- | 3D33 UART Baud Scalar Low 1200: FA92, 2400: FD41, 4800: FEA0, 9600: FF50, 19200: FFA8 low byte | + | |
- | 3D34 UART Baud Scalar Hi 57600: FFE2, 115200: FFF1 high byte | + | |
- | 3D35 UART TxBUF uart_txbuf | + | |
- | 3D36 UART RxBUF uart_rxbuf | + | |
+ | All UART registers are 8bit only. | ||
+ | |||
+ | ^ Address ^ Contents ^ | ||
+ | | 3D30 | UART Control (7: TxEn, 6: RxEn, 5: Mode, 4: MulPro, 3-2: bits per byte, 1: Tx Interrupt Enable, 0: Rx Interrupt Enable | | ||
+ | | 3D31 | UART Status | ||
+ | | 3D32 | UART Reset (bit 0) | | ||
+ | | 3D33 | UART Baudrate setting (low byte) | | ||
+ | | 3D34 | UART Baudrate setting (high byte) | | ||
+ | | 3D35 | UART Tx buffer | ||
+ | | 3D36 | UART Rx buffer | ||
+ | |||
+ | Baudrate settings: | ||
+ | |||
+ | * 1200: FA 92 | ||
+ | * 2400: FD 41 | ||
+ | * 4800: FE A0 | ||
+ | * 9600: FF 50 | ||
+ | * 19200: FF A8 | ||
+ | * 57600: FF E2 | ||
+ | * 115200: FF F1 | ||
+ | |||
+ | Before using the UART, the corresponding PINs need to be configured properly. IOC13 and IOC14 must be set to " | ||
+ | The example below also forces CTS A (IOC8) low, allowing the first controller port to transmit data. Normally this would only be done after receiving an RTS from said controller. | ||
+ | |||
+ | // Enable controller CTS | ||
+ | *PORTC_DIR = 0x89c0; | ||
+ | *PORTC_ATTR = 0x89c0; | ||
+ | *PORTC_DATA = 0xf77f; | ||
+ | |||
+ | // Enable Uart RX (controller input) | ||
+ | *UART_BAUDRATE_LOW = 0xA0; | ||
+ | *UART_BAUDRATE_HIGH = 0xFE; | ||
+ | *UART_CONTROL = 0xc3; | ||
+ | *UART_STATUS = 3; | ||
+ | |||
+ | *PORTC_SPECIAL |= 0x6000; // UART Tx and Rx in " | ||
+ | *PORTC_ATTR |= 0x6000; | ||
+ | *PORTC_DIR |= 0x4000; | ||
+ | |||
+ | Reading from the UART then is quite simple: | ||
+ | |||
+ | * Wait until the status register indicates Rx ready (bit 0) | ||
+ | * When Rx is ready, read the Rx data register to get the byte | ||
+ | |||
+ | For transmitting, | ||
====== SPI ====== | ====== SPI ====== | ||
- | 3D40 SPI Control busy txempty rxfull SPH SPO SPIEN LPM TxIntEn RxIntEn | + | ^ Address ^ Contents ^ |
- | 3D41 SPI | + | | 3D40 | SPI Control |
- | 3D42 SPI | + | | 3D41 |
+ | | 3D42 | ||
====== General DMA ====== | ====== General DMA ====== | ||
- | 3E00 DMA | + | ^ Address ^ Contents ^ |
- | 3E01 DMA | + | | 3E00 |
- | 3E02 DMA | + | | 3E01 |
- | 3E03 DMA Target Address target address | + | | 3E02 | DMA word count | |
+ | | 3E03 | ||
+ | |||
+ | This is a DMA for generic purposes. Note that there is another DMA channel in the [[PPU]] registers. | ||
+ | |||
+ | Both DMA units operate in the same way. First, set the source and destination addresses. The source can be anywhere in memory, but the destination register is only 14 bits wide, which allows to target only the internal RAM and IO registers (you wouldn' | ||
+ | The transfer is started when you write the word count register, and you can read that register to know when the transfer is done (the register is 0 when there are no more words to transfer). |