1
0
mirror of https://github.com/PDP-10/its.git synced 2026-04-29 13:22:47 +00:00
Files
PDP-10.its/src/ucode/music.16
Lars Brinkhoff 6d577568a2 KL10 microcode.
Plus assorted KL10-related documents.
2018-06-12 07:58:19 +02:00

233 lines
6.5 KiB
Plaintext
Executable File
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
.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