Learn Multi platform 6502 Assembly Programming... For Monsters!
Platform Specific Lessons
The Nes palette is slightly odd
compared to RGB systems, you can see how the HEX values map to
colors in the chart to the right-> Each tile has 4 colors*, and you can have 4 separate palettes for tiles... and a separate 4 for sprites... this makes a total of 32 color definitions for tiles and sprites combined * Though the background colors are common to all sprites. |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Our Tutorials use a common format
on all platforms, where each channel is defined by one nibble in
$-GRB format... Because this doesn't easily map to the Nes palette, we'll convert it using a Lookup table of 3x3x3 size, so RGB values will go from 0-2 |
![]() |
The NES
palette is a bit rigid, and doesn't really map to RGB very
well, but we've done what we can! If you don't like the mappings here, you can change the Lookup Table, or write your own native code. |
![]() |
While Pattern data is defined by
the Name Table, the Attribute Table defines the Color By default the NES has too little VRAM to use Name/Attrib Table 2 & 3 Specify a memory address by writing the byte pair to $2006... HIGH BYTE FIRST... (Big Endian) NOTE: Writing to VRAM outside of VBLANK will cause problems... also note, selecting an address resets PPUSCROLL EG, lets point to $3F00... and write $11 to the first palette entry! lda #$3F ;High byte sta $2006 ;Send to vram select lda #$00 ;Low byte sta $2006 ;Send to vram select lda #$11 ;New value sta $2007 ;Send to write data |
* Extra Ram Only |
||||||||||||||||||||||||||||||||||||||||||
Each palette on the NES has 3 colors -Background Color 0 is a common background color, and Color 0 in sprites transparent |
|
||||||||||||||||||||||||||||||||||||||||||
The NES Name Table defines the Tilemap's patterns... one byte
per 8x8 tile defines the number of the tile... the name table is
32x30 tiles in size, so spans from $2000-$23BF Note: Name Table 2,3 ($2800-$3000) are not available on an standard NES , they will only be available if your cartridge has Extra Ram! Color's are defined by the 'Attribute table'... effectively, each square block of 2x2 tiles (16x16 pixels) have to use the same color palette... and each block of 4x4 tiles (32x32 pixels) are defined by a single byte (2 bits per block - for 4 possible palettes) Lets take the example to the right, with different 16 tiles making up a grid of 32x32 pixels- each areas palette would be defined by a single byte in the way below:
|
![]() |
![]() |
Unfortunately on the
NES, although our tiles are 8x8 pixel, our palette is defined at
a 16x16 level You'll notice objects in NES games (Such as ? blocks in mario) are usally 16x16 to ensure this isn't a problem. |
![]() |
Lesson
P22 - Palette Definitions on the SNES / Super Famicom The Snes has 256 onscreen colors, and a superb 5 bits per channel RGB palette definition... lets learn how to use it! |
![]() |
![]() BmpTest.asm
|
|
![]() |
Two ports are used to define the color on the SNES, the first
takes a single byte and selects the color we want to change, the second takes two bytes, and defines the new RGB color for that entry. |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
The 256 colors make up 16
palettes... the first 8 are used by Background patterns... the
second 8 are used by Sprites |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
In these tutorials, we a common format using one nibble per
color channel in the format $-GRB... The SNES uses 5 bits per channel in the format %-BBBBBGG GGGRRRRR We will need to convert our format to the correct format for the SNES! |
|
The 255 onscreen
colors of the SNES are split between the Backgrounds and
Sprites, but the code will look at today will set background
and sprite colors at the same time. This will make things easier, and as we've only got 16 colors on most systems, we won't miss the extra colors in these tutorials! |
![]() |
![]() |
In these tutorials we will write a driver
called 'ChibiSound' - it takes a single byte in the
accumulator, in the format %NVPPPPPP where N=Noise, V=Volume
and P=Pitch. This allows our multiplatform games to make sound effects in a similar way on all the systems. |
Group | Name | Description | Address A80 | Address A52 | Bits | Meaning |
POKEY | AUDF1 | Audio frequency 1 control | $D200 | $E800 | FFFFFFFF | F=Frequency |
POKEY | AUDC1 | Audio channel 1 control | $D201 | $E801 | NNNNVVVV | N=Noise V=Volume |
POKEY | AUDF2 | Audio frequency 2 control | $D202 | $E802 | FFFFFFFF | F=Frequency |
POKEY | AUDC2 | Audio channel 2 control | $D203 | $E803 | NNNNVVVV | N=Noise V=Volume |
POKEY | AUDF3 | Audio frequency 3 control | $D204 | $E804 | FFFFFFFF | F=Frequency |
POKEY | AUDC3 | Audio channel 3 control | $D205 | $E805 | NNNNVVVV | N=Noise V=Volume |
POKEY | AUDF4 | Audio frequency 4 control | $D206 | $E806 | FFFFFFFF | F=Frequency |
POKEY | AUDC4 | Audio channel 4 control | $D207 | $E807 | NNNNVVVV | N=Noise V=Volume |
POKEY | AUDCTL | general audio control | $D208 | $E808 | N1234HHS | N=Noise bit depth 1234=Channel Clocks HH=highpass filters S=main clockspeed |
![]() |
The Sound on the Atari Lynx is odd...while it's very capable, compared to other systems it's very hard to understand!...Fortunately if we ignore the documentation, and just use some 'basic code' we can get some stuff working easily! |
From | To | Name | Description | Bits | Meaning |
FD1C | FD1F | TIMER7 | Timer Channel 7 and mag1b | ||
FD20 | FD20 | VOL | Audio Channel 0 � 2�s compliment Volume control | -VVVVVVV | V=Volume (0-127) |
FD21 | FD21 | FEEDBACK | Audio Channel 0 � Shift register feedback enable | FFFFFFFF | Effective
sound of instrument ($10=Square Tone / $90=Noise) |
FD22 | FD22 | RAW | Audio Channel 0 � Audio Output Value (Raw Data) | Constantly changes | |
FD23 | FD23 | SHIFTL | Audio Channel 0 � Lower 8 bits of shift register | SSSSSSSS | Shift Regsiter L |
FD24 | FD24 | FREQ | Audio Channel 0 � Audio Timer Backup Value | TTTTTTTT | T=Timer (effectively Frequency) |
FD25 | FD25 | CONTROL | Audio Channel 0 � Audio Control Bits | FTIRCKKK | F=Feedback bit 7 , reset Timer done, enable Integrate, enable Reload enable Count, clocK select |
FD26 | FD26 | COUNT | Audio Channel 0 � Audio Counter | Constantly changes | |
FD27 | FD27 | OTHER | Audio Channel 0 �Other Audio Bits | SSSS-CBB | S=Shift Register H, C=Clock state B=Borrow |
FD28 | FD28 | VOL | Audio Channel 1 � 2�s compliment Volume control | -VVVVVVV | V=Volume (0-127) |
FD29 | FD29 | FEEDBACK | Audio Channel 1 � Shift register feedback enable | FFFFFFFF | Effective pitch of instrument |
FD2A | FD2A | RAW | Audio Channel 1 � Audio Output Value (Raw Data) | Constantly changes | |
FD2B | FD2B | SHIFTL | Audio Channel 1 � Lower 8 bits of shift register | SSSSSSSS | Shift Regsiter L |
FD2C | FD2C | FREQ | Audio Channel 1 � Audio Timer Backup Value | TTTTTTTT | T=Timer (effectively Frequency) |
FD2D | FD2D | CONTROL | Audio Channel 1 � Audio Control Bits | FTIRCKKK | F=Feedback bit 7 , reset Timer done, enable Integrate, enable Reload enable Count, clocK select |
FD2E | FD2E | COUNT | Audio Channel 1 � Audio Counter | Constantly changes | |
FD2F | FD2F | OTHER | Audio Channel 1 �Other Audio Bits | SSSS-CBB | S=Shift Register H, C=Clock state B=Borrow |
FD30 | FD30 | VOL | Audio Channel 2 � 2�s compliment Volume control | -VVVVVVV | V=Volume (0-127) |
FD31 | FD31 | FEEDBACK | Audio Channel 2 � Shift register feedback enable | FFFFFFFF | Effective pitch of instrument |
FD32 | FD32 | RAW | Audio Channel 2 � Audio Output Value (Raw Data) | Constantly changes | |
FD33 | FD33 | SHIFTL | Audio Channel 2 � Lower 8 bits of shift register | SSSSSSSS | Shift Regsiter L |
FD34 | FD34 | FREQ | Audio Channel 2 � Audio Timer Backup Value | TTTTTTTT | T=Timer (effectively Frequency) |
FD35 | FD35 | CONTROL | Audio Channel 2 � Audio Control Bits | FTIRCKKK | F=Feedback bit 7 , reset Timer done, enable Integrate, enable Reload enable Count, clocK select |
FD36 | FD36 | COUNT | Audio Channel 2 � Audio Counter | Constantly changes | |
FD37 | FD37 | OTHER | Audio Channel 2 �Other Audio Bits | SSSS-CBB | S=Shift Register H, C=Clock state B=Borrow |
FD38 | FD38 | VOL | Audio Channel 3 � 2�s compliment Volume control | -VVVVVVV | V=Volume (0-127) |
FD39 | FD39 | FEEDBACK | Audio Channel 3 � Shift register feedback enable | FFFFFFFF | Effective pitch of instrument |
FD3A | FD3A | RAW | Audio Channel 3 � Audio Output Value (Raw Data) | Constantly changes | |
FD3B | FD3B | SHIFTL | Audio Channel 3 � Lower 8 bits of shift register | SSSSSSSS | Shift Regsiter L |
FD3C | FD3C | FREQ | Audio Channel 3 � Audio Timer Backup Value | TTTTTTTT | T=Timer (effectively Frequency) |
FD3D | FD3D | CONTROL | Audio Channel 3 � Audio Control Bits | FTIRCKKK | F=Feedback bit 7 , reset Timer done, enable Integrate, enable Reload enable Count, clocK select |
FD3E | FD3E | COUNT | Audio Channel 3 � Audio Counter | Constantly changes | |
FD3F | FD3F | OTHER | Audio Channel 3 �Other Audio Bits | SSSS-CBB | S=Shift Register H, C=Clock state B=Borrow |
FD40 | FD40 | ATTENREG0 | LLLLRRRR � Audio Attenuation | ||
FD41 | FD41 | ATTENREG1 | LLLLRRRR � Audio Attenuation | ||
FD42 | FD42 | ATTENREG2 | LLLLRRRR � Audio Attenuation | ||
FD43 | FD43 | ATTENREG3 | LLLLRRRR � Audio Attenuation | ||
FD44 | FD44 | MPAN | Stereo attenuation selection | ||
FD50 | FD50 | MSTEREO | Stereo disable | LLLLRRRR | 0=all on 255=all off |
These tutorials use a sound 'driver' called ChibiSound, Chibisound uses a single byte parameter in the Accumulator, and provides 64 different pitches, in low or high volume with either tones or noise. Sending a value of 0 mutes sound, all other values make a tone... Chibisound is intended to make it simple to have SFX in multiplatform games and was used in Grime Z80 and Grime 6502 |
|
These tutorials use a sound 'driver' called
ChibiSound, Chibisound uses a single byte parameter in the Accumulator, and provides 64 different pitches, in low or high volume with either tones or noise. Sending a value of 0 mutes sound, all other values make a tone... Chibisound is intended to make it simple to have SFX in multiplatform games and was used in Grime Z80 and Grime 6502 |
|
Reg | Address | Meaning | Channels | 7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
Bit Meaning |
0 | $0800 | Channel Select | All | - | - | - | - | - | C | C | C | Channel Select |
1 | $0801 | Main Amplitude Level | All | L | L | L | L | R | R | R | R | L/R Volume |
2 | $0802 | Frequency L | 0-5 | L | L | L | L | L | L | L | L | Frequency botttom 8 bits |
3 | $0803 | Frequency H | 0-5 | - | - | - | - | H | H | H | H | Frequency top 4 bits |
4 | $0804 | Channel On/Write | 0-5 | E | D | - | V | V | V | V | V | Enable (play)/write data... Direct digitaldata� channel Volume |
5 | $0805 | LR Volume | 0-5 | L | L | L | L | R | R | R | R | L/R Volume |
6 | $0806 | Waveform Data | 0-5 | - | - | - | W | W | W | W | W | Wave data (write 32 times) |
7 | $0807 | Noise Enable | 4-5 | E | - | - | N | N | N | N | N | Enable noise� Noise freq (Chn 4/5 only) |
8 | $0808 | LFO Freq | All | F | F | F | F | F | F | F | F | LFO Frequency |
9 | $0809 | LFO Control | All | T | - | - | - | - | - | C | C | LFO Trigger� Control |
Making a
beep is a bit of a pain on the PC-Engine, but it's 6 digital
sound channels give it powerful sound potential, but it's
easier to understand than the Lynx, and far easier than the
horrible complexity of the SNES (which is comparable in other
technical capabilities) |
![]() |
Address | Purpose | Bits | Details |
4000h | APU Channel 1 (Rectangle) Volume/Decay (W) | CCLEVVVV | Volume, Envelope, Length counter,duty Cycle |
4001h | APU Channel 1 (Rectangle) Sweep (W) | EUUUDSSS | Sweep, Direction,Update rate, Enabled |
4002h | APU Channel 1 (Rectangle) Frequency (W) | LLLLLLLL | frequency L byte |
4003h | APU Channel 1 (Rectangle) Length (W) | CCCCCHHH | frequency H byte, length Counter load register |
4004h | APU Channel 2 (Rectangle) Volume/Decay (W) | CCLEVVVV | Volume, Envelope, Length counter,duty Cycle |
4005h | APU Channel 2 (Rectangle) Sweep (W) | EUUUDSSS | Sweep, Direction,Update rate, Enabled |
4006h | APU Channel 2 (Rectangle) Frequency (W) | LLLLLLLL | frequency L byte |
4007h | APU Channel 2 (Rectangle) Length (W) | CCCCCHHH | frequency H byte, length Counter load register |
4008h | APU Channel 3 (Triangle) Linear Counter (W) | CLLLLLLL | Clock disable start, Linear count load reg |
4009h | APU Channel 3 (Triangle) N/A (-) | -------- | unused |
400Ah | APU Channel 3 (Triangle) Frequency (W) | LLLLLLLL | frequency L byte |
400Bh | APU Channel 3 (Triangle) Length (W) | CCCCCHHH | frequency H byte, length Counter load register |
400Ch | APU Channel 4 (Noise) Volume/Decay (W) | CCLEVVVV | Volume, Envelope, Length counter,duty Cycle |
400Dh | APU Channel 4 (Noise) N/A (-) | -------- | unused |
400Eh | APU Channel 4 (Noise) Frequency (W) | LLLLLLLL | frequency L byte |
400Fh | APU Channel 4 (Noise) Length (W) | CCCCCHHH | frequency H byte, length Counter load register |
4010h | APU Channel 5 (DMC) Play mode and DMA frequency (W) | IL�FFFF | Irq enable, Loop, Frequency |
4011h | APU Channel 5 (DMC) Delta counter load register (W) | -DDDDDDD | Delta Counter or 7bit PCM Data |
4012h | APU Channel 5 (DMC) Address load register (W) | AAAAAAAA | Address = $C000+(A*$40) |
4013h | APU Channel 5 (DMC) Length register (W) | LLLLLLLLL | Length = (L*$10)+1 Bytes |
4015h | DMC/IRQ/length counter status/Sound channel enable register (RW) | DF-54321 | Dmc irq status/ Frame irq status Channel 12345 on |
In this way we can at least manage the basics of sound on the Nes, of course the NES has more capabilities - like triangle waves, and the potential for digital sound... but if you want to use those, you'll have to figure them out yourself! | ![]() |
The SNES SPC700 sound chip uses it's own assembly language,
it's syntax is similar to z80, but it's registers are more like
the 6502! We're going to write a simple
program in these tutorials, but we're not going to cover the
whole instruction set... please see the SFC
development wiki which already covers this in far more
detail than I ever can.
In these tutorials we use VASM
for assembly, but VASM doesn't support the SPC700 instruction
set - if we were writing a complex program we could use a different
assembler, but as we're only doing the basics, we'll
define macros to simulate the SPC700 commands we need.
|
![]() |
![]() |
If you want
to make something more complex, you'll probably want to use a
real SPC700 assembler, then again, it would probably be best
to find some existing music playing software for the SPC700
and use that instead! |
65816
side |
SPC700 side |
$2140 | $00F4 |
$2141 | $00F5 |
$2142 | $00F6 |
$2143 | $00F7 |
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 |
![]() |
We can transfer more data
later, but we'll need to get the SPC700 to call the firmware at
$FFC0 somehow... The code we'll look at in moment can do this - and we use it to write our program code in one transfer, then the samples as a second. |
Port SPC700 / 65816 | Purpose |
$00F4 / $2140 | if command 3... Reg num |
$00F5 / $2141 | if command 3... Reg val |
$00F6 / $2142 | Command... 3=SetReg / 2=restart ROM data transfer |
$00F7 / $2143 | Sync... Read the value in this port, and write it back to the SPC700 to do a command.. then wait until the read data changes to know the command was processed |
![]() |
This isn't
really a smart way to use the SPC700 - really we'd want a music
player on there, so we could leave it playing music by itself
without bothering the main CPU, But in this example, we want something 'simple' so we can control the registers and learn how they work. |
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) 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 |
4D | EON | Echo enable | CCCCCCCC | Channel |
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 |
These tutorials use a sound 'driver' called
ChibiSound, Chibisound uses a single byte parameter in the Accumulator, and provides 64 different pitches, in low or high volume with either tones or noise. Sending a value of 0 mutes sound, all other values make a tone... Chibisound is intended to make it simple to have SFX in multiplatform games and was used in Grime Z80 and Grime 6502 |
|
The sound
sample format is pretty complex, it's effectively a kind of
ADPCM, you'll probably want to find a converter and convert
some WAV samples into the correct format for the SNES. The sample we use here is just a simple test so we can here the SPC700 actually do something! |
![]() |
![]() |
We've made a beep on the SNES - and it's
only taken about 200 lines of code! Of course, the SNES sound chip is really designed for making music, using digital sound samples of instruments, but if you want to try to do that, you're on your own! There are music players available for the snes - so you don't really need to write one, but for these tutorials, we always try to do things ourselves! |
VIC 20 Sound ports
There are 3 sound channels for the 3 different frequencies, one for
random noise, and a volume setting...
As well as volume The top 4 bits of the $900E also handles color
Address | Meaning | Bits | Details |
$900A | Frequency for oscillator 1 (Bass) | OFFFFFFF | O=On
F=Frequency |
$900B | Frequency for oscillator 2 (medium) | OFFFFFFF | O=On F=Frequency |
$900C | Frequency for oscillator 3 (high freq) | OFFFFFFF | O=On F=Frequency |
$900D | Frequency of noise source | OFFFFFFF | O=On F=Frequency |
$900E | Volume of all sound / Auxiliary color information | CCCCVVVV | V=Volume C=Aux color |
These tutorials use a sound 'driver' called
ChibiSound, Chibisound uses a single byte parameter in the Accumulator, and provides 64 different pitches, in low or high volume with either tones or noise. Sending a value of 0 mutes sound, all other values make a tone... Chibisound is intended to make it simple to have SFX in multiplatform games and was used in Grime Z80 and Grime 6502 |
|
We've used 2
of the 4 channels, but the other 2 are basically the same,
they just handle different sound pitches. We can change the pitch of the function by using $900A or $900C instead of $9000B in our code. |
![]() |
Address | Description | Bits | Meaning |
$D400 | Voice #1 frequency L | LLLLLLLL | |
$D401 | Voice #1 frequency H | HHHHHHHH | Higher values=higher pitch |
$D402 | Voice #1 pulse width L | LLLLLLLL | |
$D403 | Voice #1 pulse width H | ----HHHH | |
$D404 | Voice #1 control register | NPST-RSG | Noise /
Pulse / Sawtooth / Triangle / - test / Ring mod / Sync / Gate
(Turn on) |
$D405 | Voice #1 Attack and Decay length | AAAADDDD | Atack / Decay |
$D406 | Voice #1 Sustain volume and Release length. | SSSSRRRR | Sustain / Release |
$D407 | Voice #2 frequency L | LLLLLLLL | |
$D408 | Voice #2 frequency H | HHHHHHHH | Higher values=higher pitch |
$D409 | Voice #2 pulse width L | LLLLLLLL | |
$D40A | Voice #2 pulse width H | ----HHHH | |
$D40B | Voice #2 control register | NPST-RSG | Noise / Pulse / Sawtooth / Triangle / - test / Ring mod / Sync / Gate (Turn on) |
$D40C | Voice #2 Attack and Decay length | AAAADDDD | Atack / Decay |
$D40D | Voice #2 Sustain volume and Release length. | SSSSRRRR | Sustain / Release |
$D40E | Voice #3 frequency L | LLLLLLLL | |
$D40F | Voice #3 frequency H | HHHHHHHH | Higher values=higher pitch |
$D410 | Voice #3 pulse width L | LLLLLLLL | |
$D411 | Voice #3 pulse width H | ----HHHH | |
$D412 | Voice #3 control register. | NPST-RSG | Noise / Pulse / Sawtooth / Triangle / - test / Ring mod / Sync / Gate (Turn on) |
$D413 | Voice #3 Attack and Decay length. | AAAADDDD | Atack / Decay |
$D414 | Voice #3 Sustain volume and Release length. | SSSSRRRR | Sustain / Release |
$D415 | Filter cut off frequency L | -----LLL | |
$D416 | Filter cut off frequency H | HHHHHHHH | |
$D417 | Filter control | RRRREVVV | R=Resonance / External / V= Voice 3-1 |
$D418 | Volume and filter modes | MHBLVVVV | Mute3 / Highpass / Bandpass / Lowpass / Volume (0=silent) |
$D41B | Voice #3 waveform output. (Read only) | DDDDDDDD | |
$D41C | Voice #3 ADSR output. (Read only) | DDDDDDDD |
These tutorials use a sound 'driver' called
ChibiSound, Chibisound uses a single byte parameter in the Accumulator, and provides 64 different pitches, in low or high volume with either tones or noise. Sending a value of 0 mutes sound, all other values make a tone... Chibisound is intended to make it simple to have SFX in multiplatform games and was used in Grime Z80 and Grime 6502 |
|
![]() |
We've only used one
Voice in this example, but we can use the others in the same
way... we can also change the value we write to $D404, #%01000000 will be a Pulse, #%00100000 is Sawtooth, and #%00010000 is a Triangle sound. Attack and Decay can also be changed to alter the way the sound changes over time. |