diff --git a/ocanada.xcodeproj/project.pbxproj b/ocanada.xcodeproj/project.pbxproj index d7bf55b..b803305 100644 --- a/ocanada.xcodeproj/project.pbxproj +++ b/ocanada.xcodeproj/project.pbxproj @@ -17,6 +17,15 @@ 9D1A7CBB1F085D7F00669D60 /* prodos_template.dsk */ = {isa = PBXFileReference; lastKnownFileType = file; name = prodos_template.dsk; path = make/prodos_template.dsk; sourceTree = ""; }; 9D1A7CBC1F085D7F00669D60 /* tail.mk */ = {isa = PBXFileReference; lastKnownFileType = text; name = tail.mk; path = make/tail.mk; sourceTree = ""; }; 9D1A7CBD1F085D7F00669D60 /* V2Make.scpt */ = {isa = PBXFileReference; lastKnownFileType = file; name = V2Make.scpt; path = make/V2Make.scpt; sourceTree = ""; }; + 9D1A7CC31F085DA800669D60 /* flag.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = flag.c; sourceTree = ""; }; + 9D1A7CC41F085DA800669D60 /* flag.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = flag.h; sourceTree = ""; }; + 9D1A7CC51F085DA800669D60 /* song.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = song.c; sourceTree = ""; }; + 9D1A7CC61F085DA800669D60 /* song.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = song.h; sourceTree = ""; }; + 9D1A7CC71F085DA800669D60 /* mockingboard_speech.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mockingboard_speech.h; sourceTree = ""; }; + 9D1A7CC81F085DA800669D60 /* mockingboard_speech.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = mockingboard_speech.s; sourceTree = ""; }; + 9D1A7CC91F085DA800669D60 /* mockingboard.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mockingboard.c; sourceTree = ""; }; + 9D1A7CCA1F085DA800669D60 /* mockingboard.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mockingboard.h; sourceTree = ""; }; + 9D1A7CCB1F085DA800669D60 /* a2.lo.s */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm; path = a2.lo.s; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXGroup section */ @@ -32,6 +41,15 @@ children = ( 9D1A7CB31F085D7F00669D60 /* main.c */, 9D1A7CB41F085D7F00669D60 /* Makefile */, + 9D1A7CC31F085DA800669D60 /* flag.c */, + 9D1A7CC41F085DA800669D60 /* flag.h */, + 9D1A7CC51F085DA800669D60 /* song.c */, + 9D1A7CC61F085DA800669D60 /* song.h */, + 9D1A7CC71F085DA800669D60 /* mockingboard_speech.h */, + 9D1A7CC81F085DA800669D60 /* mockingboard_speech.s */, + 9D1A7CC91F085DA800669D60 /* mockingboard.c */, + 9D1A7CCA1F085DA800669D60 /* mockingboard.h */, + 9D1A7CCB1F085DA800669D60 /* a2.lo.s */, 9D1A7CB51F085D7F00669D60 /* make */, ); path = ocanada; diff --git a/ocanada.xcodeproj/xcuserdata/jrand.xcuserdatad/xcschemes/ocanada.xcscheme b/ocanada.xcodeproj/xcuserdata/jrand.xcuserdatad/xcschemes/ocanada.xcscheme index 015fcc0..c14c961 100644 --- a/ocanada.xcodeproj/xcuserdata/jrand.xcuserdatad/xcschemes/ocanada.xcscheme +++ b/ocanada.xcodeproj/xcuserdata/jrand.xcuserdatad/xcschemes/ocanada.xcscheme @@ -5,6 +5,22 @@ + + + + + + + + + + @@ -35,6 +60,15 @@ savedToolIdentifier = "" useCustomWorkingDirectory = "NO" debugDocumentVersioning = "YES"> + + + + diff --git a/ocanada/Makefile b/ocanada/Makefile index b44eee5..d4ae139 100644 --- a/ocanada/Makefile +++ b/ocanada/Makefile @@ -25,7 +25,7 @@ PGM=ocanada # Uncomment the one you want below (the first one is the default): # MACHINE = apple2 # MACHINE = apple2-dos33 -# MACHINE = apple2-system +MACHINE = apple2-system # MACHINE = apple2-loader # MACHINE = apple2-reboot # MACHINE = apple2enh diff --git a/ocanada/a2.lo.s b/ocanada/a2.lo.s new file mode 100644 index 0000000..8d2e4a0 --- /dev/null +++ b/ocanada/a2.lo.s @@ -0,0 +1,930 @@ +; +; File generated by co65 v 2.13.3 using model `cc65-module' +; +.fopt compiler,"co65 v 2.13.3" +.case on +.debuginfo off +.export _a2_lo + +; +; CODE SEGMENT +; +.segment "CODE" +_a2_lo: + .byte $74 + .byte $67 + .byte $69 + .byte $02 + .byte $28 + .byte $00 + .byte $30 + .byte $00 + .byte $10 + .byte $01 + .byte $08 + .byte $08 + .byte $00 + .byte $00 + .byte $00 + .byte $00 + .word _a2_lo+75 + .word _a2_lo+75 + .word _a2_lo+58 + .word _a2_lo+76 + .word _a2_lo+89 + .word _a2_lo+118 + .word _a2_lo+98 + .word _a2_lo+75 + .word _a2_lo+75 + .word _a2_lo+108 + .word _a2_lo+118 + .word _a2_lo+124 + .word _a2_lo+124 + .word _a2_lo+129 + .word _a2_lo+194 + .word _a2_lo+210 + .word _a2_lo+558 + .word _a2_lo+586 + .word _a2_lo+75 + .word _a2_lo+75 + .byte $00 + .byte $00 + .byte $2C + .byte $82 + .byte $C0 + .byte $20 + .byte $40 + .byte $FB + .byte $2C + .byte $52 + .byte $C0 + .byte $2C + .byte $80 + .byte $C0 + .byte $A9 + .byte $00 + .byte $8D + .word BSS+0 + .byte $60 + .byte $2C + .byte $82 + .byte $C0 + .byte $20 + .byte $99 + .byte $F3 + .byte $20 + .byte $58 + .byte $FC + .byte $2C + .byte $80 + .byte $C0 + .byte $60 + .byte $AD + .word BSS+0 + .byte $A2 + .byte $00 + .byte $8E + .word BSS+0 + .byte $60 + .byte $2C + .byte $82 + .byte $C0 + .byte $20 + .byte $32 + .byte $F8 + .byte $2C + .byte $80 + .byte $C0 + .byte $60 + .byte $2C + .byte $82 + .byte $C0 + .byte $20 + .byte $64 + .byte $F8 + .byte $2C + .byte $80 + .byte $C0 + .byte $60 + .byte $A9 + .byte $06 + .byte $8D + .word BSS+0 + .byte $60 + .byte $A9 + .byte <(_a2_lo+227) + .byte $A2 + .byte >(_a2_lo+995) + .byte $60 + .byte $2C + .byte $82 + .byte $C0 + .byte $A4 + .byte <(ZEROPAGE+8) + .byte $A5 + .byte <(ZEROPAGE+10) + .byte $20 + .byte $00 + .byte $F8 + .byte $2C + .byte $80 + .byte $C0 + .byte $60 + .byte $A5 + .byte <(ZEROPAGE+11) + .byte $30 + .byte $2E + .byte $A5 + .byte <(ZEROPAGE+9) + .byte $30 + .byte $2A + .byte $A5 + .byte <(ZEROPAGE+8) + .byte $A6 + .byte <(ZEROPAGE+9) + .byte $85 + .byte <(ZEROPAGE+16) + .byte $86 + .byte <(ZEROPAGE+17) + .byte $A2 + .byte <(ZEROPAGE+16) + .byte $AD + .word _a2_lo+4 + .byte $AC + .word _a2_lo+5 + .byte $20 + .word _a2_lo+961 + .byte $B0 + .byte $15 + .byte $A5 + .byte <(ZEROPAGE+10) + .byte $A6 + .byte <(ZEROPAGE+11) + .byte $85 + .byte <(ZEROPAGE+16) + .byte $86 + .byte <(ZEROPAGE+17) + .byte $A2 + .byte <(ZEROPAGE+16) + .byte $AD + .word _a2_lo+6 + .byte $AC + .word _a2_lo+7 + .byte $20 + .word _a2_lo+961 + .byte $90 + .byte $C0 + .byte $60 + .byte $2C + .byte $82 + .byte $C0 + .byte $A4 + .byte <(ZEROPAGE+8) + .byte $A5 + .byte <(ZEROPAGE+10) + .byte $20 + .byte $71 + .byte $F8 + .byte $A2 + .byte $00 + .byte $2C + .byte $80 + .byte $C0 + .byte $60 + .byte $A5 + .byte <(ZEROPAGE+12) + .byte $38 + .byte $E5 + .byte <(ZEROPAGE+8) + .byte $85 + .byte <(ZEROPAGE+6) + .byte $A5 + .byte <(ZEROPAGE+13) + .byte $E5 + .byte <(ZEROPAGE+9) + .byte $A8 + .byte $A5 + .byte <(ZEROPAGE+6) + .byte $20 + .word _a2_lo+943 + .byte $85 + .byte <(ZEROPAGE+6) + .byte $84 + .byte <(ZEROPAGE+7) + .byte $A5 + .byte <(ZEROPAGE+14) + .byte $38 + .byte $E5 + .byte <(ZEROPAGE+10) + .byte $8D + .word BSS+3 + .byte $A5 + .byte <(ZEROPAGE+15) + .byte $E5 + .byte <(ZEROPAGE+11) + .byte $A8 + .byte $AD + .word BSS+3 + .byte $20 + .word _a2_lo+943 + .byte $8D + .word BSS+3 + .byte $8C + .word BSS+4 + .byte $A2 + .byte <(ZEROPAGE+12) + .byte $A5 + .byte <(ZEROPAGE+8) + .byte $A4 + .byte <(ZEROPAGE+9) + .byte $20 + .word _a2_lo+961 + .byte $90 + .byte $04 + .byte $A9 + .byte $01 + .byte $D0 + .byte $02 + .byte $A9 + .byte $FF + .byte $8D + .word BSS+5 + .byte $A2 + .byte <(ZEROPAGE+14) + .byte $A5 + .byte <(ZEROPAGE+10) + .byte $A4 + .byte <(ZEROPAGE+11) + .byte $20 + .word _a2_lo+961 + .byte $90 + .byte $04 + .byte $A9 + .byte $01 + .byte $D0 + .byte $02 + .byte $A9 + .byte $FF + .byte $8D + .word BSS+6 + .byte $A9 + .byte $00 + .byte $85 + .byte <(ZEROPAGE+4) + .byte $85 + .byte <(ZEROPAGE+5) + .byte $8D + .word BSS+7 + .byte $8D + .word BSS+8 + .byte $A2 + .byte <(ZEROPAGE+6) + .byte $AD + .word BSS+3 + .byte $AC + .word BSS+4 + .byte $20 + .word _a2_lo+961 + .byte $B0 + .byte $28 + .byte $A5 + .byte <(ZEROPAGE+6) + .byte $AE + .word BSS+3 + .byte $8D + .word BSS+3 + .byte $86 + .byte <(ZEROPAGE+6) + .byte $A5 + .byte <(ZEROPAGE+7) + .byte $AE + .word BSS+4 + .byte $8D + .word BSS+4 + .byte $86 + .byte <(ZEROPAGE+7) + .byte $AD + .word BSS+5 + .byte $8D + .word BSS+7 + .byte $AD + .word BSS+6 + .byte $8D + .word BSS+8 + .byte $A9 + .byte $00 + .byte $8D + .word BSS+5 + .byte $8D + .word BSS+6 + .byte $AD + .word BSS+3 + .byte $AC + .word BSS+4 + .byte $20 + .word _a2_lo+947 + .byte $8D + .word BSS+3 + .byte $8C + .word BSS+4 + .byte $A5 + .byte <(ZEROPAGE+6) + .byte $A6 + .byte <(ZEROPAGE+7) + .byte $8D + .word BSS+1 + .byte $8E + .word BSS+2 + .byte $AD + .word BSS+1 + .byte $0D + .word BSS+2 + .byte $D0 + .byte $01 + .byte $60 + .byte $20 + .word _a2_lo+143 + .byte $A5 + .byte <(ZEROPAGE+4) + .byte $18 + .byte $6D + .word BSS+3 + .byte $85 + .byte <(ZEROPAGE+12) + .byte $A5 + .byte <(ZEROPAGE+5) + .byte $6D + .word BSS+4 + .byte $85 + .byte <(ZEROPAGE+13) + .byte $AA + .byte $A5 + .byte <(ZEROPAGE+12) + .byte $18 + .byte $65 + .byte <(ZEROPAGE+6) + .byte $85 + .byte <(ZEROPAGE+14) + .byte $8A + .byte $65 + .byte <(ZEROPAGE+7) + .byte $85 + .byte <(ZEROPAGE+15) + .byte $A2 + .byte $00 + .byte $AD + .word BSS+5 + .byte $10 + .byte $01 + .byte $CA + .byte $18 + .byte $65 + .byte <(ZEROPAGE+8) + .byte $85 + .byte <(ZEROPAGE+8) + .byte $8A + .byte $65 + .byte <(ZEROPAGE+9) + .byte $85 + .byte <(ZEROPAGE+9) + .byte $A2 + .byte $00 + .byte $AD + .word BSS+8 + .byte $10 + .byte $01 + .byte $CA + .byte $18 + .byte $65 + .byte <(ZEROPAGE+10) + .byte $85 + .byte <(ZEROPAGE+10) + .byte $8A + .byte $65 + .byte <(ZEROPAGE+11) + .byte $85 + .byte <(ZEROPAGE+11) + .byte $A5 + .byte <(ZEROPAGE+12) + .byte $A4 + .byte <(ZEROPAGE+13) + .byte $20 + .word _a2_lo+943 + .byte $85 + .byte <(ZEROPAGE+2) + .byte $84 + .byte <(ZEROPAGE+3) + .byte $A5 + .byte <(ZEROPAGE+14) + .byte $A4 + .byte <(ZEROPAGE+15) + .byte $20 + .word _a2_lo+943 + .byte $A2 + .byte <(ZEROPAGE+2) + .byte $20 + .word _a2_lo+961 + .byte $10 + .byte $07 + .byte $A5 + .byte <(ZEROPAGE+12) + .byte $A6 + .byte <(ZEROPAGE+13) + .byte $4C + .word _a2_lo+534 + .byte $A2 + .byte $00 + .byte $AD + .word BSS+7 + .byte $10 + .byte $01 + .byte $CA + .byte $18 + .byte $65 + .byte <(ZEROPAGE+8) + .byte $85 + .byte <(ZEROPAGE+8) + .byte $8A + .byte $65 + .byte <(ZEROPAGE+9) + .byte $85 + .byte <(ZEROPAGE+9) + .byte $A2 + .byte $00 + .byte $AD + .word BSS+6 + .byte $10 + .byte $01 + .byte $CA + .byte $18 + .byte $65 + .byte <(ZEROPAGE+10) + .byte $85 + .byte <(ZEROPAGE+10) + .byte $8A + .byte $65 + .byte <(ZEROPAGE+11) + .byte $85 + .byte <(ZEROPAGE+11) + .byte $A5 + .byte <(ZEROPAGE+14) + .byte $A6 + .byte <(ZEROPAGE+15) + .byte $85 + .byte <(ZEROPAGE+4) + .byte $86 + .byte <(ZEROPAGE+5) + .byte $AD + .word BSS+1 + .byte $38 + .byte $E9 + .byte $01 + .byte $8D + .word BSS+1 + .byte $90 + .byte $03 + .byte $4C + .word _a2_lo+386 + .byte $CE + .word BSS+2 + .byte $4C + .word _a2_lo+386 + .byte $2C + .byte $82 + .byte $C0 + .byte $E6 + .byte <(ZEROPAGE+14) + .byte $A6 + .byte <(ZEROPAGE+12) + .byte $86 + .byte $2C + .byte $A4 + .byte <(ZEROPAGE+8) + .byte $A5 + .byte <(ZEROPAGE+10) + .byte $20 + .byte $19 + .byte $F8 + .byte $E6 + .byte <(ZEROPAGE+10) + .byte $A5 + .byte <(ZEROPAGE+14) + .byte $C5 + .byte <(ZEROPAGE+10) + .byte $D0 + .byte $F1 + .byte $2C + .byte $80 + .byte $C0 + .byte $60 + .byte $A5 + .byte <(ZEROPAGE+16) + .byte $D0 + .byte $03 + .byte $4C + .word _a2_lo+143 + .byte $85 + .byte <(ZEROPAGE+12) + .byte $A9 + .byte $00 + .byte $85 + .byte <(ZEROPAGE+13) + .byte $85 + .byte <(ZEROPAGE+14) + .byte $85 + .byte <(ZEROPAGE+15) + .byte $85 + .byte <(ZEROPAGE+2) + .byte $85 + .byte <(ZEROPAGE+3) + .byte $A5 + .byte <(ZEROPAGE+8) + .byte $A6 + .byte <(ZEROPAGE+9) + .byte $85 + .byte <(ZEROPAGE+4) + .byte $86 + .byte <(ZEROPAGE+5) + .byte $A5 + .byte <(ZEROPAGE+10) + .byte $A6 + .byte <(ZEROPAGE+11) + .byte $85 + .byte <(ZEROPAGE+6) + .byte $86 + .byte <(ZEROPAGE+7) + .byte $A2 + .byte <(ZEROPAGE+14) + .byte $A5 + .byte <(ZEROPAGE+12) + .byte $A4 + .byte <(ZEROPAGE+13) + .byte $20 + .word _a2_lo+961 + .byte $90 + .byte $01 + .byte $60 + .byte $A5 + .byte <(ZEROPAGE+4) + .byte $18 + .byte $65 + .byte <(ZEROPAGE+12) + .byte $85 + .byte <(ZEROPAGE+8) + .byte $A5 + .byte <(ZEROPAGE+5) + .byte $65 + .byte <(ZEROPAGE+13) + .byte $85 + .byte <(ZEROPAGE+9) + .byte $A5 + .byte <(ZEROPAGE+6) + .byte $18 + .byte $65 + .byte <(ZEROPAGE+14) + .byte $85 + .byte <(ZEROPAGE+10) + .byte $48 + .byte $A5 + .byte <(ZEROPAGE+7) + .byte $65 + .byte <(ZEROPAGE+15) + .byte $85 + .byte <(ZEROPAGE+11) + .byte $48 + .byte $20 + .word _a2_lo+143 + .byte $A5 + .byte <(ZEROPAGE+6) + .byte $38 + .byte $E5 + .byte <(ZEROPAGE+14) + .byte $85 + .byte <(ZEROPAGE+10) + .byte $8D + .word BSS+5 + .byte $A5 + .byte <(ZEROPAGE+7) + .byte $E5 + .byte <(ZEROPAGE+15) + .byte $85 + .byte <(ZEROPAGE+11) + .byte $8D + .word BSS+6 + .byte $20 + .word _a2_lo+143 + .byte $68 + .byte $85 + .byte <(ZEROPAGE+11) + .byte $68 + .byte $85 + .byte <(ZEROPAGE+10) + .byte $A5 + .byte <(ZEROPAGE+4) + .byte $38 + .byte $E5 + .byte <(ZEROPAGE+12) + .byte $85 + .byte <(ZEROPAGE+8) + .byte $A5 + .byte <(ZEROPAGE+5) + .byte $E5 + .byte <(ZEROPAGE+13) + .byte $85 + .byte <(ZEROPAGE+9) + .byte $20 + .word _a2_lo+143 + .byte $AD + .word BSS+5 + .byte $85 + .byte <(ZEROPAGE+10) + .byte $AD + .word BSS+6 + .byte $85 + .byte <(ZEROPAGE+11) + .byte $20 + .word _a2_lo+143 + .byte $A5 + .byte <(ZEROPAGE+4) + .byte $18 + .byte $65 + .byte <(ZEROPAGE+14) + .byte $85 + .byte <(ZEROPAGE+8) + .byte $A5 + .byte <(ZEROPAGE+5) + .byte $65 + .byte <(ZEROPAGE+15) + .byte $85 + .byte <(ZEROPAGE+9) + .byte $A5 + .byte <(ZEROPAGE+6) + .byte $18 + .byte $65 + .byte <(ZEROPAGE+12) + .byte $85 + .byte <(ZEROPAGE+10) + .byte $48 + .byte $A5 + .byte <(ZEROPAGE+7) + .byte $65 + .byte <(ZEROPAGE+13) + .byte $85 + .byte <(ZEROPAGE+11) + .byte $48 + .byte $20 + .word _a2_lo+143 + .byte $A5 + .byte <(ZEROPAGE+6) + .byte $38 + .byte $E5 + .byte <(ZEROPAGE+12) + .byte $85 + .byte <(ZEROPAGE+10) + .byte $8D + .word BSS+5 + .byte $A5 + .byte <(ZEROPAGE+7) + .byte $E5 + .byte <(ZEROPAGE+13) + .byte $85 + .byte <(ZEROPAGE+11) + .byte $8D + .word BSS+6 + .byte $20 + .word _a2_lo+143 + .byte $68 + .byte $85 + .byte <(ZEROPAGE+11) + .byte $68 + .byte $85 + .byte <(ZEROPAGE+10) + .byte $A5 + .byte <(ZEROPAGE+4) + .byte $38 + .byte $E5 + .byte <(ZEROPAGE+14) + .byte $85 + .byte <(ZEROPAGE+8) + .byte $A5 + .byte <(ZEROPAGE+5) + .byte $E5 + .byte <(ZEROPAGE+15) + .byte $85 + .byte <(ZEROPAGE+9) + .byte $20 + .word _a2_lo+143 + .byte $AD + .word BSS+5 + .byte $85 + .byte <(ZEROPAGE+10) + .byte $AD + .word BSS+6 + .byte $85 + .byte <(ZEROPAGE+11) + .byte $20 + .word _a2_lo+143 + .byte $A5 + .byte <(ZEROPAGE+2) + .byte $A6 + .byte <(ZEROPAGE+3) + .byte $18 + .byte $65 + .byte <(ZEROPAGE+14) + .byte $A8 + .byte $8A + .byte $65 + .byte <(ZEROPAGE+15) + .byte $AA + .byte $98 + .byte $18 + .byte $65 + .byte <(ZEROPAGE+14) + .byte $A8 + .byte $8A + .byte $65 + .byte <(ZEROPAGE+15) + .byte $AA + .byte $98 + .byte $18 + .byte $69 + .byte $01 + .byte $90 + .byte $01 + .byte $E8 + .byte $8D + .word BSS+1 + .byte $8E + .word BSS+2 + .byte $38 + .byte $E5 + .byte <(ZEROPAGE+12) + .byte $A8 + .byte $8A + .byte $E5 + .byte <(ZEROPAGE+13) + .byte $AA + .byte $98 + .byte $38 + .byte $E5 + .byte <(ZEROPAGE+12) + .byte $A8 + .byte $8A + .byte $E5 + .byte <(ZEROPAGE+13) + .byte $AA + .byte $98 + .byte $18 + .byte $69 + .byte $01 + .byte $90 + .byte $01 + .byte $E8 + .byte $8D + .word BSS+3 + .byte $8E + .word BSS+4 + .byte $E6 + .byte <(ZEROPAGE+14) + .byte $D0 + .byte $02 + .byte $E6 + .byte <(ZEROPAGE+15) + .byte $AD + .word BSS+3 + .byte $AC + .word BSS+4 + .byte $20 + .word _a2_lo+943 + .byte $85 + .byte <(ZEROPAGE+2) + .byte $84 + .byte <(ZEROPAGE+3) + .byte $AD + .word BSS+1 + .byte $AC + .word BSS+2 + .byte $20 + .word _a2_lo+943 + .byte $A2 + .byte <(ZEROPAGE+2) + .byte $20 + .word _a2_lo+961 + .byte $10 + .byte $14 + .byte $A5 + .byte <(ZEROPAGE+12) + .byte $38 + .byte $E9 + .byte $01 + .byte $85 + .byte <(ZEROPAGE+12) + .byte $B0 + .byte $02 + .byte $C6 + .byte <(ZEROPAGE+13) + .byte $AD + .word BSS+3 + .byte $AE + .word BSS+4 + .byte $4C + .word _a2_lo+936 + .byte $AD + .word BSS+1 + .byte $AE + .word BSS+2 + .byte $85 + .byte <(ZEROPAGE+2) + .byte $86 + .byte <(ZEROPAGE+3) + .byte $4C + .word _a2_lo+623 + .byte $C0 + .byte $00 + .byte $10 + .byte $0D + .byte $18 + .byte $49 + .byte $FF + .byte $69 + .byte $01 + .byte $48 + .byte $98 + .byte $49 + .byte $FF + .byte $69 + .byte $00 + .byte $A8 + .byte $68 + .byte $60 + .byte $85 + .byte <(ZEROPAGE+18) + .byte $84 + .byte <(ZEROPAGE+19) + .byte $B5 + .byte $00 + .byte $48 + .byte $B5 + .byte $01 + .byte $A8 + .byte $68 + .byte $AA + .byte $98 + .byte $38 + .byte $E5 + .byte <(ZEROPAGE+19) + .byte $D0 + .byte $09 + .byte $E4 + .byte <(ZEROPAGE+18) + .byte $F0 + .byte $04 + .byte $69 + .byte $FF + .byte $09 + .byte $01 + .byte $60 + .byte $50 + .byte $04 + .byte $49 + .byte $FF + .byte $09 + .byte $01 + .byte $60 + .byte $00 + .byte $01 + .byte $02 + .byte $03 + .byte $04 + .byte $05 + .byte $06 + .byte $07 + .byte $08 + .byte $09 + .byte $0A + .byte $0B + .byte $0C + .byte $0D + .byte $0E + .byte $0F + +; +; DATA SEGMENT +; +.segment "DATA" +DATA: + +; +; BSS SEGMENT +; +.segment "BSS" +BSS: + .res 9 + +; +; ZEROPAGE SEGMENT +; +.import __ZP_START__ ; Linker generated symbol +ZEROPAGE = __ZP_START__ + +.end diff --git a/ocanada/flag.c b/ocanada/flag.c new file mode 100644 index 0000000..60f629f --- /dev/null +++ b/ocanada/flag.c @@ -0,0 +1,74 @@ +// +// flag.c +// ocanada +// +// Created by Jeremy Rand on 2017-07-01. +// Copyright © 2017 Jeremy Rand. All rights reserved. +// + +#include +#include +#include +#include + +#include "flag.h" + +// Extern symbols for graphics drivers +extern char a2_lo; + +void initGraphics(void) +{ + static bool tgi_inited = false; + + if (tgi_inited) + return; + + // Install drivers + tgi_install(&a2_lo); + + tgi_init(); + + // Mixed text and graphics mode + asm ("STA %w", 0xc053); + + tgi_inited = true; +} + + +void drawFlag(void) +{ + initGraphics(); + + tgi_setcolor(LORES_MAGENTA); + tgi_bar(0,0,9,39); + tgi_bar(30,0,39,39); + + tgi_setcolor(LORES_WHITE); + tgi_bar(10,0,29,39); + + tgi_setcolor(LORES_MAGENTA); + tgi_bar(19,4,20,34); + tgi_line(18,7,18,26); + tgi_line(21,7,21,26); + + tgi_line(17,6,17,26); + tgi_line(22,6,22,26); + + tgi_line(16,14,16,27); + tgi_line(23,14,23,27); + + tgi_line(15,13,15,27); + tgi_line(24,13,24,27); + + tgi_line(14,12,14,28); + tgi_line(25,12,25,28); + + tgi_line(13,14,13,26); + tgi_line(26,14,26,26); + + tgi_line(12,13,12,23); + tgi_line(27,13,27,23); + + tgi_line(11,16,11,20); + tgi_line(28,16,28,20); +} diff --git a/ocanada/flag.h b/ocanada/flag.h new file mode 100644 index 0000000..b1ac727 --- /dev/null +++ b/ocanada/flag.h @@ -0,0 +1,16 @@ +// +// flag.h +// ocanada +// +// Created by Jeremy Rand on 2017-07-01. +// Copyright © 2017 Jeremy Rand. All rights reserved. +// + +#ifndef __ocanada__flag__ +#define __ocanada__flag__ + + +extern void drawFlag(void); + + +#endif /* defined(__ocanada__flag__) */ diff --git a/ocanada/main.c b/ocanada/main.c index db60a73..f034e68 100644 --- a/ocanada/main.c +++ b/ocanada/main.c @@ -8,13 +8,58 @@ */ +#include +#include #include +#include #include +#include "flag.h" +#include "mockingboard.h" +#include "song.h" + + +void showTitleScreen(void) +{ + clrscr(); + printf("%s", + //0000000001111111111222222222233333333334 + //1234567890123456789012345678901234567890 + " HAPPY CANADA DAY\n" + " JULY 1, 2017\n" + " BY\n" + " JEREMY RAND\n" + "\n" + "THIS PROGRAM REQUIRES A MOCKINGBOARD TO\n" + "PLAY THE SONG\n" + "\n"); +} + + +tSlot getSlotNum(void) +{ + printf("MOCKINGBOARD SLOT NUMBER [1-7]?"); + while (true) { + char ch = cgetc(); + if ((ch >= '1') && + (ch <= '7')) + return (ch - '0'); + + if ((ch == '0') || + (ch == 'q') || + (ch == 'Q') || + (ch == CH_ESC)) + exit(0); + + printf("\007"); + } +} int main(void) { - printf("HELLO, WORLD!\n"); - cgetc(); + showTitleScreen(); + mockingBoardInit(getSlotNum(), false); + drawFlag(); + playSong(); return 0; } diff --git a/ocanada/make/V2Make.scpt b/ocanada/make/V2Make.scpt index 7f623e5..299ab4b 100644 Binary files a/ocanada/make/V2Make.scpt and b/ocanada/make/V2Make.scpt differ diff --git a/ocanada/mockingboard.c b/ocanada/mockingboard.c new file mode 100755 index 0000000..4e15492 --- /dev/null +++ b/ocanada/mockingboard.c @@ -0,0 +1,189 @@ +// +// mockingboard.c +// mocktest +// +// Created by Jeremy Rand on 2016-09-10. +// Copyright © 2016 Jeremy Rand. All rights reserved. +// + + +#include +#include +#include + +#include "mockingboard.h" +#include "mockingboard_speech.h" + + +// Defines + +#define LATCH_COMMAND 0x7 +#define WRITE_COMMAND 0x6 +#define RESET_COMMAND 0x0 +#define THROUGH_PORT_B 0x4 + +#define MOCKINGBOARD_LATCH(soundChip) writeCommand((soundChip), LATCH_COMMAND) +#define MOCKINGBOARD_WRITE(soundChip) writeCommand((soundChip), WRITE_COMMAND) +#define MOCKINGBOARD_RESET(soundChip) writeCommand((soundChip), RESET_COMMAND) + + +// Typedefs + +typedef enum { + SOUND_CHIP_1 = 0, + SOUND_CHIP_2 = 1, + NUM_SOUND_CHIPS = 2 +} tMockingBoardSoundChip; + + +// Globals + +// Addresses for the two 6522's (assuming slot 4 for now) +static uint8_t *gMockPortB[NUM_SOUND_CHIPS] = { (uint8_t *)0xc000, (uint8_t *)0xc080 }; +static uint8_t *gMockPortA[NUM_SOUND_CHIPS] = { (uint8_t *)0xc001, (uint8_t *)0xc081 }; +static uint8_t *gMockDataDirB[NUM_SOUND_CHIPS] = { (uint8_t *)0xc002, (uint8_t *)0xc082 }; +static uint8_t *gMockDataDirA[NUM_SOUND_CHIPS] = { (uint8_t *)0xc003, (uint8_t *)0xc083 }; + +static uint8_t gMockingBoardInitialized = false; +static uint8_t gMockingBoardSpeechInitialized = false; + + +// Implementation + +static uint8_t *mapIOPointer(tSlot slot, uint8_t *ptr) +{ + uint16_t temp1 = (uint16_t)ptr; + uint16_t temp2 = slot; + + temp2 <<= 8; + temp1 &= 0xf0ff; + + temp1 |= temp2; + ptr = (uint8_t *)temp1; + return ptr; +} + + +void mockingBoardInit(tSlot slot, bool hasSpeechChip) +{ + tMockingBoardSoundChip soundChip; + + if (sizeof(tMockingSoundRegisters) != 16) { + printf("The sound registers must be 16 bytes long!\n"); + } + + for (soundChip = SOUND_CHIP_1; soundChip < NUM_SOUND_CHIPS; soundChip++) { + gMockPortB[soundChip] = mapIOPointer(slot, gMockPortB[soundChip]); + gMockPortA[soundChip] = mapIOPointer(slot, gMockPortA[soundChip]); + gMockDataDirB[soundChip] = mapIOPointer(slot, gMockDataDirB[soundChip]); + gMockDataDirA[soundChip] = mapIOPointer(slot, gMockDataDirA[soundChip]); + + *(gMockDataDirA[soundChip]) = 0xff; // Set port A for output + *(gMockDataDirB[soundChip]) = 0x7; // Set port B for output + } + + if (hasSpeechChip) { + if (gMockingBoardSpeechInitialized) { + mockingBoardSpeechShutdown(); + } + mockingBoardSpeechInit(slot); + gMockingBoardSpeechInitialized = true; + } else if (gMockingBoardSpeechInitialized) { + mockingBoardSpeechShutdown(); + gMockingBoardSpeechInitialized = false; + } + + gMockingBoardInitialized = true; +} + + +void mockingBoardShutdown(void) +{ + if (gMockingBoardSpeechInitialized) { + mockingBoardSpeechShutdown(); + gMockingBoardSpeechInitialized = false; + } + + gMockingBoardInitialized = false; +} + + +static void writeCommand(tMockingBoardSoundChip soundChip, uint8_t command) +{ + volatile uint8_t *ptr = gMockPortB[soundChip]; + + *ptr = command; + *ptr = THROUGH_PORT_B; +} + + +static void mockingBoardTableAccess(tMockingBoardSoundChip soundChip, tMockingSoundRegisters *registers) +{ + uint8_t *data = (uint8_t *)registers; + volatile uint8_t *ptr = gMockPortA[soundChip]; + uint8_t index; + + if (!gMockingBoardInitialized) + return; + + MOCKINGBOARD_RESET(soundChip); + for (index = 0; index < 16; index++) { + *ptr = index; + MOCKINGBOARD_LATCH(soundChip); + *ptr = *data; + MOCKINGBOARD_WRITE(soundChip); + data++; + } +} + + +void mockingBoardPlaySound(tMockingBoardSpeaker speaker, tMockingSoundRegisters *registers) +{ + if ((speaker & SPEAKER_LEFT) != 0) { + mockingBoardTableAccess(SOUND_CHIP_1, registers); + } + + if ((speaker & SPEAKER_RIGHT) != 0) { + mockingBoardTableAccess(SOUND_CHIP_2, registers); + } +} + + +void mockingBoardStopSound(tMockingBoardSpeaker speaker) +{ + if ((speaker & SPEAKER_LEFT) != 0) { + MOCKINGBOARD_RESET(SOUND_CHIP_1); + } + + if ((speaker & SPEAKER_RIGHT) != 0) { + MOCKINGBOARD_RESET(SOUND_CHIP_2); + } +} + + +bool mockingBoardSpeechIsBusy(void) +{ + return (mockingBoardSpeechBusy != 0); +} + + +bool mockingBoardSpeechIsPlaying(void) +{ + return (mockingBoardSpeechPlaying != 0); +} + + +bool mockingBoardSpeak(uint8_t *data, uint16_t dataLen) +{ + if (!gMockingBoardSpeechInitialized) + return false; + + if (mockingBoardSpeechIsBusy()) + return false; + + mockingBoardSpeechData = data; + mockingBoardSpeechLen = dataLen; + mockingBoardSpeakPriv(); + + return true; +} diff --git a/ocanada/mockingboard.h b/ocanada/mockingboard.h new file mode 100755 index 0000000..a2deec1 --- /dev/null +++ b/ocanada/mockingboard.h @@ -0,0 +1,131 @@ +// +// mockingboard.h +// mocktest +// +// Created by Jeremy Rand on 2016-09-10. +// Copyright © 2016 Jeremy Rand. All rights reserved. +// + +#ifndef __mocktest__mockingboard__ +#define __mocktest__mockingboard__ + + +#include +#include + + +// Defines + +#define MOCK_NUM_CHANNELS 3 + + +#define TONE_PERIOD_C(octave) (0x7a3 >> (octave - 1)) +#define TONE_PERIOD_C_SHARP(octave) (0x735 >> (octave - 1)) +#define TONE_PERIOD_D(octave) (0x6cd >> (octave - 1)) +#define TONE_PERIOD_D_SHARP(octave) (0x66c >> (octave - 1)) +#define TONE_PERIOD_E(octave) (0x60f >> (octave - 1)) +#define TONE_PERIOD_F(octave) (0x5b8 >> (octave - 1)) +#define TONE_PERIOD_F_SHARP(octave) (0x566 >> (octave - 1)) +#define TONE_PERIOD_G(octave) (0x518 >> (octave - 1)) +#define TONE_PERIOD_G_SHARP(octave) (0x4cf >> (octave - 1)) +#define TONE_PERIOD_A(octave) (0x48a >> (octave - 1)) +#define TONE_PERIOD_A_SHARP(octave) (0x449 >> (octave - 1)) +#define TONE_PERIOD_B(octave) (0x40b >> (octave - 1)) + +#define MIN_NOISE_PERIOD 0 +#define MAX_NOISE_PERIOD 31 + +#define TONE_CHANNEL_A 1 +#define TONE_CHANNEL_B 2 +#define TONE_CHANNEL_C 4 +#define NOISE_CHANNEL_A 8 +#define NOISE_CHANNEL_B 16 +#define NOISE_CHANNEL_C 32 + +#define ENABLE_CHANNEL(channels) (0x3f ^ (channels)) +#define ENABLE_ALL_TONE_CHANNELS ENABLE_CHANNEL(TONE_CHANNEL_A|TONE_CHANNEL_B|TONE_CHANNEL_C) +#define ENABLE_ALL_NOISE_CHANNELS ENABLE_CHANNEL(NOISE_CHANNEL_A|NOISE_CHANNEL_B|NOISE_CHANNEL_C) +#define ENABLE_ALL_CHANNELS ENABLE_CHANNEL(TONE_CHANNEL_A|TONE_CHANNEL_B|TONE_CHANNEL_C|NOISE_CHANNEL_A|NOISE_CHANNEL_B|NOISE_CHANNEL_C) + +#define MIN_AMPLITUDE 0 +#define MAX_AMPLITUDE 15 +#define VARIABLE_AMPLITUDE 16 + +#define MIN_ENVELOPE_PERIOD 0 +#define MAX_ENVELOPE_PERIOD 65535u +#define MILLISEC_TO_ENVELOP_PERIOD(ms) ((ms) * 4) + + +// Here is a table of the envelope shapes and how they look: +// +// ENVELOPE_SHAPE_ONE_SHOT_DECAY \__________... +// +// ENVELOPE_SHAPE_ONE_SHOT_ATTACK /__________... +// +// ENVELOPE_SHAPE_CONT_DECAY \|\|\|\|\|\... +// +// ENVELOPE_SHAPE_CONT_DECAY_HOLD \__________... +// +// ENVELOPE_SHAPE_CONT_DECAY_ALT \/\/\/\/\/\... +// _________ +// ENVELOPE_SHAPE_CONT_DECAY_ALT_HOLD \| ... +// +// ENVELOPE_SHAPE_CONT_ATTACK /|/|/|/|/|/... +// __________ +// ENVELOPE_SHAPE_CONT_ATTACK_HOLD / ... +// ENVELOPE_SHAPE_CONT_ATTACK_ALT /\/\/\/\/\/... +// +// ENVELOPE_SHAPE_CONT_ATTACK_ALT_HOLD /|_________... + +#define ENVELOPE_SHAPE_ONE_SHOT_DECAY 0 +#define ENVELOPE_SHAPE_ONE_SHOT_ATTACK 4 +#define ENVELOPE_SHAPE_CONT_DECAY 8 +#define ENVELOPE_SHAPE_CONT_DECAY_HOLD 9 +#define ENVELOPE_SHAPE_CONT_DECAY_ALT 10 +#define ENVELOPE_SHAPE_CONT_DECAY_ALT_HOLD 11 +#define ENVELOPE_SHAPE_CONT_ATTACK 12 +#define ENVELOPE_SHAPE_CONT_ATTACK_HOLD 13 +#define ENVELOPE_SHAPE_CONT_ATTACK_ALT 14 +#define ENVELOPE_SHAPE_CONT_ATTACK_ALT_HOLD 15 + + + +// Typedefs + +typedef uint8_t tSlot; + + +typedef enum { + SPEAKER_NONE = 0, + SPEAKER_LEFT = (1 << 0), + SPEAKER_RIGHT = (1 << 1), + SPEAKER_BOTH = (1 << 0) | (1 << 1) +} tMockingBoardSpeaker; + + +typedef struct tMockingSoundRegisters { + uint16_t tonePeriod[MOCK_NUM_CHANNELS]; + uint8_t noisePeriod; + uint8_t enable; + uint8_t amplitude[MOCK_NUM_CHANNELS]; + uint16_t envelopePeriod; + uint8_t envelopeShape; + uint8_t dummy1; + uint8_t dummy2; +} tMockingSoundRegisters; + + +// API + +extern void mockingBoardInit(tSlot slot, bool hasSpeechChip); +extern void mockingBoardShutdown(void); + +extern void mockingBoardPlaySound(tMockingBoardSpeaker speaker, tMockingSoundRegisters *registers); +extern void mockingBoardStopSound(tMockingBoardSpeaker speaker); + +extern bool mockingBoardSpeechIsBusy(void); +extern bool mockingBoardSpeechIsPlaying(void); +extern bool mockingBoardSpeak(uint8_t *data, uint16_t dataLen); + + +#endif /* defined(__mocktest__mockingboard__) */ diff --git a/ocanada/mockingboard_speech.h b/ocanada/mockingboard_speech.h new file mode 100755 index 0000000..3228735 --- /dev/null +++ b/ocanada/mockingboard_speech.h @@ -0,0 +1,26 @@ +// +// mockingboard_speech.h +// mocktest +// +// Created by Jeremy Rand on 2016-10-17. +// Copyright © 2016 Jeremy Rand. All rights reserved. +// + +#ifndef mockingboard_speech_h +#define mockingboard_speech_h + + +#include + + +extern uint8_t *mockingBoardSpeechData; +extern uint16_t mockingBoardSpeechLen; +extern uint8_t mockingBoardSpeechBusy; +extern uint8_t mockingBoardSpeechPlaying; + +extern void mockingBoardSpeechInit(uint8_t slot); +extern void mockingBoardSpeechShutdown(void); +extern void mockingBoardSpeakPriv(void); + + +#endif /* mockingboard_speech_h */ diff --git a/ocanada/mockingboard_speech.s b/ocanada/mockingboard_speech.s new file mode 100755 index 0000000..6364996 --- /dev/null +++ b/ocanada/mockingboard_speech.s @@ -0,0 +1,265 @@ +; +; speech.s +; mocktest +; +; Created by Jeremy Rand on 2016-09-29. +; Copyright © 2016 Jeremy Rand. All rights reserved. +; + + + .export _mockingBoardSpeechInit, _mockingBoardSpeechShutdown, _mockingBoardSpeakPriv + .export _mockingBoardSpeechData, _mockingBoardSpeechLen + .export _mockingBoardSpeechBusy, _mockingBoardSpeechPlaying + .interruptor mock_irq + + +TMPPTR := $FB ; Temporary pointer used in interrupt handler +IRQL := $03FE ; Interrupt vector, low byte +IRQH := $03FF ; Interrupt vector, high byte +BASE := $40 ; First speech chip +DURPHON := BASE ; Register 0 of speech chip +INFLECT := BASE+$01 ; Register 1 of speech chip +RATEINF := BASE+$02 ; Register 2 of speech chip +CTTRAMP := BASE+$03 ; Register 3 of speech chip +FILFREQ := BASE+$04 ; Register 4 of speech chip +DDRB := $02 +DDRA := $03 +PCR := $8C ; Peripheral control register, 6522 +IFR := $8D ; Interrupt flag register, 6522 +IER := $8E + + +.DATA +_mockingBoardSpeechData: .byte $00, $00 +_mockingBoardSpeechLen: .byte $00, $00 +_outptr: .byte $00, $00 +_endptr: .byte $00, $00 +_mockingBoardSpeechBusy: .byte $00 +_mockingBoardSpeechPlaying: .byte $00 + +mock_irq: .byte $60 + .lobytes _mockInterrupt + .hibytes _mockInterrupt + + +.CODE + +writeChip: + sta $C000,X + rts + +readChip: + lda $C000,X + rts + + +.proc _mockingBoardSpeechInit + sei + +; The accumulator has the slot number of the mockingboard. +; Turn that into the address of the slot and set the address +; in the read and write functions. + and #$7 + ora #$c0 + sta writeChip+2 + sta readChip+2 + +; Write a jump instruction at mock_irq to turn on our handler + lda #$4c + sta mock_irq + + cli + rts +.endproc + + +.proc _mockingBoardSpeechShutdown + sei + +; Write a RTS instruction at mock_irq to disable our handler + lda #$60 + sta mock_irq + + cli + rts +.endproc + + +.proc _mockingBoardSpeakPriv + sei + lda #$00 + ldx #DDRA + jsr writeChip + ldx #DDRB + jsr writeChip + +; Get the starting address of the data and store in the work pointer + lda _mockingBoardSpeechData+1 + sta _outptr+1 + lda _mockingBoardSpeechData + sta _outptr + +; Calculate the end address from the start address and the length + lda _mockingBoardSpeechLen+1 + clc + adc _mockingBoardSpeechData+1 + sta _endptr+1 + lda _mockingBoardSpeechLen + clc + adc _mockingBoardSpeechData + bcc @L2 + inc _endptr+1 +@L2: + sta _endptr + +; Set the busy flag + lda #$FF + sta _mockingBoardSpeechBusy + +; Set peripheral control register to recognize the signal from the +; speech chip. + lda #$0C + ldx #PCR + jsr writeChip + +; Raise control bit in register 3 + lda #$80 + ldx #CTTRAMP + jsr writeChip + +; Set transitioned inflection mode in register 0 + lda #$C0 + ldx #DURPHON + jsr writeChip + +; Lower control bit + lda #$70 + ldx #CTTRAMP + jsr writeChip + +; Enable 6522 interrupts + lda #$82 + ldx #IER + jsr writeChip + + cli + rts +.endproc + + +.proc _mockInterrupt +; If we have a 6522 interrupt, jump to L4. + ldx #IFR + jsr readChip + bmi @L4 + +; Otherwise clear the carry to indicate we didn't handle the interrupt +; and return to the caller. + clc + rts + +@L4: +; Clear the interrupt flag + lda #$02 + ldx #IFR + jsr writeChip + +; Check for end of data file. If not the end, jump to L1 + lda _outptr+1 + cmp _endptr+1 + bcc @L1 + bne @L5 + lda _outptr + cmp _endptr + bcc @L1 + +@L5: + +; If at the end, turn everything off. Store a pause phoneme. + lda #$00 + ldx #DURPHON + jsr writeChip + +; Zero amplitude + lda #$70 + ldx #CTTRAMP + jsr writeChip + +; Clear busy and playing flags + lda #$00 + sta _mockingBoardSpeechBusy + sta _mockingBoardSpeechPlaying + +; Clear interrupt enable in 6522 + lda #$02 + ldx #IER + jsr writeChip + lda #$FF + ldx #DDRA + jsr writeChip + lda #$07 + ldx #DDRB + jsr writeChip + +@L2: +; Set the carry flag to indicate we handled the interrupt and return to the caller. + sec + rts + +@L1: + +; Set the speach playing flag + lda #$ff + sta _mockingBoardSpeechPlaying + +; Save the value of the tmp pointer on the stack + lda TMPPTR + pha + lda TMPPTR+1 + pha + +; Move the _outptr into the tmp pointer + lda _outptr + sta TMPPTR + lda _outptr+1 + sta TMPPTR+1 + +; Init registers + ldy #$00 + ldx #FILFREQ + +@L6: +; Get the next data + lda (TMPPTR),Y + +; Store in the speech chip + jsr writeChip + +; Next data + inc TMPPTR + bne @L3 + inc TMPPTR+1 + +@L3: +; Go to next register + dex + +; If we are not done the last register, then loop back to L6 + cpx #BASE-1 + bne @L6 + +; We are done writing so move the tmp pointer back into _outptr + lda TMPPTR + sta _outptr + lda TMPPTR+1 + sta _outptr+1 + +; Restore the tmp pointer from the stack + pla + sta TMPPTR+1 + pla + sta TMPPTR + +; Finish the interrupt handler + jmp @L2 +.endproc diff --git a/ocanada/song.c b/ocanada/song.c new file mode 100644 index 0000000..6592770 --- /dev/null +++ b/ocanada/song.c @@ -0,0 +1,151 @@ +// +// song.c +// ocanada +// +// Created by Jeremy Rand on 2017-07-01. +// Copyright © 2017 Jeremy Rand. All rights reserved. +// + +#include +#include +#include + +#include "mockingboard.h" +#include "song.h" + + + +typedef struct tSongNote { + uint16_t mainTone; + uint16_t bassTone; + uint8_t duration; + char *words; +} tSongNote; + + +static tSongNote notes[] = { + { TONE_PERIOD_E(4), TONE_PERIOD_C(2), 8, "\n\nO" }, + { TONE_PERIOD_G(4), TONE_PERIOD_G(2), 6, " CAN" }, + { TONE_PERIOD_G(4), TONE_PERIOD_G(2), 2, "A" }, + { TONE_PERIOD_C(4), TONE_PERIOD_A(2), 12, "DA" }, + { TONE_PERIOD_D(4), TONE_PERIOD_A(2), 4, "\nOUR" }, + { TONE_PERIOD_E(4), TONE_PERIOD_C(2), 4, " HOME" }, + { TONE_PERIOD_F(4), TONE_PERIOD_C(2), 4, " AND" }, + { TONE_PERIOD_G(4), TONE_PERIOD_C(2), 4, " NA" }, + { TONE_PERIOD_A(4), TONE_PERIOD_C(2), 4, "TIVE" }, + { TONE_PERIOD_D(4), TONE_PERIOD_G(2), 16, " LAND" }, + { TONE_PERIOD_E(4), TONE_PERIOD_C(2), 8, "\nTRUE" }, + { TONE_PERIOD_F_SHARP(4), TONE_PERIOD_D(2), 6, " PA" }, + { TONE_PERIOD_F_SHARP(4), TONE_PERIOD_D(2), 2, "TRIOT" }, + { TONE_PERIOD_G(4), TONE_PERIOD_G(2), 12, " LOVE" }, + { TONE_PERIOD_A(4), TONE_PERIOD_G(2), 4, " IN" }, + { TONE_PERIOD_B(4), TONE_PERIOD_G(2), 4, "\nALL" }, + { TONE_PERIOD_B(4), TONE_PERIOD_G(2), 4, " THY" }, + { TONE_PERIOD_A(4), TONE_PERIOD_D(2), 4, " SONS" }, + { TONE_PERIOD_A(4), TONE_PERIOD_D(2), 4, " COM" }, + { TONE_PERIOD_G(4), TONE_PERIOD_G(2), 12, "MAND" }, + { TONE_PERIOD_D(4), TONE_PERIOD_G(2), 3, "\nWITH" }, + { TONE_PERIOD_E(4), TONE_PERIOD_G(2), 1, "" }, + { TONE_PERIOD_F(4), TONE_PERIOD_G(2), 6, " GLOW" }, + { TONE_PERIOD_E(4), TONE_PERIOD_G(2), 2, "ING" }, + { TONE_PERIOD_D(4), TONE_PERIOD_G(2), 4, " HEARTS" }, + { TONE_PERIOD_E(4), TONE_PERIOD_G(2), 3, " WE" }, + { TONE_PERIOD_F(4), TONE_PERIOD_G(2), 1, "" }, + { TONE_PERIOD_G(4), TONE_PERIOD_C(2), 6, " SEE" }, + { TONE_PERIOD_F(4), TONE_PERIOD_C(2), 2, " THEE" }, + { TONE_PERIOD_E(4), TONE_PERIOD_C(2), 4, " RISE" }, + { TONE_PERIOD_F(4), TONE_PERIOD_C(2), 3, "\nTHE" }, + { TONE_PERIOD_G(4), TONE_PERIOD_C(2), 1, "" }, + { TONE_PERIOD_A(4), TONE_PERIOD_F(2), 4, " TRUE" }, + { TONE_PERIOD_G(4), TONE_PERIOD_F(2), 4, " NORTH" }, + { TONE_PERIOD_F(4), TONE_PERIOD_F(2), 4, " STRONG" }, + { TONE_PERIOD_E(4), TONE_PERIOD_F(2), 4, " AND" }, + { TONE_PERIOD_D(4), TONE_PERIOD_G(2), 12, " FREE" }, + { TONE_PERIOD_D(4), TONE_PERIOD_G(2), 3, "\nFROM" }, + { TONE_PERIOD_E(4), TONE_PERIOD_G(2), 1, "" }, + { TONE_PERIOD_F(4), TONE_PERIOD_G(2), 6, " FAR" }, + { TONE_PERIOD_E(4), TONE_PERIOD_G(2), 2, " AND" }, + { TONE_PERIOD_D(4), TONE_PERIOD_G(2), 4, " WIDE" }, + { TONE_PERIOD_E(4), TONE_PERIOD_G(2), 3, ", O" }, + { TONE_PERIOD_F(4), TONE_PERIOD_G(2), 1, "" }, + { TONE_PERIOD_G(4), TONE_PERIOD_C(2), 6, " CAN" }, + { TONE_PERIOD_F(4), TONE_PERIOD_C(2), 2, "A" }, + { TONE_PERIOD_E(4), TONE_PERIOD_C(2), 4, "DA" }, + { TONE_PERIOD_E(4), TONE_PERIOD_C(2), 4, "\nWE" }, + { TONE_PERIOD_D(4), TONE_PERIOD_G(2), 4, " STAND" }, + { TONE_PERIOD_G(4), TONE_PERIOD_G(2), 4, " ON" }, + { TONE_PERIOD_G(4), TONE_PERIOD_D(2), 2, " GUARD" }, + { TONE_PERIOD_F_SHARP(4), TONE_PERIOD_D(2), 2, "" }, + { TONE_PERIOD_E(4), TONE_PERIOD_D(2), 2, " FOR" }, + { TONE_PERIOD_F_SHARP(4), TONE_PERIOD_D(2), 2, "" }, + { TONE_PERIOD_G(4), TONE_PERIOD_G(2), 16, " THEE" }, + { TONE_PERIOD_E(4), TONE_PERIOD_C(2), 8, "\nGOD" }, + { TONE_PERIOD_G(4), TONE_PERIOD_G(2), 6, " KEEP" }, + { TONE_PERIOD_G(4), TONE_PERIOD_G(2), 2, " OUR" }, + { TONE_PERIOD_C(4), TONE_PERIOD_A(2), 16, " LAND" }, + { TONE_PERIOD_F(4), TONE_PERIOD_D(2), 8, ", GLO" }, + { TONE_PERIOD_A(4), TONE_PERIOD_D(2), 6, "RIOUS" }, + { TONE_PERIOD_A(4), TONE_PERIOD_D(2), 2, " AND" }, + { TONE_PERIOD_D(4), TONE_PERIOD_G(2), 16, " FREE" }, + { TONE_PERIOD_G(4), TONE_PERIOD_C(2), 8, "\nO" }, + { TONE_PERIOD_G_SHARP(4), TONE_PERIOD_E(2), 6, " CAN" }, + { TONE_PERIOD_G_SHARP(4), TONE_PERIOD_E(2), 2, "A" }, + { TONE_PERIOD_A(4), TONE_PERIOD_F(2), 4, "DA" }, + { TONE_PERIOD_F(4), TONE_PERIOD_F(2), 4, ", WE" }, + { TONE_PERIOD_E(4), TONE_PERIOD_C(2), 4, " STAND" }, + { TONE_PERIOD_D(4), TONE_PERIOD_C(2), 4, " ON" }, + { TONE_PERIOD_C(4), TONE_PERIOD_A(2), 8, " GUARD" }, + { TONE_PERIOD_D(4), TONE_PERIOD_D(2), 8, " FOR" }, + { TONE_PERIOD_E(4), TONE_PERIOD_E(2), 16, " THEE" }, + { TONE_PERIOD_G(4), TONE_PERIOD_C(2), 8, "\nO" }, + { TONE_PERIOD_C(5), TONE_PERIOD_C(2), 6, " CAN" }, + { TONE_PERIOD_C(5), TONE_PERIOD_C(2), 2, "A" }, + { TONE_PERIOD_A(4), TONE_PERIOD_F(2), 4, "DA" }, + { TONE_PERIOD_F(4), TONE_PERIOD_F(2), 4, ", WE" }, + { TONE_PERIOD_E(4), TONE_PERIOD_C(2), 4, " STAND" }, + { TONE_PERIOD_D(4), TONE_PERIOD_C(2), 4, " ON" }, + { TONE_PERIOD_G(4), TONE_PERIOD_C(2), 8, " GUARD" }, + { TONE_PERIOD_B(4), TONE_PERIOD_G(2), 8, " FOR" }, + { TONE_PERIOD_C(5), TONE_PERIOD_C(2), 16, " THEE!" }, +}; + + +void delay(uint8_t duration) +{ + uint8_t count; + + for (count = 0; count < duration; count++) { + uint16_t insideCount = 0; + do { + insideCount++; + } while (insideCount != 768); + } +} + + +void playSong(void) +{ + uint16_t noteNum; + static tMockingSoundRegisters regs; + + regs.noisePeriod = MIN_NOISE_PERIOD; + regs.enable = ENABLE_ALL_TONE_CHANNELS; + regs.amplitude[0] = MAX_AMPLITUDE; + regs.amplitude[1] = MAX_AMPLITUDE; + regs.amplitude[2] = MAX_AMPLITUDE; + regs.envelopePeriod = MIN_ENVELOPE_PERIOD; + regs.envelopeShape = ENVELOPE_SHAPE_CONT_ATTACK_HOLD; + + printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); + for (noteNum = 0; noteNum < (sizeof(notes) / sizeof(notes[0])); noteNum++) { + regs.tonePeriod[0] = notes[noteNum].mainTone; + regs.tonePeriod[1] = notes[noteNum].mainTone; + regs.tonePeriod[2] = notes[noteNum].bassTone; + + mockingBoardPlaySound(SPEAKER_BOTH, ®s); + printf("%s", notes[noteNum].words); + delay(notes[noteNum].duration); + } + mockingBoardStopSound(SPEAKER_BOTH); + cgetc(); +} diff --git a/ocanada/song.h b/ocanada/song.h new file mode 100644 index 0000000..9581155 --- /dev/null +++ b/ocanada/song.h @@ -0,0 +1,16 @@ +// +// song.h +// ocanada +// +// Created by Jeremy Rand on 2017-07-01. +// Copyright © 2017 Jeremy Rand. All rights reserved. +// + +#ifndef __ocanada__song__ +#define __ocanada__song__ + + +extern void playSong(void); + + +#endif /* defined(__ocanada__song__) */