Prev: 0000 Up: Map Next: 01AB
0038: Handle Interrupt
Any access to HandleInterrupt (including this opcode fetch) pages the μSpeech ROM in or out. The Spectrum IM1 handler lands here, so this ROM runs first. Every exit jumps back to HandleInterrupt, which pages the Spectrum ROM in and lets IM1 finish.
HandleInterrupt 0038 PUSH AF Keep AF unchanged.
0039 POP AF
003A DI Disable interrupts.
003B PUSH HL Stash HL, AF, BC and DE on the stack.
003C PUSH AF
003D PUSH BC
003E PUSH DE
The speech workspace is a short block just below *RAMTOP (low byte 57). A 48K machine uses FF57; a 16K machine uses 7F57.
003F LD HL,($5CB2) Fetch *RAMTOP.
0042 LD A,L Jump to ProbeWorkspace if the low byte is not 57.
0043 CP $57
0045 JR NZ,ProbeWorkspace
0047 LD A,H Jump to InstallWorkspace if this is a 48K machine.
0048 CP $FF
004A JR Z,InstallWorkspace
004C CP $7F Jump to InstallWorkspace if this is a 16K machine.
004E JR Z,InstallWorkspace
*RAMTOP is not the installed workspace yet.
ProbeWorkspace 0050 LD A,$06 Call ReadWorkspace for the saved buffer pointer.
0052 CALL ReadWorkspace
0055 LD B,H Copy the workspace address to BC.
0056 LD C,L
0057 CALL CheckMemory Call CheckMemory and jump to InstallWorkspace if the reserved block is already below *RAMTOP.
005A JR C,InstallWorkspace
005C CALL ReadBufferPointer Call ReadBufferPointer.
005F CALL CheckMemory Call CheckMemory.
0062 CALL C,ResetBufferPointer Call ResetBufferPointer if the pointer is out of range.
0065 XOR A Call ReadWorkspace for the flags byte.
0066 CALL ReadWorkspace
0069 BIT 2,A Jump to ServiceSpeech if the workspace is already live.
006B JR NZ,ServiceSpeech
006D SET 2,(HL) Mark the workspace as being installed.
006F POP DE Restore DE, BC, AF and HL from the stack.
0070 POP BC
0071 POP AF
0072 POP HL
Page the Spectrum ROM back in so IM1 can run.
ReturnToSpectrum 0073 PUSH HL No operation.
0074 PUSH HL
0075 POP HL
0076 POP HL
0077 LD HL,$0038 Set the return address to HandleInterrupt.
007A PUSH HL Stash the return address on the stack.
007B DEC SP Move SP down two bytes.
007C DEC SP
007D POP HL Restore HL from the stack.
007E JP HandleInterrupt Jump to HandleInterrupt.
Wait a few frames, then reserve a page below *RAMTOP for the speech workspace.
InstallWorkspace 0081 LD A,($5C78) Jump to ExitInterrupt if *FRAMES is still less than 05.
0084 CP $05
0086 JP C,ExitInterrupt
0089 XOR A Call ReadWorkspace for the flags byte.
008A CALL ReadWorkspace
008D DEC H Lower *RAMTOP by one page.
008E LD ($5CB2),HL
0091 INC H Write 82 to the flags byte.
0092 LD (HL),$82
0094 DEC HL Clear workspace index 01.
0095 XOR A
0096 LD (HL),A
0097 DEC HL Store the workspace page in index 02.
0098 LD (HL),H
0099 DEC HL Write 51 to the buffer pointer (index 03).
009A LD (HL),$51
009C DEC HL Clear workspace indexes 04 and 05.
009D LD (HL),A
009E DEC HL
009F LD (HL),A
00A0 LD HL,($5CB2) Fetch the new *RAMTOP.
Plant a sentinel and move the machine stack below the new *RAMTOP.
InstallWorkspace_Stack 00A3 LD (HL),$3E Write a 3E sentinel at the new *RAMTOP.
00A5 DEC HL
00A6 LD (HL),A Write 00 beneath it.
00A7 LD SP,HL Point SP at the new *RAMTOP.
00A8 DEC HL Clear the two bytes below the new stack.
00A9 LD (HL),A
00AA DEC HL
00AB LD (HL),A
00AC LD ($5C3D),HL Write the error stack to *ERR_SP.
00AF LD DE,$12A9 Set the return address to MAIN-5.
00B2 PUSH DE Stash the return address on the stack.
00B3 EI Enable interrupts.
00B4 JP HandleInterrupt Jump to HandleInterrupt.
The workspace is live. Draw the banner once, then speak.
ServiceSpeech 00B7 RES 2,(HL) Clear the "installing" flag.
00B9 BIT 7,(HL) Call PrintBanner if the banner has not been drawn yet.
00BB CALL NZ,PrintBanner
Keep *FRAMES moving while this ROM owns the interrupt.
00BE LD HL,($5C78) Fetch the *FRAMES word.
00C1 LD A,H Jump to ServiceSpeech_Tick if *FRAMES is non-zero.
00C2 OR L
00C3 JR NZ,ServiceSpeech_Tick
00C5 LD HL,$5C7A Decrease the third *FRAMES byte.
00C8 DEC (HL)
ServiceSpeech_Tick 00C9 LD HL,($5C78) Decrease the *FRAMES word.
00CC DEC HL
00CD LD ($5C78),HL
Tick the two keyboard-state timer pairs.
00D0 LD HL,$5C02 Point at the keyboard-state timers (04 bytes apart).
00D3 LD DE,$0004
00D6 CALL IncrementPair Call IncrementPair.
00D9 DEC HL Move back one byte.
00DA CALL IncrementPair Call IncrementPair.
Programs speak by assigning the BASIC string s$. Look it up and expand it into allophones if it exists.
00DD LD A,$53 Call FindVariable for "s$".
00DF CALL FindVariable
00E2 CALL Z,ParseSpeechString Call ParseSpeechString if s$ exists.
00E5 CALL TestKeysVariable Call TestKeysVariable.
00E8 JP Z,FeedAllophone Jump to FeedAllophone if key speech is enabled.
00EB XOR A Call ReadWorkspace for the flags byte.
00EC CALL ReadWorkspace
00EF LD A,($5C3B) Fetch *FLAGS.
00F2 BIT 5,A Jump to ServiceSpeech_NoKey if no new key was pressed.
00F4 JR Z,ServiceSpeech_NoKey
00F6 BIT 4,(HL) Jump to FeedAllophone if this key is already being spoken.
00F8 JR NZ,FeedAllophone
00FA JR ServiceSpeech_Key Jump to ServiceSpeech_Key.
ServiceSpeech_NoKey 00FC RES 4,(HL) Clear the "key held" flag and jump to FeedAllophone.
00FE JR FeedAllophone
A new key is in *LAST_K; turn it into allophones.
ServiceSpeech_Key 0100 SET 4,(HL) Set the "key held" flag.
0102 LD A,($5C08) Fetch *LAST_K.
0105 CP $7B Jump to ServiceSpeech_NotLetter if the code is 7B or higher.
0107 JR NC,ServiceSpeech_NotLetter
0109 CP $61 Jump to ServiceSpeech_NotLetter if the code is below "a".
010B JR C,ServiceSpeech_NotLetter
010D SUB $20 Convert a lowercase letter to uppercase and jump to ServiceSpeech_Lookup.
010F JR ServiceSpeech_Lookup
Not a letter. Block graphics share key 80; other symbols go through PunctuationKeys.
ServiceSpeech_NotLetter 0111 CP $A5 Jump to ServiceSpeech_Punctuation if the code is A5 or higher.
0113 JR NC,ServiceSpeech_Punctuation
0115 CP $80 Jump to ServiceSpeech_Punctuation if the code is below 80.
0117 JR C,ServiceSpeech_Punctuation
0119 LD A,$80 Use dictionary key 80 and jump to ServiceSpeech_Lookup.
011B JR ServiceSpeech_Lookup
ServiceSpeech_Punctuation 011D LD HL,$042D Search PunctuationKeys for this character.
0120 LD BC,$000D
0123 CPIR Jump to ServiceSpeech_Lookup if there is no mapping.
0125 JR NZ,ServiceSpeech_Lookup
0127 LD BC,$000C Fetch the replacement from PunctuationValues.
012A ADD HL,BC
012B LD A,(HL)
Look the key up in AllophoneDictionary.
ServiceSpeech_Lookup 012C LD HL,$0447 Point at AllophoneDictionary.
012F LD B,A Keep the key in B.
ServiceSpeech_FindKey 0130 BIT 7,(HL) Jump to ServiceSpeech_NextKey if this byte ends an allophone list.
0132 JR NZ,ServiceSpeech_NextKey
0134 INC HL Move to the next dictionary byte.
0135 JR ServiceSpeech_FindKey Jump to ServiceSpeech_FindKey.
ServiceSpeech_NextKey 0137 INC HL Move to the next dictionary key.
0138 XOR A Jump to FeedAllophone if the table has ended.
0139 CP (HL)
013A JR Z,FeedAllophone
013C LD A,B Jump to ServiceSpeech_Copy if this key matches.
013D CP (HL)
013E JR Z,ServiceSpeech_Copy
0140 INC HL Move to the next dictionary byte.
0141 JR ServiceSpeech_FindKey Jump to ServiceSpeech_FindKey.
Copy the matching allophones into the speech buffer.
ServiceSpeech_Copy 0143 INC HL Move to the first allophone of this entry.
0144 CALL CompareBuffer Call CompareBuffer and jump to ServiceSpeech_Store if the buffer pointers already match.
0147 JR Z,ServiceSpeech_Store
0149 INC BC Step the buffer pointer on one byte.
014A LD A,(BC) Jump to FeedAllophone if the previous allophone is not a terminator.
014B RLA
014C JR NC,FeedAllophone
014E CALL ResetBufferPointer Call ResetBufferPointer.
ServiceSpeech_Store 0151 LD A,(HL) Queue this allophone in the speech buffer.
0152 LD (BC),A
0153 DEC BC
0154 CALL CheckMemory Call CheckMemory and jump to ServiceSpeech_Flush if the buffer has hit *RAMTOP.
0157 JR C,ServiceSpeech_Flush
0159 BIT 7,(HL) Jump to ServiceSpeech_Commit if this was the last allophone of the word.
015B JR NZ,ServiceSpeech_Commit
015D INC HL Move to the next allophone.
015E JR ServiceSpeech_Store Jump to ServiceSpeech_Store.
ServiceSpeech_Flush 0160 CALL ReadBufferPointer Call ReadBufferPointer.
ServiceSpeech_Commit 0163 CALL WriteBufferPointer Call WriteBufferPointer.
The SP0256 is the speech-synthesiser chip. Read its busy flag at 1000 and send the next queued allophone if it is idle.
FeedAllophone 0166 LD A,($1000) Read the SP0256 status from 1000.
0169 BIT 0,A Jump to ExitInterrupt if the chip is still busy.
016B JR NZ,ExitInterrupt
016D LD A,($5C3A) Fetch *ERR_NR.
0170 RLA Call ResetBufferPointer if BASIC is not reporting an error.
0171 CALL NC,ResetBufferPointer
0174 CALL CompareBuffer Call CompareBuffer and jump to FeedAllophone_Write if there is something left to say.
0177 JR NZ,FeedAllophone_Write
0179 XOR A Silence the SP0256 and jump to ExitInterrupt.
017A LD ($1000),A
017D JR ExitInterrupt
The SP0256 is idle; write the next queued allophone.
FeedAllophone_Write 017F LD A,$06 Call ReadWorkspace for the next allophone.
0181 CALL ReadWorkspace
0184 LD DE,$3000 Use the low-intonation port (3000).
0187 BIT 6,A Jump to FeedAllophone_Port if bit 6 is reset.
0189 JR Z,FeedAllophone_Port
018B INC DE Use the high-intonation port instead (3001).
FeedAllophone_Port 018C LD (DE),A Select the intonation.
018D LD ($1000),A Write the allophone to the SP0256.
0190 OR A Work out how many bytes remain in the queue.
0191 SBC HL,BC
0193 INC BC Step the queue pointer on one byte.
0194 PUSH HL Stash the remaining length on the stack.
0195 CALL WriteBufferPointer Call WriteBufferPointer.
0198 LD A,$06 Call ReadWorkspace for the queue start.
019A CALL ReadWorkspace
019D LD D,H Point the copy at the previous queue byte.
019E LD E,L
019F DEC HL
01A0 POP BC Restore the remaining length from the stack.
01A1 LDDR Shuffle the queued allophones down.
Restore the Spectrum registers and page its ROM back in.
ExitInterrupt 01A3 POP DE Restore DE, BC, AF and HL from the stack.
01A4 POP BC
01A5 POP AF
01A6 POP HL
01A7 EI Enable interrupts.
01A8 JP HandleInterrupt Jump to HandleInterrupt.
Prev: 0000 Up: Map Next: 01AB