Jump to content
IGNORED

Forth Source of Speech Education Module


Recommended Posts

Posted (edited)

Forth source from the Speech Education Module User's Guide 

 

The SEM was a single-board kit produced in 1982 to support experiments with the TMS5220 speech chip.  It had the VM60002 "Industrial Vocabulary" PHROM.

(phrase ROM or TMS6100), two serial ports, and audio out jack.  User software was a speech editor, written in Forth.  The serial ports were 6850s.  There is an 8255 PIA.  COLDIO was the Forth word that initializes them. (no source code.)


The Forth source of the speech editor will be of interest to 4A users.  So I'm posting in TI-99/4A Development.   Most of the Forth should be compatible with the Speech Synthesizer. 

The 2532 EPROM in the SEM is the Forth interpreter, written in TMS7000 assembly or Forth,  plus the compiled  source listed here.
This source was Appendix L of the manual.


I don't have the complete manual.  Sadly, I don't see any source code for the Forth interpreter or kernel.  It would be really sweet to have a Forth cartridge for the CC-40 or ExelVision. 

 

If I find that source, I'll post in the CC-40 forum. 
 

 

 

About 7 more pages of code are in TMS7000 assembly.  SPK is an entry point from Forth.   SPK pops its parameters from the stack.    It sends SPEAK or SPEAK EXTERNAL commands to the TMS5200.  It processes speech bytes on frame boundaries.  The rest of  the assembly code is subroutines  of SPK.  SPK ends with BR *NEXT.

 

 

EDIT: here are cleaner files. Syntax checked in ANS Forth, any dependencies (FIG) defined empty at the top.  Probably still some typos.  My comments are in lower case (except at the top)

 

LOADMEM.fs

SPEECH_EDU.fs

SPEECH_EDU.asm SEM_DOCS.txt

Edited by FarmerPotato
Rewrote after finished the assembly code
  • Like 4
  • Thanks 2
Link to comment
Share on other sites

This is neat to see Erik. Thanks.

There must be an underlying cross-compiler environment for this code.

There are few words that have no definition. (vsp!  getbits) 

 

Question: Are the Forth word names in the ROM? 

 

There is also some evidence of someone who is still learning Forth arg management on the DATA stack. 

: DROP2
     DROP
     DROP
     ;

: DROP2UNDER       ( N1 N2 N3 -- N3 )
     ROT ROT
     DROP2
     ;

: OVER2            ( N1 N2 N3 -- N1 N2 N3 N1 )
     ROT DUP
     >R ROT ROT R>
     ;

 

DROP2UNDER would be cleaner as 

: NIP        SWAP DROP ; 
: DROP2UNDER   NIP NIP ; 

 

And you get the word NIP for when you need that function. :) 

 

OVER2 is  rather complex. It would benefit from using the PICK word.

(some folks considered it a sacrilege but on 9900 PICK about as efficient as OVER)

: OVER2     2 PICK ; 

 

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

1 hour ago, TheBF said:

Question: Are the Forth word names in the ROM? 

I look forward to dumping the ROM!  2532s. 
 

Anything you can do to test on the 4A would be welcome.  (Any typos are mine.) 

 

My thoughts: 

  1. VSP! VSP@ and GETBITS are the only words missing?  Should be straightforward to implement in 9900 assembly.  
  2. If you want to mock it up, VSP! is a no-op.  Mock up GETBITS and VSP@ to return (requested bits of?) a CALL SPGET string (XB). Maybe bit reversed.  
  3. Is this all FIG-Forth? 
     

In my dad's Lubbock speech papers, I found a 1982 version of the TI Forth manual. It is bound with a nice report cover.   Clearly there was interest in Forth at TI. 

  • Like 1
Link to comment
Share on other sites

If you read the source, you'll notice that the Speech Editor has graphical output!

 

It makes little bar charts on the terminal.

 

It puts a "display list" into the DAC buffer.  You connect the output to an oscilloscope!

 

 

  • Like 1
Link to comment
Share on other sites

Here are the pages of TMS7000 assembly source.

 

SPK is a  Forth word, coded in assembler.  It uses all the other subroutines listed here.  

 

SPK has TRAP instructions to call subroutines I don't see here.  I infer that SPLDM loads VAL with a parameter from the stack.  SPINC2 increments the stack pointer. 

 

SPK exits via BR *NEXT.

 

*----------------------------------------------------------*
* SPK                                                      *
* STACK: ADDR BITPOINTER #FRAMES PAUSE# RPTFRMS --> ..     *
*    PERFORM VSP "SPEAK EXTERNAL COMMAND", GIVEN THE       *
*    STARTING ADDRESS, BITPOINTER, NUMBER OF FRAMES, AND   *
*    NUMBER OF TIMES TO SPEAK EACH FRAME (USED BY SPEED    *
*    COMMAND)                                              * 
*                                                          *
* RPTFRM - 1-BYTE REGISTER, # OF TIMES TO REPEAT EACH      *
*          FRAME (INPUT ARG)                               *
* FRMCNT - TEMP 1-BYTE REGISTER USED TO COUNT # OF TIMES   *
*          FRAME HAS BEEN SPOKEN (RPTFM DOWNTO 0)          *
* PAUSE  - 2-BYTE REGISTER USED TO HOLD FRAME # TO PAUSE   *
*          AFTER (INPUT ARG)                               *
*         ( FORTH:                                         *
*             PAUSE := #FRAMES - (PAUSEAT - SFRAME)        *
* TEMP1  - 2-BYTE REGISTER USED TO HOLD # OF FRAMES TO     *
*          SPEAK                                           *
*          ( FORTH: #FRAMES : = EFRAME - SFRAME + 1   )    *
* TEMP3  - 2-BYTE REGISTER, MEM ADDRESS FOR NEXT BYTE OF   *
*          SPEECH DATA (INPUT ARG)                         *
* TEMP2  - 1-BYTE REGISTER, BIT POINTER 0-7 FOR STARTING   *
*          BIT (INPUT ARG)                                 *
* FRAMAD - 2-BYTE REGISTER, MEM ADDRESS FOR CURRENT FRAME  *
* TEMP2-1  TEMPORARY BYTE LOCATION                         *
* FRAMBT - 1-BYTE REGISTER, BIT POINTER FOR CURRENT FRAME  *
* ENDFRM - 1-BYTE REGISTER USED W/EXAMIN ROUTINE WHICH     *
*          DETECTS END OF FRAME                            *
*----------------------------------------------------------*
       TRAP SPLDM        GET RPTFRMS
       MOV  VAL,VAL
       JNE  SPK1
       INC  VAL          IF ZERO PASSED, MAKE IT 1
SPK1   EQU $
       MOV  VAL,RPTFRM
       TRAP SPINC2
       TRAP SPLDM        GET PAUSE#
       MOVD VAL,PAUSE    INTO PAUSE
       TRAP SPINC2
       TRAP SPLDM        GET #FRAMES
       TRAP VALTO1       INTO TEMP1
       TRAP SPINC2
       TRAP SPLDM        GET BITPOINTER
       MOV VAL,TEMP2     INTO TEMP2
       TRAP SPINC2
       TRAP SPLDM        GET ADDRESS
       MOVD VAL, TEMP3   INTO TEMP3
       TRAP SPINC2
       CMP  %8,TEMP2     ADJUST BIT POINTER TO BE 0-7
       JN   SPK2         JUMP IF LESS THAN 8
       SUB  %8, TEMP2    ELSE SUBTRACT 8
       INC  TEMP3        INCREMENT ADDRESS
       ADC  %0,TEMP3-1
*--------------------------------------------------*
* INITIALIZE ALL REMAINING REGISTERS               *
*--------------------------------------------------*
SPK2   EQU  $
       MOVD TEMP3,FRAMAD      FRAMAD := TEMP3 (ADDRESS)
       MOV  TEMP2,FRAMBT      FRAMBT := TEMP2 (BITPOINTER)
       MOV  RPTFRM,FRMCNT     FRMCNT := RPTFRM
       CALL @SPKINT      FRMLEN/BITPNT/ENERGY/REPEET/PITCH
       CLR  ENDFRM            ENDERM := 0
*--------------------------------------------------*
* ISSUE THE "SPEAK EXTERNAL" COMMAND TO VSP        *
*--------------------------------------------------*
       MOV  %SPKEXT,A    VSP SPEAK EXTERNAL COMMAND
       CALL @VSPOUT
       CALL @GNXT8           GET FIRST BYTE
*--------------------------------------------------*
* TOP OF "EXAMIN" LOOP                             *
* ASSUMES A-REGISTER CONTAINS DATA TO BE EXAMINED  *
* ENDFRM = BITPOINTER TO START EXAMINING (0  TO 7) *
*--------------------------------------------------*
SPK3   EQU  $
       CALL @EXAMIN
       MOV  ENDFRM,ENDFRM
       JNE NOTZ          JUMP IF ENDFRM <> 0
       CALL @VSPOUT      ENDFRM = 0, SEND BYTE TO VSP
       CALL @GNXT8       GET NEXT BYTE
       JMP  SPK3
NOTZ   EQU  $            ENDFRM <> 0
       CMP  %1,FRMCNT    DOES FRAME NEED REPEATING?
       JP   NOTZ2        YES! DONT CARE IF STOP FOUND
       MOV  STOPCD,STOPCD  FOUND STOP CODE ?
       JZ   NOTZ2        NO STOP CODE
       BR   @SPKSTP      YES, FOUND STOP CODE
NOTZ2  EQU  $
       CMP  %8,ENDFRM    NO, BUT IS ENDFRM=8 ?
       JNE  SPK4         JUMP IF ENDFRM <> 8
       CALL @VSPOUT      ELSE SEND BYTE VSP
       CLR  ENDFRM            AND SET ENDFRM := 0
*--------------------------------------------------*
* SEND FRAME AGAIN?                                *
*--------------------------------------------------*
SPK4   EQU  $
       DJNZ FRMCNT,SPKAA  DEC FRAME COUNT
*--------------------------------------------------*
*   NO, DON'T SEND FRAME AGAIN                     *
*--------------------------------------------------*
       MOV  RPTFRM,FRMCNT RESET FRMCNT AND GO ON
       JMP  SPK5
*--------------------------------------------------*
* YES, MUST SEND THIS FRAME AGAIN
*--------------------------------------------------*
SPK4A  EQU  $
       MOVD FRAMAD,TEMP3 RESET SPEECH DATA POINTERS
       MOV  FRAMBT,TEMP2   TO BEGINNING OF FRAME
       CALL @SPKINT      INITIALIZE FRAME VARIABLES
       CALL @SPKCLR      CLEAR UNUSED BITS IN A-REG
       PUSH A            SAVE ORIGINAL VALUE OF A-REG
       CALL @GNXT8       GET 1ST 8 BITS FROM SAME FRAME
       MOV  ENDFRM,ENDFRM   ENDFRM = O ?
       JNE  SPK4B        YES, GO PACK NEW DATA
       POP  B            NO, DATA OCCUPIES ENTIRE BYTE
       JMP  SPK4C          SO JUST THROW AWAY ORIGINAL A
SPK4B  EQU  $
       MOV  %8, B        TEMP2 := TEMP2 + (8 - ENDFRM)
       SUB  ENDFRM,B
       ADD  B,TEMP2
       CMP  %7,TEMP2     IF TEMP2 <= 7 THEN DEC TEMP3
       JP   SPK4B1       ELSE TEMP2 : = TEMP2 - 8
       DECD TEMP3
       JMP  SPK4B2
SPK4B1 EQU  $
       SUB  %8, TEMP2
SPK4B2 EQU  $
       MOV  ENDFRM, B
SPK4B3 EQU  $
       CLRC              SHIFT IN ZEROES
       RLC  A
       DJNZ B,SPR4B3 
       POP  B            GET ORIGINAL VALUE OF A-REG
       OR   B,A          PACK IN THE (8-ENDFRM) BITS
SPK4C  EQU  $
       BR  @SPK3         GO BACK TO TOP OF LOOP
*--------------------------------------------------*
* ARE WE AT THE "PAUSE" FRAME?                     *
*--------------------------------------------------*
SPK5   EQU $
       DECD TEMP1        IF TEMP1-PAUSE THEN "PAUSE"
       CMP  TEMP1-1,PAUSE-1
       JNE  SPK6         TEMP1 <> PAUSE, GO ON TO SPK6
       CMP  TEMP1, PAUSE 
       JNE  SPK6         TEMP1 <> PAUSE, GO ON TO SPK6
*--------------------------------------------------*
* YES, WE ARE AT THE PAUSE FRAME (INSERT 10        *
* SILENT FRAMES)                                   *
*--------------------------------------------------*
       PUSH A            SAVE CURRENT BYTE
       CALL @SPKCLR      CLEAR UNUSED BITS IN A-REG
       CALL @VSPOUT      BYTE 1 - INCLUDES RESIDUE FROM
       CLR  A                     PREVIOUS FRAME
       CALL @VSPOUT      BYTE 2       
       CLR  A
       CALL @VSPOUT      BYTE 3
       CLR  A
       CALL @VSPOUT      BYTE 4
       MOV  %>FF,TEMP2-1 DONE SHOVING OUT SILENT FRAMES 
       MOV  ENDFRM, B    NOW MUST GET BACK ON TRACK
SPK5A  EOU  $            SHIFT IN "O" BITS TO OLD A-REGISTER
       CLRC                TO END THE 10TH ZERO-ENERGY FRAME
       RLC  TEMP2-1
       DJNZ B,SPK5A
       POP  A            GET ORIGINAL DATA
       AND  TEMP2-1,A    CLEAR THE BITS ALREADY USED UP
*--------------------------------------------------*
* SPOKEN ALL FRAMES?
*--------------------------------------------------*
SPK6   EOU  $
       MOV  TEMP1-1,TEMP1-1   FRAME COUNTER ALREADY DEC'D
       JNE  SPK6A        JUMP IF FRAME COUNTER <> O
       MOV  TEMP1,TEMP1   
       JEQ  SPK6B        JUMP IF FRAME COUNTER = 0      
SPK6A  EQU  $            NOT SPOKEN ALL FRAMES YET
       CALL @SPKPTR      RESET FRAMAD/FRAMBT POINTERS
       MOV  ENDFRM,ENDFRM   ENDFRM=0 ?
       JZ   SPK6A1
       CALL @VSPOUT      JUMP IF ALREADY SENT BYTE
SPK6A1 EQU  $            IF ENDFRM <> 0 SEND BYTE VSP
       CLR  ENDFRM
       CALL @GNXT8       GET NEXT BYTE
       BR   @SPK3        GO BACK TO TOP OF LOOP
SPK6B  EOU  $            YES, SPOKEN ALL FRAMES  
       MOV  ENDFRM,ENDFRM
       JNE  SPK6B1
       MOV  %>F,A        ENDFRM = 0
       JMP  SPKSTP
SPK6B1 EOU  $            ENDERM <> 0      
       CALL @SPKCLR      CLEAR UNUSED BITS IN A-REGISTER
       MOV  %8,B
       SUB  ENDFRM,B     B := (8 - ENDFRM)
       PUSH A            SAVE ORIGINAL VALUE OF A 
       CLR  A            USE A FOR BIT "OR" MASK
       MOV  %>F,TEMP2-1  TEMP2-1 := VSP "STOP CODE"
SPK6B4 EQU  $
       CLRC
       RRC  TEMP2-1      SHIFT "STOP CODE" INTO 
       RRC  A              A-REGISTER
       DJNZ B,SPK6B4 
       POP  B            GET ORIGINAL VALUE OF A
       OR   B,A          "OR" IN THE STOP CODE
       CMP  %4,ENDFRM    IF ENDFRM < 4, WHOLE STOP CODE
       JN   SPKSTP          IS IN A-REGISTER
       CALL @VSPOUT      ELSE, SOME OF IT STILL IN TEMP2-1
       MOV  TEMP2-1,A
*--------------------------------------------------*
* STOP CODE DETECTED IN A-REGISTER
*--------------------------------------------------*
SPKSTP EQU  $
       CALL @VSPOUT         SEND LAST BYTE OF DATA
       MOV  %8,TEMP1        SEND 8 MORE BYTES NOP
SPKST1 EQU  $
       CLR  A               TO GET THROUGH VSP FIFO
       CALL @VSPOUT
       DJNZ TEMP1,SPKST1
       CALL @VSPTS          WAIT FOR TALK STATUS LOW
       BR   *NEXT

 

Link to comment
Share on other sites

And the subroutines:

SPKINT        INITIALIZE ALL VARIABLES USED BY SPK/EXAMIN
SPKPTR        FIX FRAMAD/FRAMBT SO THEY POINT TO THE NEXT FRAME
SPKCLR        CLEAR UNUSED BITS IN A-REG
EXAMIN        EXAMINE SPEECH DATA BYTE FOR PRESENCE OF END-OF-FRAME
GNXT8         GET NEXT 8 SPEECH DATA BITS INTO A-REG
VSPTS         WAIT FOR SPEECH STATUS
VSPOUT        ? write a speech byte

 

 

 

*--------------------------------------------------*
* SPKINT SUBROUTINE                                *
*   INITIALIZE ALL VARIABLES USED BY SPK/EXAMIN    *
*--------------------------------------------------*
SPKINT EQU  $
	MOV  %49,FRMLEN
	CLR  BITPNT
	CLR  ENERGY
	CLR  REPEET
	CLR  PITCH
	RETS
       PAGE
*==================================================*
* GNXT8 SUBROUTINE:                                *
*   GET NEXT 8 SPEECH DATA BITS, LEAVE IN A-REG    *
*   TEMP3 = ADDRESS                                *
*   TEMP2 = BITPOINTER (7-0)                       *
*==================================================*
GNXT8  EQU    $
       LDA    *TEMP3        GET NEXT BYTE OF DATA
       INC    TEMP3
       ADC    %0,TEMP3-1    INCREMENT DATA ADDRESS
       MOV    TEMP2,B       BIT POINTER -> B
       JEQ    GNXT8B        IF BITPNTR=0, ALREADY ALIGNED
       MOV    A,TEMP2-1     STORE AWAY 1ST BYTE
       LDA    *TEMP3        GET 2ND BYTE, DONT INC ADDRESS
GNXT8A EQU    $
       RR     A             BIT 0 OF 2ND BYTE TO CARRY
       RRC    TEMP2-1       SHIFT INTO TEMP RESULT
       DJNZ   B,GNXT8A      DO "BITPOINTER" TIMES
       MOV    TEMP2-1,A
GNXT8B EQU    $
       RETS
*==================================================*
* SPKPTR SUBROUTINE:                               *
*   FIX SPEECH FRAME POINTERS FRAMAD/FRAMBT        *
*   SO THEY POINT TO THE BEGINNING OF THE          *
*   NEXT FRAME COMING UP                           *
*    1. FRAMAD := TEMP3                            *
*    2. FRAMBT := ENDFRM + TEMP2                   *
*    3. IF ENDFRM = 0 THEN FRAMBT := FRAMBT + 8    *
*      (THIS IS BECAUSE ENDFRM WAS PREVIOUSLY 8)   *
*    4. IF FRAMBT <= 7 THEN FRAMAD := FRMAD - 1    *
*                      ELSE FRAMBT := FRAMBT - 8   *
*==================================================*
SPKPTR EQU    $
       MOVD   TEMP3,FRAMAD
       MOV    ENDFRM,FRAMBT
       ADD    TEMP2,FRAMBT
       MOV    ENDFRM,ENDFRM
       JNE    SPKPT1
       ADD    %8,FRAMBT
SPKPT1 EQU    $
       CMP    %7,FRAMBT
       JP     SPKPT2
       DECD   FRAMAD        FRAMBT <= 7
       JMP    SPKPT3
SPKPT2 EQU    $             FRAMBT > 7
       SUB    %8,FRAMBT
SPKPT3 EQU    $
       RETS
*==================================================*
* SPKCLR SUBROUTINE:                               *
*   CLEAR UNUSED BITS IN A-REGISTER                *
*==================================================*
SPKCLR EQU    $
       CLR    TEMP2-1       USE TEMP2-1 AS BIT MASK
       MOV    ENDFRM,B      IF ENDFRM=0, JUST RETURN
       JZ     SPKCL2         "00" IN A-REG (ALL BITS FREE)
SPKCL1 EQU    $
       SETC                 E.G. 00000111 <--- SHIFT
       RLC    TEMP2-1                       "1"S LEFT
       DJNZ   B,SPKCL1
SPKCL2 EQU    $
       AND    TEMP2-1,A     CLEAR UNUSED BITS IN A-REGISTER
       RETS
*==================================================*
*  EXAMIN SUBROUTINE:
*    EXAMINES A SPEECH DATA BYTE FOR PRESENCE OF    *
*    END-OF-FRAME.
* INPUTS:
*    ENDFRM = THE BIT POSITION TO START EXAMINING,
*       USUALLY 0, BUT CAN BE IN RANGE 0-7
* OUTPUTS:
*   STOPCD = 0 IF STOP CODE NOT FOUND
*   STOPCD <> 0 IF STOP CODE FOUND
*   ENDFRM = 0 IF END-OF-FRAME NOT FOUND
*   ENDFRM <> 0 IF END-OF-FRAME FOUND
*   ENDFRM VALUE IS BIT POSITION FOR NEXT 
*   AVAILABLE BIT IN VALUE EXAMINED 
*   (ENDFRM=8 MEANS FRAME ENDED ON LAST BIT)
*
* CALLING SEQUENCE:
*   MOV  %DATA,A      MOVE SPEECH DATA TO A
*   MOV %8,B          NUMBER OF BITS TO EXAMINE
*   CALL @EXAMIN      CALL EXAMINE ROUTINE
*   MOV ENDFRM,ENDFRM   CHECK ENDFRM
*   JNE ENDF          IF NOT ZERO, END-OF-FRAME
*                     FOUND
* EXCEPTIONS AND CONDITIONS:
*   BEFORE SENDING FIRST BYTE OF A NEW SPEECH
*   PHRASE, CALLER MUST INITIALIZE:
*     MOV  %49,FRMLEN   SET FRAME LENGTH TO 49
*     CLR  BITPNT       SET BIT POINTER TO O
*     CLR  ENERGY       SET UNPACKED ENERGY TO O
*     CLR  REPEET       SET UNPACKED REPEAT TO O
*     CLR  PITCH        SET UNPACKED PITCH TO O
*     CLR  ENDFRM       ENDFRM TO 1ST BIT POSITION *
*==================================================*
* 
*--------------------------------------------------*
* BIT MASKS FOR "ORING" INTO ENERGY/PITCH REGISTERS*
*--------------------------------------------------*
BITO   EQU  >01        0000 0001
BIT1   EQU  >02        0000 0010
BIT2   EQU  >04        0000 0100
BIT3   EOU  >08        0000 1000
BIT4   EOU  >10        0001 0000
BIT5   EQU  >20        0010 0000
*
EXAMIN EQU  $
       PUSH A             SAVE INPUT COPY OF "A"
       PUSH TEMP2-1       SAVE INPUT COPY OF "TEMP2-1"
       PUSH TEMP2         SAVE INPUT COPY OF "TEMP2" 
       PUSH TEMP3         SAVE INPUT COPY OF "TEMP3" 
       PUSH ENDFRM        SAVE INPUT COPY OF "ENDFRM"
       MOV  %8, TEMP2     TEMP2 IS THE LOOP COUNTER 
       SUB  ENDFRM,TEMP2  TEMP2 := (8 - ENDFRM)
       CLR  TEMP2-1
       CLR  STOPCD
* page break
	CLR  TEMP2-1    TEMP2-1 IS # OF BITS EXAMINED
	CLR  STOPCD     ASSUME STOP CODE NOT FOUND
*---------------------------------------------------*
* MUST SHIFT INPUT BYTE RIGHT BY "ENDFRM" BITS      *
*---------------------------------------------------*
	MOV  A, TEMP3        GET TEMP COPY
	MOV  ENDFRM,ENDFRM   ENDERM = 0 ?
	JZ   NXTBIT          YES, ALREADY SHIFTED
EXAMI1 EQU  $               NO, MUST SHIFT
	RR   TEMP3
	DJNZ ENDFRM, EXAMI1
*---------------------------------------------------*
* ENDFRM NOW SET TO ZERO, START LOOKING AT BITS     *
*---------------------------------------------------*
NXTBIT EQU  $
	CMP  %11,BITPNT      BIT POINTER < 11
	JN   NOTK            YES, MUST BE ENERGY/REPEAT/PITCH
	BR   @BP11           NO, MUST BE IN K-PARAMETERS
NOTK	EQU  $
	MOV  BITPNT,B        NO, MUST BE ENERGY/REPEAT/PITCH 
	RL   B               MPY BY 2 TO GET TABLE OFFSET
	BR   @JMPTAB(B)      JUMP TO BPN, N=BIT POINTER
*---------------------------------------------------*
* JUMP TABLE FOR BIT POINTER 0-10                   *
*---------------------------------------------------*
JMPTAB EQU  $
	JMP  BP0             BIT POINTER IS 0
	JMP  BP1             BIT POINTER IS 1
	JMP  BP2             BIT POINTER IS 2
	JMP  BP3             BIT POINTER IS 3
	JMP  BP4             BIT POINTER IS 4
	JMP  BP5             BIT POINTER IS 5
	JMP  BP6             BIT POINTER IS 6
	JMP  BP7             BIT POINTER IS 7
	JMP  BP8             BIT POINTER IS 8
	JMP  BP9             BIT POINTER IS 9
	JMP  BP10            BIT POINTER IS 10
*---------------------------------------------------*
* BIT POINTER = 0-3 "ENERGY"                        *
*---------------------------------------------------*
BP0	EQU  $
	MOV  %BIT3,MASK      0000 1000 
	JMP  BP03
BP1	EQU  $
	MOV  %BIT2,MASK      0000 0100 
	JMP  BP03
BP2	EQU  $
	MOV  %BIT1,MASK      0000 0010 
	JMP  BP03
BP3	EQU  $
	MOV  %BIT0,MASK      0000 0001
BP03	EQU  $
	RR   TEMP3           LOOK AT LSBIT OF TEMP3
	JNC  BP03A
	OR   MASK,ENERGY
BP03A	EQU  $
	CMP  %3,BITPNT       AT END OF ENERGY BITS?
	JNE  FRMTST          NO, GO DO NEXT BIT

	PAGE
	CMP  %0,ENERGY       YES
	JNE  BP03B           JUMP IF ENERGY NOT ZERO
	MOV  %3,FRMLEN       ZERO ENERGY FRAME
	JMP  FRMTST
BP03B	EQU  $
	CMP  %>0F,ENERGY     STOP CODE?
	JNE  FRMTST          NO, GO DO NEXT BIT
	MOV  %3,FRMLEN         STOP CODE FOUND
	INC  STOPCD
	JMP  FRMTST
*---------------------------------------------------*
* BIT POINTER = 4 "REPEAT"                          *
*---------------------------------------------------*
BP4    EQU  $
	CLR  REPEET          ASSUME NO REPEAT
	RR   TEMP3           REPEAT BIT SET?
	JNC  BP4A            NO, JUMP
	INC  REPEET          YES, SET REPEAT=1
	MOV  %10,FRMLEN      FRAME LENGTH SET TO 10
BP4A	EQU  $
	JMP  FRMTST
*---------------------------------------------------*
* BIT POINTER = 5-10 "PITCH"                        *
*---------------------------------------------------*
BP5	EQU  $
	MOV  %BIT5,MASK    0010 0000
	JMP  BP510
BP6	EQU  $
	MOV  %BIT4,MASK    0001 0000
	JMP  BP510
BP7	EQU  $
	MOV  %BIT3,MASK    0000 1000
	JMP  BP510
BP8    EQU  $
	MOV  %BIT2,MASK    0000 0100
	JMP  BP510
BP9    EQU  $
	MOV  %BIT1,MASK    0000 0010
	JMP  BP510
BP10   EQU  $
	MOV  %BIT0,MASK    0000 0001
BP510  EQU  $
	RR   TEMP3
	JNC  BP510A
	OR   MASK,PITCH
BP510A EOU  $
	CMP  %10,BITPNT    AT END OF PITCH BITS?
	JNE  FRMTST        NO, GO DO NEXT BIT
	CMP  %0,REPEET     YES, CHECK IF REPEAT
	JNE  FRMTST        IF REPEAT=1, FRMLEN ALREADY 10
	CMP  %0,PITCH      REPEAT=0, IS PITCH=0?
	JNE  FRMTST        NO. GO DO NEXT BIT (FRMLEN = 49)
	MOV  %28,FRMLEN    YES, SET FRAME LENGTH TO 28
	JMP  FRMTST
*---------------------------------------------------*
* BIT POINTER 11-49 "K-PARAMETERS"                  *
*---------------------------------------------------*
BP11	EQU  $
* -- page break --
	RR   TEMP3
*---------------------------------------------------*
* CHECK TO SEE IF AT END OF FRAME                   *
*---------------------------------------------------*
FRMTST EQU  $
	INC  TEMP2-1       INC NUMBER OF BITS EXAMINED
	CMP  BITPNT,FRMLEN        BITPNT = FRMLEN?
	JEQ  FRMTS1        YES, AT END OF FRAME
	INC  BITPNT        NO, INCREMENT BIT POINTER
	JMP  BITTST
FRMTS1 EQU  $
	CALL @SPKINT       YES, AT END OF FRAME
*---------------------------------------------------*
* IF ENDFRM = 0 THEN SET ENDFRM TO TEMP2-1 +        *
*                               ORIGINAL ENDFRM     *
*---------------------------------------------------*
	MOV  ENDFRM,ENDFRM
	JNE  BITTST       JUMP IF ENDFRM ALREADY SET
	POP  ENDFRM       ELSE SET ENDFRM TO BIT
	ADD  TEMP2-1,ENDFRM  POSITION OF FIRST END-OF-FRAME
*---------------------------------------------------*
* CHECK IF ALL EIGHT BITS OF "TEMP3" PROCESSED      *
*---------------------------------------------------*
BITTST	EQU  $
	DJNZ TEMP2,BITTS1 LOOK AT NEXT SPEECH BIT
	JMP  BITTS2
BITTS1	EQU  $
	BR   @NXTBIT
*---------------------------------------------------*
* RETURN                                            *
*---------------------------------------------------*
BITTS2	EQU  $
	MOV  ENDFRM,ENDFRM
	JNE  BITTS3
	POP  A
BITTS3	EQU  $
	POP  TEMP3
	POP  TEMP2
	POP  TEMP2-1
	POP  A
	RETS
*

 

 

The file with all the assembly source I have:   SPK and its subroutines.

 

 

SPEECH_EDU.asm

  • Like 1
Link to comment
Share on other sites

8 hours ago, TheBF said:

What does the TRAP instruction do?

Quote

"TRAP is a one byte subroutine call" and "provides the most efficient means of invoking subroutines".   (TMS7000 Family Data Manual)

 

The instructions TRAP and CALL enter a subroutine, saving PC on the stack (RETS is their counterpart).   The difference is that TRAP uses an index 0-23 into a table of entry vectors.  CALL takes a general operand: Register indirect, Symbolic (address), Indexed.  

 

 

TRAP takes 14 cycles and occupies 1 byte of memory (opcodes E8-FF). 

CALL @LABEL takes the same # of cycles as TRAP and uses 3 bytes of memory.    

CALL @LABEL(Rn) takes  one more cycle and also uses 3 bytes of memory.

CALL *Rn is one cycle faster than TRAP, and uses one byte of memory like TRAP.

 

The TRAP table occupies 24 words at the top of memory, FFD0 to FFFF.  TRAPs 0-3 are the interrupt handlers. (actual interrupts push the status register as well.)

 

I assume the TRAP operands shown in the code are EQU somewhere. 

 

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...