TITLE TIME MACHINE III.9 ;STARTING ADDRESS 2. ;USES INTERRUPT FOR REAL TIME CLOCK, AND TELETYPE. ;THERE ARE THREE MAIN PARTS: ; 1) TAKE CARE OF DIFFERENT MODES THE TIME MACHINE CAN BE IN. ; 2) DISPLAY STUFF. ; 3) TAKING AND INTERPRETTING COMMANDS FROM TELETYPE. ;MACROS DEFINE SKIP JMP .+2 TERMIN ;COMPARE WORDS. ; COMPARES THE NEXT CHARACTERS IN THE INPUT BUFFER TO ; THE GIVEN WORD. IF THEY DON'T MATCH, ; IT RESETS IPTR SO IT CAN BE USED AGAIN. DEFINE CWORD WRD,ADD,NUM LDA 2,A!WRD IFSN !NUM!,S,[ LDA 0,[!NUM!] STA 0,VAL ] JSR @IWORD JMP ADD ;RETURNS HERE IF MATCH ; RETURNS NEXT LOCATION IF NO MATCH. TERMIN ;COMPARE LETTERS. ; COMPARES A LETTER IN 2 WITH THE GIVEN LETTER. ; IF THEY MATCH IT JUMPS TO THE ADDRESS AND ADDS ; THE NUMBER TO COM. IF THERE IS AN S INSTEAD OF ; A NUMBER, IT USES THE PREVIOUS VALUE. DEFINE CLET LET,ADD,NUM LDA 2,["!LET!] IFSN !NUM!,S,[ LDA 0,[!NUM!] STA 0,VAL ] JSR @ILET JMP ADD TERMIN ;COMPARE TO RIGHT OR LEFT. ; LIKE CLET BUT DOESN'T CHANGE COM. ; USED IN TESTING FOR R OR L, ETC. DEFINE CRL LET,ADD LDA 3,["!LET!] SUB% 1,3(SNR) JMP ADD TERMIN ;A TEST WORD. ; SETS UP THE GIVEN WORD AS A TEST WORD DEFINE TSTWRD W A!W!: . ASCIZ \!W!\ TERMIN ;VARIABLES STORAGE AREA. DISP==41 BOX==30 NPTR==30 ENDPTR==22 PTR==23 PPTR==24 IPTR==26 WPTR==27 LOC 140 MASK: 0 DISJOB: MSGLST OKPTR: 0 MSGPTR: 0 TIME: 0 ADDR: 0 DELAY: 0 DTIME: 0 DTCNT: 0 TMAX: 0 XMCON: 101777 TEMPO: 0 SLIDEN: 0 ;RATE OF SLIDES SFACT: 0 BTSNX: 0 ;A TEMPORARY FOR BTSNUM BEATD: 0 ;0 IF BEATS ARE TO BE DISPLAYED BEATPC: 1252 BEATPR: 0 BMOVE: 0 PMOVE: 0 PIECEY: 120500 BEATY: 120300 OLDTIM: 0 CLOCK: 0 SHWFLG: 0 DRMFLG: 0 ONE: 0 COM: 0 ICNT: 0 VAL: 0 RET0: 0 RET1: 0 RET2: 0 CRNRET: 0 AMSGL: MSGLST AJBLST: JOBLST TOPLST: 0 APTIME: PTIME-1 AIBUFF: INBUFF-1 IDSPLY: DISPLA IREPLA: REPLAY ITFREQ: TFREQ ISTPTR: SETPTR IWORD: WORDS IERROR: ERROR IOKCOM: OKCOM IMODE: MODE IDEBUG: 6200 ILET: LET IACTION: ACTION IACT1: ACT1 IEVAL: EVAL IYBTS: YBTS IEOS1: EOS1 IEOS2: EOS2 IEOS3: EOS3 ISCLD: SCLD ISNUMD: SNUMD ITMPOD: TEMPOD ITNUMD: TNUMD ICRNXT: CRNXT P1END==. ;LOCS 0-4 LOC 0 0 INTRPT ;LOC. 2. STARTING ADD. IORST JMP INIT ;LOC. 4. RESTARTING ADD. JMP RINIT LOC P1END ;REINITIALIZE. ; START OVER, BUT DON'T TYPE THE 'STARTING' MESSAGE. RINIT: SUB 1,1(SKP) ;INITIALIZE. INIT: LDA 1,[14] ;TO SET MASK FOR 'STARTING MESSAGE'. INTDS LDA 0,AIBUFF ;TTY INPUT BUFFER-1 STA 0,IPTR LDA 0,[77] ;LENGTH OF TTY BUFFER. STA 0,ICNT LDA 0,[177771] MSKO 0, ;ENABLE CLOCK, TTI. DISABLE TTO. LDA 0,[2] ;SET REAL TIME CLOCK TO DOAS 0,RTC ;INTERRUPT EVERY 10 MIL-SEC. SKIP ;RESET COMMAND TYPED. RSET: SUB 1,1 STA 1,MASK LDA 0,BEATPC STA 0,BEATPR ;BEAT PERIOD. LDA 2,[4] STA 2,SFACT ;SCALING FACTOR LDA 1,[17770] ;INITIAL MAX. TIME. STA 1,TMAX LDA 1,[12] STA 1,TEMPO SUB 0,0 STA 0,BMOVE ;AM'T BEATS MOVED. STA 0,PMOVE ;AM'T PIECE MOVED. STA 0,CLOCK INC 0,0 STA 0,DRMFLG STA 0,ONE INTEN JMP RSTART ; ;SCALE. ; SCALE THE NUMBER IN AC1. SCAL: LDA 2,SFACT ;SCALING FACTOR. SUB 0,0 MOVL% 1,1(SZC) ;NUMBER NEG.? JMP .+3 ;YES. DIV ;NUMBER/SFACT. JMP 0(3) NEG 1,1 ;MAKE IT POS. DIV NEG 1,1 ;MAKE ANSWER NEG. JMP 0(3) ; ;BEATS NUMBER HACK ; TURNS OUT THAT 6000.*TEMPO/ X IS USEFUL TO COMPUTE TWICE ; CALL WITH AC1 = X . RETURN ANSWER IN AC1 ; SKIP RETURN UNLESS OVERFLOW OCCURS. BTSNUM: STA 1,BTSNX SUB 0,0 LDA 1,[13560] ;6000. LDA 2,TEMPO MUL LDA 2,BTSNX DIV MOV% 0,0(SZC) ;DIV SETS CARRY ON OVERFLOW JMP 0(3) MOVZL 0,0 ;THIS IS HOW YOU ROUND QUOTIENTS SUBZ 2,0(SZC) INC 1,1 ;ROUND IT UP JMP 1(3) ;SKIP RETURN ;INTRO MODE. ; IN THIS MODE, BEATS ARE SOUNDED, BUT NOT DISPLAYED. ; WHEN THE DRUM IS HIT, PUT THAT AT TIME = 0 AND ENTER RESTART. INTRO: SUBZL 0,0 ;1 STA 0,SHWFLG LDA 0,AMSGL STA 0,TOPLST ;TOP OF DISPLAY LIST. SUB 0,0 STA 0,DTIME INTLUP: JSR TALOT SUB 3,3 DIAS 1,BOX MOVR 1,1(SNC) ;BIT 15 IS 0 JMP DHIT ;WHEN DRUM HIT. LDA 1,BEATPR ;-1 MEANS BEATS OFF. COM% 1,1(SNR) JMP W0 LDA 0,DTIME SUBZ 1,0(SNC) ;SKIP IF DTIME>=BEATPR. JMP WAIT0 LDA 0,[4] DOAS 0,BOX ;SOUND THE BONGO. W0: STA 3,DTIME ;0 WAIT0: STA 3,TIME JSR WAIT ;DISPLAY STUFF WHILE WAITING FOR CLOCK. JMP INTLUP ;DRUM WAS HIT. ; MAKE NEXT BEAT FOLLOW CORRECTLY. DHIT: LDA 0,BEATPR ;TIME PER BEAT. LDA 1,DTIME ;TIME SINCE LAST BEAT. COM% 0,0(SZR) ;SKIP IF BEATS OFF. SUBZ 1,0(SNC) ;TIME LEFT TIL NEXT BEAT. SUB 0,0 STA 0,BMOVE ;RESTART MODE. ; IN THIS MODE THE PIECE CAN BE TAPPED IN ON THE DRUM. RSTART: JSR RRI ;INITIALIZE POINTERS,TIME,&SHWFLG. ; RETURNS WITH AC0=0, AC1=ADD.-1 OF TIME LIST, ; AC2=-1. STA 1,ENDPTR STA 0,PMOVE STA 2,@ENDPTR ;PUT -1 AT END OF TIME LIST. LDA 0,AJBLST STA 0,TOPLST ;TOP OF DISPLAY LIST. INLOOP: JSR CHKTU ;CHECK FOR TIME UP. ;TIME ISN'T UP. TEST THE DRUM. DIAS 1,BOX MOVZR 1,1(SNC) ;BIT 15 IS 0 WHEN JMP DRUMON ;THE DRUM IS ON. SUB 1,1 STA 1,DRMFLG JMP WAIT1 ;THE DRUM IS ON, BUT IS IT A NEW HIT? DRUMON: LDA 1,DRMFLG ;IF 0, THEN THIS MOV 1,1(SZR) ;IS AN NEW HIT. JMP WAIT1 ISZ DRMFLG ;SET DRMFLG=1. LDA 0,DTIME ;TIME SINCE LAST DRUM HIT. STA 0,@PPTR ;PUT INTO NEXT LOCATION IN TIME LIST. STA 1,DTIME ;AC1=0. COM 1,1 ;PUT -1 AT THE END STA 1,@ENDPTR ;OF THE TIME LIST. WAIT1: JSR TALOT JSR BTBONG ;BONG THE BONGO IF TIME FOR NEXT BEAT. JSR WAIT ;DISPLAY STUFF WHILE WAITING FOR CLOCK. JMP INLOOP ;RESTART/REPLAY INITIALIZATION. ; INITIALIZE STUFF USED BY BOTH ROUTINES. ; RETURN WITH AC0=0, AC1=APTIME, AC2=-1. RRI: LDA 1,APTIME ;ADD.-1 OF TIME LIST. STA 1,PTR STA 1,PPTR ADC 2,2 STA 2,SHWFLG STA 2,OLDTIM SUB 0,0 STA 0,TIME STA 0,DTIME JMP 0(3) ;REPLAY MODE. ; IN THIS MODE, THE PIECE THAT IS STORED IN THE TIME LIST IS PLAYED BACK. REPLAY: JSR RRI LDA 1,PMOVE ;AMOUNT THE PIECE MOVED. ;ADD UP PMOVE+DTIMES UNTIL THE SUM >=0. NUTHER: LDA 0,@PPTR ;NEXT DTIME. COM% 0,0(SNR);END OF LIST = -1. JMP NOPIC ;NO TIMES FIT. ADD 0,1(SNR);AC1=PMOVE + SUM OF DTIMES. JMP PICBON ;THE SUM = 0. MOVL% 1,1(SZC) JMP NUTHER ;THE SUM < 0. RLOOP: STA 1,DTCNT ;DTCNT = TIME UNTIL NEXT PIECE. JSR WAIT JSR CHKTU ;CHECK FOR TIME UP. JSR BTBONG JSR TALOT LDA 0,DTCNT LDA 1,DTIME SUBZ 0,1(SNC) ;SKIP IF DTIME >= DTCNT JMP RLOOP+1 PICBON: STA 1,DTIME LDA 0,[2] DOAS 0,BOX ;SOUND THE BONGO FOR THE PIECE. LDA 1,@PPTR ;NEXT DTIME. JMP RLOOP NOPIC: MOV 0,1 JMP RLOOP ; ;WAIT. ; DISPLAY STUFF WHILE WAITING FOR CLOCK TO INT. WAIT: STA 3,RET1 JSR @IDSPLY DSZ CLOCK ;CLOCK IS SET TO 1 BY CLOCK INT. ROUTINE. JMP .-2 JMP @RET1 ;THE CLOCK HAS INTERRUPTED. ; ;CHECK FOR TIME UP. ; COMPARE TIME TO THE MAXIMUM TIME. CHKTU: LDA 0,TIME LDA 1,TMAX ;MAX. TIME. SUBZ% 1,0(SZC) JMP TIMEUP JMP 0(3) ;SHOW-ALL MODE. ; IN THIS MODE, THE ENTIRE PIECE IS DISPLAYED. ; TIME IS SET TO THE LARGEST VALUE SO THE DISPLAY ROUTINE WILL SHOW ALL. SHWALL: SUBZL 0,0 ;1 STA 0,SHWFLG JSR TALOT LDA 1,TMAX STA 1,TIME JSR WAIT JMP SENTRY ;SHOW-ALL'S ENTRY IN TIMEUP. ;TEST A LOT. ; TESTS FOR RUBOUT, CARRIAGE RETURN, ^G, STARTING MESSAGE, SPACE-BAR, ; AND SLIDES. TALOT: STA 3,RET0 LDA 0,MASK LDA 3,AMSKA ADD 0,3 LDA 0,SLIDEN ;SLIDE RATE LDA 1,PMOVE ;AM'T PIECE MOVED. LDA 2,BMOVE ;AM'T BEATS MOVED. JMP @0(3) AMSKA: .+1 TFREQ COMINT ;FOR RUBOUT. COMINT ;FOR CR XSTL ;SLIDE TOGETHER LEFT. XSTR ;ETC. XSPL XSPR XSBL XSBR XSEL XSER BREAK SMSG ;STARTING MESSAGE. RSET XSBL: SUB 0,2(SKP) XSBR: ADD 0,2 JMP SDONE XSTL: SUB 0,2(SKP) XSTR: ADD 0,2(SKP) XSPL: SUB 0,1(SKP) XSPR: ADD 0,1 SDONE: STA 1,PMOVE STA 2,BMOVE JMP TFREQ XSEL: LDA 1,TMAX ;TIME OF END OF SCREEN SUBZ 0,1(SZC) ;SKIP IF TOO SMALL STA 1,TMAX JMP TFREQ XSER: LDA 1,TMAX ADD 0,1 STA 1,BTSNX ;A TEMP JSR SCAL ;START TURNING INTO X-COORD. LDA 0,[3777] SUBZ% 0,1(SZC) ;SKIP IF OKAY JMP TFREQ LDA 1,BTSNX STA 1,TMAX ;SEE ABOUT CHANGING BEAT FREQUENCY. TFREQ: DSZ ONE ;IS EITHER 0 OR 1. ISZ ONE JMP @RET0 DIAS 0,BOX MOVR 0,0 MOVR 0,0(SNC) ;BIT IS 0 FOR SPEED-UP. JMP SPDUP MOVR 0,0(SNC) SLDN: ISZ BEATPR ;INC. BEATPR TO DECREASR FREQ. JMP @RET0 SPDUP: DSZ BEATPR ;DEC. BEATPR TO INCREASE FREQ. JMP @RET0 JMP SLDN ;BEAT BONG. ; DECIDES WHETHER TO BONG THE BONGO FOR THE BEATS. BTBONG: LDA 1,TIME LDA 2,BMOVE MOVL% 2,2(SZC) ;SKIP IF NEGATIVE. JMP BMNEG SUBZ 2,1(SNC) ;TIME-BMOVE. JMP 0(3) ;TIME < BMOVE. NO BEATSYET. SKIP BMNEG: SUB 2,1 ;BMOVE NEG. TIME > BMOVE THEREFORE. SUB 0,0 LDA 2,BEATPR COM% 2,2(SNR) ;BEATPR = -1 MEANS BEATS OFF. JMP 0(3) DIV ;(TIME - BMOVE)/BEATPR. THIS EQUALS THE NUMBER OF BEATS BEING DISPLAYED. LDA 0,BMOVE MUL ;NUMBER OF BEATS BEING DISPLAYED * BEATPR + BMOVE. ; THIS IS THE TIME OF THE LAST BEAT BEING DISPLAYED. MOVZL% 1,1(SZC) ;SKIP IF LAST TIME >= 0. JMP 0(3) ;IF LAS TIME < 0, THEN IT ISN'T BEING DISPLAYED. LDA 0,OLDTIM STA 1,OLDTIM ;THE LAST TIME BECOMES THE NEW OLDTIM. COM% 0,0(SNR) ;WHEN INITIALIZED, OLDTIM WAS SET TO -1. JMP BONG ;THE FIRST TIME THAT OLDTIM IS CHANGED SHOULD ALWAYS CAUSE A BONG. ADD 2,0 ;BEATPR + OLDTIM. SUBZ 0,1(SNC) ;SKIPS IF OLDTIM + BEATPR <= LASTIM. JMP 0(3) ;THERE IS NO BONGING TO DO. BONG: LDA 0,[4] DOAS 0,BOX ;BONG THE BONGO. JMP 0(3) ;TIME IS UP. ; TIME HAS BECOME > XMAX. ; DECIDE WHAT MODE TO GO INTO. TIMEUP: LDA 0,[400] ;2 SECOND DELAY. STA 0,DELAY SENTRY: DIAS 0,BOX ;GET SWITCHES. ; THE BITS MEAN: BIT 9=WAIT, ; BIT 10=SAVE,BIT 11=SHOWALL, ; BIT 12=RESTART. MOVS 0,0 ;SWAP INFO INTO TOP BYTE. MOVL 0,0 MOVL 0,0(SNC) ;TEST FOR WAIT. JMP NOWAIT DSZ DELAY JMP SHWALL ;SHOW ALL WHILE DELAYING. NOWAIT: MOVL 0,0(SNC) ;TEST FOR SAVE. JMP NOSAVE MOVL 0,0(SNC) ;TEST FOR SHOW-ALL. JMP @IREPLA SUBZL 1,1 ;1. STA 1,DELAY ;SO THAT AFTER SHOW-ALL PROG. WON'T WAIT. JMP SHWALL NOSAVE: MOVL 0,0 ;THROW AWAY SHOW ALL BIT. MOVL 0,0(SNC) ;TEST FOR RESTART. JMP INTRO JMP RSTART ;COMMAND INTERPRETER. ; INTERPRETS COMMANDS IN THE INPUT BUFFER. COMINT: DSZ MASK ;MASK IS EITHER 1 OR 2. DSZ MASK JMP RUBOUT ;CARRIAGE RETURN. LDA 0,[177773] MSKO 0, ;DISABLE TTI. TTO REMAINS DISABLED. LDA 0,AIBUFF ;ADD-1 OF INPUT BUFFER. STA 0,IPTR ;AUTO-INCREMENTING. SUB 0,0 STA 0,COM ;INDEX OF COMMAND ;SET POINTERS. JSR @ISTPTR ;COMPARE INPUT BUFFER WITH TEST WORDS. CWORD MOVE,WRD2,0 CWORD RESET,YRSET,S CWORD DEBUG,@IDEBUG,S CWORD DISPLAY,WRD2,100 CWORD HIDE,WRD2,40 CWORD SLIDE,WRD2,12 CWORD SET,WRD2,S JMP LET1 ;RUBOUT. ; DELETE PREVIOUS CHAR. IF NONE, THEN ISSUE NEW LINE. RUBOUT: DSZ IPTR LDA 0,@IPTR ;PREVIOUS CHAR. INC% 0,0(SNR) ;WORD BEFORE BUFFER = -1. JMP @IOKCOM DSZ IPTR DOAS 0,TTO ISZ ICNT JMP @ITFREQ ;YES RESET YRSET: LDA 0,[15] STA 0,MASK JMP @IOKCOM ;THESE ARE TEST WORDS. IRP W,,[MOVE,RESET,DEBUG,DISPLAY,HIDE,SLIDE,SET] TSTWRD W TERMIN ;NOT A WORD. COMPARE TO TEST LETTERS. LET1: LDA 1,@IPTR CLET M,WRD2,0 CLET L,@IACTION,S CLET R,@IACT1,S CLET B,@IYBTS,S CLET D,WRD2,100 CLET H,WRD2,40 CLET S,WRD2,12 JMP @IERROR ;THE FIRST WORD IN THE BUFFER ISN'T VALID. ;COMPARE 2ND WORD TO TEST WORDS. WRD2: JSR @ISTPTR CWORD TOG,WRD3,0 CWORD TEMPO,WRD3,S CWORD PIECE,WRD3,2 CWORD BEATS,WRD3,4 CWORD END,WRD3,6 CWORD SCALE,WRD3,10 ;NOT A WORD. COMPARE TO TEST LETTERS. LDA 1,@IPTR CLET S,WRD3,S CLET E,WRD3,6 CLET B,WRD3,4 CLET P,WRD3,2 CLET T,WRD3,0 JMP @IERROR ;THE SECOND WORD WASN'T VALID. ;THESE ARE TEST WORDS. IRP W,,[PIECE,BEATS,TEMPO,END,SCALE] TSTWRD W TERMIN ATOG: . ASCIZ \TOGETHER\ ;COMPARE 3RD WORD TO TEST WORDS. WRD3: JSR @ISTPTR CWORD LEFT,ACTION,0 CWORD RIGHT,ACT1,S ;NOT A WORD. COMPARE TO TEST LETTERS. LDA 1,@IPTR CRL L,ACTION CRL R,ACT1 CRL <,ACTION CRL >,ACT1 ;THERE'S NO THIRD WORD. ;SOME COMMANDS DON'T HAVE A 3RD WORD, THOUGH. DSZ IPTR ;SET IPTR TO VERY NEXT CHAR. LDA 2,COM ;IS IT HIDE BEATS OR DISPLAY BEATS LDA 1,[104] SUB% 1,2(SNR) JMP YDB ;DISPLAY BEATS LDA 1,[44] SUB% 1,2(SNR) JMP YHB ;HIDE BEATS JSR @IEVAL LDA 2,COM LDA 1,[12] SUB% 1,2(SNR) JMP YST ;SET TEMPO. LDA 1,[16] SUB% 2,1(SNR) JMP YBTS+1 ;'SB' HAS COM OF 16. LDA 1,[22] SUB% 2,1(SZR) JMP @IERROR ;THE COMMAND IS 'SET SCALE'. STA 0,SFACT LDA 1,TMAX JMP EON ;IS THE END-OF-SCREEN ON THE SCREEN? ;ACTION. ; CHOOSE ROUTINE TO DO COMMAND. ACT1: ISZ COM ACTION: DSZ SHWFLG ;1 IF IN SHOW-ALL OR INTRO. JMP @IMODE ;SLIDE AND MOVE NOT VALID NOW. ISZ SHWFLG ;PUT SHWFLG BACK UP. LDA 1,[12] LDA 3,COM SUBZ% 1,3(SZC) ;SKIP IF THIS IS A MOVE. JMP NOTMV LDA 2,ACOMRA ;ADDRESS OF THE COMMAND ARRAY. ADD 3,2 STA 2,ADDR JSR EVAL ;EVALUATE NUMBER IN INPUT BUFFER. LDA 1,TMAX LDA 2,PMOVE LDA 3,BMOVE JMP @ADDR ;HERE ARE THE TEST WORD FOR WORD 3. TSTWRD LEFT TSTWRD RIGHT ;COMMAND ARRAY. ACOMRA: .+1 SUB 0,3(SKP) ;MTL ADD 0,3(SKP) ;MTR JMP XMPL JMP XMPR JMP XMBL JMP XMBR JMP XMEL JMP XMER JMP ERROR ;NOT VALID. JMP ERROR ;NOT VALID ; XMBL: SUB 0,3(SKP) ;3 HAS BMOVE. XMBR: ADD 0,3 JMP MOVED ;ALL MOVING DONE. XMPL: SUB 0,2(SKP) XMPR: ADD 0,2 MOVED: STA 2,PMOVE STA 3,BMOVE JMP OKCOM XMER: ADD 0,1 STA 1,TMAX ;IS THE END-OF-SCREEN ON THE SCREEN? EON: JSR SCAL LDA 0,[3777] SUBZ% 0,1(SNC) JMP OKCOM ;END STILL ON SCREEN. ;UNSCALE XMCON INTO TIME. LDA 1,XMCON MOVZL 1,1 SUB 0,0 LDA 2,SFACT MUL JMP ENDMV XMEL: SUBZ% 1,0(SZC) ;SKIP IF AC0