1;* ======================================================================== *; 2;* The routines and data in this file (ivoice.asm) are dedicated to the *; 3;* public domain via the Creative Commons CC0 v1.0 license by its author, *; 4;* Joseph Zbiciak. *; 5;* *; 6;* https://creativecommons.org/publicdomain/zero/1.0/ *; 7;* ======================================================================== *; 8 9;; ======================================================================== ;; 10;; INTELLIVOICE DRIVER ROUTINES ;; 11;; Written in 2002 by Joe Zbiciak <intvnut AT gmail.com> ;; 12;; http://spatula-city.org/~im14u2c/intv/ ;; 13;; ======================================================================== ;; 14 15;; ======================================================================== ;; 16;; GLOBAL VARIABLES USED BY THESE ROUTINES ;; 17;; ;; 18;; Note that some of these routines may use one or more global variables. ;; 19;; If you use these routines, you will need to allocate the appropriate ;; 20;; space in either 16-bit or 8-bit memory as appropriate. Each global ;; 21;; variable is listed with the routines which use it and the required ;; 22;; memory width. ;; 23;; ;; 24;; Example declarations for these routines are shown below, commented out. ;; 25;; You should uncomment these and add them to your program to make use of ;; 26;; the routine that needs them. Make sure to assign these variables to ;; 27;; locations that aren't used for anything else. ;; 28;; ======================================================================== ;; 29 30 ; Used by Req'd Width Description 31 ;----------------------------------------------------- 32;IV.QH EQU $110 ; IV_xxx 8-bit Voice queue head 33;IV.QT EQU $111 ; IV_xxx 8-bit Voice queue tail 34;IV.Q EQU $112 ; IV_xxx 8-bit Voice queue (8 bytes) 35;IV.FLEN EQU $11A ; IV_xxx 8-bit Length of FIFO data 36;IV.FPTR EQU $320 ; IV_xxx 16-bit Current FIFO ptr. 37;IV.PPTR EQU $321 ; IV_xxx 16-bit Current Phrase ptr. 38 39;; ======================================================================== ;; 40;; MEMORY USAGE ;; 41;; ;; 42;; These routines implement a queue of "pending phrases" that will be ;; 43;; played by the Intellivoice. The user calls IV_PLAY to enqueue a ;; 44;; phrase number. Phrase numbers indicate either a RESROM sample or ;; 45;; a compiled in phrase to be spoken. ;; 46;; ;; 47;; The user must compose an "IV_PHRASE_TBL", which is composed of ;; 48;; pointers to phrases to be spoken. Phrases are strings of pointers ;; 49;; and RESROM triggers, terminated by a NUL. ;; 50;; ;; 51;; Phrase numbers 1 through 42 are RESROM samples. Phrase numbers ;; 52;; 43 through 255 index into the IV_PHRASE_TBL. ;; 53;; ;; 54;; SPECIAL NOTES ;; 55;; ;; 56;; Bit 7 of IV.QH and IV.QT is used to denote whether the Intellivoice ;; 57;; is present. If Intellivoice is present, this bit is clear. ;; 58;; ;; 59;; Bit 6 of IV.QT is used to denote that we still need to do an ALD $00 ;; 60;; for FIFO'd voice data. ;; 61;; ======================================================================== ;; 62 63 64;; ======================================================================== ;; 65;; NAME ;; 66;; IV_INIT Initialize the Intellivoice ;; 67;; ;; 68;; AUTHOR ;; 69;; Joseph Zbiciak <intvnut AT gmail.com> ;; 70;; ;; 71;; REVISION HISTORY ;; 72;; 15-Sep-2002 Initial revision . . . . . . . . . . . J. Zbiciak ;; 73;; ;; 74;; INPUTS for IV_INIT ;; 75;; R5 Return address ;; 76;; ;; 77;; OUTPUTS ;; 78;; R0 0 if Intellivoice found, -1 if not. ;; 79;; ;; 80;; DESCRIPTION ;; 81;; Resets Intellivoice, determines if it is actually there, and ;; 82;; then initializes the IV structure. ;; 83;; ------------------------------------------------------------------------ ;; 84;; Copyright (c) 2002, Joseph Zbiciak ;; 85;; ======================================================================== ;; 86 87IV_INIT PROC 88 MVII #$0400, R0 ; 89 MVO R0, $0081 ; Reset the Intellivoice 90 91 MVI $0081, R0 ; \ 92 RLC R0, 2 ; |-- See if we detect Intellivoice 93 BOV @@no_ivoice ; / once we've reset it. 94 95 CLRR R0 ; 96 MVO R0, IV.FPTR ; No data for FIFO 97 MVO R0, IV.PPTR ; No phrase being spoken 98 MVO R0, IV.QH ; Clear our queue 99 MVO R0, IV.QT ; Clear our queue 100 JR R5 ; Done! 101 102@@no_ivoice: 103 CLRR R0 104 MVO R0, IV.FPTR ; No data for FIFO 105 MVO R0, IV.PPTR ; No phrase being spoken 106 DECR R0 107 MVO R0, IV.QH ; Set queue to -1 ("No Intellivoice") 108 MVO R0, IV.QT ; Set queue to -1 ("No Intellivoice") 109 JR R5 ; Done! 110 ENDP 111 112;; ======================================================================== ;; 113;; NAME ;; 114;; IV_ISR Interrupt service routine to feed Intellivoice ;; 115;; ;; 116;; AUTHOR ;; 117;; Joseph Zbiciak <intvnut AT gmail.com> ;; 118;; ;; 119;; REVISION HISTORY ;; 120;; 15-Sep-2002 Initial revision . . . . . . . . . . . J. Zbiciak ;; 121;; ;; 122;; INPUTS for IV_ISR ;; 123;; R5 Return address ;; 124;; ;; 125;; OUTPUTS ;; 126;; R0, R1, R4 trashed. ;; 127;; ;; 128;; NOTES ;; 129;; Call this from your main interrupt service routine. ;; 130;; ------------------------------------------------------------------------ ;; 131;; Copyright (c) 2002, Joseph Zbiciak ;; 132;; ======================================================================== ;; 133IV_ISR PROC 134 ;; ------------------------------------------------------------ ;; 135 ;; Check for Intellivoice. Leave if none present. ;; 136 ;; ------------------------------------------------------------ ;; 137 MVI IV.QT, R1 ; Get queue tail 138 SWAP R1, 2 139 BPL @@ok ; Bit 7 set? If yes: No Intellivoice 140@@ald_busy: 141@@leave JR R5 ; Exit if no Intellivoice. 142 143 144 ;; ------------------------------------------------------------ ;; 145 ;; Check to see if we pump samples into the FIFO. 146 ;; ------------------------------------------------------------ ;; 147@@ok: MVI IV.FPTR, R4 ; Get FIFO data pointer 148 TSTR R4 ; is it zero? 149 BEQ @@no_fifodata ; Yes: No data for FIFO. 150@@fifo_fill: 151 MVI $0081, R0 ; Read speech FIFO ready bit 152 SLLC R0, 1 ; 153 BC @@fifo_busy 154 155 MVI@ R4, R0 ; Get next word 156 MVO R0, $0081 ; write it to the FIFO 157 158 MVI IV.FLEN, R0 ;\ 159 DECR R0 ; |-- Decrement our FIFO'd data length 160 MVO R0, IV.FLEN ;/ 161 BEQ @@last_fifo ; If zero, we're done w/ FIFO 162 MVO R4, IV.FPTR ; Otherwise, save new pointer 163 B @@fifo_fill ; ...and keep trying to load FIFO 164 165@@last_fifo MVO R0, IV.FPTR ; done with FIFO loading. 166 ; fall into ALD processing. 167 168 169 ;; ------------------------------------------------------------ ;; 170 ;; Try to do an Address Load. We do this in two settings: ;; 171 ;; -- We have no FIFO data to load. ;; 172 ;; -- We've loaded as much FIFO data as we can, but we ;; 173 ;; might have an address load command to send for it. ;; 174 ;; ------------------------------------------------------------ ;; 175@@fifo_busy: 176@@no_fifodata: 177 MVI $0080, R0 ; Read LRQ bit from ALD register 178 SLLC R0, 1 179 BNC @@ald_busy ; LRQ is low, meaning we can't ALD. 180 ; So, leave. 181 182 ;; ------------------------------------------------------------ ;; 183 ;; We can do an address load (ALD) on the SP0256. Give FIFO ;; 184 ;; driven ALDs priority, since we already started the FIFO ;; 185 ;; load. The "need ALD" bit is stored in bit 6 of IV.QT. ;; 186 ;; ------------------------------------------------------------ ;; 187 ANDI #$40, R1 ; Is "Need FIFO ALD" bit set? 188 BEQ @@no_fifo_ald 189 XOR IV.QT, R1 ;\__ Clear the "Need FIFO ALD" bit. 190 MVO R1, IV.QT ;/ 191 CLRR R1 192 MVO R1, $80 ; Load a 0 into ALD (trigger FIFO rd.) 193 JR R5 ; done! 194 195 ;; ------------------------------------------------------------ ;; 196 ;; We don't need to ALD on behalf of the FIFO. So, we grab ;; 197 ;; the next thing off our phrase list. ;; 198 ;; ------------------------------------------------------------ ;; 199@@no_fifo_ald: 200 MVI IV.PPTR, R4 ; Get phrase pointer. 201 TSTR R4 ; Is it zero? 202 BEQ @@next_phrase ; Yes: Get next phrase from queue. 203 204 MVI@ R4, R0 205 TSTR R0 ; Is it end of phrase? 206 BNEQ @@process_phrase ; !=0: Go do it. 207 208 MVO R0, IV.PPTR ; 209@@next_phrase: 210 MVI IV.QT, R1 ; reload queue tail (was trashed above) 211 MOVR R1, R0 ; copy QT to R0 so we can increment it 212 ANDI #$7, R1 ; Mask away flags in queue head 213 CMP IV.QH, R1 ; Is it same as queue tail? 214 BEQ @@leave ; Yes: No more speech for now. 215 216 INCR R0 217 ANDI #$F7, R0 ; mask away the possible 'carry' 218 MVO R0, IV.QT ; save updated queue tail 219 220 ADDI #IV.Q, R1 ; Index into queue 221 MVI@ R1, R4 ; get next value from queue 222 CMPI #43, R4 ; Is it a RESROM or Phrase? 223 BNC @@play_resrom_r4 224@@new_phrase: 225 ADDI #IV_PHRASE_TBL - 43, R4 ; Index into phrase table 226 MVI@ R4, R4 ; Read from phrase table 227 MVO R4, IV.PPTR 228 JR R5 ; we'll get to this phrase next time. 229 230@@play_resrom_r4: 231 MVO R4, $0080 ; Just ALD it 232 JR R5 ; and leave. 233 234 ;; ------------------------------------------------------------ ;; 235 ;; We're in the middle of a phrase, so continue interpreting. ;; 236 ;; ------------------------------------------------------------ ;; 237@@process_phrase: 238 239 MVO R4, IV.PPTR ; save new phrase pointer 240 CMPI #43, R0 ; Is it a RESROM cue? 241 BC @@play_fifo ; Just ALD it and leave. 242@@play_resrom_r0: 243 MVO R0, $0080 ; Just ALD it 244 JR R5 ; and leave. 245@@play_fifo: 246 MVI IV.FPTR,R1 ; Make sure not to stomp existing FIFO 247 TSTR R1 ; data. 248 BEQ @@new_fifo_ok 249 DECR R4 ; Oops, FIFO data still playing, 250 MVO R4, IV.PPTR ; so rewind. 251 JR R5 ; and leave. 252 253@@new_fifo_ok: 254 MOVR R0, R4 ; 255 MVI@ R4, R0 ; Get chunk length 256 MVO R0, IV.FLEN ; Init FIFO chunk length 257 MVO R4, IV.FPTR ; Init FIFO pointer 258 MVI IV.QT, R0 ;\ 259 XORI #$40, R0 ; |- Set "Need ALD" bit in QT 260 MVO R0, IV.QT ;/ 261 262 IF 1 ; debug code ;\ 263 ANDI #$40, R0 ; | Debug code: We should only 264 BNEQ @@qtok ; |-- be here if "Need FIFO ALD" 265 HLT ;BUG!! ; | was already clear. 266@@qtok ;/ 267 ENDI 268 JR R5 ; leave. 269 270 ENDP 271 272 273;; ======================================================================== ;; 274;; NAME ;; 275;; IV_PLAY Play a voice sample sequence. ;; 276;; ;; 277;; AUTHOR ;; 278;; Joseph Zbiciak <intvnut AT gmail.com> ;; 279;; ;; 280;; REVISION HISTORY ;; 281;; 15-Sep-2002 Initial revision . . . . . . . . . . . J. Zbiciak ;; 282;; ;; 283;; INPUTS for IV_PLAY ;; 284;; R5 Invocation record, followed by return address. ;; 285;; 1 DECLE Phrase number to play. ;; 286;; ;; 287;; INPUTS for IV_PLAY.1 ;; 288;; R0 Address of phrase to play. ;; 289;; R5 Return address ;; 290;; ;; 291;; OUTPUTS ;; 292;; R0, R1 trashed ;; 293;; Z==0 if item not successfully queued. ;; 294;; Z==1 if successfully queued. ;; 295;; ;; 296;; NOTES ;; 297;; This code will drop phrases if the queue is full. ;; 298;; Phrase numbers 1..42 are RESROM samples. 43..255 will index ;; 299;; into the user-supplied IV_PHRASE_TBL. 43 will refer to the ;; 300;; first entry, 44 to the second, and so on. Phrase 0 is undefined. ;; 301;; ;; 302;; ------------------------------------------------------------------------ ;; 303;; Copyright (c) 2002, Joseph Zbiciak ;; 304;; ======================================================================== ;; 305IV_PLAY PROC 306 MVI@ R5, R0 307 308@@1: ; alternate entry point 309 MVI IV.QT, R1 ; Get queue tail 310 SWAP R1, 2 ;\___ Leave if "no Intellivoice" 311 BMI @@leave ;/ bit it set. 312@@ok: 313 DECR R1 ;\ 314 ANDI #$7, R1 ; |-- See if we still have room 315 CMP IV.QH, R1 ;/ 316 BEQ @@leave ; Leave if we're full 317 318@@2: MVI IV.QH, R1 ; Get our queue head pointer 319 PSHR R1 ;\ 320 INCR R1 ; | 321 ANDI #$F7, R1 ; |-- Increment it, removing 322 MVO R1, IV.QH ; | carry but preserving flags. 323 PULR R1 ;/ 324 325 ADDI #IV.Q, R1 ;\__ Store phrase to queue 326 MVO@ R0, R1 ;/ 327 328@@leave: JR R5 ; Leave. 329 ENDP 330 331;; ======================================================================== ;; 332;; NAME ;; 333;; IV_PLAYW Play a voice sample sequence. Wait for queue room. ;; 334;; ;; 335;; AUTHOR ;; 336;; Joseph Zbiciak <intvnut AT gmail.com> ;; 337;; ;; 338;; REVISION HISTORY ;; 339;; 15-Sep-2002 Initial revision . . . . . . . . . . . J. Zbiciak ;; 340;; ;; 341;; INPUTS for IV_PLAY ;; 342;; R5 Invocation record, followed by return address. ;; 343;; 1 DECLE Phrase number to play. ;; 344;; ;; 345;; INPUTS for IV_PLAY.1 ;; 346;; R0 Address of phrase to play. ;; 347;; R5 Return address ;; 348;; ;; 349;; OUTPUTS ;; 350;; R0, R1 trashed ;; 351;; ;; 352;; NOTES ;; 353;; This code will wait for a queue slot to open if queue is full. ;; 354;; Phrase numbers 1..42 are RESROM samples. 43..255 will index ;; 355;; into the user-supplied IV_PHRASE_TBL. 43 will refer to the ;; 356;; first entry, 44 to the second, and so on. Phrase 0 is undefined. ;; 357;; ;; 358;; ------------------------------------------------------------------------ ;; 359;; Copyright (c) 2002, Joseph Zbiciak ;; 360;; ======================================================================== ;; 361IV_PLAYW PROC 362 MVI@ R5, R0 363 364@@1: ; alternate entry point 365 MVI IV.QT, R1 ; Get queue tail 366 SWAP R1, 2 ;\___ Leave if "no Intellivoice" 367 BMI IV_PLAY.leave ;/ bit it set. 368@@ok: 369 DECR R1 ;\ 370 ANDI #$7, R1 ; |-- See if we still have room 371 CMP IV.QH, R1 ;/ 372 BEQ @@1 ; wait for room 373 B IV_PLAY.2 374 375 ENDP 376 377;; ======================================================================== ;; 378;; NAME ;; 379;; IV_HUSH Flush the speech queue, and hush the Intellivoice. ;; 380;; ;; 381;; AUTHOR ;; 382;; Joseph Zbiciak <intvnut AT gmail.com> ;; 383;; ;; 384;; REVISION HISTORY ;; 385;; 02-Feb-2018 Initial revision . . . . . . . . . . . J. Zbiciak ;; 386;; ;; 387;; INPUTS for IV_HUSH ;; 388;; None. ;; 389;; ;; 390;; OUTPUTS ;; 391;; R0 trashed. ;; 392;; ;; 393;; NOTES ;; 394;; Returns via IV_WAIT. ;; 395;; ;; 396;; ======================================================================== ;; 397IV_HUSH PROC 398 MVI IV.QH, R0 399 SWAP R0, 2 400 BMI IV_WAIT.leave 401 402 DIS 403 ;; We can't stop a phrase segment that's being FIFOed down. 404 ;; We need to remember if we've committed to pushing ALD. 405 ;; We _can_ stop new phrase segments from going down, and _can_ 406 ;; stop new phrases from being started. 407 408 ;; Set head pointer to indicate we've inserted one item. 409 MVI IV.QH, R0 ; Re-read, as an interrupt may have occurred 410 ANDI #$F0, R0 411 INCR R0 412 MVO R0, IV.QH 413 414 ;; Reset tail pointer, keeping "need ALD" bit and other flags. 415 MVI IV.QT, R0 416 ANDI #$F0, R0 417 MVO R0, IV.QT 418 419 ;; Reset the phrase pointer, to stop a long phrase. 420 CLRR R0 421 MVO R0, IV.PPTR 422 423 ;; Queue a PA1 in the queue. Since we're can't guarantee the user 424 ;; has included resrom.asm, let's just use the raw number (5). 425 MVII #5, R0 426 MVO R0, IV.Q 427 428 ;; Re-enable interrupts and wait for Intellivoice to shut up. 429 ;; 430 ;; We can't just jump to IV_WAIT.q_loop, as we need to reload 431 ;; IV.QH into R0, and I'm really committed to only using R0. 432; JE IV_WAIT 433 EIS 434 ; fallthrough into IV_WAIT 435 ENDP 436 437;; ======================================================================== ;; 438;; NAME ;; 439;; IV_WAIT Wait for voice queue to empty. ;; 440;; ;; 441;; AUTHOR ;; 442;; Joseph Zbiciak <intvnut AT gmail.com> ;; 443;; ;; 444;; REVISION HISTORY ;; 445;; 15-Sep-2002 Initial revision . . . . . . . . . . . J. Zbiciak ;; 446;; 02-Feb-2018 Shave cycles on presence detect . . . J. Zbiciak ;; 447;; 02-Aug-2018 Wait for last phrase to complete . . . J. Zbiciak ;; 448;; ;; 449;; INPUTS for IV_WAIT ;; 450;; R5 Return address ;; 451;; ;; 452;; OUTPUTS ;; 453;; R0 trashed. ;; 454;; ;; 455;; NOTES ;; 456;; This waits until the Intellivoice is nearly completely quiescent. ;; 457;; Some voice data may still be spoken from the last triggered ;; 458;; phrase. To truly wait for *that* to be spoken, speak a 'pause' ;; 459;; (eg. RESROM.pa1) and then call IV_WAIT. ;; 460;; ------------------------------------------------------------------------ ;; 461;; Copyright (c) 2002, Joseph Zbiciak ;; 462;; ======================================================================== ;; 463IV_WAIT PROC 464 MVI IV.QH, R0 465 CMPI #$80, R0 466 BC @@leave 467 468 ; Wait for queue to drain. 469@@q_loop: CMP IV.QT, R0 470 BNEQ @@q_loop 471 472 ; Wait for last phrase to complete. 473 CLRR R0 474@@p_loop: CMP IV.PPTR,R0 475 BNEQ @@p_loop 476 477 ; Wait for FIFO and LRQ to say ready. 478@@s_loop: MVI $81, R0 ; Read FIFO status. 0 == ready. 479 COMR R0 480 AND $80, R0 ; Merge w/ LRQ status. 1 == ready 481 TSTR R0 482 BPL @@s_loop ; if bit 15 == 0, not ready. 483 484@@leave: JR R5 485 ENDP 486 487;; ======================================================================== ;; 488;; End of File: ivoice.asm ;; 489;; ======================================================================== ;; 490