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