mirror of
https://github.com/PDP-10/its.git
synced 2026-04-29 13:22:47 +00:00
233 lines
6.5 KiB
Plaintext
Executable File
233 lines
6.5 KiB
Plaintext
Executable File
.TOC "MUSIC MICROCODE"
|
||
|
||
.IF/MUSIC
|
||
|
||
;;; MUSIC MICROCODE FOR KL-10
|
||
;;;
|
||
;;; BASIC SETUP:
|
||
;;; THERE ARE SIX VOICES.
|
||
;;; MUSIC IS PLAYED BY PUTTING BITS IN A REGISTER
|
||
;;; WHICH LIVES IN THE NETWORK IMP INTERFACE. THIS
|
||
;;; REGISTER IS LOADED BY A DATAO. THE BITS ARE LOADED
|
||
;;; AT SUCH A RATE THAT THE LOW SIX BITS PRODUCE SQUARE
|
||
;;; WAVES OF THE CORRECT FREQUENCIES. TO ACCOMPLISH THIS,
|
||
;;; THE KL-10'S 10.-USEC INTERVAL TIMER IS USURPED.
|
||
;;;
|
||
;;; FOR EACH VOICE THERE IS A BASE REGISTER (VNBR),
|
||
;;; A TIME (VNTIM, THE INVERSE OF THE FREQUENCY),
|
||
;;; AND A COUNTER (VNCTR).
|
||
;;; THERE ARE ALSO SEVERAL OTHER REGISTERS:
|
||
;;; MUSDEV CONTAINS A DATAO INSTRUCTION TO THE REGISTER.
|
||
;;; MUSMIN THE MINIMUM INTERVAL BETWEEN CHANGES TO THE
|
||
;;; REGISTER. USED TO PREVENT GOBBLING TOO MUCH
|
||
;;; MACHINE TIME. MEASURED IN 10.-USEC UNITS,
|
||
;;; WITH THE BINARY POINT BETWEEN THE HALVES
|
||
;;; OF THE WORD.
|
||
;;; CN7777 CONTAINS 7777, WHICH IS THE MAXIMUM INTERVAL
|
||
;;; THE TIMER'S 12.-BIT COUNTER CAN HANDLE.
|
||
;;; MUSBT1 THE BITS TO LOAD INTO THE REGISTER WHEN THE
|
||
;;; TIMER NEXT GOES OFF.
|
||
;;; MUSBT2 THE BITS TO TOGGLE AFTER THE REGISTER IS LOADED.
|
||
;;; MUSAOB AN AOBJN POINTER TO THE MUSIC DATA.
|
||
;;; MUSTIM THE QUANTITY FOR THE INTERVAL TIMER'S LIMIT
|
||
;;; REGISTER AFTER IT NEXT GOES OFF. THIS IS IN
|
||
;;; THE LEFT HALF, WITH THE CONTROL BITS FOR THE TIMER.
|
||
;;; CHDTIM THE TIME REMAINING FOR THE CURRENT CHORD,
|
||
;;; IN 10.-USEC UNITS.
|
||
;;; EACH BASE REGISTER POINTS TO A 64.-WORD TABLE. EACH
|
||
;;; ENTRY IS THE INVERSE FREQUENCY OF A TONE FOR THAT VOICE,
|
||
;;; MEASURED IN 10.-USEC UNITS, WITH THE BINARY POINT
|
||
;;; BETWEEN THE HALVES OF THE WORD.
|
||
;;; THE AOBJN POINTER POINTS TO A TABLE OF 2-WORD ENTRIES.
|
||
;;; THE FIRST WORD OF EACH ENTRY HAS SIX 6-BIT BYTES, ONE
|
||
;;; FOR EACH VOICE, THE FIRST VOICE BEING LEFTMOST.
|
||
;;; EACH BYTE IS USED AS AN INDEX INTO A VOICE TABLE TO
|
||
;;; FETCH AN INVERSE FREQUENCY. THE SECOND WORD IS THE
|
||
;;; LENGTH OF THE CHORD IN 10.-USEC TICKS (BINARY POINT
|
||
;;; AT THE RIGHT END OF THE WORD). WHEN THIS WORD IS
|
||
;;; FETCHED, IT IS WRITTEN BACK WITH THE SIGN BIT SET SO
|
||
;;; THAT THE MACRO-CODE CAN CHECK THE PROGRESS OF THE
|
||
;;; MUSIC PLAYER.
|
||
;;;
|
||
;;; THE MUSIC ALGORITHM:
|
||
;;; THE INSTRUCTION PLAY=DATAO TIM, IS PUT IN THE FIRST
|
||
;;; LOCATION OF THE INTERVAL TIMER'S INTERRUPT VECTOR.
|
||
;;; WHEN EXECUTED AS A PI INSTRUCTION, PLAY DOES:
|
||
;;;
|
||
;;; CONO TIM,<460000+C(MUSTIM)> ;RESET TIMER, RESTART
|
||
;;; DATAO MUSREG,MUSBT1
|
||
;;; XOR MUSBT2 INTO MUSBT1
|
||
;;; SET MUSBT2 TO 0
|
||
;;; COMPUTE MUSTIM=LOGAND(<-1,,0>,
|
||
;;; MAX(MUSMIN,
|
||
;;; MIN(V1CTR, V2CTR, ...,
|
||
;;; V6CTR, 7777)))
|
||
;;; FOR N FROM 1 TO 6 DO
|
||
;;; BEGIN
|
||
;;; SUBTRACT MUSTIM FROM V<N>CTR
|
||
;;; IF RESULT NEGATIVE, SET BIT IN MUSBT2
|
||
;;; FOR VOICE <N>, AND KEEP ADDING
|
||
;;; V<N>TIM INTO V<N>CTR UNTIL POSITIVE
|
||
;;; END
|
||
;;; SUBTRACT MUSTIM FROM CHDTIM
|
||
;;; IF RESULT NEGATIVE THEN
|
||
;;; IF MUSAOB HAS RUN OUT THEN
|
||
;;; TAKE PI CYCLE 2 (SECOND INT INSTR)
|
||
;;; ELSE BEGIN
|
||
;;; FETCH VOICES WORD (SIX 6-BIT BYTES)
|
||
;;; FETCH DURATION WORD, PUT IN CHDTIM
|
||
;;; BUMP MUSAOB BY <2,,2>
|
||
;;; FOR N FROM 1 TO 6 DO
|
||
;;; BEGIN
|
||
;;; CLEAR V<N>CTR
|
||
;;; FETCH V<N>TIM TO THE WORD
|
||
;;; ADDRESSED BY C(V<N>BR)
|
||
;;; PLUS A 6-BIT BYTE
|
||
;;; END
|
||
;;; DISMISS INTERRUPT
|
||
;;; END
|
||
|
||
|
||
=0
|
||
PLAY0: AR_BR,J/UUO ;IF NOT PI CYCLE, BE A UUO
|
||
GET ECL EBUS,AR_AR SWAP
|
||
CONO TIM ;START THE TIMER FOR NEXT TICK
|
||
REL ECL EBUS
|
||
GEN MUSDEV,LOAD IR ;SET UP FOR DATAO TO REGISTER
|
||
=10 AR_MUSBT1,CALL,SKP IO LEGAL,J/GTEBUS ;DO THE DATAO
|
||
AR_MUSBT2 ;XOR MUSBT2 INTO MUSBT1
|
||
AR_AR*MUSBT1,AD/XOR
|
||
MUSBT1_AR
|
||
AR_CN7777,BRX/ARX ;FIND MIN OF 7777 AND ALL VNCTRS
|
||
BR/AR,SKP AR GT FM,V1CTR,ARX/AD ;"SKP GT" IS AN XOR OPERATION
|
||
=0
|
||
PLAY01: BR/AR,SKP AR GT FM,V2CTR,ARX/AD,J/PLAY23
|
||
AR_ARX*BR,AD/XOR,J/PLAY01 ;XOR'ING IN XOR'D QUANTITY
|
||
=0
|
||
PLAY12: BR/AR,SKP AR GT FM,V3CTR,ARX/AD,J/PLAY23
|
||
AR_ARX*BR,AD/XOR,J/PLAY12
|
||
=0
|
||
PLAY23: BR/AR,SKP AR GT FM,V4CTR,ARX/AD,J/PLAY34
|
||
AR_ARX*BR,AD/XOR,J/PLAY23
|
||
=0
|
||
PLAY34: BR/AR,SKP AR GT FM,V5CTR,ARX/AD,J/PLAY45
|
||
AR_ARX*BR,AD/XOR,J/PLAY34
|
||
=0
|
||
PLAY45: BR/AR,SKP AR GT FM,V6CTR,ARX/AD,J/PLAY56
|
||
AR_ARX*BR,AD/XOR,J/PLAY45
|
||
=0
|
||
PLAY56: BR/AR,SKP AR GT FM,MUSMIN,ARX/AD,J/PLAY6M
|
||
AR_ARX*BR,AD/XOR,J/PLAY56
|
||
=0
|
||
PLAY6M: AR_ARX*BR,AD/XOR ;MAX RESULT WITH MUSMIN
|
||
ARL_ARL,CLR/ARR
|
||
ARX_-AR-1,P_#,#/6 ;CONTROL BITS FOR TIMER
|
||
MUSTIM_AR
|
||
|
||
;THE THEORY BEHIND USING "ARX_-AR-1" INSTEAD OF "ARX_-AR" IS TO
|
||
;AVOID UNFORTUNATE COINCIDENCES WHERE WE REACH ZERO EXACTLY,
|
||
;SINCE WE ARE REALLY DOING A SIGN BIT CHECK. THE EXTRA 1 ONLY
|
||
;THROWS IT OFF BY (10. USEC)*(2^-18) = .38 PICOSEC.
|
||
|
||
PLAYV1: AR_ARX+V1CTR,SKP AD0
|
||
=0 V1CTR_AR,BRX/ARX,ARX_BRX*2,J/PLAYQ1
|
||
BRX/ARX,ARX_BRX*2+1
|
||
BRX/ARX,ARX_BRX,J/PLAYZ1
|
||
=0
|
||
PLAYX1: V1CTR_AR,J/PLAYV2
|
||
PLAYZ1: AR_AR+V1TIM,SKP AD0,J/PLAYX1
|
||
PLAYQ1: BRX/ARX,ARX_BRX
|
||
|
||
PLAYV2: AR_ARX+V2CTR,SKP AD0
|
||
=0 V2CTR_AR,BRX/ARX,ARX_BRX*2,J/PLAYQ2
|
||
BRX/ARX,ARX_BRX*2+1
|
||
BRX/ARX,ARX_BRX,J/PLAYZ2
|
||
=0
|
||
PLAYX2: V2CTR_AR,J/PLAYV3
|
||
PLAYZ2: AR_AR+V2TIM,SKP AD0,J/PLAYX2
|
||
PLAYQ2: BRX/ARX,ARX_BRX
|
||
|
||
PLAYV3: AR_ARX+V3CTR,SKP AD0
|
||
=0 V3CTR_AR,BRX/ARX,ARX_BRX*2,J/PLAYQ3
|
||
BRX/ARX,ARX_BRX*2+1
|
||
BRX/ARX,ARX_BRX,J/PLAYZ3
|
||
=0
|
||
PLAYX3: V3CTR_AR,J/PLAYV4
|
||
PLAYZ3: AR_AR+V3TIM,SKP AD0,J/PLAYX3
|
||
PLAYQ3: BRX/ARX,ARX_BRX
|
||
|
||
PLAYV4: AR_ARX+V4CTR,SKP AD0
|
||
=0 V4CTR_AR,BRX/ARX,ARX_BRX*2,J/PLAYQ4
|
||
BRX/ARX,ARX_BRX*2+1
|
||
BRX/ARX,ARX_BRX,J/PLAYZ4
|
||
=0
|
||
PLAYX4: V4CTR_AR,J/PLAYV5
|
||
PLAYZ4: AR_AR+V4TIM,SKP AD0,J/PLAYX4
|
||
PLAYQ4: BRX/ARX,ARX_BRX
|
||
|
||
PLAYV5: AR_ARX+V5CTR,SKP AD0
|
||
=0 V5CTR_AR,BRX/ARX,ARX_BRX*2,J/PLAYQ5
|
||
BRX/ARX,ARX_BRX*2+1
|
||
BRX/ARX,ARX_BRX,J/PLAYZ5
|
||
=0
|
||
PLAYX5: V5CTR_AR,J/PLAYV6
|
||
PLAYZ5: AR_AR+V5TIM,SKP AD0,J/PLAYX5
|
||
PLAYQ5: BRX/ARX,ARX_BRX
|
||
|
||
PLAYV6: AR_ARX+V6CTR,SKP AD0
|
||
=0 V6CTR_AR,BRX/ARX,ARX_BRX*2,AR_ARX,J/PLAYQ6
|
||
BRX/ARX,ARX_BRX*2+1
|
||
BRX/ARX,ARX_BRX,J/PLAYZ6
|
||
=0
|
||
PLAYX6: V6CTR_AR,J/PLAY40
|
||
PLAYZ6: AR_AR+V6TIM,SKP AD0,J/PLAYX6
|
||
PLAYQ6: BRX/ARX,ARX_BRX
|
||
|
||
PLAY40: AR_BRX,ARX_AR SWAP
|
||
MUSBT2_AR
|
||
AR_ARX+CHDTIM,SKP AD0
|
||
=0 CHDTIM_AR,J/PIDONE
|
||
AR_MUSAOB+1,GEN CRY18,SKP AD0
|
||
=0 J/PICY2V
|
||
VMA_AR,LOAD ARX
|
||
AR_AR+1,GEN CRY18
|
||
MUSAOB_AR
|
||
ARX_MEM
|
||
VMA_VMA+1,LOAD AR
|
||
AR_MEM
|
||
CHDTIM_AR
|
||
P_P OR #,#/40,STORE
|
||
MEM_AR,AR_0S,SC_#,#/6
|
||
|
||
V1CTR_AR,ARX_SHIFT,AR_ARX (AD)
|
||
VMA_ARX+FM,V1BR,ARX_SHIFT,LOAD AR
|
||
AR_MEM
|
||
V1TIM_AR,AR_0S
|
||
|
||
V2CTR_AR,ARX_SHIFT,AR_ARX (AD)
|
||
VMA_ARX+FM,V2BR,ARX_SHIFT,LOAD AR
|
||
AR_MEM
|
||
V2TIM_AR,AR_0S
|
||
|
||
V3CTR_AR,ARX_SHIFT,AR_ARX (AD)
|
||
VMA_ARX+FM,V3BR,ARX_SHIFT,LOAD AR
|
||
AR_MEM
|
||
V3TIM_AR,AR_0S
|
||
|
||
V4CTR_AR,ARX_SHIFT,AR_ARX (AD)
|
||
VMA_ARX+FM,V4BR,ARX_SHIFT,LOAD AR
|
||
AR_MEM
|
||
V1TIM_AR,AR_0S
|
||
|
||
V5CTR_AR,ARX_SHIFT,AR_ARX (AD)
|
||
VMA_ARX+FM,V5BR,ARX_SHIFT,LOAD AR
|
||
AR_MEM
|
||
V1TIM_AR,AR_0S
|
||
|
||
V6CTR_AR,ARX_SHIFT,AR_ARX (AD)
|
||
VMA_ARX+FM,V6BR,ARX_SHIFT,LOAD AR
|
||
AR_MEM
|
||
V6TIM_AR,J/PIDONE
|
||
|
||
.ENDIF/MUSIC
|
||
|