-
Notifications
You must be signed in to change notification settings - Fork 3
The Super Nintendo CPU (S-CPU) is a Ricoh 5A22 processor, which is based on a WDC 65816 core. A 65816 processor can operate in 2 modes: native mode and emulation mode. In emulation mode a 65816 processor emulates a 6502 processor. A 65816 starts in emulation mode, and can be switched to native mode by executing the clc
instruction to set the carry flag to 0, followed by the xce
instruction to exchange the carry flag with the emulation flag.
This document assumes native mode operation of the S-CPU.
The S-CPU has 24 address lines and with a 24-bit address space it can address 16MiB. A 24-bit address consists of an 8-bit bank selector and a 16-bit address, giving 256 banks of 64KiB each. Each bank has 256 pages of 256 bytes. The first page of the first bank is the zero page.
The S-CPU has the following built-in registers:
- 1 status register: Processor Status
- 3 general purpose registers: Accumulator, X Index and Y Index
- 2 registers to assist addressing: Direct and Data Bank
- 3 registers for program control: Program Counter, Program Bank and Stack Pointer
Contains status flags for ALU operations and mode select bits. The status flags c, z, v, and n, are tested by conditional branch instructions. P(e) is a hidden bit, its value can be swapped with the P(c) bit using the xce
instruction.
_: e Emulation mode select
0: c Carry status flag
1: z Zero status flag
2: i IRQ disabled mode select
3: d Decimal mode select
4: x Index 8-bit mode select
5: m Memory/Accumulator 8-bit mode select
6: v Overflow status flag (for signed arithmetic)
7: n Negative status flag (for unsiged arithmetic)
Status flags initialization:
- P(i)=1 after reset
- P(d)=0 after reset (binary mode)
- P(x)=1 after reset and after switching to native mode
- P(m)=1 after reset and after switching to native mode
In 16-bit mode certain instructions can take a 16-bit operands, e.g. lda $1234
or sta $1234
. These instructions will map the low order byte of the register to the effective address, and the register's high order byte to the effective address + 1.
In 16-bit mode, when executing push or pull instructions, the high order byte is pushed first, followed by the low order byte, and the low order byte is pulled first, followed by the high order byte. (This seems like the reverse compared to e.g. lda
, but the stack grows downwards, so values are consistently stored in memory.)
General purpose register, stores one of the operands or the result of the arithmetic and logic unit (ALU).
In 8-bit mode the low order byte is designated A, and the high order byte is designated B, but not directly accessible. The low order A and high order B bytes can be exchanged using the xba
instruction, or A and B can be tranferred to a 16-bit index register (B becomes the high order byte). In 16-bit mode the 16-bit register is designated C.
When switching between 8-bit and 16-bit mode the high order byte is retained.
sep #%00010000 ; 8-bit mode, sets P(m) to 1
rep #%00010000 ; 16-bit mode, resets P(m)
General purpose register, also used in indexed addressing modes to calculate an effective address by adding the index value to the address prior to performing the operation.
When switching to 8-bit mode the high order byte is lost, switching back to 16-bit mode sets it to zero.
sep #%00001000 ; 8-bit mode, sets P(x) to 1
rep #%00001000 ; 16-bit mode, resets P(x)
Location of the next available location on the stack. The stack is always in bank 0, but is relocatable and not restricted to 256 bytes.
Initialized to $0100
during reset.
Start of 'page zero' in bank 0. Used as an offset for direct addressing mode instructions. Can be any value, but it is preferred to keep the low order byte at zero, to align with 256 byte page boundaries, e.g. $3F00
or $4000
. D can be set using the tcd
instruction, to tranfer the value from C to D, or using the pld
instruction, to pull the value off the stack.
A direct page address combined with an index that crosses the page boundary will roll into the next page (no wrap-around).
Initialized to zero during reset.
The default bank address or 'bank byte' for memory transfers. Combined as the highest order byte with the 16-bit effective instruction address to form a 24-bit address used for storing and retrieving data. DB is incremented automatically for indexed addressing that crosses a bank boundary, en automatically decremented afterwards.
Initialized to zero during reset.
Pointer to next instruction in memory (combined with the PB). PC is incremented after each instruction or operand fetch. Program segments cannot cross the boundary of a bank, because at $FFFF
the program counter will reset to $0000
.
The bank address for fetching instructions ('bank byte' for the PC). The highest order byte of 24-bit addresses used in jump instructions. Relative branch instructions do not use the PB and when crossing the $FFFF
boundary will loop around to $0000
.
Initialized to zero after reset.
When a hardware interrupt (reset, NMI, IRQ, or abort) or software interrupt (break or co-processor instruction) occurs, the S-CPU must first perform a sequence of operations to allow for rti
. This sequence causes some interrupt latency. The S-CPU can be set to wait for an IRQ using the wai
instruction. In this state it will continue with the next instruction when an IRQ occurs.
To handle an interrupt a pointer to the address of the interrupt handler (in bank 0) must be set in the interrupt vector table, according to the table below:
Address | Interrupt |
---|---|
$FFE4 |
COP |
$FFE6 |
BRK |
$FFE8 |
Abort |
$FFEA |
NMI |
$FFEE |
IRQ |
$FFFC |
Reset |
After a reset or powerup P is set to %00110100
(emulation mode, binary mode, 8-bit mode for A and X/Y), and S is initialized to %00010000
(stack at $0100
).
The S-CPU supports 25 addressing modes, consisting of (combinations of) general modes which determine how the effective address for the instruction is established.
Indexed ,x
/,y
: the value of X or Y is added to the operand (operand,x
), or, when combined with indirect mode, it is added to the operand before fetching an address from memory (pre-indexing (operand,x)
), or after an address was fetched from memory (postindexing (operand),x
).
Indirect ()
/[]
: the base or effective address is fetched from memory using a pointer (based on the operand, optionally combined with D and/or X/Y, shown as <...>
in the table below).
Direct: in direct mode D is used as an offset for the 8-bit operand and bank zero is default, unless direct mode is combined with indirect mode, in which case DB is used (unless combined with long mode).
Absolute: DB is used as an offset for a 16-bit operand, or the instruction uses a 24-bit operand.
24-bit | Code | Addressing mode | Example | Effective address (or constant value) |
---|---|---|---|---|
A | Accumulator | dec a |
(accumulator) | |
i | Implied | clc |
(implied) | |
# | Immediate | sep #$12 |
operand | |
Immediate, accumulator | inc #$12 |
operand | ||
Immediate, accumulator (16-bit) | lda #$1234 |
operand | ||
Immediate, index | ldx #$12 |
operand | ||
Immediate, index (16-bit) | ldy #$1234 |
operand | ||
* | a | Absolute | and $1234 |
DB:operand |
* | al | Absolute long | and $123456 |
operand |
* | al,x | Absolute long indexed | and $123456,x |
operand + X |
* | a,x | Absolute indexed with X | and $1234,x |
DB:(operand + X) |
* | a,y | Absolute indexed with Y | and $1234,y |
DB:(operand + Y) |
(a,x) | Absolute indexed indirect | jmp ($1234,x) |
PC = <00:(operand + X)> | |
(a) | Absolute indirect | jmp ($1234) |
PC = <00:operand> | |
(al) | Absolute indirect long | jml [$1234] |
PC,PB = <00:operand>,<00:(operand + 2)> | |
d | Direct | and $12 |
00:(D + operand) | |
d,x | Direct indexed with X | stz $12,x |
00:(D + operand + X) | |
d,y | Direct indexed with Y | stx $12,y |
00:(D + operand + X) | |
* | (d,x) | Direct indexed indirect | and ($12,x) |
DB:<(D + operand + X> |
* | (d) | Direct indirect | and ($12) |
DB:<00:operand> |
* | [d] | Direct indirect long | and [$12] |
<00:operand> |
* | (d),y | Direct indirect indexed | and ($12),y |
(DB:<00:(D + operand)>) + Y |
* | [d],y | Direct indirect long indexed | and [$12],y |
<00:(D + operand)> + Y |
r | Program Counter relative | beq $12 |
PC + operand (signed 8-bit value) | |
rl | Program Counter relative long | brl $1234 |
PC + operand (signed 16-bit value) | |
s | Stack | rts |
||
d,s | Stack relative | and $12,s |
00:(S + operand) | |
* | (d,s),y | Stack relative indirect indexed | and ($12,s),y |
(DB:<00:(S + operand)>) + Y |
xya | Block move | mvp $12,$34 |
*) 24-bit effective address mode
--