\S CAM interrupt service routine (c) Margolus/Toffoli 03Jul87cam Mnem off bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 SSR 1F8 EVENT DPYLIN VRUN HRUN STEPRQ INTFLG PROC DIAG SRQ 1F9 SCHED xxxxxx xxxxxx xxxxxx xxxxxx xxxxxx xxxxxx xxxxxxCCR 1FA USETAB DPYRQ VGLUE HGLUE LDTBL INTENB DPYNRM CAMOUTAAR 1FB PCLB PCLA V-ORG H-ORG P3 P2 P1 P0 TAA 1FC TAC TAM TAS5 TAS4 TAS3 TAS2 TAS1 TAS0 TBA 1FD TBC TBM TBS5 TBS4 TBS3 TBS2 TBS1 TBS0 PCA 1FE xxxxxx xxxxxx PRA 1FF CMAP 200 xxxxxx xxxxxx xxxxxx xxxxxx -Inten -Red -Green -Blue ECNT 210 TDAT 400 TBD3 TBD2 TBD1 TBD0 TAD3 TAD2 TAD1 TAD0 PDAT 600 * SSR & ECNT read-only, TDAT & PDAT read/write, rest write-only.\ CAM interrupt service routine: load screen 24Aug86nhm HEX VARIABLE OLD-DP : BEGIN-MACROS HERE OLD-DP ! 800 ALLOT ; : USE-MACROS OLD-DP @ DP ! ASSEMBLER ; : FORGET-MACROS HERE (FORGET) ; : CODE-FOR ( ---- name ) HERE ' ! ASSEMBLER ; : [ASM] ASSEMBLER ; IMMEDIATE : [4TH] FORTH ; IMMEDIATE : JUMP [ASM] EB IF ; : TO-HERE [ASM] THEN ; : EOI [ASM] AX PUSH 20 # AL MOV 20 # AL OUT AX POP ; : EQU (S value -- ) ( ---- name) CONSTANT ; --> \ CAM interrupt service routine: global variables 16Oct85nhm VARIABLE CAM-BASE \ seg; up to 8 CAMs, last is master VARIABLE STEP-BASE \ seg; CAM-step control and status info 16 ALLOT \ std last 16 bytes of precomp stack VARIABLE CAM-IRQ# \ IRQ which CAM-INIT sets up VARIABLE MISSING-CAMS \ number (0 to 7) that aren't installed VARIABLE MISSING-MASK \ 0 bit => missing CAM, 1 => present VARIABLE TIME-COUNT \ used to let CAM take over timer INT VARIABLE UPDATE? \ internal flag: shadow-needs-updating? VARIABLE SAVE-SS \ temp loc used for stack-switching VARIABLE SAVE-SP \ temp loc used for stack-switching VARIABLE ACTIVE-MONITOR \ jump address used by event monitor 2VARIABLE SHARED-INT \ points to non-CAM int on same IRQ ASSEMBLER EOI IRET ( SHARED-INT normally points here ) --> \ CAM interrupt service routine: step-info format 05Jul85nhm \ Step and Event public variables: 0 EQU STEP-PENDING \ 0 => step not pending; else pending 1 EQU STEP-TYPE \ -ive is active, else idle 2 EQU STEP-COUNT \ double word (incr for each active step) 6 EQU EVENT-MASK \ 0 bit => ignore corresponding event 7 EQU EVENT-TYPE \ 0 bit => +ive event, 1 => -ive event 8 EQU EVENT-LEN \ 0, 1 or 2 events may be in queue 9 EQU EVENT-STOP \ non-zero => stop, bit no. == cam no. A EQU EVENT-1 \ latest event B EQU EVENT-2 \ second most recent event --> \ Only the FLY routines are concerned with C thru 5F. \ 60 thru 15F are the CAM shadow info, 20 bytes per CAM. \ CAM interrupt service routine: step-info format 14Feb86nhm--> offset ( precomputed stack starts at offset C ) used-by: 0 ***** ***** ***** ***** see 8 ***** ***** SETUP-JUMP DMASK/LEN above 10 SOURCE-SEG SOURCE-OFFS DEST-SEG DEST-OFFS r/w-on18 SHAD-CCR-PTR CAM-CCR-PTR AAR/CCR-MASK R/W-JUMP fly 20 R/W-POINTERS (10 words) r/w 40 SHAD-SEG SHAD-OFFS CAM-SEG CAM-OFFS copy- 48 SRC-DELTA DEST-DELTA INFO-LEN SHADOW-JUMP shadow 50 CAM-SEG MONITOR-MASK MONITOR-JUMP ECOUNT-JUMP event \ CAM interrupt service routine: step-info format 30Oct85nhm--> offsets 60 thru 15F contain shadow data, 20 bytes per CAM: bytes 0- 5: CCR AAR TAA TBA PCA PRA ( shadow registers ) bytes 6-15: CMAP ( shadow color map ) bytes 16,17: ECNT-1 ( latest event cnt ) bytes 18,19: ECNT-2 ( 2nd latest count ) bytes 1A-1F: ECNT-TOTAL ( 6 byte cumulative event cnt ) You can switch to another 160 byte step-info buffer: Wait for STEP-PENDING to clear, set it and wait again, setup new buffer (using data from old) and set STEP-BASE to point to new buffer. Offset 40 (SHAD-SEG) of buffer must also contain buffer segment. If you don't want the display to jump around, you should copy PCAs and PRAs when switching buffers, since they change. \ CAM interrupt service routine: pointers to code 15Oct85nhm \ Equates to be filled in later: 0000 EQU CAM-INTERRUPT 0000 EQU CAM-SUSPEND 0000 EQU CAM-RESUME \ Displaced headers, modified later: CODE CAM-INIT (S #cams -- ) END-CODE CODE R/FLY-ITEMS (S #items -- ) END-CODE CODE W/FLY-ITEMS (S #items -- ) END-CODE BEGIN-MACROS B 24 THRU USE-MACROS 7 A THRU FORGET-MACROS \ CAM interrupt service routine: cam interrupt 15Oct85nhm HERE IS CAM-INTERRUPT SAVE-REGISTERS NON-CAM-INT? IF RESTORE-REGISTERS NON-CAM-EXIT THEN CAM-IS-BUSY? *NOT SWITCH-TO-PRECOMPUTED-STACK SETUP-REGISTERS-AND-WAIT-FOR-VSYNC ?READ/WRITE-PLANES COPY-SHADOWS-TO-CAM ?MONITOR-EVENT-AND-SCHEDULE-STEP RESTORE-STACK *THEN ALLOW-HIGHER-PRIORITY-INTERRUPTS TIME-FOR-TIMER-INTERRUPT? IF TIMER ( allows all int when done ) ELSE ALLOW-ALL-INTERRUPTS-EXCEPT-CAM THEN ?UPDATE-STEP-INFO RESTORE-REGISTERS ALLOW-ANOTHER-CAM-INTERRUPT IRET \ CAM interrupt service routine: cam initialization 15Oct85nhm \ The following default value is setup when the code is loaded: DC00 CAM-BASE ! ( Adapter ROM is allowed from C000 thru DFFF ) CODE-FOR CAM-INIT (S #cams --) CX POP CX DEC 0< *NOT SI PUSH CLI INITIALIZE-GLOBAL-INFO INITIALIZE-STEP-INFO INSTALL-CAM-INTERRUPT ENABLE-CAM-INTERRUPT STI SI POP *THEN NEXT \ CAM interrupt service routine: r/w planes on fly 29Mar87nhm CODE-FOR R/FLY-ITEMS (S #items --) READ-START # BX MOV RJUMP-DELTA # AX MOV HERE CX POP CALC-ADDR>AX DS PUSH STEP-BASE #) DS MOV PUSHF AX R/W-JUMP #) MOV 0 # CH CMP 0= IF CLI SETUP-TO-NOT-SEND-CMAP THEN DO-PLANES/FLY # SETUP-JUMP #) MOV POPF DS POP NEXT CODE-FOR W/FLY-ITEMS (S #items --) WRITE-START # BX MOV WJUMP-DELTA # AX MOV #) JMP \ CAM interrupt service routine: suspend and resume 15Sep85nhm HERE IS CAM-SUSPEND CS: BYTE 0 # SERVICE-JUMP #) MOV RET HERE IS CAM-RESUME CS: BYTE 3 # SERVICE-JUMP #) MOV RET \ restore redefined DEFERed definitions ASSEMBLER ' A?>RESOLVE IS ?>RESOLVE ' A? ABORT" Conditionals too far apart" ; : MY?>RESOLVE HERE OVER 1+ - DUP ?TOO-FAR SWAP C! ?CONDITION ; : MY?RESOLVE IS ?>RESOLVE ' MY?AL DPYRQ NOT [ASM] # AL MOV ; : SETUP-FOR-PLANES [ASM] DX POP CX POP SI POP ES POP DI POP BP POP BX POP AX POP 0 [BP] AL AND 4 [BP] BP MOV CLD SS: MASTER-CCR-SHADOW #) DH AND ; : SETUP-FOR-SHADOWS [ASM] BP POP SI POP ES POP DI POP DX POP BX POP CX POP CL AH MOV -DPYRQ>AL STD SS: MASTER-CCR-SHADOW #) AL AND ; : WAIT-FOR-VSYNC [ASM] BEGIN BYTE VRUN # MASTER-SSR #) TEST 0= UNTIL ; \ CAM interrupt macros: setup & wait for vert. sync. 14Feb86nhm0000 EQU DO-PLANES/FLY 0000 EQU NO-PLANES/FLY : SETUP-REGISTERS-AND-WAIT-FOR-VSYNC [ASM] HERE IS DO-PLANES/FLY SETUP-FOR-PLANES WAIT-FOR-VSYNC DH MASTER-CCR #) MOV DH DH XOR AX 0 [BX] MOV 8080 # 2 [BX] MOV CX DS MOV RET HERE IS NO-PLANES/FLY COPY-SHADOWS-STACK-START # SP MOV SETUP-FOR-SHADOWS WAIT-FOR-VSYNC AL MASTER-CCR #) MOV BP DS MOV RET ; \ RET is used here as a jump to an address that was left on the \ precomputed stack \ CAM interrupt macros: values for precomputing stack 15Oct85nhm 0000 EQU READ-START 0000 EQU READ-END 0000 EQU WRITE-START 0000 EQU WRITE-END 0000 EQU SHADOW0 0000 EQU SHADOW7 0000 EQU EVENT0 0000 EQU EVENT8 0000 EQU COUNT0 0000 EQU COUNT8 0000 EQU EVENT-SKIP : RJUMP-DELTA READ-END READ-START - 10 / ; : WJUMP-DELTA WRITE-END WRITE-START - 10 / ; : SJUMP-DELTA SHADOW7 SHADOW0 - 7 / ; : EJUMP-DELTA EVENT8 EVENT0 - 8 / ; : CJUMP-DELTA COUNT8 COUNT0 - 8 / ; \ CAM interrupt macros: read/write planes on-the-fly 04Sep85nhm : ?READ/WRITE-PLANES [ASM] HERE IS WRITE-START [4TH] 10 0 DO [ASM] AX POP BP AX ADD ES: AX PCA #) MOV DX CX MOV BYTE REP MOVS [4TH] LOOP [ASM] HERE IS WRITE-END *JUMP HERE IS READ-START [4TH] 10 0 DO [ASM] AX POP BP AX ADD AX PCA #) MOV PDAT #) CL MOV DX CX MOV BYTE REP MOVS [4TH] LOOP [ASM] HERE IS READ-END *TO-HERE COPY-SHADOWS-STACK-START # SP MOV DS POP SI POP ES POP DI POP DX POP BX POP CX POP CL AH MOV STD RET ( jump ) ; \ CAM interrupt macros: copy shadows to CAM 29Aug85nhm : COPY-SHADOWS-TO-CAM [ASM] HERE IS SHADOW0 [4TH] 7 0 DO [ASM] REP MOVS DX SI ADD BX DI ADD AH CL MOV [4TH] LOOP [ASM] HERE IS SHADOW7 REP MOVS CLD ; \ Notice that shadow data for each CAM is copied in reverse \ order, so that the CCR is written last. CAMs are updated \ in descending numerical order, so that the MASTER CAM is last.\ Thus the last word of SHADOW data written is MASTER AAR/CCR. \ This avoids the possibility of restarting display (DPYRQ=1) \ before the MASTER PRA and PCA have been written. \ CAM interrupt macros: monitor event 15Oct85nhm : ?DL>MASTER-SRQ [ASM] 0= IF DL MASTER-SRQ #) MOV THEN ; : UPDATE-EVENT-INFO [ASM] SS: EVENT-1 #) BL MOV SS: BL EVENT-2 #) MOV CS: MISSING-MASK #) AH AND SS: AX EVENT-STOP #) MOV BYTE SS: EVENT-LEN #) INC RET HERE IS COUNT0 [4TH] 8 0 DO [ASM] I 800 * ECNT + #) AX MOV AX PUSH [4TH] LOOP [ASM] HERE IS COUNT8 CS: TRUE # UPDATE? #) MOV ; : RESTORE-STACK [ASM] CS: SAVE-SS #) SS MOV CS: SAVE-SP #) SP MOV ; \ CAM interrupt macros: monitor event 15Oct85nhm : ?MONITOR-EVENT-AND-SCHEDULE-STEP [ASM] DS POP BX POP SS: STEP-TYPE #) DL MOV RET ( jump ) HERE IS EVENT0 [4TH] 8 0 DO [ASM] I 800 * SSR + #) AL MOV AX SHL [4TH] LOOP [ASM] HERE IS EVENT8 AH AL MOV BH AL XOR BL AL AND ?DL>MASTER-SRQ UPDATE-EVENT-INFO JUMP HERE IS EVENT-SKIP BYTE SS: 0 # EVENT-STOP #) CMP ?DL>MASTER-SRQ BYTE CS: FF # UPDATE? #) MOV TO-HERE ; \ CAM interrupt macros: simulate timer interrupt? 24Jun85nhm \ Initialization should have turned off the hardware timer \ interrupt, so that it won't interfere with CAM. We must \ simulate this interrupt, using CAM as a clock. DECIMAL 1667 EQU CAM-DELTA 5493 EQU TIMER-DELTA HEX : TIME-FOR-TIMER-INTERRUPT? [ASM] CS: CAM-DELTA # TIME-COUNT #) ADD 0>= ; : TIMER [ASM] CS: TIMER-DELTA # TIME-COUNT #) SUB 8 INT ; \ CAM interrupt macros: data lengths 16Oct85nhm 400 EQU CAM-LEN ( words ) B0 EQU STEP-BUF-LEN ( words ) 10 EQU SHAD-LEN ( words ) C EQU STD-IDLE-LEN ( words ) B EQU STD-INFO-LEN ( words ) 8 EQU CMAP-INFO-LEN ( words ) 3 EQU SHORT-INFO-LEN ( words ) \ CAM interrupt macros: allow another CAM interrupt 17Jul85nhm : ALLOW-HIGHER-PRIORITY-INTERRUPTS [ASM] CS: STEP-BASE #) DS MOV MASTER-CCR-SHADOW #) AL MOV INTENB [4TH] NOT [ASM] # AL AND CS: CAM-BASE #) DS MOV AL MASTER-CCR #) MOV STI ; : ALLOW-ALL-INTERRUPTS-EXCEPT-CAM [ASM] 20 # AL MOV 20 # AL OUT ; ( signal end of interrupt ) : ALLOW-ANOTHER-CAM-INTERRUPT [ASM] DS PUSH AX PUSH CS: STEP-BASE #) DS MOV MASTER-CCR-SHADOW #) AL MOV CS: CAM-BASE #) DS MOV INTENB # AL OR CLI AL MASTER-CCR #) MOV AX POP DS POP ; \ CAM interrupt macros: update step information 29Oct85nhm : ?COUNT-EVENTS [ASM] BYTE CS: 0 # UPDATE? 1+ #) CMP <> IF EVENT-1 #) BL MOV DX DX XOR MASTER-ECNT-SHADOW # DI MOV CS: MISSING-CAMS #) SI MOV 8 # CX MOV SI CX SUB SI SHL SRC-DELTA # SI ADD HERE 0 [DI] AX MOV AX 2 [DI] MOV AX LODS AX STOS DX AX CMP <> IF BL SHR AX 2 [DI] ADD ELSE BL SHR THEN DX 4 [DI] ADC DX 6 [DI] ADC SHAD-LEN 2* 2+ # DI SUB LOOP 1 # STEP-COUNT #) ADD DX STEP-COUNT 2+ #) ADC THEN ; \ CAM interrupt macros: update step information 29Oct85nhm PRECOMPUTED-STACK-START EQU SETUP-JUMP : SETUP-FOR-STD-IDLE-STEP [ASM] CS PUSH DS POP STD-IDLE-LEN # CX MOV STEP-BASE # SI MOV COPY-SHADOWS-STACK-START # DI MOV REP MOVS ES PUSH DS POP NO-PLANES/FLY # SETUP-JUMP #) MOV ; \ CAM interrupt macros: update step information 18Oct85nhm : IDLE-STEP-WAS-JUST-SCHEDULED? [ASM] BYTE -1 # STEP-TYPE #) CMP <= IF BYTE 0 # EVENT-STOP #) CMP THEN <> ; : ACTIVE-STEP-UPDATE [ASM] MASTER-PCA-SHADOW # DI MOV 8 # CX MOV CS: MISSING-CAMS #) CX SUB HERE 0 [DI] AX MOV 102 # AX ADD 3F # AL AND AX STOS SHAD-LEN 2* 2+ # DI SUB LOOP EVENT-MASK #) AX MOV CS: MISSING-MASK #) AL AND AX MONITOR-MASK #) MOV CS: ACTIVE-MONITOR #) AX MOV AX MONITOR-JUMP #) MOV 0 # EVENT-MASK #) MOV ; \ CAM interrupt macros: update step information 16Oct85nhm : ?UPDATE-STEP-INFO [ASM] BYTE CS: 0 # UPDATE? #) CMP 0= *NOT CS: STEP-BASE #) DS MOV DS PUSH ES POP BYTE 0 # STEP-PENDING #) MOV ?COUNT-EVENTS SETUP-FOR-STD-IDLE-STEP IDLE-STEP-WAS-JUST-SCHEDULED? *NOT BYTE 0 # STEP-TYPE #) MOV ACTIVE-STEP-UPDATE *THEN CS: 0 # UPDATE? #) MOV *THEN ; \ CAM interrupt macros: r/w planes on fly 14Oct85nhm \ CX is the number of items, AX is number of code-bytes/item, \ BX is the starting address of the item code. \ On exit, AX= calculated jump address, CX is unchanged. : CALC-ADDR>AX [ASM] CX DX MOV DX DEC F # DX AND F # DX XOR DX MUL BX AX ADD ; \ These pointers are restored by the interrupt after being used : SETUP-TO-NOT-SEND-CMAP [ASM] SHORT-INFO-LEN # AX MOV INFO-LEN #) AX SUB AX SHL AX SHAD-OFFS #) ADD AX CAM-OFFS #) ADD AX SRC-DELTA #) ADD AX DEST-DELTA #) ADD SHORT-INFO-LEN # INFO-LEN #) MOV ; \ CAM interrupt macros: cam initialization 25Mar87nhm : INITIALIZE-GLOBAL-INFO [ASM] 7 # CX AND 7 # CL XOR CX MISSING-CAMS #) MOV SHARED-INT 4 + # SHARED-INT #) MOV CS PUSH AX POP AX SHARED-INT 2+ #) MOV SEG-TOT @ # AX ADD AX STEP-BASE #) MOV AX AX XOR AX TIME-COUNT #) MOV AX UPDATE? #) MOV BYTE 3 # SERVICE-JUMP #) MOV EJUMP-DELTA # AX MOV CX MUL EVENT0 # AX ADD AX ACTIVE-MONITOR #) MOV FF # AX MOV AX CL SHR AX MISSING-MASK #) MOV ; \ CAM interrupt macros: cam initialization 16Oct85nhm : ZERO-STEP-BUFFER [ASM] AX AX XOR AX DI MOV STEP-BUF-LEN # CX MOV REP AX STOS ; : SETUP-COPY-SHADOWS [ASM] SHAD-LEN 2* # AX MOV MISSING-CAMS #) MUL SHADOWS-OFFSET 2- STD-INFO-LEN 2* + # AX ADD AX STOS CAM-BASE #) AX MOV AX STOS CAM-LEN 2* # AX MOV MISSING-CAMS #) MUL CMAP 2- CMAP-INFO-LEN 2* + # AX ADD AX STOS SHAD-LEN STD-INFO-LEN + 2* # AX MOV AX STOS CAM-LEN STD-INFO-LEN + 2* # AX MOV AX STOS STD-INFO-LEN # AX MOV AX STOS MISSING-CAMS #) AX MOV SJUMP-DELTA # BX MOV BX MUL SHADOW0 # AX ADD AX STOS ; \ CAM interrupt macros: cam initialization 16Oct85nhm : SETUP-MONITOR-EVENTS [ASM] CAM-BASE #) AX MOV AX STOS ( don't care what value ) AX STOS EVENT-SKIP # AX MOV AX STOS MISSING-CAMS #) AX MOV CJUMP-DELTA # BX MOV BX MUL COUNT0 # AX ADD AX STOS ; : INITIALIZE-STEP-INFO [ASM] CS PUSH ES POP STEP-BASE 2+ # DI MOV SETUP-COPY-SHADOWS SETUP-MONITOR-EVENTS STEP-BASE #) ES MOV ZERO-STEP-BUFFER STEP-BASE # SI MOV COPY-SHADOWS-STACK-START # DI MOV STD-IDLE-LEN # CX MOV REP MOVS ES: NO-PLANES/FLY # SETUP-JUMP #) MOV ; \ CAM interrupt macros: cam initialization 02Sep85nhm 2 IS CAM-IRQ# ( this is the default, but is not set by INIT ) : INSTALL-CAM-INTERRUPT [ASM] CAM-IRQ# #) AL MOV 7 # AX AND AX CAM-IRQ# #) MOV BX BX XOR BX ES MOV 20 # DI MOV AX SHL AX SHL AX DI ADD CAM-INTERRUPT # AX MOV AX STOS CS AX MOV AX STOS ; : ENABLE-CAM-INTERRUPT [ASM] CAM-IRQ# #) CL MOV FE # AH MOV AH CL ROL 21 # AL IN 1 # AL OR AH AL AND 21 # AL OUT CAM-BASE #) ES MOV BYTE ES: 0 # MASTER-CCR #) MOV BYTE ES: INTENB # MASTER-CCR #) MOV ; \S CAM interrupt service routine (c) Margolus/Toffoli 16Oct85nhm This is the CAM interrupt service routine, and associated initialization and control routines. Screens 1 thru 6 contain all of the variables, equates, and headers that will remain after this file has been loaded. Screen 6 directs the rest of the loading: -- B thru 24 contain macros that will be used and forgotten -- 7 thru A make use of the macros to create machine code The assembled routines occupy about 2K bytes. They assume that the CAM memory map is as given on screen 0. \ CAM interrupt service routine: load screen 01May86nhm OLD-DP used by BEGIN-MACROS to remember Dictionary Ptr BEGIN-MACROS leaves some empty space for the machine code USE-MACROS moves DP back to space left by BEGIN-MACROS FORGET-MACROS forgets everything after machine code (ie MACROS)CODE-FOR named word becomes displaced-header for this code[ASM] is an IMMEDIATE version of ASSEMBLER [4TH] is an IMMEDIATE version of FORTH JUMP assemble an unconditional short jump to TO-HERE TO-HERE resolves unconditional forward jump from JUMP EOI End Of Interrupt -- resets 8259 interrupt flag EQU same as CONSTANT (short for "equate") \ CAM interrupt service routine: global variables 05Jul85nhm These are the global variables which are used by the interrupt service routine. CAM-BASE and CAM-IRQ# have default values at program-load time, but may be reassigned and then CAM should be re-initialized using CAM-INIT ( you should also restore the IRQ vector corresponding to the former value of CAM-IRQ# ). STEP-BASE is initially FORTH-SEG plus 1000; SHARED-INT is a two-word vector that will be FAR JUMPed via if the interrupt is entered and CAM's interrupt flag is not set. The rest of these are used internally by the interrupt, and should only be modified via CAM-INIT. \ CAM interrupt service routine: step-info format 16Oct85nhm The current status of up to eight CAMs is reflected entirely by the information contained in a 160 byte step-info buffer. The first C bytes contain variables that may be examined and freely changed: ** a STEP-PENDING flag which is not used by the interrupt, but is cleared each time the shadow-info is copied ** a STEP-TYPE flag, which is sent to the MASTER CAM's SRQ during a non-busy int if EVENT-STOP is zero, and cleared only ifit is sent ** STEP-COUNT, a double-word counter which is incremented each time an active step is completed ** EVENT-MASK and EVENT-TYPE, which are used to control which CAM's events can set EVENT-STOP non-zero. After each active (ie. compute) step, EVENT-1 is copied to EVENT-2, the 8 new event bits are copied to EVENT-1, and EVENT-LEN is incremented. \ CAM interrupt service routine: step-info format 17Oct85nhm In order to let the CAM interrupt be as fast as possible, it sets up register values from a precomputed stack, which is switched to during the interrupt. From the stack, any register can be loaded with a one-byte instruction -- this is important since the 8088 will almost never have a chance to prefetch instructions as we transfer data around during the interrupt. The precomputed stack begins at offset C of the step control segment. The first word is a jump address, which points either to code to setup for r/w-on-fly, or to setup for copying shadows. The next 19 words are used by r/w-on-fly, the following 8 by copy-shadows-to-CAM, and the final 4 by the monitor-events-and-schedule-steps code. The 4 words between this stack and the shadow-data are unused. \ CAM interrupt service routine: step-info format 17Oct85nhm The remaining 100 bytes of this step-info buffer contains shadow information for each of up to 8 CAMs: 20 bytes per CAM, with MASTER-CAM (ie. CAM #0) last. Note that each CAM's shadow area starts on an even segment boundary -- this is convenient when selecting a current-CAM to which commands apply. The first 16 bytes hold the write-only data for CAM control registers and color map -- CCR AAR TAA TBA PCA PRA and CMAP. This data is copied to CAM during VSYNC time of every non-busy (see CAM-IS-BUSY? macro) interrupt. The remaining A bytes contain event-count data which, togetherwith the EVENT-1 and EVENT-2 bytes, allow you to monitor all counts without missing any (despite overlapping sched/running). ECNT-1 is the latest event-count, ECNT-2 the 2nd latest, and ECNT-TOTAL contains a triple-word (30 bit) cumulative total. \ CAM interrupt service routine: pointers to code 15Sep85nhm To give us a simple way to forget MACROs without forgetting the machine code they generate, execution of the macros does notproduce any word-headers in the Forth dictionary. Instead, these 6 headers are modified by the macros to point to the appropriate pieces of code. CAM-INTERRUPT will point to the beginning of the interrupt code.CAM-SUSPEND will cause the CAM interrupt to skip servicing CAMs, but will not affect SHARED-INT behaviour, or TIMER simulation. CAM-RESUME again allows CAM service. CAM-INIT takes #cams as an argument & initializes the interrupt.R/FLY-ITEMS and W/FLY-ITEMS are used to setup the precomputed stack to read or write plane data on-the-fly. \ CAM interrupt service routine: cam interrupt 05Jul85nhm This code, executed after the macros have been compiled, will generate the entire machine language interrupt service routine. The interrupt has three parts: 1) If CAMs didn't interrupt, exit via the SHARED-INT vector. 2) If CAMs aren't busy, switch stacks and service them. 3) Simulate system timer interrupt, which has been turned off. Part 3, and any updating of step control and status info needed, is done with other interrupts allowed -- CAM's interrupt-enable is kept off until this is done. Part 2, the time-critical code, is done with all interrupts disabled. It will r/w plane data if this was requested, then copy shadows to CAM, monitor events if the previous step was active, and send STEP-TYPE to SRQ if EVENT-STOP isn't set. \ CAM interrupt service routine: cam initialization 03Jul85nhm CAM-INIT is called as an ordinary Forth CODE word, with an argument of the number of CAMs to assume are installed. This number may have been determined by trying to read and write to CAMs, or it may be chosen arbitrarily for testing software designed to use more CAMs than you have. If this number is zero, this word does nothing. CAM-INIT will setup the global variables, precompute the interrupt-stack values, turn off the system timer so that it won't compete with the CAM interrupt, install the CAM interrupt as the CAM-IRQ# interrupt, and enable interrupts. \ CAM interrupt service routine: r/w planes on fly 29Mar87nhm R/FLY-ITEMS and W/FLY-ITEMS are called as ordinary Forth CODE words, with an argument of the number of items to schedule to be read or written to a CAM during the CAM-service interrupt. These words schedule a number (up to 10) of read *or* write operations (not both) to apply to a CAM in the next interrupt. They modify SETUP-JUMP and R/W-JUMP in the precomputed stack. They should be called after another routine has set up the rest of the rw/fly info (offsets E thru 1D and 20 thru 3F on the precomputed stack) which specifies where the data buffer is, which CAM is involved, the item length (up to 10 words) and includes a row/col start address (plus 101) for each transfer. If the hi-byte of the item# is zero, the copy-shadow info will be modified to leave out the CMAP info (this time only). \ CAM interrupt service routine: suspend and resume 18Oct85nhm CAM-SUSPEND & CAM-RESUME return pointers to these subroutines. These words are provided to allow the interrupt to temporarilysuspend CAM servicing without affecting its interrupt-sharing and timer-simulating functions. They operate by changing a jump displacement value within the CAM interrupt service routine (see CAM-IS-BUSY? macro). When CAM service is suspended, no step-info is transferred or modified by the interrupt -- except for the MASTER-CCR which is*always* updated from its shadow register during each interrupt. It is necessary to suspend copying of shadow info to CAMs during plane and table i/o operations, so that the interrupt won't alter parameters being used in plane or table i/o. \ CAM interrupt macros: assembler patches 08Jul85nhm ***************************************************************** This is the start of the CAM interrupt macros ***************************************************************** We begin with some ASSEMBLER macros which cure deficiencies in the Forth assembler. New definitions for the ?>RESOLVE and ? CAM is idle 11 => a step is just finishing 10 can't happen 01 => scheduled step has not yet begun Thus CAM is about to be idle for both even-parity cases, and parity-odd can be interpreted as "CAM is busy". The mainline can suspend CAM servicing by modifying the conditional jump which tests the parity, so CAM is always busy. \ CAM interrupt macros: shadow equates 17Oct85nhm Bytes C thru 57 constitute a pre-computed stack, which is switched to during the interrupt, and used to setup registers. It is computed by the CAM-INIT routine, and modified by the r/w-planes-on-fly Forth words, and by the interrupt itself. Standard values for the last C words of this pre-comp stack (beginning at COPY-SHADOWS-STACK-START) are setup at STEP-BASE (global variables area) and following it -- this data is copied at the end of each non-busy CAM-interrupt, as part of the setup for the next interrupt. The event-counting routines make use of this fact by pushing counts temporarily onto this stack after the old precomp data has been used, and before the new is setup (lets us shorten interval with interrupts disabled). Bytes 60 thru 15F contain CAM shadow data: 20 bytes per CAM, with the MASTER-CAM shadows last (just as with CAM-addresses). \ CAM interrupt macros: switch to precomputed stack 17Oct85nhm During the time-critical portion of the interrupt, registers are loaded using POPs directly from a precomputed stack, setup at the end of the preceeding interrupt, and modified from Forth. While we use this precomputed stack, all interrupts will be disabled (this is why we don't need to leave any room between the public-variables step-info and the precomp stack). We will switch back to the original stack before we allow interrupts. The RET instruction is used here as an "IP POP" instruction --ie. a jump. The first item on the precomp stack is used to jump to either the DO-PLANES/FLY routine, or the NO-PLANES/FLY routine. \ CAM interrupt macros: setup & wait for vert. sync. 14Feb86nhm CAM will interrupt 2 scan lines (about 600 clocks on IBM-PC) before the start of VSYNC time. This gives the service routine time to push all word registers, and pop new values into them. (CS, IP and flags are pushed by the interrupt, SS and SP are saved and altered with MOVs, rather than PUSHs and POPs). If plane data is to be read or written by the interrupt, this is done first (subsequent copying of shadow info to CAMs will reset any registers that were altered). If no plane i/o is scheduled, we will setup directly for shadow copying. In eithercase, once the registers are setup, we will wait for VSYNC. No assumptions about the values of CAM shadow registers are implicit in the data on the precomp-stack -- thus in the PLANES setup, to zero DPYRQ in the master CCR, we load a mask into DH with DPYRQ off, and AND it with MASTER-CCR-SHADOW at setup time.\ CAM interrupt macros: setup & wait for vert. sync. 14Feb86nhm SETUP-JUMP (the first item on the precomputed stack) will cause a jump to either DO-PLANES/FLY or NO-PLANES/FLY. If CAM-service is to begin by reading or writing plane data, we set DX=DMASK/LEN CX=SOURCE-SEG SI=SOURCE-OFFS ES=DEST-SEG DI=DEST-OFFS BP=PRA/PCA-VALUE BX=CAM-CCR-PTR AX=AAR/CCR-VALUEand wait for VSYNC. Then we turn off DPYRQ in the MASTER-CCR (using DH) and setup CCR AAR TAA and TBA, copy SOURCE-SEG to DS and jump into the middle of READ/WRITE-PLANES code. If instead we are to begin directly by copying shadows withoutfirst r/w planes, we set BP=SHAD-SEG SI=SHAD-OFFS ES=CAM-SEG DI=CAM-OFFS DX=SRC-DELTA BX=DEST-DELTA CX=AH=INFO-LEN and wait for VSYNC. Then we turn off DPYRQ, copy SHAD-SEG into DS, and jump into the middle of COPY-SHADOWS-TO-CAM code. \ CAM interrupt macros: values for precomputing stack 06Jul85nhm To avoid the overhead of executing a loop in order to transferseveral pieces of data, this interrupt has the necessary code repeated the maximum number of times that may be required, and we just skip over the unneeded repetitions and execute the required code serially. Given the starting and ending addresses for each such piece ofcode, we can compute the length of the code for each data transfer. These addresses will be filled in as the code is defined below, and then code to setup and modify jump addresses will be defined that make use of these. \ CAM interrupt macros: read/write planes on-the-fly 17Oct85nhm To write plane data, pop the uncorrected PRA/PCA value off the stack, then add the correction (current offset of upper left corner of the CAM screen) and send value to CAM, then copy DX bytes from buffer to CAM. Repeat this for each item. To read plane data, pop uncorrected PRA/PCA off the stack, add the correction and send value to CAM, then do one dummy readfrom PDAT to prime the read machinery, and then copy DX bytes from CAM to the buffer. Repeat this for each item. When done, setup to copy shadows to CAMs, and jump into COPY-SHADOWS code. \ CAM interrupt macros: copy shadows to CAM 17Oct85nhm Copy shadow info to a CAM, and then setup for the next CAM. After the MASTER CAM, don't setup for any more. Each CAM's shadow data occupies 20 bytes (in order to start on an even segment boundary) and each CAM occupies 800 bytes of address space; but we only copy at most 16 bytes of control data from shadows to CAMs. Thus after each copy, both SI and DI must be incremented in preparation for sending to the next CAM (in fact we copy the data backwards in order to send CCR last, but we would have had to increment SI and DI anyways). When setting up the precomputed stack for reading or writing plane data on the fly, we have the option of not sending CMAP in order to save time. In this case, the string length and the offset values setup for SI and DI are changed. \ CAM interrupt macros: monitor event 16Oct85nhm ?DL>MASTER-SRQ and UPDATE-EVENT-INFO are macros used by the ?MONITOR-EVENT-AND-SCHEDULE-STEP macro. By programming the auxiliary tables and the color map appropriately, the Intensity bit of CAM's output can be used to signal interesting events. The ECNT (event count) register is clocked (during active steps) by this bit, and the EVENT bit of the SSR indicates whether or not any "events" have occured during the latest active-step. The EVENT bit serves as a flag (have any events happened?) and when the 16-bit ECNT register is zero, it distinguishes between counts of 0 and 10000. When the interrupt schedules an active step, it also modifies values in the precomputed stack (MONITOR-MASK and MONITOR-JUMP) to schedule monitoring of EVENT bits when this step finishes. \ CAM interrupt macros: monitor event 16Oct85nhm Since there may be up to eight CAMs, there may be up to eight EVENT bits. We gather them all together into one byte. Missing CAMs are not checked, but those that are installed will have their EVENT bit shifted into the appropriate bit of AL. We use the value that EVENT-MASK had when the step was started(saved in MONITOR-MASK) to decide if we should stop because of an event. The lo byte masks off bits to be ignored, the hi bytesignals bits to be inverted. If the result (which is saved in EVENT-STOP) is non-zero, then don't send STEP-TYPE to SRQ. The accumulated EVENT byte is saved in EVENT-1 (with bits corresponding to missing CAMs set to 0). The former EVENT-1 is moved to EVENT-2, and EVENT-LEN is incremented. ECNT values are now read (even though a new step may have started, the value of ECNT doesn't change until the end of the step, and so may still be read) and saved on the stack for later processing. \ CAM interrupt macros: simulate timer interrupt? 06Jul85nhm CAM interrupts every 16.67 milliseconds (unless DPYNRM is 0). The system timer normally interrupts every 54.93 milliseconds. To avoid contention, the system timer is turned off when CAM is initialized, and the CAM interrupt simulates the timer int as appropriate, during non-critical time. Each time CAM interrupts, we increment TIME-COUNT by decimal 1667. When TIME-COUNT becomes positive, we decrement TIME-COUNTby decimal 5493 and call the timer interrupt. \ CAM interrupt macros: data lengths 17Oct85nhm CAM-LEN # of words in the address space of 1 CAM STEP-BUF-LEN # of words in the step-info buffer SHAD-LEN # of words in the shadow info for 1 CAM STD-IDLE-LEN # of words in precomp stack in std-idle-setup STD-INFO-LEN # of shadow words normally copied for 1 CAM CMAP-INFO-LEN # of shadow words copied for CMAP of 1 CAM SHORT-INFO-LEN # of shadow words copied when CMAP is omitted. For speed, all string moves are word-moves. Thus all lengths are in words. \ CAM interrupt macros: allow another CAM interrupt 17Jul85nhm ALLOW-HIGHER-PRIORITY-INTERRUPTS turns off the MASTER CAM's interrupt-enable bit before setting the 8088 interrupt-enable flag. When all interrupts are re-enabled, this flag will let CAM tell whether or not a call to this IRQ came from CAM. ALLOW-ALL-INTERRUPTS-EXCEPT-CAM resets the 8259 interrupt flag that was set when CAM interrupted. ALLOW-ANOTHER-CAM-INTERRUPT turns back on the MASTER CAM's interrupt-enable bit, in preparation for ending the interrupt-service routine. (We clear the 8088 interrupt-enable bit before enabling CAM's interrupt --- the IRET will set the 8088 interrupt-enable bit as we exit). \ CAM interrupt macros: update step information 16Oct85nhm The second byte of the UPDATE? flag is only set if this interrupt is the first following an active (compute) step. This flag was set when we pushed the event-counts from CAMs onto the stack immediately after scheduling the next step (active or idle). Since these counts would be updated at the end of an active step, we could not re-enable interrupts until after we had saved these values, for fear we might not get to process these values before the new step completed. We now finish processing these values with all interrupts allowed (but CAM's disabled). For each CAM, we copy ECNT-1 to ECNT-2, save the new count as ECNT-1, and also add this count to ECNT-TOTAL (or add 10000 if the count is 0 but the EVENT bit for this CAM was on). Finally, we increment STEP-COUNT, the count of how many active steps have completed. \ CAM interrupt macros: update step information 14Oct85nhm If CAM was serviced during this interrupt (ie. CAM wasn't busy) then we will need to update some of the information in the step-info buffer. We start off by assuming that the next non-busy interrupt willbe one in which an idle step has just completed, and no r/w on the fly is scheduled. To set this up, we setup COPY-SHADOWS to its standard parameters (ie. include CMAP) and SETUP-JUMP shouldstart directly with COPY-SHADOWS (no r/w on fly). MONITOR-JUMP should be set for an idle step -- no monitoring is to be done at the end of this step. \ CAM interrupt macros: update step information 14Oct85nhm If we didn't set up for an idle step (STEP-TYPE is negative and EVENT-STOP is zero) then we should modify step-info to reflect an active step: All PRA/PCA values corresponding to CAMs which are present should be updated. We should set up to monitor any EVENTs produced by this step the next time CAM is not busy (ie. when the step has run). To setup to monitor an event, we copy EVENT-MASK to MONITOR-MASK (being careful to first set the mask to ignore CAMswhich aren't present) so that the mask at schedule-time is the relevant one. Then we setup MONITOR-JUMP and zero EVENT-MASK. \ CAM interrupt macros: update step information 17Oct85nhm Step-info will only be updated if CAM was serviced during thisinterrupt. We can determine if CAM was serviced by checking the UPDATE? flag -- if events were monitored during this interrupt, both bytes of UPDATE? will be set; if monitoring wasn't done but step-info was copied, only the low-order byte of UPDATE? will be set; if servicing was suspended, UPDATE? = 0. Any step-info updating is done with all interrupts allowed. Thus if other interrupts have been waiting, they get a chance before we update. Any time that CAM is serviced, the STEP-PENDING flag is cleared, to let the mainline know. If an active step was just scheduled, the STEP-TYPE flag will also be cleared. \ CAM interrupt macros: r/w planes on fly 14Oct85nhm ***************************************************************** read or write planes on the fly ***************************************************************** CALC-ADDR>AX Calculate R/W-JUMP address and leave it in AX. SETUP-TO-NOT-SEND-CMAP Schedule the CMAP info to be omitted from the next COPY-SHADOWS-TO-CAM, to give more time for the r/w on fly. \ CAM interrupt macros: cam initialization 18Mar87nhm ***************************************************************** initialize CAMs ***************************************************************** INITIALIZE-GLOBAL-INFO Given the number of CAMs minus one in CX, we first calculate MISSING-CAMS, setup SHARED-INT to point to EOI IRET, STEP-BASE to point to first free segment, TIME-COUNT and UPDATE? to both be zero, SERVICE-JUMP to *not* be permanently busy, calculate the jump address to use when scheduling monitoring of an active step (ACTIVE-MONITOR) and setup the mask to use to ignore eventsfrom non-installed CAMs (MISSING-MASK). \ CAM interrupt macros: cam initialization 29Aug85nhm ZERO-STEP-BUFFER Set all 160 bytes of step-info-buf to zero SETUP-COPY-SHADOWS Shadows for non-existent CAMs are not copied. Thus CAM-OFFS and SHAD-OFFS must correspond to the first installed CAM and its shadow, respectively. Since shadow data is copied in reverse order (AAR/CCR last), we must set initial offsets pointing to the last words of these data areas. \ CAM interrupt macros: cam initialization 17Oct85nhm SETUP-MONITOR-EVENTS Setup to skip monitoring of EVENTS, but also setup ECOUNT-JUMP address which will be used for updating ECNT values if MONITOR-JUMP is changed to not skip. INITIALIZE-STEP-INFO We setup standard values for the copy-shadows and monitor-events portions of the precomp-stack, and leave them in a buffer in the global-variables area. Then we clear the step-buffer and copy these standard values, and also set the SETUP-JUMP address to go directly to copy-shadows (ie. no r/w planes on fly).\ CAM interrupt macros: cam initialization 28Jul85nhm 2 IS CAM-IRQ# IRQ 2 is highest priority IRQ on bus. INSTALL-CAM-INTERRUPT Use CAM-IRQ# to decide which vector to use (only 0 thru 7 are allowed, since CAM uses only the 8-bit-bus i/o channel). Install a pointer to CAM-INTERRUPT in appropriate vector. ENABLE-CAM-INTERRUPT Mask IRQ 0 (timer interrupt) and unmask CAM IRQ. Enable interrupt from MASTER CAM.