thinking outside the cartridge
jake "ferris" taylor
hello everyone
![](https://s3.amazonaws.com/media-p.slid.es/uploads/yupferris/images/1180716/sneslogo.png)
love your process
FIRST THINGS FIRST
what does a snes look like?
![](https://s3.amazonaws.com/media-p.slid.es/uploads/yupferris/images/1180785/Super_Nintendo_Entertainment_System-USA.jpg)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/yupferris/images/1180792/1139313-snes_800.jpg)
AUDIO
MAIN SYSTEM
VIDEO
CPU
128kb RAM
CPU
64kb RAM
DSP
PPU
64kb VRAM
512b CGRAM
544b OAM
CARTRIDGE
1-4MB ROM
AUDIO
MAIN SYSTEM
VIDEO
CPU
128kb RAM
CPU
64kb RAM
DSP
PPU
64kb VRAM
512b CGRAM
544b OAM
CARTRIDGE
1-4MB ROM
DMA!!
brief intro to oldschool coding
main() { printf("Hello World"); }
public void Render(int width, int height, Sync sync, double time)
{
GL.ClearColor(Color.FromArgb(0, 0, 68));
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.LoadIdentity();
GL.Translate(0.0f, 0.0f, -25.0f);
var color = Color.FromArgb(113, 232, 81);
Helpers.Bar(color, 0.0f, -1.0f, 3.0f, 0.5f);
Helpers.Bar(color, 0.0f, 0.0f, 3.0f, 0.5f);
Helpers.Bar(color, 0.0f, 1.0f, 3.0f, 0.5f);
}
; x = voice data offset (trashes y)
ReadPatternByte:
mov a, VoiceState::CompType + x
bne +
; Uncompressed
call ReadNextByte
ret
; Rle (run length, symbol)
+: mov a, VoiceState::CompParam1 + x
bne +
; Start next run
call ReadNextByte
push a
call ReadNextByte
mov VoiceState::CompParam2 + x, a
pop a
+: ; Read next byte from run
dec a
mov VoiceState::CompParam1 + x, a
mov a, VoiceState::CompParam2 + x
ret
; x = voice data offset (trashes y)
ReadNextByte:
mov a, VoiceState::PatternAddrLow + x
mov CurrentByteAddrLow, a
clrc
adc a, #$01
mov VoiceState::PatternAddrLow + x, a
mov a, VoiceState::PatternAddrHigh + x
mov CurrentByteAddrHigh, a
adc a, #$00
mov VoiceState::PatternAddrHigh + x, a
mov y, #$00
mov a, [CurrentByteAddr] + y
ret
; a = note, x = voice data offset
SetNote:
asl a
mov y, a
mov a, !MusicData.PitchTable + y
mov VoiceState::PitchLow + x, a
inc y
mov a, !MusicData.PitchTable + y
mov VoiceState::PitchHigh + x, a
ret
; a = instrument number
LoadInstrumentDataAddr:
push x
dec a
asl a
mov x, a
mov a, !MusicData.InstrumentTable + x
mov CurrentInstrAddrLow, a
inc x
mov a, !MusicData.InstrumentTable + x
mov CurrentInstrAddrHigh, a
pop x
ret
EffectArpeggio:
pop x
mov y, #$00
mov a, VoiceState::EffectParam2 + x
cmp a, #$01
bne ++++
mov a, VoiceState::EffectParam1 + x
xcn a
mov y, a
++++: cmp a, #$02
bne ++++
mov a, VoiceState::EffectParam1 + x
mov y, a
++++: mov a, y
and a, #$0f
clrc
adc a, VoiceState::Note + x ; TODO: Handle overflows
call SetNote
mov a, VoiceState::EffectParam2 + x
inc a
cmp a, #$03
bcc ++++
mov a, #$00
++++: mov VoiceState::EffectParam2 + x, a
jmp EffectEnd
EffectPitchUp:
pop x
mov a, VoiceState::EffectParam1 + x
xcn a
mov y, a
and a, #$f0
clrc
adc a, VoiceState::PitchLow + x
mov VoiceState::PitchLow + x, a
mov a, y
and a, #$0f
adc a, VoiceState::PitchHigh + x
mov VoiceState::PitchHigh + x, a
jmp EffectEnd
EffectPitchDown:
pop x
mov a, VoiceState::EffectParam1 + x
xcn a
mov y, a
and a, #$f0
mov FxWork1, a
mov a, VoiceState::PitchLow + x
setc
sbc a, FxWork1
mov VoiceState::PitchLow + x, a
mov a, y
and a, #$0f
mov FxWork1, a
mov a, VoiceState::PitchHigh + x
sbc a, FxWork1
mov VoiceState::PitchHigh + x, a
jmp EffectEnd
CHRONOLOGY
1991
childhood
yes i listened to the chrono trigger soundtrack on repeat while preparing this
~2000
~2004
~2008-2011
kickassembler
// Execute macro
:ClearScreen($0400,$20) // Since they are encapsulated in a scope
:ClearScreen($4400,$20) // the two resulting loop labels don’t
// interfere
// Define macro
.macro ClearScreen(screen,clearByte) {
lda #clearByte
ldx #0
Loop: // The loop label can’t be seen from the outside
sta screen,x
sta screen+$100,x
sta screen+$200,x
sta screen+$300,x
inx
bne Loop
}
~2008-2011
November 2011
![](https://s3.amazonaws.com/media-p.slid.es/uploads/yupferris/images/1180889/25-jahre-game-boy-nintendos-kleines-grosses-wunder_nqxd.jpg)
gameboy demo workflow
demon blood
![](https://s3.amazonaws.com/media-p.slid.es/uploads/yupferris/images/1180917/00059196.png)
Assembler round 2
MUSIC
official tools
xmsnes
make my own!
be rad
how to do a demo in 3 weeks
video
video compression
image sequence
delta encoding
0 1 2 3 4 5 6 7
0 1 1 1 1 1 1 1
0 1
temporal delta encoding
![](https://s3.amazonaws.com/media-p.slid.es/uploads/yupferris/images/1180956/IP-Video-tutorial-video-compression.jpg)
representing video on snes
virtual machine
LoadPaletteData address length data LoadVramData address length data
EndOfFrame
EndOfTransmission
LoadPaletteData 0x00 0x16 [...] LoadVramData 0x2000 0x0800 [...] EndOfFrame
nu
![](http://38.media.tumblr.com/951dec8e108481e5a5ac0f59abc6c535/tumblr_nk3elhPWaz1unpujno1_r1_500.gif)
![](http://31.media.tumblr.com/18883a7753148531bc9844c5ebac242f/tumblr_nk3elhPWaz1unpujno2_r1_500.gif)
- Heavily inspired by/ripped off of beeple's four.color.process series
refining the tech
then it hit me
cracking the code
full control
ideal snes coding environment
- I could program in F#
- Using pure, immutable data
- Composing with code and syncing with Ableton Live
then it hit me ...again
opcodes!!
any.
way.
i.
want.
smash it
![](http://33.media.tumblr.com/d3a2b7a04e4626d60cd3948c5d08e4d7/tumblr_nk3elhPWaz1unpujno3_r1_500.gif)
![](http://38.media.tumblr.com/efd46f0ca2a0931167aa268f4e6832eb/tumblr_nk3elhPWaz1unpujno4_r1_500.gif)
conclusion
what's next
thinking outside the cartridge
thank you!
Thinking Outside the Cartridge
By yupferris
Thinking Outside the Cartridge
Modern Ideas Applied to Archaic Devices
- 1,481