From 860de1701a753f0a47b65f9f6c377d2c92879a59 Mon Sep 17 00:00:00 2001 From: Vince Weaver Date: Tue, 14 Sep 2021 13:57:44 -0400 Subject: [PATCH] wargames: it's the speech synthesis --- demos/wargames/Makefile | 34 ++++ demos/wargames/hardware.inc | 102 ++++++++++++ demos/wargames/hello.bas | 2 + demos/wargames/map.png | Bin 0 -> 2140 bytes demos/wargames/ssi263.inc | 100 +++++++++++ demos/wargames/ssi263_detect.s | 134 +++++++++++++++ demos/wargames/ssi263_simple_speech.s | 231 ++++++++++++++++++++++++++ demos/wargames/wargames.s | 202 ++++++++++++++++++++++ 8 files changed, 805 insertions(+) create mode 100644 demos/wargames/Makefile create mode 100644 demos/wargames/hardware.inc create mode 100644 demos/wargames/hello.bas create mode 100644 demos/wargames/map.png create mode 100644 demos/wargames/ssi263.inc create mode 100644 demos/wargames/ssi263_detect.s create mode 100644 demos/wargames/ssi263_simple_speech.s create mode 100644 demos/wargames/wargames.s diff --git a/demos/wargames/Makefile b/demos/wargames/Makefile new file mode 100644 index 00000000..c0a7f7d4 --- /dev/null +++ b/demos/wargames/Makefile @@ -0,0 +1,34 @@ +include ../../Makefile.inc + +DOS33 = ../../utils/dos33fs-utils/dos33 +TOKENIZE = ../../utils/asoft_basic-utils/tokenize_asoft +EMPTY_DISK = ../../empty_disk/empty.dsk + +all: wargames.dsk + +wargames.dsk: HELLO WARGAMES + cp $(EMPTY_DISK) speech.dsk + $(DOS33) -y speech.dsk SAVE A HELLO + $(DOS33) -y speech.dsk BSAVE -a 0x1000 WARGAMES + +### + +WARGAMES: wargames.o + ld65 -o WARGAMES wargames.o -C ../../linker_scripts/apple2_1000.inc + +wargames.o: wargames.s ssi263.inc ssi263_detect.s ssi263_simple_speech.s + ca65 -o wargames.o wargames.s -l wargames.lst + + +### + + +HELLO: hello.bas + $(TOKENIZE) < hello.bas > HELLO + +#### + +clean: + rm -f *~ *.o *.lst HELLO WARGAMES + + diff --git a/demos/wargames/hardware.inc b/demos/wargames/hardware.inc new file mode 100644 index 00000000..b52d7281 --- /dev/null +++ b/demos/wargames/hardware.inc @@ -0,0 +1,102 @@ +; HARDWARE LOCATIONS + +KEYPRESS = $C000 +KEYRESET = $C010 + +; SOFT SWITCHES +CLR80COL = $C000 ; PAGE1/PAGE1 normal +SET80COL = $C001 ; PAGE1/PAGE2 switches PAGE1 in Aux instead +EIGHTYCOLOFF = $C00C +EIGHTYCOLON = $C00D +TBCOLOR = $C022 ; IIgs text foreground / background colors +NEWVIDEO = $C029 ; IIgs graphics modes +SPEAKER = $C030 +CLOCKCTL = $C034 ; bits 0-3 are IIgs border color +SET_GR = $C050 +SET_TEXT = $C051 +FULLGR = $C052 +TEXTGR = $C053 +PAGE1 = $C054 +PAGE2 = $C055 +LORES = $C056 ; Enable LORES graphics +HIRES = $C057 ; Enable HIRES graphics +AN3 = $C05E ; Annunciator 3 + +PADDLE_BUTTON0 = $C061 +PADDL0 = $C064 +PTRIG = $C070 + +; APPLESOFT BASIC ROUTINES + +;NORMAL = $F273 +HGR2 = $F3D8 +;HGR = $F3E2 +;BKGND0 = $F3F4 ; clear current page to A +HPOSN = $F411 ; (Y,X),(A) (values stores in HGRX,XH,Y) +HPLOT0 = $F457 ; plot at (Y,X), (A) +;COLOR_SHIFT = $F47E +;HLINRL = $F530 ; (X,A),(Y) +;HGLIN = $F53A ; line to (X,A),(Y) +;COLORTBL = $F6F6 + + +; MONITOR ROUTINES + +;HLINE = $F819 ; HLINE Y,$2C at A +;VLINE = $F828 ; VLINE A,$2D at Y +;CLRSCR = $F832 ; Clear low-res screen +;CLRTOP = $F836 ; clear only top of low-res screen +;SETCOL = $F864 ; COLOR=A +;ROM_TEXT2COPY = $F962 ; iigs +TEXT = $FB36 ; qboot +;TABV = $FB5B ; VTAB to A +;ROM_MACHINEID = $FBB3 ; iigs +;BELL = $FBDD ; ring the bell +;BASCALC = $FBC1 ; +;VTAB = $FC22 ; VTAB to CV +HOME = $FC58 ; Clear the text screen ; qboot +WAIT = $FCA8 ; delay 1/2(26+27A+5A^2) us +;CROUT1 = $FD8B +;SETINV = $FE80 ; INVERSE +;SETNORM = $FE84 ; NORMAL +COUT = $FDED ; output A to screen ; qboot +COUT1 = $FDF0 ; output A to screen ; qload + + + + + + + +COLOR_BLACK = 0 +COLOR_RED = 1 +COLOR_DARKBLUE = 2 +COLOR_PURPLE = 3 +COLOR_DARKGREEN = 4 +COLOR_GREY = 5 +COLOR_MEDIUMBLUE = 6 +COLOR_LIGHTBLUE = 7 +COLOR_BROWN = 8 +COLOR_ORANGE = 9 +COLOR_GREY2 = 10 +COLOR_PINK = 11 +COLOR_LIGHTGREEN = 12 +COLOR_YELLOW = 13 +COLOR_AQUA = 14 +COLOR_WHITE = 15 + +COLOR_BOTH_BLACK = $00 +COLOR_BOTH_RED = $11 +COLOR_BOTH_DARKBLUE = $22 +COLOR_BOTH_DARKGREEN = $44 +COLOR_BOTH_GREY = $55 +COLOR_BOTH_MEDIUMBLUE = $66 +COLOR_BOTH_LIGHTBLUE = $77 +COLOR_BOTH_BROWN = $88 +COLOR_BOTH_ORANGE = $99 +COLOR_BOTH_PINK = $BB +COLOR_BOTH_LIGHTGREEN = $CC +COLOR_BOTH_YELLOW = $DD +COLOR_BOTH_AQUA = $EE +COLOR_BOTH_WHITE = $FF + diff --git a/demos/wargames/hello.bas b/demos/wargames/hello.bas new file mode 100644 index 00000000..d824b243 --- /dev/null +++ b/demos/wargames/hello.bas @@ -0,0 +1,2 @@ +5 HOME +120 PRINT CHR$(4);"BRUN WARGAMES" diff --git a/demos/wargames/map.png b/demos/wargames/map.png new file mode 100644 index 0000000000000000000000000000000000000000..e4534f992c05bbfcee4058b3e143bfceea5f19e5 GIT binary patch literal 2140 zcmV-i2&4CjP)EX>4Tx04R}tkv&MmKpe$iTcuU19qb_DkfAzR5EXIMDionYs1;guFuC*#nlvOS zE{=k0!NHHks)LKOt`4q(Aou~|=H{g6A|?JWDYS_3;J6>}?mh0_0scmXsb<$WplX(p zP9}tGZdC}rq6htmAcVNYOnpuiQ}7&L_we!cF3z*O&;2?2l)T9RpFljzbi*RvAfDc| zbk6(4QC5-^;&b9LgDyz?$aUG}H_kjWYY7*QDULk!Ey()lA#h$5yuo&qkMnX zWrgz=XSGset$XqphV$CWGS_JiBZ);UL4*JqHIz|-g*dGmDJIgipYZSxIew8`GP%lN zuDQLn_Hp_EWT>mu4RCM> zj20<--Q(S%&ffk#)9UXBPyKS4P{;2g0000IP)t-s0000R%K_vx{{R2~&07H*n*NcW zLm2=7010qNS#tmY6R!XO6R!bd=8nSv000McNlirueSad^g zZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00t;YL_t(|+U=YRa^o-vhS?kRKg(W$ zE9m}L*(QGJ1ws;zJsW2_og_`;FM!|&%OUE$0ie6w@WQzZ3s#~_&5_)}rPe?l>LRn? zPB8D^xE$v25Gp}*70iKy>shb`GOo&dpu#Y?j3;(d{46faHTkh&jA1^_OF~vwS@=JN zfxMWFUOEA$Wf*)0W~)ppjJUMCVT7Z>B>vcQJ(*yD&-p14G*uX-R=L3-mJd42`RfT$ zHPYf&uMF%AQ#%@Js`Nw{GQza{kf=C zN2TUGhIrUEd#s=rhDm^Vn~Fz6IEJxlyDE&+;*PsD8w^(%X4W?9D!dmaV)>;R1;Sn* z5t{}bUgA7rm0v3NV1lQVY*d=5vEe9r1LvC-j_RD zH`ZuEJq4C9aj%5ET61?FS*2;iq~b45dkY*V^46SW71IPU86%(8C*cgxh4Z1#49r3kXbB$;25Y=3 zFfYT*!Gu-ofRv@Z)l1ffB5%V?!UU<;ME)Q-Im*?5#;lvrpu!;8Ru0t9WMg#qc`zB~$jR|OCxEgc zR{Y`oE%%_oOBRCFP07M;!i;U(?Sj!|Y2ngIn$S{V$1uGC zGsN;P({`9W+w>}EyYdW+d=J6;_E5(a6C10sHWEQhdE($mz?p%;k$HoaMcaBmv*Ubu z!x0z(2lJ-s>S*HaB=CnpS9gW-N)jM%$_FD@+HIw@bSMW*m{xbf=QF}2qc@DWD9Cb! zIxSP2ghBUul4vX&+LNG31IH7lFQXzo?E-3zOS@K-Qfi?{zu1@ejS}>{p!`!v0 zXlAuWfTLXIUN8y`)PgeEay!ASy_DK;eiFt$I&ljc41BcHmQ%Cw!|5=vPNx8eOydLt z@=tpzjF!>v1XH;_6tgr?*DMU}u%l@jFc^A=>tJTPU04K-Rs@X~YB{Lji(t@dWiXbi z9AOLtn6HLWkAR;W!FWb+>l>v&wi9umf`MfO2GhF@4MhaatxUjDhvFm{(*P`YC@x~D zM%S3MafBhbz<7OOl6+;|1u(Pu2A(W%j5<#@T@N!Ezs@i;4Re?9y(P>|z992fFm$6Y zF@0c~(&$bR{AGUnd!yR}^T0eX56lDez&tPy%meelJTMQ;1M|Qmb_irq + sta $3ff + + ; Set 6522#2 peripheral control register to recognize the signal + ; from the speech chip. + lda #(VIA6522_PCR2_CA2_LOW|VIA6522_PCR2_CA1_NEG) + ldx #VIA6522_PCR2 + jsr ssi263_d_write_chip + + ; Raise control bit in register 3 of SSI-263 + lda #SSI263_CAA_CTL + ldx #SSI263_CAA + jsr ssi263_d_write_chip + + ; Transitioned inflection (when CTL is toggled) + lda #SSI263_DRP_TRANSITIONED_INFLECTION + ldx #SSI263_DRP + jsr ssi263_d_write_chip + + ; Lower control bit in SSI-263 + lda #$70 ; CTL=0, T=6, AMP=0 + ldx #SSI263_CAA + jsr ssi263_d_write_chip + + ; Enable 6522 interrupt on input CA2 + lda #(VIA6522_IER2_SET|VIA6522_IER2_CA1) + ldx #VIA6522_IER2 + jsr ssi263_d_write_chip + + ldx #0 ; clear counts + ldy #0 + + cli ; enable interrupts + +wait_irq: + lda irq_count ; see if irq happened + + bne got_irq + + iny ; otherwise increase counts + bne wait_irq + inx ; + bne wait_irq + +got_irq: + sei ; disable interrupts + + rts + + + ;======================== + ; detection IRQ handler + ;======================== +mb_irq: + txa ; save X + pha + + ; Clear the 6522 interrupt flag + lda #VIA6522_IFR2_CA1 + ldx #VIA6522_IFR2 + jsr ssi263_d_write_chip + + ; disable speech + + ; Raise control bit in register 3 of SSI-263 + lda #SSI263_CAA_CTL + ldx #SSI263_CAA + jsr ssi263_d_write_chip + + ; Disable talking on SSI-263 (when CTL is toggled) + lda #SSI263_DRP_DISABLE_AR + ldx #SSI263_DRP + jsr ssi263_d_write_chip + + ; Lower control bit in SSI-263 + lda #$70 ; also T=7? + ldx #SSI263_CAA + jsr ssi263_d_write_chip + + ; increment our irq count + + inc irq_count + + ; Disable 6522 interrupts + lda #VIA6522_IER2_CA1 + ldx #VIA6522_IER2 + jsr ssi263_d_write_chip + + pla ; restore X + tax + + lda $45 ; restore accumulator + + rti ; return from interrupt + + + ;======================== + ; write_chip + ;======================== +ssi263_d_write_chip: +ssid_wc_smc1: + sta $C000,X + rts + +irq_count: .byte $00 +irq1backup: .byte $00 +irq2backup: .byte $00 diff --git a/demos/wargames/ssi263_simple_speech.s b/demos/wargames/ssi263_simple_speech.s new file mode 100644 index 00000000..52bbacfc --- /dev/null +++ b/demos/wargames/ssi263_simple_speech.s @@ -0,0 +1,231 @@ +; Simple speech routine for ssi-263 + +; to save space we only change the Phoneme/Delay each time, we don't +; mess with the other registers + + ;======================== + ; ssi263_write_chip + ;======================== +ssi263_write_chip: +wc_smc1: + sta $C000,X + rts + + ;======================== + ; read_chip + ;======================== +ssi263_read_chip: +rc_smc1: + lda $C000,X + rts + + + ;======================== + ; ssi263_speech_init + ;======================== + ; A = slot number of mockingboard +ssi263_speech_init: + sei ; disable interrupts + + and #$7 + ora #$c0 ; turn slot number into address + sta wc_smc1+2 ; update the read/write routines + sta rc_smc1+2 + + lda #ssi263_speech_irq + sta $3ff + + + ; set defaults + + ; filter frequency + lda #$E9 + ldx #SSI263_F + jsr ssi263_write_chip + + ; control / articulation/ amplitude + lda #$5C + ldx #SSI263_CAA + jsr ssi263_write_chip + + ; rate/inflection + lda #$A8 + ldx #SSI263_RI + jsr ssi263_write_chip + + ; inflection + lda #$50 + ldx #SSI263_I + jsr ssi263_write_chip + + cli ; enable interrupts + + rts + + + ;============================ + ; ssi263_speech_shutdown + ;============================ + +ssi263_speech_shutdown: + sei + + rts + + + + ;========================= + ; ssi263_speak + ;========================= + ; pointer to data in SPEECH_PTRL/H + +ssi263_speak: + + sei ; disable interrupts + + ; Set the busy flag + lda #$FF + sta speech_busy + + ; Set peripheral control register to recognize the signal from the + ; speech chip. + lda #(VIA6522_PCR2_CA2_LOW|VIA6522_PCR2_CA1_NEG) + ldx #VIA6522_PCR2 + jsr ssi263_write_chip + + ; Set transitioned inflection by setting value while toggling CTL + + lda #SSI263_CAA_CTL + ldx #SSI263_CAA + jsr ssi263_write_chip + + ; Set transitioned inflection mode in register 0 + lda #SSI263_DRP_TRANSITIONED_INFLECTION + ldx #SSI263_DRP + jsr ssi263_write_chip + + ; Lower control bit + lda #$70 ; also T=7 + ldx #SSI263_CAA + jsr ssi263_write_chip + + ; Enable 6522 interrupts + lda #(VIA6522_IER2_SET|VIA6522_IER2_CA1) + ldx #VIA6522_IER2 + jsr ssi263_write_chip + + cli ; re-enable interrupts + + rts + + + ;==================== + ; speech interrupt + ;==================== +ssi263_speech_irq: + + php ; save flags + cld + + pha ; save A + txa + pha ; save X + tya + pha ; save Y + + inc $0404 ; irq indicator on screen + + ; be sure it was a 6522#2 interrupt + ldx #VIA6522_IFR2 + jsr ssi263_read_chip + bmi have_interrupt + + ; wasn't us, return to caller + ; this assumes we can handle multiple interrupt sources + + jmp end_interrupt + +have_interrupt: + ; Clear the 6522#2 CA interrupt flag + lda #VIA6522_IFR2_CA1 + ldx #VIA6522_IFR2 + jsr ssi263_write_chip + + ; Check if done with speech + ldy #0 + lda (SPEECH_PTRL),Y + cmp #$ff + beq speech_end + +not_end: + + ; Set the speech playing flag + lda #$ff + sta speech_playing + + + ldy #$00 + ; Get the next data + lda (SPEECH_PTRL),Y + ldx #SSI263_DRP ; duration/phoneme + jsr ssi263_write_chip + + ; Next data (inc 16 bit) + inc SPEECH_PTRL + bne no_oflo + inc SPEECH_PTRH +no_oflo: + + ; Finish the interrupt handler + jmp end_interrupt + +speech_end: + + ; If at the end, turn everything off + + ; Toggle CTL while DR set to disable A/!R + + lda #SSI263_CAA_CTL + ldx #SSI263_CAA + jsr ssi263_write_chip + + lda #SSI263_DRP_DISABLE_AR + ldx #SSI263_DRP + jsr ssi263_write_chip + + ; Zero amplitude + lda #$70 + ldx #SSI263_CAA + jsr ssi263_write_chip + + ; Clear busy and playing flags + lda #$00 + sta speech_busy + sta speech_playing + + ; Re-enable interrupt in 6522 + lda #VIA6522_IER2_CA1 + ldx #VIA6522_IER2 + jsr ssi263_write_chip + +end_interrupt: + + pla + tay ; restore Y + pla + tax ; restore X + + pla ; restore A + +interrupt_smc: + lda $45 ; restore A (II+/IIe) + + plp ; restore flags + + rti ; return from interrupt + +speech_busy: .byte $00 +speech_playing: .byte $00 + diff --git a/demos/wargames/wargames.s b/demos/wargames/wargames.s new file mode 100644 index 00000000..b007cf17 --- /dev/null +++ b/demos/wargames/wargames.s @@ -0,0 +1,202 @@ +; +; wargames.s +; +; like from the movie + +.include "hardware.inc" + +.include "ssi263.inc" + + +speech_test: + + jsr HOME + + lda #4 ; assume slot #4 for now + jsr detect_ssi263 + + lda irq_count + clc + adc #'A' ; hack to show if detected or not + sta $400 ; (B is detected, A is not) + + lda #4 ; assume slot #4 for now + jsr ssi263_speech_init + + +speech_loop: + + ; trogdor + + lda #trogdor + sta SPEECH_PTRH + + jsr ssi263_speak + + jsr wait_until_keypress + + jmp speech_loop + +wait_until_keypress: + + lda KEYPRESS + bpl wait_until_keypress + + bit KEYRESET + + rts + + +.include "ssi263_detect.s" + +.include "ssi263_simple_speech.s" + + ; the document + ; "Phonetic Speech Dictionary for the SC-01 Speech Synthesizer" + ; sc01-dictionary.pdf + ; was very helpful here + +trogdor: + .byte PHONEME_PAUSE ; PA + .byte PHONEME_PAUSE ; PA + + .byte PHONEME_KV ; KV ; Greetings + .byte PHONEME_R ; R +; .byte PHONEME_E1 ; E1 + .byte PHONEME_Y ; Y + .byte PHONEME_T ; T + .byte PHONEME_I ; I + .byte PHONEME_NG ; NG + .byte PHONEME_Z ; Z + + .byte PHONEME_PAUSE ; PA + .byte PHONEME_PAUSE ; PA + + .byte PHONEME_P ; P ; Professor + .byte PHONEME_R ; R + .byte PHONEME_UH1 ; UH1 + .byte PHONEME_F ; F + .byte PHONEME_EH1 ; EH1 +; .byte PHONEME_EH1 ; EH1 + .byte PHONEME_S ; S + .byte PHONEME_O ; O +; .byte PHONEME_O ; O + .byte PHONEME_R ; R + + .byte PHONEME_PAUSE ; PA + .byte PHONEME_PAUSE ; PA + + .byte PHONEME_F ; F ; Falken + .byte PHONEME_AW ; AW + .byte PHONEME_L ; L + .byte PHONEME_K ; K + .byte PHONEME_UH1 ; UH1 + .byte PHONEME_N ; N + + .byte PHONEME_PAUSE ; PA + .byte PHONEME_PAUSE ; PA + .byte PHONEME_PAUSE ; PA + .byte PHONEME_PAUSE ; PA + .byte PHONEME_PAUSE ; PA + .byte PHONEME_PAUSE ; PA + .byte PHONEME_PAUSE ; PA + .byte PHONEME_PAUSE ; PA + + ; A strange game. + +; .byte PHONEME_A1 ; A1 ; A + .byte PHONEME_AY ; AY + .byte PHONEME_Y ; Y + .byte PHONEME_PAUSE ; PA + .byte PHONEME_PAUSE ; PA + + .byte PHONEME_S ; S ; strange + .byte PHONEME_T ; T + .byte PHONEME_R ; R +; .byte PHONEME_A1 ; A1 + .byte PHONEME_AY ; AY + .byte PHONEME_Y ; Y + .byte PHONEME_N ; N + .byte PHONEME_D ; D + .byte PHONEME_J ; J + .byte PHONEME_PAUSE ; PA + .byte PHONEME_PAUSE ; PA + + .byte PHONEME_KV ; G ; game +; .byte PHONEME_A1 ; A1 + .byte PHONEME_AY ; AY + .byte PHONEME_Y ; Y + .byte PHONEME_M ; M + .byte PHONEME_PAUSE ; PA + .byte PHONEME_PAUSE ; PA + + .byte PHONEME_PAUSE ; PA + .byte PHONEME_PAUSE ; PA + + ; The only winning move is not to play. + + .byte PHONEME_THV ; THV ; The + .byte PHONEME_UH1 ; UH1 + .byte PHONEME_UH3 ; UH3 + .byte PHONEME_PAUSE ; PA + .byte PHONEME_PAUSE ; PA + + .byte PHONEME_OU ; O1 ; Only +; .byte PHONEME_O2 ; O2 + .byte PHONEME_N ; N + .byte PHONEME_L ; L + .byte PHONEME_Y ; Y + .byte PHONEME_PAUSE ; PA + .byte PHONEME_PAUSE ; PA + + .byte PHONEME_W ; W ; Winning + .byte PHONEME_I ; I1 +; .byte PHONEME_I3 ; I3 + .byte PHONEME_N ; N + .byte PHONEME_N ; N + .byte PHONEME_I ; I + .byte PHONEME_NG ; NG + .byte PHONEME_PAUSE ; PA + .byte PHONEME_PAUSE ; PA + + .byte PHONEME_W ; M ; Move + .byte PHONEME_U1 ; U1 + .byte PHONEME_U1 ; U1 + .byte PHONEME_V ; V + .byte PHONEME_PAUSE ; PA + .byte PHONEME_PAUSE ; PA + + .byte PHONEME_I ; I1 ; Is +; .byte PHONEME_I3 ; I3 + .byte PHONEME_Z ; Z + .byte PHONEME_PAUSE ; PA + .byte PHONEME_PAUSE ; PA + + .byte PHONEME_N ; N ; Not + .byte PHONEME_AH1 ; AH1 + .byte PHONEME_UH3 ; UH3 + .byte PHONEME_T ; T + .byte PHONEME_PAUSE ; PA + .byte PHONEME_PAUSE ; PA + + .byte PHONEME_T ; T ; To + .byte PHONEME_IU ; IU + .byte PHONEME_U1 ; U1 + .byte PHONEME_U1 ; U1 + .byte PHONEME_PAUSE ; PA + .byte PHONEME_PAUSE ; PA + + .byte PHONEME_P ; P ; Play + .byte PHONEME_L ; L + .byte PHONEME_A ; A1 + .byte PHONEME_I ; I3 + .byte PHONEME_Y ; Y + + .byte PHONEME_PAUSE ; PA + .byte PHONEME_PAUSE ; PA + + .byte $FF + +