OpenSNES
Modern Open-Source SNES Development SDK
Loading...
Searching...
No Matches
sa1.h File Reference

SA-1 Enhancement Chip Interface. More...

#include <snes/types.h>

Go to the source code of this file.

Macros

#define REG_SA1_BMAP   (*(volatile u8*)0x2225)
#define REG_SA1_BMAPS   (*(volatile u8*)0x2224)
#define REG_SA1_BWPA   (*(volatile u8*)0x2228)
#define REG_SA1_CBWE   (*(volatile u8*)0x2227)
#define REG_SA1_CCNT   (*(volatile u8*)0x2200)
#define REG_SA1_CDMA   (*(volatile u8*)0x2231)
#define REG_SA1_CFR   (*(volatile u8*)0x2301)
#define REG_SA1_CIC   (*(volatile u8*)0x220B)
#define REG_SA1_CIE   (*(volatile u8*)0x220A)
#define REG_SA1_CIVH   (*(volatile u8*)0x2208)
#define REG_SA1_CIVL   (*(volatile u8*)0x2207)
#define REG_SA1_CIWP   (*(volatile u8*)0x222A)
#define REG_SA1_CNVH   (*(volatile u8*)0x2206)
#define REG_SA1_CNVL   (*(volatile u8*)0x2205)
#define REG_SA1_CRVH   (*(volatile u8*)0x2204)
#define REG_SA1_CRVL   (*(volatile u8*)0x2203)
#define REG_SA1_CXB   (*(volatile u8*)0x2220)
#define REG_SA1_DCNT   (*(volatile u8*)0x2230)
#define REG_SA1_DDAB   (*(volatile u8*)0x2237)
#define REG_SA1_DDAH   (*(volatile u8*)0x2236)
#define REG_SA1_DDAL   (*(volatile u8*)0x2235)
#define REG_SA1_DTCH   (*(volatile u8*)0x2239)
#define REG_SA1_DTCL   (*(volatile u8*)0x2238)
#define REG_SA1_DXB   (*(volatile u8*)0x2221)
#define REG_SA1_EXB   (*(volatile u8*)0x2222)
#define REG_SA1_FXB   (*(volatile u8*)0x2223)
#define REG_SA1_HCRH   (*(volatile u8*)0x2303)
#define REG_SA1_HCRL   (*(volatile u8*)0x2302)
#define REG_SA1_MAH   (*(volatile u8*)0x2252)
#define REG_SA1_MAL   (*(volatile u8*)0x2251)
#define REG_SA1_MBH   (*(volatile u8*)0x2254)
#define REG_SA1_MBL   (*(volatile u8*)0x2253)
#define REG_SA1_MCNT   (*(volatile u8*)0x2250)
#define REG_SA1_MR   (*(volatile u32*)0x2306)
#define REG_SA1_OF   (*(volatile u8*)0x230B)
#define REG_SA1_SBWE   (*(volatile u8*)0x2226)
#define REG_SA1_SCNT   (*(volatile u8*)0x2209)
#define REG_SA1_SDAB   (*(volatile u8*)0x2234)
#define REG_SA1_SDAH   (*(volatile u8*)0x2233)
#define REG_SA1_SDAL   (*(volatile u8*)0x2232)
#define REG_SA1_SFR   (*(volatile u8*)0x2300)
#define REG_SA1_SIC   (*(volatile u8*)0x2202)
#define REG_SA1_SIE   (*(volatile u8*)0x2201)
#define REG_SA1_SIWP   (*(volatile u8*)0x2229)
#define REG_SA1_VCRH   (*(volatile u8*)0x2305)
#define REG_SA1_VCRL   (*(volatile u8*)0x2304)
#define SA1_CCNT_MSG   0x0F
#define SA1_CCNT_SA1_IRQ   0x80
#define SA1_CCNT_SA1_NMI   0x10
#define SA1_CCNT_SA1_RDYB   0x40
#define SA1_CCNT_SA1_RESB   0x20
#define SA1_IRAM   ((volatile u8*)SA1_IRAM_BASE)
 I-RAM as a byte pointer.
#define SA1_IRAM_BASE   0x3000
 I-RAM base address (2KB shared between SNES CPU and SA-1).
#define SA1_IRAM_SIZE   2048
 I-RAM size in bytes.
#define SA1_READY_ADDR   SA1_IRAM_BASE
 I-RAM address for SA-1 ready flag.
#define SA1_READY_MAGIC   0xA5
 Magic value written by SA-1 boot stub to confirm it's running.

Functions

u8 sa1IsReady (void)
 Did the SA-1 boot? (crt0 starts it; this only reads the outcome).

Detailed Description

SA-1 Enhancement Chip Interface.

The SA-1 is a 65c816 coprocessor clocked at 10.74 MHz, integrated into SA-1 cartridges. Its effective speed depends on where both CPUs run from: ~10.7 MHz when the SA-1 runs from I-RAM, about 5.0 MHz when both CPUs run from ROM, ~2.7 MHz when both hit BW-RAM (the SA-1 Speed Test of the higan test ROMs, as photographed on one real console; its README table says 5.4 for ROM / ROM, the photographs 5.04). It shares the main CPU's instruction set, but the SDK runs assembly on it, not C: the SA-1 cannot see work RAM, where the C runtime keeps its globals and its register file (see docs/tutorials/sa1.md).

Memory accessible by SA-1:

  • ROM ($00-$3F:$8000-$FFFF via Super MMC)
  • I-RAM ($3000-$37FF, 2KB, shared with main CPU)
  • BW-RAM (up to 256 KB, mirrors from $44: banks $40-$4F from the main CPU — fullsnes, "Memory Map (SNES Side)" — and $40-$5F from the SA-1 according to the SNESLAB wiki, Vitor Vilela's notes and three emulators, no console reading of $50-$5F being on record; the SA-1 also sees it as a 2/4-bit pixel buffer from $60. This SDK's header declares 32 KB, and both write enables, SBWE by crt0 and CBWE by the boot stub, are set at reset)

Memory NOT accessible by SA-1:

  • Main WRAM ($7E-$7F)
  • PPU registers ($2100-$213F)
  • APU registers ($2140-$2143)
  • Standard CPU I/O ($4200-$43FF)
Author
OpenSNES Team

Macro Definition Documentation

◆ REG_SA1_BMAP

#define REG_SA1_BMAP   (*(volatile u8*)0x2225)

SA-1 BW-RAM mapping

◆ REG_SA1_BMAPS

#define REG_SA1_BMAPS   (*(volatile u8*)0x2224)

SNES BW-RAM mapping

◆ REG_SA1_BWPA

#define REG_SA1_BWPA   (*(volatile u8*)0x2228)

BW-RAM write-protected area

◆ REG_SA1_CBWE

#define REG_SA1_CBWE   (*(volatile u8*)0x2227)

SA-1 BW-RAM write enable

◆ REG_SA1_CCNT

#define REG_SA1_CCNT   (*(volatile u8*)0x2200)

SA-1 CPU control

◆ REG_SA1_CDMA

#define REG_SA1_CDMA   (*(volatile u8*)0x2231)

Character conversion DMA

◆ REG_SA1_CFR

#define REG_SA1_CFR   (*(volatile u8*)0x2301)

SA-1 CPU status flags

◆ REG_SA1_CIC

#define REG_SA1_CIC   (*(volatile u8*)0x220B)

SA-1 CPU interrupt clear

◆ REG_SA1_CIE

#define REG_SA1_CIE   (*(volatile u8*)0x220A)

SA-1 CPU interrupt enable

◆ REG_SA1_CIVH

#define REG_SA1_CIVH   (*(volatile u8*)0x2208)

SA-1 IRQ vector high

◆ REG_SA1_CIVL

#define REG_SA1_CIVL   (*(volatile u8*)0x2207)

SA-1 IRQ vector low

◆ REG_SA1_CIWP

#define REG_SA1_CIWP   (*(volatile u8*)0x222A)

SA-1 I-RAM write protect

◆ REG_SA1_CNVH

#define REG_SA1_CNVH   (*(volatile u8*)0x2206)

SA-1 NMI vector high

◆ REG_SA1_CNVL

#define REG_SA1_CNVL   (*(volatile u8*)0x2205)

SA-1 NMI vector low

◆ REG_SA1_CRVH

#define REG_SA1_CRVH   (*(volatile u8*)0x2204)

SA-1 reset vector high

◆ REG_SA1_CRVL

#define REG_SA1_CRVL   (*(volatile u8*)0x2203)

SA-1 reset vector low

◆ REG_SA1_CXB

#define REG_SA1_CXB   (*(volatile u8*)0x2220)

Bank C ROM mapping

◆ REG_SA1_DCNT

#define REG_SA1_DCNT   (*(volatile u8*)0x2230)

DMA control

◆ REG_SA1_DDAB

#define REG_SA1_DDAB   (*(volatile u8*)0x2237)

DMA dest address bank (unused for I-RAM)

◆ REG_SA1_DDAH

#define REG_SA1_DDAH   (*(volatile u8*)0x2236)

DMA dest address high

◆ REG_SA1_DDAL

#define REG_SA1_DDAL   (*(volatile u8*)0x2235)

DMA dest address low

◆ REG_SA1_DTCH

#define REG_SA1_DTCH   (*(volatile u8*)0x2239)

DMA byte count high

◆ REG_SA1_DTCL

#define REG_SA1_DTCL   (*(volatile u8*)0x2238)

DMA byte count low

◆ REG_SA1_DXB

#define REG_SA1_DXB   (*(volatile u8*)0x2221)

Bank D ROM mapping

◆ REG_SA1_EXB

#define REG_SA1_EXB   (*(volatile u8*)0x2222)

Bank E ROM mapping

◆ REG_SA1_FXB

#define REG_SA1_FXB   (*(volatile u8*)0x2223)

Bank F ROM mapping

◆ REG_SA1_HCRH

#define REG_SA1_HCRH   (*(volatile u8*)0x2303)

H-counter high

◆ REG_SA1_HCRL

#define REG_SA1_HCRL   (*(volatile u8*)0x2302)

H-counter low

◆ REG_SA1_MAH

#define REG_SA1_MAH   (*(volatile u8*)0x2252)

Multiplicand/dividend high

◆ REG_SA1_MAL

#define REG_SA1_MAL   (*(volatile u8*)0x2251)

Multiplicand/dividend low

◆ REG_SA1_MBH

#define REG_SA1_MBH   (*(volatile u8*)0x2254)

Multiplier/divisor high

◆ REG_SA1_MBL

#define REG_SA1_MBL   (*(volatile u8*)0x2253)

Multiplier/divisor low

◆ REG_SA1_MCNT

#define REG_SA1_MCNT   (*(volatile u8*)0x2250)

Arithmetic control (0=mul, 1=div)

◆ REG_SA1_MR

#define REG_SA1_MR   (*(volatile u32*)0x2306)

Arithmetic result (read as 32-bit)

◆ REG_SA1_OF

#define REG_SA1_OF   (*(volatile u8*)0x230B)

Arithmetic overflow

◆ REG_SA1_SBWE

#define REG_SA1_SBWE   (*(volatile u8*)0x2226)

SNES BW-RAM write enable

◆ REG_SA1_SCNT

#define REG_SA1_SCNT   (*(volatile u8*)0x2209)

SNES CPU control

◆ REG_SA1_SDAB

#define REG_SA1_SDAB   (*(volatile u8*)0x2234)

DMA source address bank

◆ REG_SA1_SDAH

#define REG_SA1_SDAH   (*(volatile u8*)0x2233)

DMA source address high

◆ REG_SA1_SDAL

#define REG_SA1_SDAL   (*(volatile u8*)0x2232)

DMA source address low

◆ REG_SA1_SFR

#define REG_SA1_SFR   (*(volatile u8*)0x2300)

SNES CPU status flags

◆ REG_SA1_SIC

#define REG_SA1_SIC   (*(volatile u8*)0x2202)

SNES CPU interrupt clear

◆ REG_SA1_SIE

#define REG_SA1_SIE   (*(volatile u8*)0x2201)

SNES CPU interrupt enable

◆ REG_SA1_SIWP

#define REG_SA1_SIWP   (*(volatile u8*)0x2229)

SNES I-RAM write protect

◆ REG_SA1_VCRH

#define REG_SA1_VCRH   (*(volatile u8*)0x2305)

V-counter high

◆ REG_SA1_VCRL

#define REG_SA1_VCRL   (*(volatile u8*)0x2304)

V-counter low

◆ SA1_CCNT_MSG

#define SA1_CCNT_MSG   0x0F

Message to SA-1 (4 bits)

◆ SA1_CCNT_SA1_IRQ

#define SA1_CCNT_SA1_IRQ   0x80

Send IRQ to SA-1

◆ SA1_CCNT_SA1_NMI

#define SA1_CCNT_SA1_NMI   0x10

Bit 4: send NMI to the SA-1

◆ SA1_CCNT_SA1_RDYB

#define SA1_CCNT_SA1_RDYB   0x40

Bit 6: SA-1 wait (0 = ready, 1 = wait). Was 0x60, which also set RESB

◆ SA1_CCNT_SA1_RESB

#define SA1_CCNT_SA1_RESB   0x20

Bit 5: SA-1 reset (1 = reset, 0 = run — crt0 writes $00 to release). The comment had the polarity inverted

◆ SA1_IRAM

#define SA1_IRAM   ((volatile u8*)SA1_IRAM_BASE)

I-RAM as a byte pointer.

◆ SA1_IRAM_BASE

#define SA1_IRAM_BASE   0x3000

I-RAM base address (2KB shared between SNES CPU and SA-1).

◆ SA1_IRAM_SIZE

#define SA1_IRAM_SIZE   2048

I-RAM size in bytes.

◆ SA1_READY_ADDR

#define SA1_READY_ADDR   SA1_IRAM_BASE

I-RAM address for SA-1 ready flag.

◆ SA1_READY_MAGIC

#define SA1_READY_MAGIC   0xA5

Magic value written by SA-1 boot stub to confirm it's running.

Function Documentation

◆ sa1IsReady()

u8 sa1IsReady ( void )

Did the SA-1 boot? (crt0 starts it; this only reads the outcome).

crt0 writes the SA-1 reset vector, enables I-RAM/BW-RAM access, releases the chip from reset and waits for its ready byte in I-RAM — all before main(). This function reads that outcome. Until 2026-09-22 it bore a name ending in Init (removed on 2026-10-05), whose doc claimed it did the boot itself; docs cited sa1IsReady() for years before it existed.

Returns
1 if the SA-1 wrote SA1_READY_MAGIC ($A5) to I-RAM, 0 if crt0 timed out (no chip, or a boot failure — KNOWN_LIMITATIONS.md)