INDEX | ROMS | CODE MAP
WiLL-i-ROMS mods
Disassembly of Defender sound ROM code and use of Heathkit ET-3400 to play the SYNTHs and change a parameter via the PIA B input binary bit data switches. Audio is typically sent from the 8 bit accumulator A to the PIA port A output address 0x8000 (arcade: 0x0400). PIA port B is the sound select port on pinball and arcade games, but here it is assigned to parameter changes via an 8 bit binary data switch. The digital audio sent out from the PIA is then piggy-backed onto a modified sound board's 1408 DAC chip and then amplified with the TDA2002 8 watt amplifier.
Link to the WiLL-i-ROMS repo of functioning .asm files.
Below is the first mod hardware version of a Heathkit ET-3400 mpu system with added PIA and addressing logic and a modified system 7 sound board with RAM, ROM, MPU and PIA ICs removed:
An updated hardware mod version now has a breakout board consisting of two PIAs and two 8 bit switches to allow for adjusting two parameters within the assembly code. PIA 2 port A is free for a possible future addition of an 8 bit rotary encoder. Experiments with extracted assembly code from various System 4-7 ROM SYNTH routines have their own repo, linked below.
Link to the DEF-ROM repo of experimental .asm files.
Below is the latest (2021) mod hardware version of a Heathkit ET-3400 mpu system with breakout board of two PIAs and necessary addressing logic jumpered to a modified system 7 sound board using only DAC to amplifier signal path with RAM, ROM, MPU and PIA ICs removed:
Williams Defender sound ROM code layout
The following table shows the current state of figuring out the assembly routines for the 2kb Sound Rom 15.
It has been updated to show the merged source file labels (work in progress).
Link to merged file here in the github repo.
Sound ROM 15 notes:
DEFENDER SOUNDS REV. 1.0 BY SAM D 10/80
COPYRIGHT WILLIAMS ELECTRONICS 1980
PROGRAM ORIGINATION DATE 10/24/80
PROGRAM RELEASE 10/31/80
PROGRAMMER: SAM DICKER
General Definitions:
PARAM : modifier or setter of parameters that affect the sound
SYNTH : looping code with output writes to generate sound via the PIA/DAC
UTIL : similar to PARAM
IRQ : routine handles the interrupt request vectors that select the sound
CALCOS : calculate offset routine for both sound select and PARAM modifiers
NMI : non-masking interrupt routine to handle the test/reset button press
VWTAB : vector table (fdb) addresses for PARAM/SYNTH routines as per IRQ
VVECT : table (fcb) parameters for SYNTHs (7x 8 bit params and 1x 16 bit counter)
WAVFCB : waveform data called by SYNTHs or PARAMs
MOTVCT : Motorola vector table for IRQ, SWI, NMI, RESET
Addr Label Source Label Notes
____ _____ ____________ _____
F800 ORG ORG
F801 RESET SETUP
F82A PARAM1 VARILD Vari Loader
F83F SYNTH1 VARI Variable Duty Cycle Square Wave Routine
F88C PARAM2 LITE Lightning
F894 SYNTH2 APPEAR Appear
F89E " " LITEN Lightning+Appear Routine
F8CD SYNTH3 TURBO Turbo
F8DC " " NOISE White Noise Routine
F913 PARAM3 BG1 Background 1 Routine
F91C PARAM4 THRUST Thrust
F923 PARAM5 CANNON Cannon
F930 SYNTH4 FNOISE Filtered Noise Routine
F9A6 SYNTH5 RADIO Radio
F9D4 SYNTH6 HYPER Hyper
F9F3 SYNTH7 SCREAM Scream
FA44 PARAM6 ORGANT Organ Tune
FA48 PARAM7 ORGNT1 " "
FA84 PARAM8 ORGANN Organ Note 4 BYTES(MODE,OSCILLATOR MASK HI+1,LO+1,NOTE#)
FA89 PARAM9 ORGNN1 " "
FA9A SYNTH8 ORGNN2 " "
FAB3 " " ORGANL Organ Loader OSCIL=OSCILLATOR MASK, ACCA=DELAY, DUR=DURATION
FADB " " ORGAN Organ Routine DUR=DURATION, OSCILLATOR MASK
FB0A UTIL1 TRANS Parameter Transfer
FB1E PARAM10 BGEND Background End Routine
FB24 PARAM11 BG2INC Background Sound #2 Increment
FB34 UTIL2 BG2 Background 2 Routine
FB49 PARAM12 SP1 Spinner #1 Sound
FB71 PARAM13 BON2 Laser Ball Bonus #2
FB81 " " GWLD GWAVE Loader
FBE7 SYNTH9 GWAVE GWAVE Routine ACCA= FREQ PATTERN LENGTH, X= FREQ PAT ADDR
FC21 PARAM14 " " "
FC4B PARAM15 " " "
FC56 PARAM16 " " "
FC65 PARAM17 " " "
FC75 PARAM18 WVTRAN Wave Transfer Routine
FC87 PARAM19 WVDECA Wave Decay Routine DECAY AMOUNT IN ACCA(1/16 PER DECAY)
FCB6 IRQ IRQ Interrupt Processing
FD0E IRQ2 IRQ3 " "
FD21 CALCOS ADDX Add A to X Register
FD2F NMI NMI Diagnostic Processing
FD58 VWTAB JMPTBL Special Routine Jump Table
FD76 VVECT VVECT Vari Vectors
FD9A WAVFCB1 RADSND Radio Sound Waveform
FDAA " ORGTAB Organ Tune Table Phantom
FDB7 " " " " " Taccata (JS Bach's Toccata and Fugue in D Minor)
FE41 WAVFCB2 NOTTAB Organ Note Table
FE4D WAVFCB3 GWVTAB Wave Table 1ST BYTE= WAVELENGTH
FEEC WAVFCB4 SVTAB GWAVE Sound Vector Table
FF55 WAVFCB5 GFRTAB GWAVE Freq Pattern Table
FFF8 MOTVCT MOTVCT Motorola Vector Table
WiLL-i-ROMS mods code
Sample code for SYNTH1 / VARI (Variable Duty Cycle Square Wave Routine):
; SYNTH1/PARAM1 CODE - 24 Apr 2021
; hack for Heathkit ET-3400 Audio Setup - 2x PIA input params
; user RAM = 197 + 256 bytes = 453
; addr 0000 - 00C4 and 0100 - 01FF
; using PIA1 addr 8000-8003 (DAC, param1)
; and PIA2 addr 8004-8007 (param3)
; mpu clock speed is default/low (quoted as 0.5 MHz), expecting ~894750 cycles per second
; using edited subroutines RESET, NMI, PARAM1, CALCOS, UTIL1, SYNTH1
;
; PIA Addressing changes for breakout board
; fix for PIA2 DDR/CR set using extended addressing
; PIA init code refactoring
;
;*************************************;
; USED RAM ADDR LOCATIONS (typical values)
;*************************************;
0000 : 00 24 ; CALCOS, UTIL1
0002 : 01 08 ; X, UTIL1
0004 : 00 18 ; X
0006 : nn 01 ; X, nn countdown, SAW params 000F to 0017
0008 : 00 08 ; A, A
000A : 81 02 ; A, X
000C : 00 FF ; X, A
000E : FF nn ; nn countdown
0010 : nn ; nn rapid
;*************************************;
;RESET INIT (POWER-ON) org 0011
;*************************************;
0011 : 8E 01 FF lds #$01FF ; load SP with 01FFh
0014 : CE 80 00 ldx #$8000 ; load X with 8000h, PIA1 (DAC) addr
0017 : 6F 02 clr $02,x ; clear(00) addr X + 02h (set 8002 PIA1 PR/DDR port B in)
0019 : 86 FF ldaa #$FF ; load A with FFh (1111 1111)
001B : A7 00 staa $00,x ; store A in addr X + 00h (set 8000 PIA1 PR/DDR port A out)
001D : 86 3C ldaa #$3C ; load A with 3Ch(0011 1100)
001F : A7 01 staa $01,x ; store A in addr X + 01h (8001 PIA1 CR port A)
0021 : 86 37 ldaa #$37 ; load A with 37h(0011 0111)
0023 : A7 03 staa $03,x ; store A in addr X + 03h (8003 PIA1 CR port B)
0025 : 7F 40 02 clr $4002 ; clear(00) 4002h (set PIA2 PR/DDR port B in)
0028 : 86 04 ldaa #$04 ; set CR bit 2 high for PIA2
002A : B7 40 03 staa $4003 ; store A in addr 4003 (PIA2 CR port B)
002D : 01 nop ;
; ~ all nops here - SPARE
0030 : 01 nop ;
;*************************************;
;NMI - MAIN LOOP - 0031
;*************************************;
0031 : CE FF FF ldx #$FFFF ; load X with value FFFFh ( or 78h )
0034 : 5F clrb ; clear (00) B
0035 : E9 00 adcb $00,x ; add B + X + 00h with Carry into B
0037 : 86 01 ldaa #$01 ; load A with value 01h (0000 0001)
;*************************************;
;PARAM1 - Vari Loader - 0039
;*************************************;
;VARILD
0039 : 16 tab ; transfer A to B
003A : 48 asla ; arith shift left in A (x2)
003B : 48 asla ; arith shift left in A (x4)
003C : 48 asla ; arith shift left in A (x8)
003D : 1B aba ; add A + B into A (x9)
003E : CE 00 06 ldx #$0006 ; load X with value 0006
0041 : DF 02 stx $02 ; store X in addr 02
0043 : CE 01 0E ldx #$010E ; load X with value 010E (FOSHIT)
0046 : BD 01 00 jsr L0100 ; jump sub ADDX
0049 : C6 09 ldab #$09 ; load B with 09h (0000 1001)
;*************************************;
;UTIL1 - Parameter Transfer - 004B
;**************************************;
;TRANS
004B : 36 psha ; push A into stack(A into SP)
;TRANS1
004C : A6 00 ldaa $00,x ; load A with value in X + 00h
004E : DF 00 stx $00 ; store X in 00
0050 : DE 02 ldx $02 ; load X with value in 02
0052 : A7 00 staa $00,x ; store A in X + 00h
0054 : 08 inx ; increment X
0055 : DF 02 stx $02 ; store X in 02
0057 : DE 00 ldx $00 ; load X with value in 00
0059 : 08 inx ; increment X
005A : 5A decb ; decrement B
005B : 26 EF bne L004C ; branch Z=0 PC - EFh (TRANS1)(-17)
005D : 32 pula ; pull into A from stack (SP into A)
;*************************************;
;SYNTH1 - Variable Duty Cycle Square Wave Routine - 005E
;*************************************;
;VARI
005E : 96 0E ldaa $0E ; load A with value in addr 0E
0060 : B7 80 00 staa $8000 ; store A in addr 8000 (SOUND)
;VAR0
0063 : 96 06 ldaa $06 ; load A with value in addr 06
0065 : 97 0F staa $0F ; store A in addr 0F
0067 : 96 07 ldaa $07 ; load A with value in addr 07
0069 : 97 10 staa $10 ; store A in addr 10
;V0
006B : DE 0B ldx $0B ; load X with value in 0B
;V0LP
006D : 96 0F ldaa $0F ; load A with value in addr 0F
006F : 73 80 00 com $8000 ; complement 1s in addr 8000 (invert)(SOUND)
;V1
0072 : 09 dex ; decrement X (X = X - 1)
0073 : 27 10 beq L0085 ; branch Z=1 PC + 10h (VSWEEP)
0075 : 4A deca ; decrement A (A = A - 1)
0076 : 26 FA bne L0072 ; branch Z=0 PC - FAh (V1)(-6)
0078 : 73 80 00 com $8000 ; complements 1s in addr 8000 (SOUND)
007B : 96 10 ldaa $10 ; load A with value in 10
;V2
007D : 09 dex ; decrement X
007E : 27 05 beq L0085 ; branch Z=1 PC + 05h (VSWEEP)(+5)
0080 : 4A deca ; decrement A
0081 : 26 FA bne L007D ; branch Z=0 PC - FAh (V2)(-6)
0083 : 20 E8 bra L006D ; branch always to addr PC - E8h (V0LP)(-24)
;VSWEEP
0085 : B6 80 00 ldaa $8000 ; load A with value in addr 8000 (SOUND)
0088 : 2B 01 bmi L008B ; branch N=1 PC + 01h (VS1)
008A : 43 coma ; complements 1s in A
;VS1
008B : 8B 00 adda #$00 ; add A with 00h (A = A + 00h)
008D : B7 80 00 staa $8000 ; store A in addr 8000 (SOUND)
0090 : 96 0F ldaa $0F ; load A with value in 0F
0092 : 9B 08 adda $08 ; add A with value in addr 08
0094 : 97 0F staa $0F ; store A in addr 0F
0096 : 96 10 ldaa $10 ; load A with value in 10
0098 : 9B 09 adda $09 ; add A with value in addr 09
009A : 97 10 staa $10 ; store A in addr 10
009C : 91 0A cmpa $0A ; compare A with value in addr 0A
009E : 26 CB bne L006B ; branch Z=0 PC - CBh (V0)(-53)
00A0 : 96 0D ldaa $0D ; load A with value in 0D
00A2 : 27 06 beq L00AA ; branch Z=1 PC + 06h (VARX)
00A4 : 9B 06 adda $06 ; add A with value in addr 06
00A6 : 97 06 staa $06 ; store A in addr 06
00A8 : 26 B9 bne L0063 ; branch Z=0 PC - B9h (VAR0)(-71)
;VARX
00AA : 8D 05 bsr L00B1 ; branch sub to PIA read PC + 05h
00AC : 86 02 ldaa #$02 ; load A with value 02h (0000 0010)
00AE : 7E 00 31 jmp L0031 ; jump to start L0031
;*************************************;
; PIA B read subroutine - 00B1
;*************************************;
00B1 : 4F clra ; clear A
00B2 : B6 80 02 ldaa $8002 ; load A with PIA1 B
00B5 : 43 coma ; complement A
00B6 : B7 01 0E staa $010E ; store A in 010E (p1)
00B9 : B6 40 02 ldaa $4002 ; load A with PIA2 B
00BC : 43 coma ; complement A
00BD : B7 01 10 staa $0110 ; store A in 0110 (p3)
00C0 : 39 rts ; return from subroutine
;*************************************;
;CALCOS (Add A to Index Register) - 0100
;*************************************;
;ADDX
0100 : DF 00 stx $00 ; store X in 00
0102 : 9B 01 adda $01 ; add A with value in 01
0104 : 97 01 staa $01 ; store A in 01
0106 : 24 05 bcc L00BF ; branch C=0 PC + 05 (ADDX1)
0108 : 7C 00 00 inc $0000 ; increment value in 00
010B : DE 00 ldx $00 ; load X with value in 00
;ADDX1
010D : 39 rts ; return from subroutine
;*************************************;
;PARAM WAVEFORM FCB - Vari Vector
;*************************************;
; :|p1|p2|p3|p4|p5|p6|p7|count ;
010E : 28 01 00 08 81 02 00 FF FF ; FOSHIT, Williams Boot
;*************************************;
alternative VVECTS:
010E : 40 01 00 10 E1 00 80 FF FF ;SAW
010E : 28 81 00 FC 01 02 00 FC FF ;QUASAR
010E : FF 01 00 18 41 04 80 00 FF ;CABSHK
;*************************************;
Image of spectrogram of the Synth7 Heathkit modded assembly routine, recorded off the original sound board hardware.