ChibiAkumas Tutorials
Lesson A1 - Extra commands in the 65c02/65816 | |
Lesson H8 - Hello World on the SNES / Super Famicom | |
Lesson H1 - Hello World on the Super Nintendo (65816 version) | |
Lesson S8 - Bitmap Drawing on the SNES / Super Famicom | |
Lesson S17 - Joypad Reading on the SNES / Super Famicom | |
Lesson S1 - Moving a bitmap on the SNES (65816 version) | |
Lesson S28 - Tile Bitmap Clipping on the SNES | |
Lesson S29 - Hardware Sprite Clipping on the SNES | |
|
Lesson P7 - Bitmap Functions on the SNES / Super Famicom |
Lesson P15 - Joystick Reading on the NES / Famicom and SNES | |
Lesson P22 - Palette Definitions on the SNES / Super Famicom | |
Lesson P27 - Sound on the SNES / Super Famicom: the SPC700 | |
Lesson
P35 - Hardware Sprites on the SNES / Super Famicom |
|
Lesson
P41 - Multiple layers on the SNES |
|
Lesson P42 - Color maths on the Super Nintendo | |
Lesson P52 - Sound on the SuperNintendo (ChibiSound Pro) | |
Lesson P64 - Multiplatform Software tilemap on the SNES | |
Useful Document
SNES Documentation v2.30: Written by Yoshi
nocash SNES hardware specifications
Memory Map
The 65816 has a 16 bit address bus,
it generally works with a 16 bit address, and a 8 bit Data Bank
register (DB) The ZeroPage and Stack pointer are relocatable, but default to the 6502 normal of $0000-$01FF Our minimal 32k cartridge will appear in rom from $8000, and execution will start there, the CPU will default in 8 bit mode. |
|
Address | Use |
$0000 | BG1 Tilemap |
$1000 | Tile Patterns |
$4000 | Sprite Patterns |
$7FFF | Last byte of ram |
Address | Bytes | Category | Purpose | Example |
$FFC0 | 21 | Rom | Cartridge title (Space Padded) | Test Rom9012345678901 |
$FFD6 | 1 | Rom | ROM/RAM information on cart. | $00 |
$FFD7 | 1 | Rom | ROM size. | $01 |
$FFD8 | 1 | Rom | RAM size. | $00 |
$FFD9 | 1 | Rom | Developer ID code. | $00 |
$FFDB | 1 | Rom | Version number. | $00 |
$FFDC | 2 | Rom | Checksum complement. | $???? |
$FFDE | 2 | Rom | Checksum. | $???? |
$FFE0 | 2 | 65816 Mode | $0000 | |
$FFE2 | 2 | 65816 Mode | $0000 | |
$FFE4 | 2 | 65816 Mode | COP Vector | $0000 |
$FFE6 | 2 | 65816 Mode | Brk Vector | $0000 |
$FFE8 | 2 | 65816 Mode | Abort Vector (Unused) | $0000 |
$FFEA | 2 | 65816 Mode | NMI Vector (V-blank) | $0000 |
$FFEC | 2 | 65816 Mode | Reset Vector (Unused) | $0000 |
$FFEE | 2 | 65816 Mode | IRQ Vector (H/V/External) | $0000 |
$FFF0 | 2 | 6502 Mode | $0000 | |
$FFF2 | 2 | 6502 Mode | $0000 | |
$FFF4 | 2 | 6502 Mode | COP Vector | $0000 |
$FFF6 | 2 | 6502 Mode | BRK Vector (unused) | $0000 |
$FFF8 | 2 | 6502 Mode | Abort Vector (Unused) | $0000 |
$FFFA | 2 | 6502 Mode | NMI Vector (V-blank) | $0000 |
$FFFC | 2 | 6502 Mode | Reset Vector (6502 Mode) | $8000 |
$FFFE | 2 | 6502 Mode | IRQ/BRK Vector | $0000 |
Byte 1 | Byte 2 | |
First 16 bytes | 00111100 01111111 01100011 01100011 01111111 01100011 01100011 00000000 |
00222200 02222222 02200022 02200022 02222222 02200022 02200022 00000000 |
Second 16 bytes | 00333300 03333333 03300033 03300033 03333333 03300033 03300033 00000000 |
00444400 04444444 04400044 04400044 04444444 04400044 04400044 00000000 |
F | E | D | C | B | A | 9 | 8 | |
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
|
V | H | L | P | P | P | T | T | T | T | T | T | T | T | T | T | V=vflip
H=hflip L=layer (in
front of sprites) P=palette
T=tile number
(0-1023) |
Palette Definitions
Palettes are defined by something called 'CGRAM' there are 256 palette entries... Because we can only select 8 palettes for Tiles/Sprites, assuming our sprites and tiles are 16 colors the first 128 colors will be used by Tiles, and the second 128 will be used by Sprites To define a palette entry we need to select a palette entry number by writing it's number as a byte to $2121 We have to write two bytes to $2122... we write them in REVERSE order, so the low byte is written first!
|
|
1 | 2 |
16 | 17 |
Lets look at this example of a 16x16
sprite in AkuSprite Editor... Akusprite editor is designed for 8x8
sprites, but we can export a 16x16 one in the following way If we want to export this quickly, so we can use it as a single doublesize sprite, one option is to tick the 'FixedSize' tickbox, and set the size to 128,16 This will export the sprite correctly - of course there will be a lot of unused space in the exported file... so we would want to combine all our 16x16 together into a single image Generally it would be easier to build up a 16x16 sprite from 4 8x8 sprites |
![]() |
Address | Name | Purpose | Bits | Details |
$2101 | OBSEL | OAM size (Sprite) | SSSNNBBB | S=size (See below) N=Bame addr B=Base addr |
$2102 | OAMADDL/L | OAM address | LLLLLLLL | a=oam address L |
$2103 | OAMADDL/H | OAM address | R000000H | R= priority Rotation / H=oam address MSB |
$2104 | OAMDATA | OAM data | ???????? | |
$212C | TM | Main screen designation | ---S4321 | S=sprites 4-1=enable Bgx |
$2138 | OAMDATAREAD | Read data from OAM |
Sprite Sizes
Sprite size is set for all sprites, but each sprite can either be normal or large defined by a single bit from address $0100 onwards
SSS |
Size (Normal / Large) |
0 %000 |
8x8 / 16x16 |
1 %001 | 8x8 / 32x32 |
2 %010 | 8x8 / 64x64 |
3 %011 | 16x16 / 32x32 |
4 %100 | 16x16 / 64x64 |
5 %101 | 32x32 / 64x64 |
6 %110 | 16x32 / 32x64 (Undocumented) |
7 %111 | 16x32 / 32x32 (Undocumented) |
Sprite Definitions - OAM Data
The SNES has 128 hardware sprites.
Selecting a HL address is done by setting registers $2102 (L) and $2103 (H)
Each address below $0100 holds Two Bytes (The first table)...each address $0100 or above holds just one!... All data is written via the $2104Address | Byte 1 | Byte 2 | Meaning | SprNum |
$0000 | XXXXXXXX | YYYYYYYY | X=Xpos (bits 0-7) Y=Ypos | 0 |
$0001 | TTTTTTTT | YXPPCCCT | T=Tile Y=yflip X=xflip P=priority compared to BG C=palette +128 | 0 |
$0002 | XXXXXXXX | YYYYYYYY | X=Xpos (bits 0-7) Y=Ypos | 1 |
$0003 | TTTTTTTT | YXPPCCCT | T=Tile Y=yflip X=xflip P=priority compared to BG C=palette +128 | 1 |
� | � | � | � | � |
� | � | � | � | � |
$00FE | XXXXXXXX | YYYYYYYY | X=Xpos (bits 0-7) Y=Ypos | 127 |
$00FF | TTTTTTTT | YXPPCCCT | T=Tile
Y=yflip X=xflip P=priority compared to BG C=palette +128
|
127 |
$0100 | SXSXSXSX | (no 2nd byte) | S=LargeSize (1=Large size) sprite X=Xpos (bit 8) | 0-3 |
$0101 | SXSXSXSX | (no 2nd byte) | S=LargeSize (1=Large size) sprite X=Xpos (bit 8) | 4-6 |
� | � | � | � | |
$011F | SXSXSXSX | (no 2nd byte) | S=LargeSize (1=Large size) sprite X=Xpos (bit 8) | 124-127 |
Presumably because of the planned backwards compatibility, the SNES actually uses the same ports in the same way as the NES! However, because the SNES has more buttons, we can do 16 reads rather than 8 to get the extra buttons.
Mode | Port | Purpose | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Write | $4016 | Strobe (reset) | - | - | - | - | - | - | - | Strobe |
Read | $4016 | Joypad 1/3 | - | - | - | - | - | Mic | Pad3 | Pad1 |
Read | $4017 | Joypad 2/4 | - | - | - | - | - | - | Pad4 | Pad2 |
F | E | D | C | B | A | 9 | 8 | |
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
- | - | - | - | R | L | X | A | Right | Left | Down | Up | Start | Select | Y | B |
The SNES firmware also reads in these ports automatically, and stores these in ram - we can use these versions if we prefer.
Address | Name | Purpose | Bits |
$4218 | JOY1L | Joypad #1 status (set during interrupt) | AXLR---- |
$4219 | JOY1H | Joypad #1 status (if $4200 is set) | BYSTUDLR |
$421A | JOY2L | Joypad #2 status | AXLR---- |
$421B | JOY2H | Joypad #2 status | BYSTUDLR |
$421C | JOY3L | Joypad #3 status | AXLR---- |
$421D | JOY3H | Joypad #3 status | BYSTUDLR |
$421E | JOY4L | Joypad #4 status | AXLR---- |
$421F | JOY4H | Joypad #4 status | BYSTUDLR |
Ports
rw | Address | Name | Purpose | Bits | Details |
w | $2100 | INIDISP | Screen display | x000bbbb | x=screen disable (1=disable) bbbb=brightness (15=max) |
w | $2101 | OBSEL | OAM size (Sprite) | sssnnbbb | sss^size nn=name addr bb=base addr |
w 2 | $2102 | OAMADDL/H | OAM address | aaaaaaaa r000000m | a=oam address r=priority m=addr MSB |
wd | $2104 | OAMDATA | OAM data | ???????? ???????? | |
w | $2105 | BGMODE | Screen mode | abcdefff | abcd=tile sizes (8x8 or 16x16) e=pri fff=mode def |
w | $2106 | MOSAIC | Screen pixelation | xxxxabcd | xxxxx=pixel size abcd=affect background layer |
w | $2107 | BG1SC | BG1 Tilemap VRAM location | xxxxxxab | xxx=address
(* $800 bytes / $400 words) ab SC size 00=32x32 01=64x32 10=32x64 11=64x64 |
w | $2108 | BG2SC | BG2 Tilemap VRAM location | xxxxxxab | xxx=address
(* $800 bytes / $400 words) ab SC size 00=32x32 01=64x32 10=32x64 11=64x64 |
w | $2109 | BG3SC | BG3 Tilemap VRAM location | xxxxxxab | xxx=address
(* $800 bytes / $400 words) SC size 00=32x32 01=64x32 10=32x64 11=64x64 |
w | $210A | BG4SC | BG4 Tilemap VRAM location | xxxxxxab | xxx=address
(* $800 bytes / $400 words) SC size 00=32x32 01=64x32 10=32x64 11=64x64 |
w | $210B | BG12NBA | BG1 & BG2 VRAM location | aaaabbbb | aaaa=base
addr for BG1 (* $2000 bytes / $1000 words) bbbb=base addr for BG2 (* $2000 bytes / $1000 words) |
w | $210C | BG34NBA | BG3 & BG4 VRAM location | ccccdddd | cccc=base
addr for BG3 (*
$2000 bytes / $1000 words) dddd=base addr for BG4 (* $2000 bytes / $1000 words) |
wd | $210D | BG1HOFS | BG1 horizontal scroll | mmmmmaaa aaaaaaaa | aaa=horiz offset, mmm=Mode 7 option |
wd | $210E | BG1VOFS | BG1 vertical scroll |
|
Write L then
H byte of offset to this address |
wd | $210F | BG2HOFS | BG2 horizontal scroll |
|
Write L then H byte of offset to this address |
wd | $2110 | BG2VOFS | BG3 vertical scroll |
|
Write L then H byte of offset to this address |
wd | $2111 | BG3HOFS | BG3 horizontal scroll | - Same as $210D. | Write L then H byte of offset to this address |
wd | $2112 | BG3VOFS | BG3 vertical scroll |
|
Write L then H byte of offset to this address |
wd | $2113 | BG4HOFS | BG4 horizontal scroll |
|
Write L then H byte of offset to this address |
wd | $2114 | BG4VOFS | BG4 vertical scroll |
|
Write L then H byte of offset to this address |
w | $2115 | VMAIN | Video port control | i000abcd | I 0=inc on $2118 or $2139 1=$2119 or $213A� abcd=move size |
w 2 | $2116-$2117 | VMADDL/H | Video port address | LLLLLLLL HHHHHHHH | Memory address (in bytepairs)$0000-$7FFF |
w 2 | $2118-$2119 | VMDATAL/H | Video port data (Write) |
LLLLLLLL HHHHHHHH | Byte Data |
w | $211A | M7SEL | MODE7 settings | ab0000yx | ab=out of area function x=xflip y=yflip |
w | $211B | M7A | COS rotate angle / X Expnsn | ||
w | $211C | M7B | SIN rotate angle / X Expnsn | ||
w | $211D | M7C | SIN rotate angle / Y Expnsn | ||
w | $211E | M7D | COS rotate angle / Y Expnsn | ||
wd | $211F | M7X | Center position X (13-bit data only) | ||
wd | $2120 | M7Y | Center position Y (13-bit data only) | ||
w | $2121 | CGADD | Colour # (or pallete) selection | xxxxxxxx | x=color (0-255) |
wd | $2122 | CGDATA | Colour data | -bbbbbgg gggrrrrr | Color Data BGR |
w | $2123 | W12SEL | Window mask settings | abcdefghv | |
w | $2124 | W34SEL | Window mask settings | abcdefgh | |
w | $2125 | WOBJSEL | Window mask settings | abcdefgh | |
w | $2126 | WH0 | Window 1 left position | aaaaaaaa | a=position |
w | $2127 | WH1 | Window 1 right position |
|
|
w | $2128 | WH2 | Window 2 left position | - Same as $2126. | |
w | $2129 | WH3 | Window 2 right position |
|
|
w | $212A | WBGLOG | Mask logic cfg for Win 1 & 2 per scr | aabbccdd | aa..dd=BG 4321 |
w | $212B | WOBJLOG | Mask logic for Colour Win & OBJ Win | 0000aabb | a=color params b=obj window params |
w | $212C | TM | Main screen designation | ---S4321 | S=sprites 4-1=enable Bgx |
w | $212D | TD | Sub-screen designation | *** Same as $212C | |
w | $212E | TMW | Window mask main screen desig | *** Same as $212C | |
w | $212F | TSW | Window mask sub screen desig | *** Same as $212C | |
w | $2130 | CGWSEL | Fixed color addition or screen addition | abcd00ef | ab=main cd=sub ef=color data |
w | $2131 | CGADSUB | Addition/subtraction for screens | mrgsabcd | & OBJs [CGADSUB] |
w | $2132 | COLDATA | Fixed colour data for fixed colour +/- | bgrdddddd | Blue Green Red dddd=constant |
w | $2133 | SETINI | Screen mode/video select | sn00pvshi | |
r | $2134 | MPYL | Multiplication result (low) | ||
r | $2135 | MPYM | Multiplication result (middle) | ||
r | $2136 | MPYH | Multiplication result (high) | ||
r | $2137 | SLHV | Software latch for H/V counter | aaaaaaaa | a=result |
r | $2138 | OAMDATAREAD | Read data from OAM | ||
r 2 | $2139-$213A | VMDATAL/H READ | Video port data (Read) | ||
r | $213B | CGDATAREAD | Read data from CG-RAM (colour) | ||
r d | $213C | OPHCT | Horizontal scanline location | ||
r d | $213D | OPVCT | Vertical scanline location | ||
r | $213E | STAT77 | PPU status flag & version number | trm0vvvv | |
r | $213F | STAT78 | PPU status flag & version number | fl0mvvvv | |
rw | $2140 | APUI00 | APUI00 � Sound Port 0 |
|
|
rw | $2141 | APUI01 | APUI01 � Sound Port 1 | ||
rw | $2142 | APUI02 | APUI02 � Sound Port 2 |
|
|
rw | $2143 | APUI03 | APUI03 � Sound Port 3 |
|
|
rw | $2180 | WMDATA | Read/write WRAM | ||
rw | $2181 | WMADDL | WRAM data (low byte) | ||
rw | $2182 | WMADDM | WRAM data (middle byte) | ||
rw | $2183 | WMADDH | WRAM data (high byte) | ||
rw | $4016 | JOYWR/JOYA | Joypad Output / JOY 1 Read (bit 0 x12) | ||
r | $4017 | JOYB | JOY 2 Read (bit 0 x12) | ||
w | $4200 | NMITIMEN | Interrupt Enable and Joypad Request | v0yx000j | V=Vblank NMI
/ YX=HorizVert interrupt / J=Joypad Request |
w | $4201 | WRIO | Programmable I/O port (out-port) | ||
w | $4202 | WRMPYA | Multiplicand 'A' | ||
w | $4203 | WRMPYB | Multiplier 'B� | ||
w 2 | $4204 | WRDIVL/H | Dividend C | ||
w | $4205 | WRDIVB | Divisor B | ||
w 2 | $4207 | HTIMEL/H | Video H IRQ beam pos/pointer | 0000000x xxxxxxxx | x: Beam position. |
w 2 | $4209 | VTIMEL/H | Video V IRQ beam pos/pointer | 0000000y yyyyyyyy | y: Beam position. |
w | $420B | MDMAEN | DMA enable | 76543210 | |
w | $420C | HDMAEN | HDMA enable . | ||
w | $420D | MEMSEL | Cycle speed | 0000000x | 0=2.68 1=3.58 |
r | $4210 | RDNMI | NMI | x000vvvv | x=disable NMI v=version |
rw | $4211 | TIMEUP | Video IRQ | i0000000 | i=irq enabled |
rw | $4212 | HVBJOY | Status | xy00000a | x=vblank state y=hblank state a=joypad ready |
r | $4213 | RDIO | Programmable I/O port (in-port) | ||
r 2 | $4214 | RDDIVL/H | Quotient of divide result | ||
r 2 | $4216 | RDMPYL/H | Multiplication or divide result | ||
r | $4218 | JOY1L | Joypad #1 status (set during interrupt) | AXLR---- | |
r | $4219 | JOY1H | Joypad #1 status (if $4200 is set) | BYSTUDLR | |
r | $421A | JOY2L | Joypad #2 status | AXLR---- | |
r | $421B | JOY2H | Joypad #2 status | BYSTUDLR | |
r | $421C | JOY3L | Joypad #3 status | AXLR---- | |
r | $421D | JOY3H | Joypad #3 status | BYSTUDLR | |
r | $421E | JOY4L | Joypad #4 status | AXLR---- | |
r | $421F | JOY4H | Joypad #4 status | BYSTUDLR | |
w | $43x0 | DMAPX | DMA Control | vh0cbaaa | |
w | $43x1 | BBADX | DMA Destination | LLLLLLLL | H=$21 |
w 2 | $43x2 | A1TXL/H | Source address | ||
w | $43x4 | A1BX | Source bank address | ||
w 2 | $43x5 | DASXL/H | DMA transfer size & HDMA address | ||
w | $43xA | NTRLX | Number of lines for HDMA transfer | cxxxxxxx | C=continue (0=yes) x=lines to transfer |
WD=Write Double byte
2=Write 2 byte word
Sound on the SNES via the SPC700
To make sound on the SNES we have to use it:s SPC700
processor! what's the SPC700? well it's an 8 bit dedicated sound CPU with
64k of isolated memory - meaning that it can't be directly accessed from
the main CPU!
The SPC700 is a great sound processor, used by the Super Nintendo and many
other systems like... er.. the super nintendo!
Ok, so nothing else uses it, and it's a total pain! while it's sound
ability is good, its a real hassle to program... it uses it's own special
instruction set, and its bytecode matches no other CPU, and data has to be
transferred to it using a special procedure because we can't access it's
memory directly.
The CPU is 8 bit and Little endian, so $1234 is stored in ram as
$34,$12... it's registers are the same as the 6502, but it has some 16 bit
commands that use YA as a 16-bit pair like the Z80
it has a ZeroPage, but the ZeroPage is referred to as the
DirectPage, as it can be at $00xx or $01xx... $01xx is also used as the
Stack
Most data transfer commands are done with MOVe commands (like the 68000),
but like the z80, the destination is on the left... for example:
mov a, #$00 ;Set A to $00
I'm not planning to go into greater detail than I need on this CPU, so
please see the tutorials below:
Best SP700
reference
Also a good
tutorial
Sound samples must also be held in SPC700 ram... Pointers to Sound samples are stored in a single block.. this block must be byte aliened, and has 256 sound definitions - each of which contains 2 pointers... one for the start of the sample, and one for the loop For example, take the example definition, this will be loaded into SPC700 ram at $300... we would tell the sound chip to use $03 as the memory position using the "DIR" sound register $5D The sound samples themselves are made up of 9 byte chunks, the first byte is a header, and the other 16 nibbles are the sound data... the final sample in the sound should have the End bit set in the header, and the Loop bit if you wish |
align
8 SFXBank: ;We're going to load this into $0300 dw SFXBank_Sound1-SFXBank+$300 ;Sample 0 main dw SFXBank_Sound1-SFXBank+$300 ;Sample 0 Loop align 4 SFXBank_Sound1: ; SSSSFFLE S= bitshift (0-12) FF=Filter L=Loop E=End db %11000111,$FF,$F0,$F0,$F0,$F0,$F0,$F0,$F0 ; 01 23 45 67 89 AB CD EF |
The SPC700 Memory Map
Start
|
End | Purpose |
0000 | 00EF
|
Zero Page / Direct Page |
00F0 | 00F0 | Unused |
00F1 | 00F1 | Control Port (Timers & reset) |
00F2 | 00F2 | Sound Register Select |
00F3 | 00F3 | Sound Register Value |
00F4 | 00F4 | Link to 65816 address $2140 |
00F5 | 00F5 | Link to 65816 address $2141 |
00F6 | 00F6 | Link to 65816 address $2142 |
00F7 | 00F7 | Link to 65816 address $2143 |
0100 | 01FF | Stack |
0200 | FFBF | RAM |
FFC0 | FFFF | ROM |
The SPC700 Registers
Address | Register | Description | Bits | Meaning |
c0 | VOL (L) | Left Volume | -VVVVVVV | Volume |
c1 | VOL (R) | Right Volume | -VVVVVVV | Volume |
c2 | P (L) | Pitch L | PPPPPPPP | Pitch |
c3 | P (H) | Pitch H | --PPPPPP | Pitch |
c4 | SRCN | Source number (references the source directory) | SSSSSSSS | Source |
c5 | ADSR (1) | If bit7 is set, ADSR is enabled. If cleared GAIN is used. | EDDDAAAA | Enable, Dr, Ar |
c6 | ADSR (2) | These two registers control the ADSR envelope. | LLLRRRRR | sL,sR |
c7 | GAIN | This register provides function for software envelopes. | GGGGGGGG | G=Envelope bits |
c8 | -ENVX | (auto updated) Readable current Envelope Value | 0VVVVVVV | Value |
c9 | -OUTX | (auto updated) Readable current Waveform Value | SVVVVVVV | Signed Value |
0C | MVOL (L) | Main Volume Left | -VVVVVVV | Volume |
1C | MVOL (R) | Main Volume Right | -VVVVVVV | Volume |
2C | EVOL (L) | Echo Volume Left | -VVVVVVV | Volume |
3C | EVOL (R) | Echo Volume Right | -VVVVVVV | Volume |
4C | KON | Key On | CCCCCCCC | Channel |
5C | KOF | Key Off | CCCCCCCC | Channel |
6C | FLG | DSP Flags. (used for MUTE,ECHO,RESET,NOISE CLOCK) | RMENNNNN | Reset
(0=off) Mute (0=off) Echo (1=0ff) N=Noise clock |
7C | -ENDX | (auto updated) read to see if channel done | CCCCCCCC | Channel |
0D | EFB | Echo Feedback | SFFFFFFF | Signed Feedback |
2D | PMON | Pitch modulation | CCCCCCC- | Channel (1-7) |
3D | NON | Noise enable | CCCCCCCC | Channel (0=off) |
4D | EON | Echo enable | CCCCCCCC | Channel
(0=off) |
5D | DIR | Offset of source directory (DIR*100h = memory offset) | OOOOOOOO | Offset $oo00 |
6D | ESA | Echo buffer start offset (ESA*100h = memory offset) | OOOOOOOO | Offset $oo00 |
7D | EDL | Echo delay, 4-bits, higher values require more memory. | ----EEEE | Echo delay |
fF | COEF | 8-tap FIR Filter coefficients | SCCCCCCC | Signed Coeficcient |
c = Channel 0-7� f = filter coefficient 0-7 |
SPC700 and VASM
Vasm doesn't support the SPC700, but we can simulate the commands with macros, for example, we can set an immediate value with the macro to the right | macro
s_mov_a_ii,aval ;Set
A=immediate value db $E8 db \aval endm |
If we want to do a relative jump, we can calculate the relative offset with Destination-(*+1) | s_bne_r SoundCallPause-(*+1) |
If we want to include our SPC700 code in our main rom, we'll need to adjust call addresses for the changing location, to do this we can use the formula [DestinationLabel]- [StartOfProgramInMainRom]+ [DestinationOfProgramInSPC700Ram] | s_call_addr SoundCallResume-SoundProgram+SndPrgMemLoc |