1
0
mirror of https://github.com/livingcomputermuseum/ContrAlto.git synced 2026-01-23 19:06:39 +00:00
2015-10-20 15:32:26 -07:00

2233 lines
66 KiB
Plaintext
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.

; A L T O I I C O D E 3 . M U
; Copyright Xerox Corporation 1979
;***Derived from ALTOIICODE2.MU, as last modified by
;***Tobol, August 5, 1976 12:13 PM -- fix DIOG2 bug
;***modified by Ingalls, September 6, 1977
; BitBLT fixed (LREG bug) and extended for new memory
;***modified by Boggs and Taft September 15, 1977 10:10 PM
; Modified MRT to refresh 16K chips and added XMSTA and XMLDA.
; Fixed two bugs in DEXCH and a bug in the interval timer.
; Moved symbol and constant definitions into AltoConsts23.mu.
; MRT split and moved into two 'get' files.
;***modified by Boggs and Taft November 21, 1977 5:10 PM
; Fixed a bug in the Ethernet input main loop.
;***modified by Boggs November 28, 1977 3:53 PM
; Mess with the information returned by VERS
;***modified by Dersch, August 26, 2015 4:04 PM
; Annotated with PROM addresses and Tasks for use in Contralto
;Get the symbol and constant definitions
#AltoConsts23.mu;
;LABEL PREDEFINITIONS
;The reset locations of the tasks:
!17,20,NOVEM,,,,KSEC,,,EREST,MRT,DWT,CURT,DHT,DVT,PART,KWDX,;
;Locations which may need to be accessible from the Ram, or Ram
; locations which are accessed from the Rom (TRAP1):
!37,20,START,RAMRET,RAMCYCX,,,,,,,,,,,,,TRAP1;
;Macro-op dispatch table:
!37,20,DOINS,DOIND,EMCYCLE,NOPAR,JSRII,U5,U6,U7,,,,,,,RAMTRAP,TRAP;
;Parameterless macro-op sub-table:
!37,40,DIR,EIR,BRI,RCLK,SIO,BLT,BLKS,SIT,JMPR,RDRM,WTRM,DIRS,VERS,DREAD,DWRITE,DEXCH,MUL,DIV,DIOG1,DIOG2,BITBLT,XMLDA,XMSTA,,,,,,,,,;
;Cycle dispatch table:
!37,20,L0,L1,L2,L3,L4,L5,L6,L7,L8,R7,R6,R5,R4,R3X,R2X,R1X;
;some global R-Registers
$NWW $R4; State of interrupt system
$R37 $R37; Used by MRT, interval timer and EIA
$MTEMP $R25; Public temporary R-Register
;The Display Controller
; its R-Registers:
$CBA $R22;
$AECL $R23;
$SLC $R24;
$HTAB $R26;
$YPOS $R27;
$DWA $R30;
$CURX $R20;
$CURDATA $R21;
; its task specific functions:
$EVENFIELD $L024010,000000,000000; F2 = 10 DHT DVT
$SETMODE $L024011,000000,000000; F2 = 11 DHT
$DDR $L026010,000000,124100; F2 = 10 DWT
!1,2,DVT1,DVT11;
!1,2,MOREB,NOMORE;
!1,2,NORMX,HALFX;
!1,2,NODD,NEVEN;
!1,2,DHT0,DHT1;
!1,2,NORMODE,HALFMODE;
!1,2,DWTZ,DWTY;
!1,2,DOTAB,NOTAB;
!1,2,XNOMORE,DOMORE;
;Display Vertical Task
DV00014> DVT: MAR<- L<- DASTART+1;
DV00001> CBA<- L, L<- 0;
DV00005> CURDATA<- L;
DV00006> SLC<- L;
DV00017> T<- MD; CAUSE A VERTICAL FIELD INTERRUPT
DV00023> L<- NWW OR T;
DV00036> MAR<- CURLOC; SET UP THE CURSOR
DV00046> NWW<- L, T<- 0-1;
DV00047> L<- MD XOR T; HARDWARE EXPECTS X COMPLEMENTED
DV00050> T<- MD, EVENFIELD;
DV00051> CURX<- L, :DVT1;
DV00002> DVT1: L<- BIAS-T-1, TASK, :DVT2; BIAS THE Y COORDINATE
DV00003> DVT11: L<- BIAS-T, TASK;
DV00052> DVT2: YPOS<- L, :DVT;
;Display Horizontal Task.
;11 cycles if no block change, 17 if new control block.
DH00013> DHT: MAR<- CBA-1;
DH00053> L<- SLC -1, BUS=0;
DH00054> SLC<- L, :DHT0;
DH00032> DHT0: T<- 37400; MORE TO DO IN THIS BLOCK
DH00055> SINK<- MD;
DH00056> L<- T<- MD AND T, SETMODE;
DH00057> HTAB<- L LCY 8, :NORMODE;
DH00034> NORMODE:L<- T<- 377 . T;
DH00070> AECL<- L, :REST;
DH00035> HALFMODE: L<- T<- 377 . T;
DH00071> AECL<- L, :REST, T<- 0;
DH00072> REST: L<- DWA + T,TASK; INCREMENT DWA BY 0 OR NWRDS
DH00073> NDNX: DWA<- L, :DHT;
DH00033> DHT1: L<- T<- MD+1, BUS=0;
DH00074> CBA<- L, MAR<- T, :MOREB;
DH00025> NOMORE: BLOCK, :DNX;
DH00024> MOREB: T<- 37400;
DH00075> L<- T<- MD AND T, SETMODE;
DH00127> MAR<- CBA+1, :NORMX, EVENFIELD;
DH00026> NORMX: HTAB<- L LCY 8, :NODD;
DH00027> HALFX: HTAB<- L LCY 8, :NEVEN;
DH00030> NODD: L<-T<- 377 . T;
DH00130> AECL<- L, :XREST; ODD FIELD, FULL RESOLUTION
DH00031> NEVEN: L<- 377 AND T; EVEN FIELD OR HALF RESOLUTION
DH00131> AECL<-L, T<-0;
DH00132> XREST: L<- MD+T;
DH00133> T<-MD-1;
DH00134> DNX: DWA<-L, L<-T, TASK;
DH00135> SLC<-L, :DHT;
;Display Word Task
DW00011> DWT: T<- DWA;
DW00136> T<- -3+T+1;
DW00137> L<- AECL+T,BUS=0,TASK; AECL CONTAINS NWRDS AT THIS TIME
DW00140> AECL<-L, :DWTZ;
DW00041> DWTY: BLOCK;
DW00141> TASK, :DWTF;
DW00040> DWTZ: L<-HTAB-1, BUS=0,TASK;
DW00142> HTAB<-L, :DOTAB;
DW00042> DOTAB: DDR<-0, :DWTZ;
DW00043> NOTAB: MAR<-T<-DWA;
DW00143> L<-AECL-T-1;
DW00144> ALUCY, L<-2+T;
DW00145> DWA<-L, :XNOMORE;
DW00045> DOMORE: DDR<-MD, TASK;
DW00146> DDR<-MD, :NOTAB;
DW00144> XNOMORE:DDR<- MD, BLOCK;
DW00147> DDR<- MD, TASK;
DW00150> DWTF: :DWT;
;Alto Ethernet Microcode, Version III, Boggs and Metcalfe
;4-way branches using NEXT6 and NEXT7
!17,20,EIFB00,EODOK,EOEOK,ENOCMD,EIFB01,EODPST,EOEPST,EOREST,EIFB10,EODCOL,EOECOL,EIREST,EIFB11,EODUGH,EOEUGH,ERBRES;
;2-way branches using NEXT7
;EOCDW1, EOCDWX, and EIGO are all related. Be careful!
!7,10,,EIFOK,,EOCDW1,,EIFBAD,EOCDWX,EIGO;
;Miscellaneous address constraints
!7,10,,EOCDW0,EODATA,EIDFUL,EIDZ4,EOCDRS,EIDATA,EPOST;
!7,10,,EIDOK,,,EIDMOR,EIDPST;
!1,1,EIFB1;
!1,1,EIFRST;
;2-way branches using NEXT9
!1,2,EOINPR,EOINPN;
!1,2,EODMOR,EODEND;
!1,2,EOLDOK,EOLDBD;
!1,2,EIFCHK,EIFPRM;
!1,2,EOCDWT,EOCDGO;
!1,2,ECNTOK,ECNTZR;
!1,2,EIFIGN,EISET;
!1,2,EIFNBC,EIFBC;
;R Memory Locations
$ECNTR $R12; Remaining words in buffer
$EPNTR $R13; points BEFORE next word in buffer
;Ethernet microcode Status codes
$ESIDON $377; Input Done
$ESODON $777; Output Done
$ESIFUL $1377; Input Buffer full - words lost from tail of packet
$ESLOAD $1777; Load location overflowed
$ESCZER $2377; Zero word count for input or output command
$ESABRT $2777; Abort - usually caused by reset command
$ESNEVR $3377; Never Happen - Very bad if it does
;Main memory locations in page 1 reserved for Ethernet
$EPLOC $600; Post location
$EBLOC $601; Interrupt bit mask
$EELOC $602; Ending count location
$ELLOC $603; Load location
$EICLOC $604; Input buffer Count
$EIPLOC $605; Input buffer Pointer
$EOCLOC $606; Output buffer Count
$EOPLOC $607; Output buffer Pointer
$EHLOC $610; Host Address
;Function Definitions
$EIDFCT $L000000,014004,000100; BS = 4, Input data
$EILFCT $L016013,070013,000100; F1 = 13, Input Look
$EPFCT $L016014,070014,000100; F1 = 14, Post
$EWFCT $L016015,000000,000000; F1 = 15, Wake-Up
$EODFCT $L026010,000000,124000; F2 = 10, Output data
$EOSFCT $L024011,000000,000000; F2 = 11, Start output
$ERBFCT $L024012,000000,000000; F2 = 12, Rest branch
$EEFCT $L024013,000000,000000; F2 = 13, End of output
$EBFCT $L024014,000000,000000; F2 = 14, Branch
$ECBFCT $L024015,000000,000000; F2 = 15, Countdown branch
$EISFCT $L024016,000000,000000; F2 = 16, Start input
; - Whenever a label has a pending branch, the list of possible
; destination addresses is shown in brackets in the comment field.
; - Special functions are explained in a comment near their first use.
; - To avoid naming conflicts, all labels and special functions
; have "E" as the first letter.
;Top of Ethernet Task loop
;Ether Rest Branch Function - ERBFCT
;merge ICMD and OCMD Flip Flops into NEXT6 and NEXT7
;ICMD and OCMD are set from AC0 [14:15] by the SIO instruction
; 00 neither
; 01 OCMD - Start output
; 10 ICMD - Start input
; 11 Both - Reset interface
;in preparation for a hack at EIREST, zero EPNTR
EN00007> EREST: L<- 0,ERBFCT; What's happening ?
EN00152> EPNTR<- L,:ENOCMD; [ENOCMD,EOREST,EIREST,ERBRES]
EN00203> ENOCMD: L<- ESNEVR,:EPOST; Shouldn't happen
EN00217> ERBRES: L<- ESABRT,:EPOST; Reset Command
;Post status and halt. Microcode status in L.
;Put microstatus,,hardstatus in EPLOC, merge c(EBLOC) into NWW.
;Note that we write EPLOC and read EBLOC in one operation
;Ether Post Function - EPFCT. Gate the hardware status
;(LOW TRUE) to Bus [10:15], reset interface.
EN00237> EPOST: MAR<- EELOC;
EN00220> EPNTR<- L,TASK; Save microcode status in EPNTR
EN00222> MD<- ECNTR; Save ending count
EN00224> MAR<- EPLOC; double word reference
EN00230> T<- NWW;
EN00240> MD<- EPNTR,EPFCT; BUS AND EPNTR with Status
EN00260> L<- MD OR T,TASK; NWW OR c(EBLOC)
EN00261> NWW<- L,:EREST; Done. Wait for next command
;This is a subroutine called from both input and output (EOCDGO
;and EISET). The return address is determined by testing ECBFCT,
;which will branch if the buffer has any words in it, which can
;only happen during input.
EN00262> ESETUP: NOP;
EN00263> L<- MD,BUS=0; check for zero length
EN00264> T<- MD-1,:ECNTOK; [ECNTOK,ECNTZR] start-1
EN00253> ECNTZR: L<- ESCZER,:EPOST; Zero word count. Abort
;Ether Countdown Branch Function - ECBFCT.
;NEXT7 = Interface buffer not empty.
EN00252> ECNTOK: ECNTR<- L,L<- T,ECBFCT,TASK;
EN00265> EPNTR<- L,:EODATA; [EODATA,EIDATA]
;Ethernet Input
;It turns out that starting the receiver for the first time and
;restarting it after ignoring a packet do the same things.
EN00213> EIREST: :EIFIGN; Hack
;Address filtering code.
;When the first word of a packet is available in the interface
;buffer, a wakeup request is generated. The microcode then
;decides whether to accept the packet. Decision must be reached
;before the buffer overflows, within about 14*5.44 usec.
;if EHLOC is zero, machine is 'promiscuous' - accept all packets
;if destination byte is zero, it is a 'broadcast' packet, accept.
;if destination byte equals EHLOC, packet is for us, accept.
;EIFRST is really a subroutine that can be called from EIREST
;or from EIGO, output countdown wait. If a packet is ignored
;and EPNTR is zero, EIFRST loops back and waits for more
;packets, else it returns to the countdown code.
;Ether Branch Function - EBFCT
;NEXT7 = IDL % OCMD % ICMD % OUTGONE % INGONE (also known as POST)
;NEXT6 = COLLision - Can't happen during input
EN00153> EIFRST: MAR<- EHLOC; Get Ethernet address
EN00266> T<- 377,EBFCT; What's happening?
EN00267> L<- MD AND T,BUS=0,:EIFOK;[EIFOK,EIFBAD] promiscuous?
EN00221> EIFOK: MTEMP<- LLCY8,:EIFCHK; [EIFCHK,EIFPRM] Data wakeup
EN00225> EIFBAD: ERBFCT,TASK,:EIFB1; [EIFB1] POST wakeup; xCMD FF set?
EN00151> EIFB1: :EIFB00; [EIFB00,EIFB01,EIFB10,EIFB11]
EN00200> EIFB00: :EIFIGN; IDL or INGONE, restart rcvr
EN00204> EIFB01: L<- ESABRT,:EPOST; OCMD, abort
EN00210> EIFB10: L<- ESABRT,:EPOST; ICMD, abort
EN00214> EIFB11: L<- ESABRT,:EPOST; ICMD and OCMD, abort
EN00247> EIFPRM: TASK,:EIFBC; Promiscuous. Accept
;Ether Look Function - EILFCT. Gate the first word of the
;data buffer to the bus, but do not increment the read pointer.
EN00246> EIFCHK: L<- T<- 177400,EILFCT; Mask off src addr byte (BUS AND)
EN00270> L<- MTEMP-T,SH=0; Broadcast?
EN00271> SH=0,TASK,:EIFNBC; [EIFNBC,EIFBC] Our Address?
EN00256> EIFNBC: :EIFIGN; [EIFIGN,EISET]
EN00257> EIFBC: :EISET; [EISET] Enter input main loop
;Ether Input Start Function - EISFCT. Start receiver. Interface
;will generate a data wakeup when the first word of the next
;packet arrives, ignoring any packet currently passing.
EN00254> EIFIGN: SINK<- EPNTR,BUS=0,EPFCT;Reset; Called from output?
EN00272> EISFCT,TASK,:EOCDWX; [EOCDWX,EIGO] Restart rcvr
EN00226> EOCDWX: EWFCT,:EOCDWT; Return to countdown wait loop
EN00255> EISET: MAR<- EICLOC,:ESETUP; Double word reference
;Input Main Loop
;Ether Input Data Function - EIDFCT. Gate a word of data to
;the bus from the interface data buffer, increment the read ptr.
; * * * * * W A R N I N G * * * * *
;The delay from decoding EIDFCT to gating data to the bus is
;marginal. Some logic in the interface detects the situation
;(which only happens occasionally) and stops SysClk for one cycle.
;Since memory data must be available during cycle 4, and SysClk
;may stop for one cycle, this means that the MD<- EIDFCT must
;happen in cycle 3. There is a bug in this logic which occasionally
;stops the clock in the instruction following the EIDFCT, so
;the EIDFCT instruction should not be the last one of the task,
;or it may screw up someone else (such as RDRAM).
;EIDOK, EIDMOR, and EIDPST must have address bits in the pattern:
;xxx1 xxx4 xxx5
;ECBFCT is used to force an unconditional branch on NEXT7
EN00236> EIDATA: T<- ECNTR-1, BUS=0;
EN00273> MAR<- L<- EPNTR+1, EBFCT; [EIDMOR,EIDPST] What's happening
EN00244> EIDMOR: EPNTR<- L, L<- T, ECBFCT; [EIDOK,EIDPST] Guaranteed to branch
EN00241> EIDOK: MD<- EIDFCT, TASK; [EIDZ4] Read a word from the interface
EN00234> EIDZ4: ECNTR<- L, :EIDATA;
; We get to EIDPST for one of two reasons:
; (1) The buffer is full. In this case, an EBFCT (NEXT[7]) is pending.
; We want to post "full" if this is a normal data wakeup (no branch)
; but just "input done" if hardware input terminated (branch).
; (2) Hardware input terminated while the buffer was not full.
; In this case, an unconditional branch on NEXT[7] is pending, so
; we always terminate with "input done".
EN00245> EIDPST: L<- ESIDON, :EIDFUL; [EIDFUL,EPOST] Presumed to be INGONE
EN00233> EIDFUL: L<- ESIFUL, :EPOST; Input buffer overrun
;Ethernet output
;It is possible to get here due to a collision. If a collision
;happened, the interface was reset (EPFCT) to shut off the
;transmitter. EOSFCT is issued to guarantee more wakeups while
;generating the countdown. When this is done, the interface is
;again reset, without really doing an output.
EN00207> EOREST: MAR<- ELLOC; Get load
EN00274> L<- R37; Use clock as random # gen
EN00275> EPNTR<- LLSH1; Use bits [2:9]
EN00276> L<- MD,EOSFCT; L<- current load
EN00277> SH<0,ECNTR<- L; Overflowed?
EN00300> MTEMP<- LLSH1,:EOLDOK; [EOLDOK,EOLDBD]
EN00243> EOLDBD: L<- ESLOAD,:EPOST; Load overlow
EN00242> EOLDOK: L<- MTEMP+1; Write updated load
EN00301> MAR<- ELLOC;
EN00302> MTEMP<- L,TASK;
EN00303> MD<- MTEMP,:EORST1; New load = (old lshift 1) + 1
EN00304> EORST1: L<- EPNTR; Continue making random #
EN00305> EPNTR<- LRSH1;
EN00306> T<- 377;
EN00307> L<- EPNTR AND T,TASK;
EN00310> EPNTR<- L,:EORST2;
;At this point, EPNTR has 0,,random number, ENCTR has old load.
EN00311> EORST2: MAR<- EICLOC; Has an input buffer been set up?
EN00312> T<- ECNTR;
EN00313> L<- EPNTR AND T; L<- Random & Load
EN00314> SINK<- MD,BUS=0;
EN00315> ECNTR<- L,SH=0,EPFCT,:EOINPR;[EOINPR,EOINPN]
EN00154> EOINPR: EISFCT,:EOCDWT; [EOCDWT,EOCDGO] Enable in under out
EN00155> EOINPN: :EOCDWT; [EOCDWT,EOCDGO] No input.
;Countdown wait loop. MRT will generate a wakeup every
;37 usec which will decrement ECNTR. When it is zero, start
;the transmitter.
;Ether Wake Function - EWFCT. Sets a flip flop which will cause
;a wakeup to this task the next time MRT wakes up (every 37 usec).
;Wakeup is cleared when Ether task next runs. EWFCT must be
;issued in the instruction AFTER a task.
EN00250> EOCDWT: L<- 177400,EBFCT; What's happening?
EN00316> EPNTR<- L,ECBFCT,:EOCDW0;[EOCDW0,EOCDRS] Packet coming in?
EN00231> EOCDW0: L<- ECNTR-1,BUS=0,TASK,:EOCDW1; [EOCDW1,EIGO]
EN00223> EOCDW1: ECNTR<- L,EWFCT,:EOCDWT; [EOCDWT,EOCDGO]
EN00235> EOCDRS: L<- ESABRT,:EPOST; [EPOST] POST event
EN0227> EIGO: :EIFRST; [EIFRST] Input under output
;Output main loop setup
EN00251> EOCDGO: MAR<- EOCLOC; Double word reference
EN00317> EPFCT; Reset interface
EN00320> EOSFCT,:ESETUP; Start Transmitter
;Ether Output Start Function - EOSFCT. The interface will generate
;a burst of data requests until the interface buffer is full or the
;memory buffer is empty, wait for silence on the Ether, and begin
;transmitting. Thereafter it will request a word every 5.44 us.
;Ether Output Data Function - EODFCT. Copy the bus into the
;interface data buffer, increment the write pointer, clears wakeup
;request if the buffer is now nearly full (one slot available).
;Output main loop
EN00232> EODATA: L<- MAR<- EPNTR+1,EBFCT; What's happening?
EN00321> T<- ECNTR-1,BUS=0,:EODOK; [EODOK,EODPST,EODCOL,EODUGH]
EN00201> EODOK: EPNTR<- L,L<- T,:EODMOR; [EODMOR,EODEND]
EN00156> EODMOR: ECNTR<- L,TASK;
EN00322> EODFCT<- MD,:EODATA; Output word to transmitter
EN00205> EODPST: L<- ESABRT,:EPOST; [EPOST] POST event
EN00211> EODCOL: EPFCT,:EOREST; [EOREST] Collision
EN00215> EODUGH: L<- ESABRT,:EPOST; [EPOST] POST + Collision
;Ether EOT Function - EEFCT. Stop generating output data wakeups,
;the interface has all of the packet. When the data buffer runs
;dry, the interface will append the CRC and then generate an
;OUTGONE post wakeup.
EN00157> EODEND: EEFCT; Disable data wakeups
EN00323> TASK; Wait for EEFCT to take
EN00324> :EOEOT; Wait for Outgone
;Output completion. We are waiting for the interface buffer to
;empty, and the interface to generate an OUTGONE Post wakeup.
EN00325> EOEOT: EBFCT; What's happening?
EN00326> :EOEOK; [EOEOK,EOEPST,EOECOL,EOEUGH]
EN00202> EOEOK: L<- ESNEVR,:EPOST; Runaway Transmitter. Never Never.
EN00206> EOEPST: L<- ESODON,:EPOST; POST event. Output done
EN00212> EOECOL: EPFCT,:EOREST; Collision
EN00216> EOEUGH: L<- ESABRT,:EPOST; POST + Collision
;Memory Refresh Task,
;Mouse Handler,
;EIA Handler,
;Interval Timer,
;Calender Clock, and
;part of the cursor.
!17,20,TX0,TX6,TX3,TX2,TX8,TX5,TX1,TX7,TX4,,,,,,,;
!1,2,DOTIMER,NOTIMER;
!1,2,NOTIMERINT,TIMERINT;
!1,2,DOCUR,NOCUR;
!1,2,SHOWC,WAITC;
!1,2,SPCHK,NOSPCHK;
!1,2,NOCLK,CLOCK;
!1,1,MRTLAST;
!1,2,CNOTLAST,CLAST;
$CLOCKTEMP $R11;
$REFIIMSK $7777;
; * * * A T T E N T I O N * * *
;There are two versions of the Memory refresh code:
; AltoIIMRT4K.mu for refreshing 4K chips
; AltoIIMRT16K.mu for refreshing 16K chips
;You must name one or the other 'AltoIIMRT.mu'.
;I suggest the following convention for naming the resulting .MB file:
; AltoIICode3.MB for the 4K version
; AltoIICode3XM.MB for the 16K version
#AltoIIMRT.mu;
MR00355> CLOCK: MAR<- CLOCKLOC; R37 OVERFLOWED.
MR00412> NOP;
MR00413> L<- MD+1; INCREMENT CLOCK IM MEMORY
MR00414> MAR<- CLOCKLOC;
MR00415> MTEMP<- L, TASK;
MR00416> MD<- MTEMP, :NOCLK;
MR00334> DOCUR: L<- T<- YPOS; CHECK FOR VISIBLE CURSOR ON THIS SCAN
MR00417> SH<0, L<- 20-T-1; ***x13 change: the constant 20 was 17
MR00420> SH<0, L<- 2+T, :SHOWC; [SHOWC,WAITC]
MR00337> WAITC: YPOS<- L, L<- 0, TASK, :MRTLAST; SQUASHES PENDING BRANCH
MR00336> SHOWC: MAR<- CLOCKLOC+T+1, :CNOTLAST;
MR00356> CNOTLAST: T<- CURX, :CURF;
MR00357> CLAST: T<- 0;
MR00421> CURF: YPOS<- L, L<- T;
MR00422> CURX< L;
MR00423> L<- MD, TASK;
MR00424> CURDATA<- L, :MRT;
;AFTER THIS DISPATCH, T WILL CONTAIN XCHANGE, L WILL CONTAIN YCHANGE-1
MR00346> TX1: L<- T<- ONE +T, :M00; Y=0, X=1
MR00343> TX2: L<- T<- ALLONES, :M00; Y=0, X=-1
MR00342> TX3: L<- T<- 0, :M00; Y=1, X=0
MR00350> TX4: L<- T<- ONE AND T, :M00; Y=1, X=1
MR00345> TX5: L<- T<- ALLONES XOR T, :M00; Y=1, X=-1
MR00341> TX6: T<- 0, :M00; Y=-1, X=0
MR00347> TX7: T<- ONE, :M00; Y=-1, X=1
MR00344> TX8: T<- ALLONES, :M00; Y=-1, X=-1
MR00425> M00: MAR<- MOUSELOC; START THE FETCH OF THE COORDINATES
MR00426> MTEMP<- L; YCHANGE -1
MR00427> L<- MD+ T; X+ XCHANGE
MR00430> T<- MD; Y
MR00431> T<- MTEMP+ T+1; Y+ (YCHANGE-1) + 1
MR00432> MTEMP<- L, L<- T;
MR00433> MAR<- MOUSELOC; NOW RESTORE THE UPDATED COORDINATES
MR00434> CLOCKTEMP<- L;
MR00435> MD<- MTEMP, TASK;
MR00436> MD<- CLOCKTEMP, :MRTA;
;CURSOR TASK
;Cursor task specific functions
$XPREG $L026010,000000,124000; F2 = 10
$CSR $L026011,000000,124000; F2 = 11
CU00012> CURT: XPREG<- CURX, TASK;
CU00437> CSR<- CURDATA, :CURT;
;PREDEFINITION FOR PARITY TASK.
;THE CODE IS AT THE END OF THE FILE
!17,20,PR0,,PR2,PR3,PR4,PR5,PR6,PR7,PR8,,,,,,,;
;NOVA EMULATOR
$SAD $R5;
$PC $R6; USED BY MEMORY INIT
!7,10,Q0,Q1,Q2,Q3,Q4,Q5,Q6,Q7;
!1,2,FINSTO,INCPC;
!1,2,EReRead,FINJMP; ***X21 addition.
!1,2,EReadDone,EContRead; ***X21 addition.
!1,2,EtherBoot,DiskBoot; ***X21 addition.
EM00000> NOVEM: IR<-L<-MAR<-0, :INXB,SAD<- L; LOAD SAD TO ZERO THE BUS. STORE PC AT 0
EM00460> Q0: L<- ONE, :INXA; EXECUTED TWICE
EM00461> Q1: L<- TOTUWC, :INXA;
EM00462> Q2: L<-402, :INXA; FIRST READ HEADER INTO 402, THEN
EM00463> Q3: L<- 402, :INXA; STORE LABEL AT 402
EM00464> Q4: L<- ONE, :INXA; STORE DATA PAGE STARTING AT 1
EM00465> Q5: L<-377+1, :INXE; Store Ethernet Input Buffer Length ***X21.
EM00466> Q6: L<-ONE, :INXE; Store Ethernet Input Buffer Pointer ***X21.
EM00467> Q7: MAR<- DASTART; CLEAR THE DISPLAY POINTER
EM00441> L<- 0;
EM00451> R37<- L;
EM00472> MD<- 0;
EM00473> MAR<- 177034; FETCH KEYBOARD
EM00474> L<- 100000;
EM00475> NWW<- L, T<- 0-1;
EM00476> L<- MD XOR T, BUSODD; *** X21 change.
EM00477> MAR<- BDAD, :EtherBoot; [EtherBoot, DiskBoot] *** X21 change.
; BOOT DISK ADDRESS GOES IN LOCATION 12
EM00471> DiskBoot: SAD<- L, L<- 0+1;
EM00500> MD<- SAD;
EM00501> MAR<- KBLKADR, :FINSTO;
; Ethernet boot section added in X21.
$NegBreathM1 $177175;
$EthNovaGo $3; First data location of incoming packet
EM00470> EtherBoot: L<-EthNovaGo, :EReRead; [EReRead, FINJMP]
EM00454> EReRead:MAR<- EHLOC; Set the host address to 377 for breath packets
EM00502> TASK;
EM00503> MD<- 377;
EM00504> MAR<- EPLOC; Zero the status word and start 'er up
EM00505> SINK<- 2, STARTF;
EM00506> MD <- 0;
EM00457> EContRead: MAR<- EPLOC; See if status is still 0
EM00507> T<- 377; Status for correct read
EM00510> L<- MD XOR T, TASK, BUS=0;
EM00511> SAD<- L, :EReadDone; [EReadDone, EContRead]
EM00456> EReadDone: MAR<- 2; Check the packet type
EM00512> T<- NegBreathM1; -(Breath-of-life)-1
EM00513> T<-MD+T+1;
EM00514> L<-SAD OR T;
EM00515> SH=0, :EtherBoot;
; SUBROUTINE USED BY INITIALIZATION TO SET UP BLOCKS OF MEMORY
$EIOffset $576;
EM00516> INXA: T<-ONE, :INXCom; ***X21 change.
EM00517> INXE: T<-EIOffset, :INXCom; ***X21 addition.
EM00520> INXCom: MAR<-T<-IR<- SAD+T; *** X21 addition.
EM00521> PC<- L, L<- 0+T+1; *** X21 change.
EM00522> INXB: SAD<- L; **NB (JDersch 9/14 -- this is actually MD<-PC !)
EM00523> SINK<- DISP, BUS,TASK;
EM00524> SAD<- L, :Q0;
;REGISTERS USED BY NOVA EMULATOR
$AC0 $R3; AC'S ARE BACKWARDS BECAUSE THE HARDWARE SUPPLIES THE
$AC1 $R2; COMPLEMENT ADDRESS WHEN ADDRESSING FROM IR
$AC2 $R1;
$AC3 $R0;
$XREG $R7;
;PREDEFINITIONS FOR NOVA
!17,20,GETAD,G1,G2,G3,G4,G5,G6,G7,G10,G11,G12,G13,G14,G15,G16,G17;
!17,20,XCTAB,XJSR,XISZ,XDSZ,XLDA,XSTA,CONVERT,,,,,,,,,;
!3,4,SHIFT,SH1,SH2,SH3;
!1,2,MAYBE,NOINT;
!1,2,DOINT,DIS0;
!1,2,SOMEACTIVE,NOACTIVE;
!1,2,IEXIT,NIEXIT;
!17,1,ODDCX;
!1,2,EIR0,EIR1;
!7,1,INTCODE;
!1,2,INTSOFF,INTSON; ***X21 addition for DIRS
!7,10,EMCYCRET,RAMCYCRET,CYX2,CYX3,CYX4,CONVCYCRET,,;
!7,2,MOREBLT,FINBLT;
!1,2,DOIT,DISABLED;
; ALL INSTRUCTIONS RETURN TO START WHEN DONE
EM00020> START: T<- MAR<-PC+SKIP;
EM00525> START1: L<- NWW, BUS=0; BUS# 0 MEANS DISABLED OR SOMETHING TO DO
EM00576> :MAYBE, SH<0, L<- 0+T+1; SH<0 MEANS DISABLED
EM00526> MAYBE: PC<- L, L<- T, :DOINT;
EM00527> NOINT: PC<- L, :DIS0;
EM00534> DOINT: MAR<- WWLOC, :INTCODE; TRY TO CAUSE AN INTERRUPT
;DISPATCH ON FUNCTION FIELD IF ARITHMETIC INSTRUCTION,
;OTHERWISE ON INDIRECT BIT AND INDEX FIELD
EM00535> DIS0: L<- T<- IR<- MD; SKIP CLEARED HERE
;DISPATCH ON SHIFT FIELD IF ARITHMETIC INSTRUCTION,
;OTHERWISE ON THE INDIRECT BIT OR IR[3-7]
EM00612> DIS1: T<- ACSOURCE, :GETAD;
;GETAD MUST BE 0 MOD 20
EM00540> GETAD: T<- 0, :DOINS; PAGE 0
EM00541> G1: T<- PC -1, :DOINS; RELATIVE
EM00542> G2: T<- AC2, :DOINS; AC2 RELATIVE
EM00543> G3: T<- AC3, :DOINS; AC3 RELATIVE
EM00544> G4: T<- 0, :DOINS; PAGE 0 INDIRECT
EM00545> G5: T<- PC -1, :DOINS; RELATIVE INDIRECT
EM00546> G6: T<- AC2, :DOINS; AC2 RELATIVE INDIRECT
EM00547> G7: T<- AC3, :DOINS; AC3 RELATIVE INDIRECT
EM00550> G10: L<- 0-T-1, TASK, :SHIFT; COMPLEMENT
EM00551> G11: L<- 0-T, TASK, :SHIFT; NEGATE
EM00552> G12: L<- 0+T, TASK, :SHIFT; MOVE
EM00553> G13: L<- 0+T+1, TASK, :SHIFT; INCREMENT
EM00554> G14: L<- ACDEST-T-1, TASK, :SHIFT; ADD COMPLEMENT
EM00555> G15: L<- ACDEST-T, TASK, :SHIFT; SUBTRACT
EM00556> G16: L<- ACDEST+T, TASK, :SHIFT; ADD
EM00557> G17: L<- ACDEST AND T, TASK, :SHIFT;
EM00530> SHIFT: DNS<- L LCY 8, :START; SWAP BYTES
EM00531> SH1: DNS<- L RSH 1, :START; RIGHT 1
EM00532> SH2: DNS<- L LSH 1, :START; LEFT 1
EM00533> SH3: DNS<- L, :START; NO SHIFT
EM00060> DOINS: L<- DISP + T, TASK, :SAVAD, IDISP; DIRECT INSTRUCTIONS
EM00061> DOIND: L<- MAR<- DISP+T; INDIRECT INSTRUCTIONS
EM00613> XREG<- L;
EM00614> L<- MD, TASK, IDISP, :SAVAD;
EM00102> BRI: L<- MAR<- PCLOC ;INTERRUPT RETURN BRANCH
EM00615> BRI0: T<- 77777;
EM00616> L<- NWW AND T, SH < 0;
EM00617> NWW<- L, :EIR0; BOTH EIR AND BRI MUST CHECK FOR INTERRUPT
; REQUESTS WHICH MAY HAVE COME IN WHILE
; INTERRUPTS WERE OFF
EM00572> EIR0: L<- MD, :DOINT;
EM00573> EIR1: L<- PC, :DOINT;
;***X21 addition
; DIRS - 61013 - Disable Interrupts and Skip if they were On
EM00113> DIRS: T<-100000;
EM00620> L<-NWW AND T;
EM00621> L<-PC+1, SH=0;
; DIR - 61000 - Disable Interrupts
EM00100> DIR: T<- 100000, :INTSOFF;
EM00574> INTSOFF: L<- NWW OR T, TASK, :INTZ;
EM00575> INTSON: PC<-L, :INTSOFF;
;EIR - 61001 - Enable Interrupts
EM00101> EIR: L<- 100000, :BRI0;
;SIT - 61007 - Start Interval Timer
EM00107> SIT: T<- AC0;
EM00622> L<- R37 OR T, TASK;
EM00623> R37<- L, :START;
EM00624> FINJSR: L<- PC;
EM00625> AC3<- L, L<- T, TASK;
EM00455> FINJMP: PC<- L, :START;
EM00626> SAVAD: SAD<- L, :XCTAB;
;JSRII - 64400 - JSR double indirect, PC relative. Must have X=1 in opcode
;JSRIS - 65000 - JSR double indirect, AC2 relative. Must have X=2 in opcode
EM00064> JSRII: MAR<- DISP+T; FIRST LEVEL
EM00627> IR<- JSRCX; <JSR 0>
EM00630> T<- MD, :DOIND; THE IR<- INSTRUCTION WILL NOT BRANCH
;TRAP ON UNIMPLEMENTED OPCODES. SAVES PC AT
;TRAPPC, AND DOES A JMP@ TRAPVEC ! OPCODE.
EM00077> TRAP: XREG<- L LCY 8; THE INSTRUCTION
EM00037> TRAP1: MAR<- TRAPPC;***X13 CHANGE: TAG 'TRAP1' ADDED
EM00631> IR<- T<- 37;
EM00632> MD<- PC;
EM00633> T<- XREG.T;
EM00634> T<- TRAPCON+T+1, :DOIND; T NOW CONTAINS 471+OPCODE
; THIS WILL DO JMP@ 530+OPCODE
;***X21 CHANGE: ADDED TAG RAMTRAP
EM00076> RAMTRAP: SWMODE, :TRAP;
; Parameterless operations come here for dispatch.
!1,2,NPNOTRAP,NPTRAP;
EM00063> NOPAR: XREG<-L LCY 8; ***X21 change. Checks < 27.
EM00635> T<-27; ***IIX3. Greatest defined op is 26.
EM00640> L<-DISP-T;
EM00641> ALUCY;
EM00642> SINK<-DISP, SINK<-X37, BUS, TASK, :NPNOTRAP;
EM00636> NPNOTRAP: :DIR;
EM00637> NPTRAP: :TRAP1;
;***X21 addition for debugging w/ expanded DISP Prom
EM00065> U5: :RAMTRAP;
EM00066> U6: :RAMTRAP;
EM00067> U7: :RAMTRAP;
;MAIN INSTRUCTION TABLE. GET HERE:
; (1) AFTER AN INDIRECTION
; (2) ON DIRECT INSTRUCTIONS
EM00560> XCTAB: L<- SAD, TASK, :FINJMP; JMP
EM00561> XJSR: T<- SAD, :FINJSR; JSR
EM00562> XISZ: MAR<- SAD, :ISZ1; ISZ
EM00563> XDSZ: MAR<- SAD, :DSZ1; DSZ
EM00564> XLDA: MAR<- SAD, :FINLOAD; LDA 0-3
EM00565> XSTA: MAR<- SAD; /*NORMAL
EM00643> XSTA1: L<- ACDEST, :FINSTO; /*NORMAL
; BOUNDS-CHECKING VERSION OF STORE
; SUBST ";**<CR>" TO "<CR>;**" TO ENABLE THIS CODE:
;** !1,2,XSTA1,XSTA2;
;** !1,2,DOSTA,TRAPSTA;
;**XSTA: MAR<- 10; LOCS 10,11 CONTAINS HI,LO BOUNDS
;** T<- SAD
;** L<- MD-T; HIGHBOUND-ADDR
;** T<- MD, ALUCY;
;** L<- SAD-T, :XSTA1; ADDR-LOWBOUND
;**XSTA1: TASK, :XSTA3;
;**XSTA2: ALUCY, TASK;
;**XSTA3: L<- 177, :DOSTA;
;**TRAPSTA: XREG<- L, :TRAP1; CAUSE A SWAT
;**DOSTA: MAR<- SAD; DO THE STORE NORMALLY
;** L<- ACDEST, :FINSTO;
;**
EM00644> DSZ1: T<- ALLONES, :FINISZ;
EM00645> ISZ1: T<- ONE, :FINISZ;
EM00452> FINSTO: SAD<- L,TASK;
EM00646> FINST1: MD<-SAD, :START;
EM00647> FINLOAD: NOP;
EM00650> LOADX: L<- MD, TASK;
EM00651> LOADD: ACDEST<- L, :START;
EM00652> FINISZ: L<- MD+T;
EM00653> MAR<- SAD, SH=0;
EM00654> SAD<- L, :FINSTO;
EM00453> INCPC: MD<- SAD;
EM00655> L<- PC+1, TASK;
EM00656> PC<- L, :START;
;DIVIDE. THIS DIVIDE IS IDENTICAL TO THE NOVA DIVIDE EXCEPT THAT
;IF THE DIVIDE CANNOT BE DONE, THE INSTRUCTION FAILS TO SKIP, OTHERWISE
;IT DOES. CARRY IS UNDISTURBED.
!1,2,DODIV,NODIV;
!1,2,DIVL,ENDDIV;
!1,2,NOOVF,OVF;
!1,2,DX0,DX1;
!1,2,NOSUB,DOSUB;
EM00121> DIV: T<- AC2;
EM00657> DIVX: L<- AC0 - T; DO THE DIVIDE ONLY IF AC2>AC0
EM00672> ALUCY, TASK, SAD<- L, L<- 0+1;
EM00673> :DODIV, SAD<- L LSH 1; SAD<- 2. COUNT THE LOOP BY SHIFTING
EM00661> NODIV: :FINBLT; ***X21 change.
EM00660> DODIV: L<- AC0, :DIV1;
EM00662> DIVL: L<- AC0;
EM00674> DIV1: SH<0, T<- AC1; WILL THE LEFT SHIFT OF THE DIVIDEND OVERFLOW?
EM00675> :NOOVF, AC0<- L MLSH 1, L<- T<- 0+T; L<- AC1, T<- 0
EM00665> OVF: AC1<- L LSH 1, L<- 0+INCT, :NOV1; L<- 1. SHIFT OVERFLOWED
EM00664> NOOVF: AC1<- L LSH 1 , L<- T; L<- 0. SHIFT OK
EM00676> NOV1: T<- AC2, SH=0;
EM00677> L<- AC0-T, :DX0;
EM00667> DX1: ALUCY; DO THE TEST ONLY IF THE SHIFT DIDN'T OVERFLOW. IF
; IT DID, L IS STILL CORRECT, BUT THE TEST WOULD GO
; THE WRONG WAY.
EM00700> :NOSUB, T<- AC1;
EM00666> DX0: :DOSUB, T<- AC1;
EM00671> DOSUB: AC0<- L, L<- 0+INCT; DO THE SUBTRACT
EM00701> AC1<- L; AND PUT A 1 IN THE QUOTIENT
EM00670> NOSUB: L<- SAD, BUS=0, TASK;
EM00702> SAD<- L LSH 1, :DIVL;
EM00663> ENDDIV: L<- PC+1, TASK, :DOIT; ***X21 change. Skip if divide was done.
;MULTIPLY. THIS IS AN EXACT EMULATION OF NOVA HARDWARE MULTIPLY.
;AC2 IS THE MULTIPLIER, AC1 IS THE MULTIPLICAND.
;THE PRODUCT IS IN AC0 (HIGH PART), AND AC1 (LOW PART).
;PRECISELY: AC0,AC1 <- AC1*AC2 + AC0
!1,2,DOMUL,NOMUL;
!1,2,MPYL,MPYA;
!1,2,NOADDIER,ADDIER;
!1,2,NOSPILL,SPILL;
!1,2,NOADDX,ADDX;
!1,2,NOSPILLX,SPILLX;
EM00120> MUL: L<- AC2-1, BUS=0;
EM00703> MPYX: XREG<-L,L<- 0, :DOMUL; GET HERE WITH AC2-1 IN L. DON'T MUL IF AC2=0
EM00704> DOMUL: TASK, L<- -10+1;
EM00720> SAD<- L; COUNT THE LOOP IN SAD
EM00706> MPYL: L<- AC1, BUSODD;
EM00721> T<- AC0, :NOADDIER;
EM00710> NOADDIER: AC1<- L MRSH 1, L<- T, T<- 0, :NOSPILL;
EM00711> ADDIER: L<- T<- XREG+INCT;
EM00722> L<- AC1, ALUCY, :NOADDIER;
EM00713> SPILL: T<- ONE;
EM00712> NOSPILL: AC0<- L MRSH 1;
EM00723> L<- AC1, BUSODD;
EM00724> T<- AC0, :NOADDX;
EM00714> NOADDX: AC1<- L MRSH 1, L<- T, T<- 0, :NOSPILLX;
EM00715> ADDX: L<- T<- XREG+ INCT;
EM00725> L<- AC1,ALUCY, :NOADDX;
EM00717> SPILLX: T<- ONE;
EM00716> NOSPILLX: AC0<- L MRSH 1;
EM00726> L<- SAD+1, BUS=0, TASK;
EM00727> SAD<- L, :MPYL;
EM00705> NOMUL: T<- AC0;
EM00730> AC0<- L, L<- T, TASK; CLEAR AC0
EM00731> AC1<- L; AND REPLACE AC1 WITH AC0
EM00707> MPYA: :FINBLT; ***X21 change.
;CYCLE AC0 LEFT BY DISP MOD 20B, UNLESS DISP=0, IN WHICH
;CASE CYCLE BY AC1 MOD 20B
;LEAVES AC1=CYCLE COUNT-1 MOD 20B
$CYRET $R5; Shares space with SAD.
$CYCOUT $R7; Shares space with XREG.
!1,2,EMCYCX,ACCYCLE;
!1,1,Y1;
!1,1,Y2;
!1,1,Y3;
!1,1,Z1;
!1,1,Z2;
!1,1,Z3;
EM00062> EMCYCLE: L<- DISP, SINK<- X17, BUS=0; CONSTANT WITH BS=7
EM00734> CYCP: T<- AC0, :EMCYCX;
EM00733> ACCYCLE: T<- AC1;
EM00736> L<- 17 AND T, :CYCP;
EM00732> EMCYCX: CYCOUT<-L, L<-0, :RETCYCX;
EM00022> RAMCYCX: CYCOUT<-L, L<-0+1;
EM00740> RETCYCX: CYRET<-L, L<-0+T;
EM00742> SINK<-CYCOUT, BUS;
EM00744> TASK, :L0;
;TABLE FOR CYCLE
EM00174> R4: CYCOUT<- L MRSH 1;
EM00741> Y3: L<- T<- CYCOUT, TASK;
EM00175> R3X: CYCOUT<- L MRSH 1;
EM00737> Y2: L<- T<- CYCOUT, TASK;
EM00176> R2X: CYCOUT<- L MRSH 1;
EM00735> Y1: L<- T<- CYCOUT, TASK;
EM00177> R1X: CYCOUT<- L MRSH 1, :ENDCYCLE;
EM00164> L4: CYCOUT<- L MLSH 1;
EM00747> Z3: L<- T<- CYCOUT, TASK;
EM00163> L3: CYCOUT<- L MLSH 1;
EM00745> Z2: L<- T<- CYCOUT, TASK;
EM00162> L2: CYCOUT<- L MLSH 1;
EM00743> Z1: L<- T<- CYCOUT, TASK;
EM00161> L1: CYCOUT<- L MLSH 1, :ENDCYCLE;
EM00160> L0: CYCOUT<- L, :ENDCYCLE;
EM00164> L8: CYCOUT<- L LCY 8, :ENDCYCLE;
EM00165> L7: CYCOUT<- L LCY 8, :Y1;
EM00166> L6: CYCOUT<- L LCY 8, :Y2;
EM00165> L5: CYCOUT<- L LCY 8, :Y3;
EM00171> R7: CYCOUT<- L LCY 8, :Z1;
EM00172> R6: CYCOUT<- L LCY 8, :Z2;
EM00173> R5: CYCOUT<- L LCY 8, :Z3;
EM00746> ENDCYCLE: SINK<- CYRET, BUS, TASK;
EM00750> :EMCYCRET;
EM00600> EMCYCRET: L<-YCOUT, TASK, :LOADD;
EM00601> RAMCYCRET: T<-PC, BUS, SWMODE, :TORAM;
; Scan convert instruction for characters. Takes DWAX (Destination
; word address)-NWRDS in AC0, and a pointer to a .AL-format font
; in AC3. AC2+displacement contains a pointer to a two-word block
; containing NWRDS and DBA (Destination Bit Address).
$XH $R10;
$DWAX $R35;
$MASK $R36;
!1,2,HDLOOP,HDEXIT;
!1,2,MERGE,STORE;
!1,2,NFIN,FIN;
!17,2,DOBOTH,MOVELOOP;
EM00566> CONVERT: MAR<-XREG+1; Got here via indirect mechanism which
; left first arg in SAD, its address in XREG.
EM00751> T<-17;
EM00760> L<-MD AND T;
EM00761> T<-MAR<-AC3;
EM00762> AC1<-L; AC1<-DBA&#17
EM00763> L<-MD+T, TASK;
EM00764> AC3<-L; AC3<-Character descriptor block address(Char)
EM00765> MAR<-AC3+1;
EM00766> T<-177400;
EM00767> IR<-L<-MD AND T; IR<-XH
EM00770> XH<-L LCY 8, :ODDCX; XH register temporarily contains HD
EM00577> ODDCX: L<-AC0, :HDENTER;
EM00752> HDLOOP: T<-SAD; (really NWRDS)
EM00771> L<-DWAX+T;
EM00772> HDENTER: DWAX<-L; DWAX <- AC0+HD*NWRDS
EM00773> L<-XH-1, BUS=0, TASK;
EM00774> XH<-L, :HDLOOP;
EM00753> HDEXIT: T<-MASKTAB;
EM00775> MAR<-T<-AC1+T; Fetch the mask.
EM01000> L<-DISP;
EM01001> XH<-L; XH register now contains XH
EM01002> L<-MD;
EM01003> MASK<-L, L<-0+T+1, TASK;
EM01004> AC1<-L; ***X21. AC1 <- (DBA&#17)+1
EM01005> L<-5; ***X21. Calling conventions changed.
EM01006> IR<-SAD, TASK;
EM01007> CYRET<-L, :MOVELOOP; CYRET<-CALL5
EM00777> MOVELOOP: L<-T<-XH-1, BUS=0;
EM01010> MAR<-AC3-T-1, :NFIN; Fetch next source word
EM00756> NFIN: XH<-L;
EM01011> T<-DISP; (really NWRDS)
EM01012> L<-DWAX+T; Update destination address
EM01013> T<-MD;
EM01014> SINK<-AC1, BUS;
EM01015> DWAX<-L, L<-T, TASK, :L0; Call Cycle subroutine
EM00605> CONVCYCRET: MAR<-DWAX;
EM01016> T<-MASK, BUS=0;
EM01017> T<-CYCOUT.T, :MERGE; Data for first word. If MASK=0
; then store the word rather than
; merging, and do not disturb the
; second word.
EM00754> MERGE: L<-XREG AND NOT T; Data for second word.
EM01020> T<-MD OR T; First word now merged,
EM01021> XREG<-L, L<-T;
EM01022> MTEMP<-L;
EM01023> MAR<-DWAX; restore it.
EM01024> SINK<-XREG, BUS=0, TASK;
EM01025> MD<-MTEMP, :DOBOTH; XREG=0 means only one word
; is involved.
EM00776> DOBOTH: MAR<-DWAX+1;
EM01026> T<-XREG;
EM01027> L<-MD OR T;
EM01030> MAR<-DWAX+1;
EM01031> XREG<-L, TASK; ***X21. TASK added.
EM00755> STORE: MD<-XREG, :MOVELOOP;
EM00757> FIN: L<-AC1-1; ***X21. Return AC1 to DBA&#17.
EM01032> AC1<-L; *** ... bletch ...
EM01033> IR<-SH3CONST;
EM01034> L<-MD, TASK, :SH1;
;RCLK - 61003 - Read the Real Time Clock into AC0,AC1
EM00103> RCLK: MAR<- CLOCKLOC;
EM01035> L<- R37;
EM01036> AC1<- L, :LOADX;
;SIO - 61004 - Put AC0 on the bus, issue STARTF to get device attention,
;Read Host address from Ethernet interface into AC0.
EM0104> SIO: L<- AC0, STARTF;
EM1037> T<- 77777; ***X21 sets AC0[0] to 0
EM1040> L<- RSNF AND T;
EM1041> LTOAC0: AC0<- L, TASK, :TOSTART;
;EngNumber is a constant returned by VERS that contains a discription
;of the Alto and it's Microcode. The composition of EngNumber is:
; bits 0-3 Alto engineering number
; bits 4-7 Alto build
; bits 8-15 Version number of Microcode
;Use of the Alto Build number has been abandoned.
;the engineering number (EngNumber) is in the MRT files because it
; it different for Altos with and without Extended memory.
EM00114> VERS: T<- EngNumber; ***V3 change
EM01042> L<- 3+T, :LTOAC0; ***V3 change
;XMLDA - Extended Memory Load Accumulator.
; AC0 <- @AC1 in the alternate bank
EM00125> XMLDA: XMAR<- AC1, :FINLOAD; ***V3 change
;XMSTA - Extended Memory Store Accumulator
; @AC1 <- AC0 in the alternate bank
EM00126> XMSTA: XMAR<- AC1, :XSTA1; ***V3 change
;BLT - 61005 - Block Transfer
;BLKS - 61006 - Block Store
; Accepts in
; AC0/ BLT: Address of first word of source block-1
; BLKS: Data to be stored
; AC1/ Address of last word of destination block
; AC3/ NEGATIVE word count
; Leaves
; AC0/ BLT: Address of last word of source block+1
; BLKS: Unchanged
; AC1/ Unchanged
; AC2/ Unchanged
; AC3/ 0
; These instructions are interruptable. If an interrupt occurs,
; the PC is decremented by one, and the ACs contain the intermediate
; so the instruction can be restarted when the interrupt is dismissed.
!1,2,PERHAPS, NO;
EM00105> BLT: L<- MAR<- AC0+1;
EM01043> AC0<- L;
EM01046> L<- MD, :BLKSA;
EM00106> BLKS: L<- AC0;
EM01047> BLKSA: T<- AC3+1, BUS=0;
EM01050> MAR<- AC1+T, :MOREBLT;
EM00606> MOREBLT: XREG<- L, L<- T;
EM01051> AC3<- L, TASK;
EM01052> MD<- XREG; STORE
EM01053> L<- NWW, BUS=0; CHECK FOR INTERRUPT
EM01054> SH<0, :PERHAPS, L<- PC-1; Prepare to back up PC.
EM01045> NO: SINK<- DISP, SINK<- M7, BUS, :DISABLED;
EM01044> PERHAPS: SINK<- DISP, SINK<- M7, BUS, :DOIT;
EM00610> DOIT: PC<-L, :FINBLT; ***X21. Reset PC, terminate instruction.
EM00611> DISABLED: :DIR; GOES TO BLT OR BLKS
EM00607> FINBLT: T<-777; ***X21. PC in [177000-177777] means Ram return
EM01055> L<-PC+T+1;
EM01056> L<-PC AND T, TASK, ALUCY;
EM01057> TOSTART: XREG<-L, :START;
EM00021> RAMRET: T<-XREG, BUS, SWMODE;
EM01060> TORAM: :NOVEM;
;PARAMETERLESS INSTRUCTIONS FOR DIDDLING THE WCS.
;JMPRAM - 61010 - JUMP TO THE RAM ADDRESS SPECIFIED BY AC1
EM00110> JMPR: T<-AC1, BUS, SWMODE, :TORAM;
;RDRAM - 61011 - READ THE RAM WORD ADDRESSED BY AC1 INTO AC0
EM00111> RDRM: T<- AC1, RDRAM;
EM01061> L<- ALLONES, TASK, :LOADD;
;WRTRAM - 61012 - WRITE AC0,AC3 INTO THE RAM LOCATION ADDRESSED BY AC1
EM00112> WTRM: T<- AC1;
EM01062> L<- AC0, WRTRAM;
EM01063> L<- AC3, :FINBLT;
;DOUBLE WORD INSTRUCTIONS
;DREAD - 61015
; AC0<- rv(AC3); AC1<- rv(AC3 xor 1)
EM00115> DREAD: MAR<- AC3; START MEMORY CYCLE
EM01064> NOP; DELAY
EM01065> DREAD1: L<- MD; FIRST READ
EM01066> T<-MD; SECOND READ
EM01067> AC0<- L, L<-T, TASK; STORE MSW
EM01070> AC1<- L, :START; STORE LSW
;DWRITE - 61016
; rv(AC3)<- AC0; rv(AC3 xor 1)<- AC1
EM00116> DWRITE: MAR<- AC3; START MEMORY CYCLE
EM01071> NOP; DELAY
EM01072> MD<- AC0, TASK; FIRST WRITE
EM01073> MD<- AC1, :START; SECOND WRITE
;DEXCH - 61017
; t<- rv(AC3); rv(AC3)<- AC0; AC0<- t
; t<- rv(AC3 xor 1); rv(AC3 xor 1)<- AC1; AC1<- t
EM00117> DEXCH: MAR<- AC3; START MEMORY CYCLE
EM01074> NOP; DELAY
EM01075> MD<- AC0; FIRST WRITE
EM01076> MD<- AC1,:DREAD1; SECOND WRITE, GO TO READ
;DIOGNOSE INSTRUCTIONS
;DIOG1 - 61022
; Hamming Code<- AC2
; rv(AC3)<- AC0; rv(AC3 xor 1)<- AC1
EM00122> DIOG1: MAR<- ERRCTRL; START WRITE TO ERROR CONTROL
EM01077> NOP; DELAY
EM01100> MD<- AC2,:DWRITE; WRITE HAMMING CODE, GO TO DWRITE
;DIOG2 - 61023
; rv(AC3)<- AC0
; rv(AC3)<- AC0 xor AC1
EM00123> DIOG2: MAR<- AC3; START MEMORY CYCLE
EM01101> T<- AC0; SETUP FOR XOR
EM01102> L<- AC1 XORT; DO XOR
EM01103> MD<- AC0; FIRST WRITE
EM01104> MAR<- AC3; START MEMORY CYCLE
EM01105> AC0<- L, TASK; STORE XOR WORD
EM01106> MD<- AC0, :START; SECOND WRITE
;INTERRUPT SYSTEM. TIMING IS 0 CYCLES IF DISABLED, 18 CYCLES
;IF THE INTERRUPTING CHANEL IS INACTIVE, AND 36+6N CYCLES TO CAUSE
;AN INTERRUPT ON CHANNEL N
EM00567> INTCODE:PC<- L, IR<- 0;
EM01107> T<- NWW;
EM01110> T<- MD OR T;
EM01111> L<- MD AND T;
EM01112> SAD<- L, L<- T, SH=0; SAD HAD POTENTIAL INTERRUPTS
EM01113> NWW<- L, L<- 0+1, :SOMEACTIVE; NWW HAS NEW WW
EM00537> NOACTIVE: MAR<- WWLOC; RESTORE WW TO CORE
EM01114> L<- SAD; AND REPLACE IT WITH SAD IN NWW
EM01115> MD<- NWW, TASK;
EM01116> INTZ: NWW<- L, :START;
EM00536> SOMEACTIVE: MAR<- PCLOC; STORE PC AND SET UP TO FIND HIGHEST PRIORITY REQUEST
EM01117> XREG<- L, L<- 0;
EM01120> MD<- PC, TASK;
EM01121> ILPA: PC<- L;
EM01122> ILP: T<- SAD;
EM01123> L<- T<- XREG AND T;
EM01124> SH=0, L<- T, T<- PC;
EM01125> :IEXIT, XREG<- L LSH 1;
EM00571> NIEXIT: L<- 0+T+1, TASK, :ILPA;
EM00570> IEXIT: MAR<- PCLOC+T+1; FETCH NEW PC. T HAS CHANNEL #, L HAS MASK
EM01126> XREG<- L;
EM01127> T<- XREG;
EM01130> L<- NWW XOR T; TURN OFF BIT IN WW FOR INTERRUPT ABOUT TO HAPPEN
EM01131> T<- MD;
EM01132> NWW<- L, L<- T;
EM01133> PC<- L, L<- T<- 0+1, TASK;
EM01134> SAD<- L MRSH 1, :NOACTIVE; SAD<- 1B5 TO DISABLE INTERRUPTS
;
; ************************
; * BIT-BLT - 61024 *
; ************************
; Modified September 1977 to support Alternate memory banks
; Last modified Sept 6, 1977 by Dan Ingalls
;
; /* NOVA REGS
; AC2 -> BLT DESCRIPTOR TABLE, AND IS PRESERVED
; AC1 CARRIES LINE COUNT FOR RESUMING AFTER AN
; INTERRUPT. MUST BE 0 AT INITIAL CALL
; AC0 AND AC3 ARE SMASHED TO SAVE S-REGS
;
; /* ALTO REGISTER USAGE
;DISP CARRIES: TOPLD(100), SOURCEBANK(40), DESTBANK(20),
; SOURCE(14), OP(3)
$MASK1 $R0;
$YMUL $R2; HAS TO BE AN R-REG FOR SHIFTS
$RETN $R2;
$SKEW $R3;
$TEMP $R5;
$WIDTH $R7;
$PLIER $R7; HAS TO BE AN R-REG FOR SHIFTS
$DESTY $R10;
$WORD2 $R10;
$STARTBITSM1 $R35;
$SWA $R36;
$DESTX $R36;
$LREG $R40; HAS TO BE R40 (COPY OF L-REG)
$NLINES $R41;
$RAST1 $R42;
$SRCX $R43;
$SKMSK $R43;
$SRCY $R44;
$RAST2 $R44;
$CONST $R45;
$TWICE $R45;
$HCNT $R46;
$VINC $R46;
$HINC $R47;
$NWORDS $R50;
$MASK2 $R51; WAS $R46;
;
$LASTMASKP1 $500; MASKTABLE+021
$170000 $170000;
$CALL3 $3; SUBROUTINE CALL INDICES
$CALL4 $4;
$DWAOFF $2; BLT TABLE OFFSETS
$DXOFF $4;
$DWOFF $6;
$DHOFF $7;
$SWAOFF $10;
$SXOFF $12;
$GRAYOFF $14; GRAY IN WORDS 14-17
$LASTMASK $477; MASKTABLE+020 **NOT IN EARLIER PROMS!
; BITBLT SETUP - CALCULATE RAM STATE FROM AC2'S TABLE
;----------------------------------------------------------
;
; /* FETCH COORDINATES FROM TABLE
!1,2,FDDX,BLITX;
!1,2,FDBL,BBNORAM;
!17,20,FDBX,,,,FDX,,FDW,,,,FSX,,,,,; FDBL RETURNS (BASED ON OFFSET)
; (0) 4 6 12
EM00124> BITBLT: L<- 0;
EM01135> SINK<-LREG, BUSODD; SINK<- -1 IFF NO RAM
EM01142> L<- T<- DWOFF, :FDBL;
EM01141> BBNORAM: TASK, :NPTRAP; TRAP IF NO RAM
;
EM01166> FDW: T<- MD; PICK UP WIDTH, HEIGHT
EM01143> WIDTH<- L, L<- T, TASK, :NZWID;
EM01144> NZWID: NLINES<- L;
EM01145> T<- AC1;
EM01146> L<- NLINES-T;
EM01147> NLINES<- L, SH<0, TASK;
EM01150> :FDDX;
;
EM01136> FDDX: L<- T<- DXOFF, :FDBL; PICK UP DEST X AND Y
EM01164> FDX: T<- MD;
EM01151> DESTX<- L, L<- T, TASK;
EM01152> DESTY<- L;
;
EM01153> L<- T<- SXOFF, :FDBL; PICK UP SOURCE X AND Y
EM01172> FSX: T<- MD;
EM01154> SRCX<- L, L<- T, TASK;
EM01155> SRCY<- L, :CSHI;
;
; /* FETCH DOUBLEWORD FROM TABLE (L<- T<- OFFSET, :FDBL)
EM01140> FDBL: MAR<- AC2+T;
EM01156> SINK<- LREG, BUS;
EM01160> FDBX: L<- MD, :FDBX;
;
; /* CALCULATE SKEW AND HINC
!1,2,LTOR,RTOL;
EM01157> CSHI: T<- DESTX;
EM01161> L<- SRCX-T-1;
EM01165> T<- LREG+1, SH<0; TEST HORIZONTAL DIRECTION
EM01167> L<- 17.T, :LTOR; SKEW <- (SRCX - DESTX) MOD 16
EM01163> RTOL: SKEW<- L, L<- 0-1, :AH, TASK; HINC <- -1
EM00162> LTOR: SKEW<- L, L<- 0+1, :AH, TASK; HINC <- +1
EM01170> AH: HINC<- L;
;
; CALCULATE MASK1 AND MASK2
!1,2,IFRTOL,LNWORDS;
!1,2,POSWID,NEGWID;
EM01171> CMASKS: T<- DESTX;
EM01173> T<- 17.T;
EM01200> MAR<- LASTMASKP1-T-1;
EM01201> L<- 17-T; STARTBITS <- 16 - (DESTX.17)
EM01202> STARTBITSM1<- L;
EM01203> L<- MD, TASK;
EM01204> MASK1<- L; MASK1 <- @(MASKLOC+STARTBITS)
EM01205> L<- WIDTH-1;
EM01206> T<- LREG-1, SH<0;
EM01207> T<- DESTX+T+1, :POSWID;
EM01176> POSWID: T<- 17.T;
EM01210> MAR<- LASTMASK-T-1;
EM01211> T<- ALLONES; MASK2 <- NOT
EM01212> L<- HINC-1;
EM01213> L<- MD XOR T, SH=0, TASK; @(MASKLOC+(15-((DESTX+WIDTH-1).17)))
EM01214> MASK2<- L, :IFRTOL;
; /* IF RIGHT TO LEFT, ADD WIDTH TO X'S AND EXCH MASK1, MASK2
EM01174> IFRTOL: T<- WIDTH-1; WIDTH-1
EM01215> L<- SRCX+T;
EM01216> SRCX<- L; SRCX <- SCRX + (WIDTH-1)
EM01217> L<- DESTX+T;
EM01220> DESTX<- L; DESTX <- DESTX + (WIDTH-1)
EM01221> T<- DESTX;
EM01222> L<- 17.T, TASK;
EM01223> STARTBITSM1<- L; STARTBITS <- (DESTX.17) + 1
EM01224> T<- MASK1;
EM01225> L<- MASK2;
EM01226> MASK1<- L, L<- T,TASK; EXCHANGE MASK1 AND MASK2
EM01227> MASK2<-L;
;
; /* CALCULATE NWORDS
!1,2,LNW1,THIN;
EM01175> LNWORDS:T<- STARTBITSM1+1;
EM01232> L<- WIDTH-T-1;
EM01233> T<- 177760, SH<0;
EM01234> T<- LREG.T, :LNW1;
EM01230> LNW1: L<- CALL4; NWORDS <- (WIDTH-STARTBITS)/16
EM01235> CYRET<- L, L<- T, :R4, TASK; CYRET<-CALL4
; **WIDTH REG NOW FREE**
EM00604> CYX4: L<- CYCOUT, :LNW2;
EM01231> THIN: T<- MASK1; SPECIAL CASE OF THIN SLICE
EM01236> L<-MASK2.T;
EM01237> MASK1<- L, L<- 0-1; MASK1 <- MASK1.MASK2, NWORDS <- -1
EM01240> LNW2: NWORDS<- L; LOAD NWORDS
; **STARTBITSM1 REG NOW FREE**
;
; /* DETERMINE VERTICAL DIRECTION
!1,2,BTOT,TTOB;
T<- SRCY;
EM01244> L<- DESTY-T;
EM01245> T<- NLINES-1, SH<0;
EM01246> L<- 0, :BTOT; VINC <- 0 IFF TOP-TO-BOTTOM
EM01242> BTOT: L<- ALLONES; ELSE -1
EM01247> BTOT1: VINC<- L;
EM01250> L<- SRCY+T; GOING BOTTOM TO TOP
EM01251> SRCY<- L; ADD NLINES TO STARTING Y'S
EM01252> L<- DESTY+T;
EM01253> DESTY<- L, L<- 0+1, TASK;
EM01254> TWICE<-L, :CWA;
;
EM01243> TTOB: T<- AC1, :BTOT1; TOP TO BOT, ADD NDONE TO STARTING Y'S
; **AC1 REG NOW FREE**;
;
; /* CALCULATE WORD ADDRESSES - DO ONCE FOR SWA, THEN FOR DWAX
EM01255> CWA: L<- SRCY; Y HAS TO GO INTO AN R-REG FOR SHIFTING
EM01256> YMUL<- L;
EM01257> T<- SWAOFF; FIRST TIME IS FOR SWA, SRCX
EM01260> L<- SRCX;
; **SRCX, SRCY REG NOW FREE**
EM01261> DOSWA: MAR<- AC2+T; FETCH BITMAP ADDR AND RASTER
EM01262> XREG<- L;
EM01263> L<-CALL3;
EM01264> CYRET<- L; CYRET<-CALL3
EM01265> L<- MD;
EM01266> T<- MD;
EM01267> DWAX<- L, L<-T, TASK;
EM01270> RAST2<- L;
EM01271> T<- 177760;
EM01272> L<- T<- XREG.T, :R4, TASK; SWA <- SWA + SRCX/16
EM00603> CYX3: T<- CYCOUT;
EM01273> L<- DWAX+T;
EM01274> DWAX<- L;
;
!1,2,NOADD,DOADD;
!1,2,MULLP,CDELT; SWA <- SWA + SRCY*RAST1
EM01275> L<- RAST2;
EM01302> SINK<- YMUL, BUS=0, TASK; NO MULT IF STARTING Y=0
EM01303> PLIER<- L, :MULLP;
EM01300> MULLP: L<- PLIER, BUSODD; MULTIPLY RASTER BY Y
EM01304> PLIER<- L RSH 1, :NOADD;
EM01276> NOADD: L<- YMUL, SH=0, TASK; TEST NO MORE MULTIPLIER BITS
EM01305> SHIFTB: YMUL<- L LSH 1, :MULLP;
EM01277> DOADD: T<- YMUL;
EM01306> L<- DWAX+T;
EM01307> DWAX<- L, L<-T, :SHIFTB, TASK;
; **PLIER, YMUL REG NOW FREE**
;
!1,2,HNEG,HPOS;
!1,2,VPOS,VNEG;
!1,1,CD1; CALCULATE DELTAS = +-(NWORDS+2)[HINC] +-RASTER[VINC]
EM01301> CDELT: L<- T<- HINC-1; (NOTE T<- -2 OR 0)
EM01314> L<- T<- NWORDS-T, SH=0; (L<-NWORDS+2 OR T<-NWORDS)
EM01315> CD1: SINK<- VINC, BUSODD, :HNEG;
EM01310> HNEG: T<- RAST2, :VPOS;
EM01311> HPOS: L<- -2-T, :CD1; (MAKES L<- -(NWORDS+2))
EM01312> VPOS: L<- LREG+T, :GDELT, TASK; BY NOW, LREG = +-(NWORDS+2)
EM01313> VNEG: L<- LREG-T, :GDELT, TASK; AND T = RASTER
EM01316> GDELT: RAST2<- L;
;
; /* END WORD ADDR LOOP
!1,2,ONEMORE,CTOPL;
EM01317> L<- TWICE-1;
EM01322> TWICE<- L, SH<0;
EM01323> L<- RAST2, :ONEMORE; USE RAST2 2ND TIME THRU
EM01320> ONEMORE: RAST1<- L;
EM01324> L<- DESTY, TASK; USE DESTY 2ND TIME THRU
EM01325> YMUL<- L;
EM01326> L<- DWAX; USE DWAX 2ND TIME THRU
EM01327> T<- DESTX; CAREFUL - DESTX=SWA!!
EM01330> SWA<- L, L<- T; USE DESTX 2ND TIME THRU
EM01331> T<- DWAOFF, :DOSWA; AND DO IT AGAIN FOR DWAX, DESTX
; **TWICE, VINC REGS NOW FREE**
;
; /* CALCULATE TOPLD
!1,2,CTOP1,CSKEW;
!1,2,HM1,H1;
!1,2,NOTOPL,TOPL;
EM01321> CTOPL: L<- SKEW, BUS=0, TASK; IF SKEW=0 THEN 0, ELSE
EM01340> CTX: IR<- 0, :CTOP1;
EM01332> CTOP1: T<- SRCX; (SKEW GR SRCX.17) XOR (HINC EQ 0)
EM01341> L<- HINC-1;
EM01342> T<- 17.T, SH=0; TEST HINC
EM01343> L<- SKEW-T-1, :HM1;
EM01335> H1: T<- HINC, SH<0;
EM01344> L<- SWA+T, :NOTOPL;
EM01334> HM1: T<- LREG; IF HINC=-1, THEN FLIP
EM01345> L<- 0-T-1, :H1; THE POLARITY OF THE TEST
EM01336> NOTOPL: SINK<- HINC, BUSODD, TASK, :CTX; HINC FORCES BUSODD
EM01337> TOPL: SWA<- L, TASK; (DISP <- 100 FOR TOPLD)
EM01346> IR<- 100, :CSKEW;
; **HINC REG NOW FREE**
;
; /* CALCULATE SKEW MASK
!1,2,THINC,BCOM1;
!1,2,COMSK,NOCOM;
EM01333> CSKEW: T<- SKEW, BUS=0; IF SKEW=0, THEN COMP
EM01347> MAR<- LASTMASKP1-T-1, :THINC;
EM01350> THINC: L<-HINC-1;
EM01354> SH=0; IF HINC=-1, THEN COMP
EM01351> BCOM1: T<- ALLONES, :COMSK;
EM01352> COMSK: L<- MD XOR T, :GFN;
EM01353> NOCOM: L<- MD, :GFN;
;
; /* GET FUNCTION
EM01355> GFN: MAR<- AC2;
EM01356> SKMSK<- L;
EM01357> T- MD;
EM01360> L<- DISP+T, TASK;
EM01361> IR<- LREG, :BENTR; DISP <-DISP .OR. FUNCTION
; BITBLT WORK - VERT AND HORIZ LOOPS WITH 4 SOURCES, 4 FUNCTIONS
;-----------------------------------------------------------------------
;
; /* VERTICAL LOOP: UPDATE SWA, DWAX
!1,2,DO0,VLOOP;
EM01363> VLOOP: T<- SWA;
EM01364> L<- RAST1<-T; INC SWA BY DELTA
EM01365> SWA<- L;
EM01366> T<- DWAX;
EM01367> L<- RAST2+T, TASK; INC DWAX BY DELTA
EM01370> DWAX<- L;
;
; /* TEST FOR DONE, OR NEED GRAY
!1,2,MOREV,DONEV;
!1,2,BMAYBE,BNOINT;
!1,2,BDOINT,BDIS0;
!1,2,DOGRAY,NOGRAY;
EM01371> BENTR: L<- T<- NLINES-1; DECR NLINES AND CHECK IF DONE
EM01402> NLINES<- L, SH<0;
EM01403> L<- NWW, BUS=0, :MOREV; CHECK FOR INTERRUPTS
EM01372> MOREV: L<- 3.T, :BMAYBE, SH<0; CHECK DISABLED ***V3 change
EM01375> BNOINT: SINK<- DISP, SINK<- lgm10, BUS=0, :BDIS0, TASK;
EM01374> BMAYBE: SINK<- DISP, SINK<- lgm10, BUS=0, :BDOINT, TASK; TEST IF NEED GRAY(FUNC=8,12)
EM01377> BDIS0: CONST<- L, :DOGRAY; ***V3 change
;
; /* INTERRUPT SUSPENSION (POSSIBLY)
!1,1,DOI1; MAY GET AN OR-1
EM01376> BDOINT: :DOI1; TASK HERE
EM01405> DOI1: T<- AC2;
EM01404> MAR<- DHOFF+T; NLINES DONE = HT-NLINES-1
EM01406> T<- NLINES;
EM01407> L<- PC-1; BACK UP THE PC, SO WE GET RESTARTED
EM01410> PC<- L;
EM01411> L<- MD-T-1, :BLITX, TASK; ...WITH NO LINES DONE IN AC1
;
; /* LOAD GRAY FOR THIS LINE (IF FUNCTION NEEDS IT)
!1,2,PRELD,NOPLD;
EM01400> DOGRAY: T<- CONST-1;
EM01414> T<- GRAYOFF+T+1;
EM01415> MAR<- AC2+T;
EM01416> NOP; UGH
EM01417> L<- MD;
EM01401> NOGRAY: SINK<- DISP, SINK<- lgm100, BUS=0, TASK; TEST TOPLD
EM01420> CONST<- L, :PRELD;
;
; /* NORMAL COMPLETION
EM01177> NEGWID: L<- 0, :BLITX, TASK;
EM01373> DONEV: L<- 0, :BLITX, TASK; MAY BE AN OR-1 HERE!
EM01137> BLITX: AC1<- L, :FINBLT;
;
; /* PRELOAD OF FIRST SOURCE WORD (DEPENDING ON ALIGNMENT)
!1,2,AB1,NB1;
EM01412> PRELD: SINK<- DISP, SINK<- lgm40, BUS=0; WHICH BANK
EM01421> T<- HINC, :AB1;
EM01423> NB1: MAR<- SWA-T, :XB1; (NORMAL BANK)
EM01422> AB1: XMAR<- SWA-T, :XB1; (ALTERNATE BANK)
EM01424> XB1: NOP;
EM01425> L<- MD, TASK;
EM01426> WORD2<- L, :NOPLD;
;
;
; /* HORIZONTAL LOOP - 3 CALLS FOR 1ST, MIDDLE AND LAST WORDS
!1,2,FDISPA,LASTH;
%17,17,14,DON0,,DON2,DON3; CALLERS OF HORIZ LOOP
; NOTE THIS IGNORES 14-BITS, SO lgm14 WORKS LIKE L<-0 FOR RETN
!14,1,LH1; IGNORE RESULTING BUS
EM01413> NOPLD: L<- 3, :FDISP; CALL #3 IS FIRST WORD
EM01437> DON3: L<- NWORDS;
EM01427> HCNT<- L, SH<0; HCNT COUNTS WHOLE WORDS
EM01434> DON0: L<- HCNT-1, :DO0; IF NEG, THEN NO MIDDLE OR LAST
EM01362> DO0: HCNT<- L, SH<0; CALL #0 (OR-14!) IS MIDDLE WORDS
; UGLY HACK SQUEEZES 2 INSTRS OUT OF INNER LOOP:
EM01432> L<- DISP, SINK<- lgm14, BUS, TASK, :FDISPA; (WORKS LIKE L<-0)
EM01431> LASTH: :LH1; TASK AND BUS PENDING
EM01435> LH1: L<- 2, :FDISP; CALL #2 IS LAST WORD
EM01436> DON2: :VLOOP;
;
;
; /* HERE ARE THE SOURCE FUNCTIONS
!17,20,,,,F0,,,,F1,,,,F2,,,,F3; IGNORE OP BITS IN FUNCTION CODE
!17,20,,,,F0A,,,,F1A,,,,F2A,,,, ; SAME FOR WINDOW RETURNS
!3,4,OP0,OP1,OP2,OP3;
!1,2,AB2,NB2;
EM01433> FDISP: SINK<- DISP, SINK<-lgm14, BUS, TASK;
EM01430> FDISPA: RETN<- L, :F0;
EM01443> F0: SINK<- DISP, SINK<- lgm40, BUS=0, :WIND; FUNC 0 - WINDOW
EM01447> F1: SINK<- DISP, SINK<- lgm40, BUS=0, :WIND; FUNC 1 - NOT WINDOW
EM01467> F1A: T<- CYCOUT;
EM01442> L<- ALLONES XOR T, TASK, :F3A;
EM01453> F2: SINK<- DISP, SINK<- lgm40, BUS=0, :WIND; FUNC 2 - WINDOW .AND. GRAY
EM01473> F2A: T<- CYCOUT;
EM01444> L<- ALLONES XOR T;
EM01445> SINK<- DISP, SINK<- lgm20, BUS=0; WHICH BANK
EM01446> TEMP<- L, :AB2; TEMP <- NOT WINDOW
EM01441> NB2: MAR<- DWAX, :XB2; (NORMAL BANK)
EM01440> AB2: XMAR<- DWAX, :XB2; (ALTERNATE BANK)
EM01450> XB2: L<- CONST AND T; WINDOW .AND. GRAY
EM01451> T<- TEMP;
EM01452> T<- MD .T; DEST.AND.NOT WINDOW
EM01454> L<- LREG OR T, TASK, :F3A; (TRANSPARENT)
EM01457> F3: L<- CONST, TASK, :F3A; FUNC 3 - CONSTANT (COLOR)
;
;
; /* AFTER GETTING SOURCE, START MEMORY AND DISPATCH ON OP
!1,2,AB3,NB3;
EM01455> F3A: CYCOUT<- L; (TASK HERE)
EM01463> F0A: SINK<- DISP, SINK<- lgm20, BUS=0; WHICH BANK
EM01456> SINK<- DISP, SINK<- lgm3, BUS, :AB3; DISPATCH ON OP
EM01461> NB3: T<- MAR<- DWAX, :OP0; (NORMAL BANK)
EM01460> AB3: T<- XMAR<- DWAX, :OP0; (ALTERNATE BANK)
;
;
; /* HERE ARE THE OPERATIONS - ENTER WITH SOURCE IN CYCOUT
%16,17,15,STFULL,STMSK; MASKED OR FULL STORE (LOOK AT 2-BIT)
; OP 0 - SOURCE
EM01474> OP0: SINK<- RETN, BUS; TEST IF UNMASKED
EM01462> OP0A: L<- HINC+T, :STFULL; ELSE :STMSK
EM01475> OP1: T<- CYCOUT; OP 1 - SOURCE .OR. DEST
EM01464> L<- MD OR T, :OPN;
EM01476> OP2: T<- CYCOUT; OP 2 - SOURCE .XOR. DEST
EM01465> L<- MD XOR T, :OPN;
EM01477> OP3: T<- CYCOUT; OP 3 - (NOT SOURCE) .AND. DEST
EM01466> L<- 0-T-1;
EM01470> T<- LREG;
EM01471> L<- MD AND T, :OPN;
EM01472> OPN: SINK<- DISP, SINK<- lgm20, BUS=0, TASK; WHICH BANK
EM01500> CYCOUT<- L, :AB3;
;
;
; /* STORE MASKED INTO DESTINATION
!1,2,STM2,STM1;
!1,2,AB4,NB4;
EM01517> STMSK: L<- MD;
EM01501> SINK<- RETN, BUSODD, TASK; DETERMINE MASK FROM CALL INDEX
EM01506> TEMP<- L, :STM2; STACHE DEST WORD IN TEMP
EM01503> STM1: T<-MASK1, :STM3;
EM01502> STM2: T<-MASK2, :STM3;
EM01507> STM3: L<- CYCOUT AND T; ***X24. Removed TASK clause.
EM01510> CYCOUT<- L, L<- 0-T-1; AND INTO SOURCE
EM01511> T<- LREG; T<- MASK COMPLEMENTED
EM01512> T<- TEMP .T; AND INTO DEST
EM01513> L<- CYCOUT OR T; OR TOGETHER THEN GO STORE
EM01514> SINK<- DISP, SINK<- lgm20, BUS=0, TASK; WHICH BANK
EM01516> CYCOUT<- L, :AB4;
EM01505> NB4: T<- MAR<- DWAX, :OP0A; (NORMAL BANK)
EM01504> AB4: T<- XMAR<- DWAX, :OP0A; (ALTERNATE BANK)
;
; /* STORE UNMASKED FROM CYCOUT (L=NEXT DWAX)
EM01515> STFULL: MD<- CYCOUT;
EM01520> STFUL1: SINK<- RETN, BUS, TASK;
EM01521> DWAX<- L, :DON0;
;
;
; /* WINDOW SOURCE FUNCTION
; TASKS UPON RETURN, RESULT IN CYCOUT
!1,2,DOCY,NOCY;
!17,1,WIA;
!1,2,NZSK,ZESK;
!1,2,AB5,NB5;
EM01530> WIND: L<- T<- SKMSK, :AB5; ENTER HERE (8 INST TO TASK)
EM01527> NB5: MAR<- SWA, :XB5; (NORMAL BANK)
EM01526> AB5: XMAR<- SWA, :XB5; (ALTERNATE BANK)
EM01531> XB5: L<- WORD2.T, SH=0;
EM01532> CYCOUT<- L, L<- 0-T-1, :NZSK; CYCOUT<- OLD WORD .AND. MSK
EM01525> ZESK: L<- MD, TASK; ZERO SKEW BYPASSES LOTS
EM01533> CYCOUT<- L, :NOCY;
EM01524> NZSK: T<- MD;
EM01534> L<- LREG.T;
EM01535> TEMP<- L, L<-T, TASK; TEMP<- NEW WORD .AND. NOTMSK
EM01536> WORD2<- L;
EM01540> T<- TEMP;
EM01541> L<- T<- CYCOUT OR T; OR THEM TOGETHER
EM01542> CYCOUT<- L, L<- 0+1, SH=0; DONT CYCLE A ZERO ***X21.
EM01543> SINK<- SKEW, BUS, :DOCY;
EM01522> DOCY: CYRET<- L LSH 1, L<- T, :L0; CYCLE BY SKEW ***X21.
EM01523> NOCY: T<- SWA, :WIA; (MAY HAVE OR-17 FROM BUS)
EM00602> CYX2: T<- SWA;
EM01537> WIA: L<- HINC+T;
EM01544> SINK<- DISP, SINK<- lgm14, BUS, TASK; DISPATCH TO CALLER
EM01545> SWA<- L, :F0A;
; THE DISK CONTROLLER
; ITS REGISTERS:
$DCBR $R34;
$KNMAR $R33;
$CKSUMR $R32;
$KWDCT $R31;
$KNMARW $R33;
$CKSUMRW $R32;
$KWDCTW $R31;
; ITS TASK SPECIFIC FUNCTIONS AND BUS SOURCES:
$KSTAT $L020012,014003,124100; DF1 = 12 (LHS) BS = 3 (RHS)
$RWC $L024011,000000,000000; NDF2 = 11
$RECNO $L024012,000000,000000; NDF2 = 12
$INIT $L024010,000000,000000; NDF2 = 10
$CLRSTAT $L016014,000000,000000; NDF1 = 14
$KCOMM $L020015,000000,124000; DF1 = 15 (LHS only) Requires bus def
$SWRNRDY $L024014,000000,000000; NDF2 = 14
$KADR $L020016,000000,124000; DF1 = 16 (LHS only) Requires bus def
$KDATA $L020017,014004,124100; DF1 = 17 (LHS) BS = 4 (RHS)
$STROBE $L016011,000000,000000; NDF1 = 11
$NFER $L024015,000000,000000; NDF2 = 15
$STROBON $L024016,000000,000000; NDF2 = 16
$XFRDAT $L024013,000000,000000; NDF2 = 13
$INCRECNO $L016013,000000,000000; NDF1 = 13
; THE DISK CONTROLLER COMES IN TWO PARTS. THE SECTOR
; TASK HANDLES DEVICE CONTROL AND COMMAND UNDERSTANDING
; AND STATUS REPORTING AND THE LIKE. THE WORD TASK ONLY
; RUNS AFTER BEING ENABLED BY THE SECTOR TASK AND
; ACTUALLY MOVES DATA WORDS TO AND FRO.
; THE SECTOR TASK
; LABEL PREDEFINITIONS:
!1,2,COMM,NOCOMM;
!1,2,COMM2,IDLE1;
!1,2,BADCOMM,COMM3;
!1,2,COMM4,ILLSEC;
!1,2,COMM5,WHYNRDY;
!1,2,STROB,CKSECT;
!1,2,STALL,CKSECT1;
!1,2,KSFINI,CKSECT2;
!1,2,IDLE2,TRANSFER;
!1,2,STALL2,GASP;
!1,2,INVERT,NOINVERT;
SE00004> KSEC: MAR<- KBLKADR2;
SE01574> KPOQ: CLRSTAT; RESET THE STORED DISK ADDRESS
SE01575> MD<-L<-ALLONES+1, :GCOM2; ALSO CLEAR DCB POINTER
SE01576> GETCOM: MAR<-KBLKADR; GET FIRST DCB POINTER
SE01577> GCOM1: NOP;
SE01600> L<-MD;
SE01601> GCOM2: DCBR<-L,TASK;
SE01602> KCOMM<-TOWTT; IDLE ALL DATA TRANSFERS
SE01603> MAR<-KBLKADR3; GENERATE A SECTOR INTERRUPT
SE01604> T<-NWW;
SE01605> L<-MD OR T;
SE01606> MAR<-KBLKADR+1; STORE THE STATUS
SE01607> NWW<-L, TASK;
SE01610> MD<-KSTAT;
SE01611> MAR<-KBLKADR; WRITE THE CURRENT DCB POINTER
SE01612> KSTAT<-5; INITIAL STATUS IS INCOMPLETE
SE01613> L<-DCBR,TASK,BUS=0;
SE01614> MD<-DCBR, :COMM;
; BUS=0 MAPS COMM TO NOCOMM
SE01546> COMM: T<-2; GET THE DISK COMMAND
SE01615> MAR<-DCBR+T;
SE01616> T<-TOTUWC;
SE01617> L<-MD XOR T, TASK, STROBON;
SE01620> KWDCT<-L, :COMM2;
; STROBON MAPS COMM2 TO IDLE1
SE01550> COMM2: T<-10; READ NEW DISK ADDRESS
SE01621> MAR<-DCBR+T+1;
SE01622> T<-KWDCT;
SE01623> L<-ONE AND T;
SE01624> L<- -400 AND T, SH=0;
SE01625> T<-MD, SH=0, :INVERT;
; SH=0 MAPS INVERT TO NOINVERT
SE01572> INVERT: L<-2 XOR T, TASK, :BADCOMM;
SE01573> NOINVERT: L<-T, TASK, :BADCOMM;
; SH=0 MAPS BADCOMM TO COMM3
SE01553> COMM3: KNMAR<-L;
SE01626> MAR<-KBLKADR2; WRITE THE NEW DISK ADDRESS
SE01627> T<-SECT2CM; CHECK FOR SECTOR > 13
SE01630> L<-T<-KDATA<-KNMAR+T; NEW DISK ADDRESS TO HARDWARE
SE01631> KADR<-KWDCT,ALUCY; DISK COMMAND TO HARDWARE
SE01632> L<-MD XOR T,TASK, :COMM4; COMPARE OLD AND NEW DISK ADDRESSES
; ALUCY MAPS COMM4 TO ILLSEC
SE01554> COMM4: CKSUMR<-L;
SE01633> MAR<-KBLKADR2; WRITE THE NEW DISK ADDRESS
SE01634> T<-CADM,SWRNRDY; SEE IF DISK IS READY
SE01635> L<-CKSUMR AND T, :COMM5;
; SWRNRDY MAPS COMM5 TO WHYNRDY
SE01556> COMM5: MD<-KNMAR; COMPLETE THE WRITE
SE01636> SH=0,TASK;
SE01637> :STROB;
; SH=0 MAPS STROB TO CKSECT
SE01561> CKSECT: T<-KNMAR,NFER;
SE01640> L<-KSTAT XOR T, :STALL;
; NFER MAPS STALL TO CKSECT1
SE01563> CKSECT1: CKSUMR<-L,XFRDAT;
SE01641> T<-CKSUMR, :KSFINI;
; XFRDAT MAPS KSFINI TO CKSECT2
SE01565> CKSECT2: L<-SECTMSK AND T;
SE01642> KSLAST: BLOCK,SH=0;
SE01571> GASP: TASK, :IDLE2;
; SH=0 MAPS IDLE2 TO TRANSFER
SE01567> TRANSFER: KCOMM<-TOTUWC; TURN ON THE TRANSFER
!1,2,ERRFND,NOERRFND;
!1,2,EF1,NEF1;
SE01643> DMPSTAT: T<-COMERR1; SEE IF STATUS REPRESENTS ERROR
SE01650> L<-KSTAT AND T;
SE01651> MAR<-DCBR+1; WRITE FINAL STATUS
SE01652> KWDCT<-L,TASK,SH=0;
SE01653> MD<-KSTAT,:ERRFND;
; SH=0 MAPS ERRFND TO NOERRFND
SE01645> NOERRFND: T<-6; PICK UP NO-ERROR INTERRUPT WORD
SE01654> INTCOM: MAR<-DCBR+T;
SE01655> T<-NWW;
SE01656> L<-MD OR T;
SE01657> SINK<-KWDCT,BUS=0,TASK;
SE01660> NWW<-L,:EF1;
; BUS=0 MAPS EF1 TO NEF1
SE01647> NEF1: MAR<-DCBR,:GCOM1; FETCH ADDRESS OF NEXT CONTROL BLOCK
SE01644> ERRFND: T<-7,:INTCOM; PICK UP ERROR INTERRUPT WORD
SE01646> EF1: :KSEC;
SE01547> NOCOMM: L<-ALLONES,CLRSTAT,:KSLAST;
SE01551> IDLE1: L<-ALLONES,:KSLAST;
SE01566> IDLE2: KSTAT<-LOW14, :GETCOM; NO ACTIVITY THIS SECTOR
SE01552> BADCOMM: KSTAT<-7; ILLEGAL COMMAND ONLY NOTED IN KBLK STAT
SE01661> BLOCK;
SE01662> TASK,:EF1;
SE01557> WHYNRDY: NFER;
SE01562> STALL: BLOCK, :STALL2;
; NFER MAPS STALL2 TO GASP
SE01570> STALL2: TASK;
SE01663> :DMPSTAT;
SE01555> ILLSEC: KSTAT<-7, :STALL; ILLEGAL SECTOR SPECIFIED
SE01560> STROB: CLRSTAT;
SE01664> L<-ALLONES,STROBE,:CKSECT1;
SE01564> KSFINI: KSTAT<-4, :STALL; COMMAND FINISHED CORRECTLY
;DISK WORD TASK
;WORD TASK PREDEFINITIONS
!37,37,,,,RP0,INPREF1,CKP0,WP0,,PXFLP1,RDCK0,WRT0,REC1,,REC2,REC3,,,REC0RC,REC0W,R0,,CK0,W0,,R2,,W2,,REC0,,KWD;
!1,2,RW1,RW2;
!1,2,CK1,CK2;
!1,2,CK3,CK4;
!1,2,CKERR,CK5;
!1,2,PXFLP,PXF2;
!1,2,PREFDONE,INPREF;
!1,2,,CK6;
!1,2,CKSMERR,PXFLP0;
KW01737> KWD: BLOCK,:REC0;
; SH<0 MAPS REC0 TO REC0
; ANYTHING=INIT MAPS REC0 TO KWD
KW01735> REC0: L<-2, TASK; LENGTH OF RECORD 0 (ALLOW RELEASE IF BLOCKED)
KW01665> KNMARW<-L;
KW01702> T<-KNMARW, BLOCK, RWC; GET ADDR OF MEMORY BLOCK TO TRANSFER
KW01710> MAR<-DCBR+T+1, :REC0RC;
; WRITE MAPS REC0RC TO REC0W
; INIT MAPS REC0RC TO KWD
KW01722> REC0RC: T<-MFRRDL,BLOCK, :REC12A; FIRST RECORD READ DELAY
KW01723> REC0W: T<-MFR0BL,BLOCK, :REC12A; FIRST RECORD 0'S BLOCK LENGTH
KW01714> REC1: L<-10, INCRECNO; LENGTH OF RECORD 1
KW01715> T<-4, :REC12;
KW01716> REC2: L<-PAGE1, INCRECNO; LENGTH OF RECORD 2
KW01725> T<-5, :REC12;
KW01730> REC12: MAR<-DCBR+T, RWC; MEM BLK ADDR FOR RECORD
KW01732> KNMARW<-L, :RDCK0;
; RWC=WRITE MAPS RDCK0 INTO WRT0
; RWC=INIT MAPS RDCK0 INTO KWD
KW01712> RDCK0: T<-MIRRDL, :REC12A;
KW01713> WRT0: T<-MIR0BL, :REC12A;
KW01734> REC12A: L<-MD;
KW01736> KWDCTW<-L, L<-T;
KW01740> COM1: KCOMM<- STUWC, :INPREF0;
KW01701> INPREF: L<-CKSUMRW+1, INIT, BLOCK;
KW01741> INPREF0: CKSUMRW<-L, SH<0, TASK, :INPREF1;
; INIT MAPS INPREF1 TO KWD
KW01705> INPREF1: KDATA<-0, :PREFDONE;
; SH<0 MAPS PREFDONE TO INPREF
KW01700> PREFDONE: T<-KNMARW; COMPUTE TOP OF BLOCK TO TRANSFER
KW00016> KWDX: L<-KWDCTW+T,RWC; (ALSO USED FOR RESET)
KW01742> KNMARW<-L,BLOCK,:RP0;
; RWC=CHECK MAPS RP0 TO CKP0
; RWC=WRITE MAPS RP0 AND CKP0 TO WP0
; RWC=INIT MAPS RP0, CKP0, AND WP0 TO KWD
KW01704> RP0: KCOMM<-STRCWFS,:WP1;
KW01706> CKP0: L<-KWDCTW-1; ADJUST FINISHING CONDITION BY 1 FOR CHECKING ONLY
KW01743> KWDCTW<-L,:RP0;
KW01707> WP0: KDATA<-ONE; WRITE THE SYNC PATTERN
KW01744> WP1: L<-KBLKADR,TASK,:RW1; INITIALIZE THE CHECKSUM AND ENTER XFER LOOP
KW01745> XFLP: T<-L<-KNMARW-1; BEGINNING OF MAIN XFER LOOP
KW01746> KNMARW<-L;
KW01747> MAR<-KNMARW,RWC;
KW01750> L<-KWDCTW-T,:R0;
; RWC=CHECK MAPS R0 TO CK0
; RWC=WRITE MAPS R0 AND CK0 TO W0
; RWC=INIT MAPS R0, CK0, AND W0 TO KWD
KW01724> R0: T<-CKSUMRW,SH=0,BLOCK;
KW01751> MD<-L<-KDATA XOR T,TASK,:RW1;
; SH=0 MAPS RW1 TO RW2
KW01666> RW1: CKSUMRW<-L,:XFLP;
KW01727> W0: T<-CKSUMRW,BLOCK;
KW01752> KDATA<-L<-MD XOR T,SH=0;
KW01753> TASK,:RW1;
; AS ALREADY NOTED, SH=0 MAPS RW1 TO RW2
KW01726> CK0: T<-KDATA,BLOCK,SH=0;
KW01754> L<-MD XOR T,BUS=0,:CK1;
; SH=0 MAPS CK1 TO CK2
KW01670> CK1: L<-CKSUMRW XOR T,SH=0,:CK3;
; BUS=0 MAPS CK3 TO CK4
KW01672> CK3: TASK,:CKERR;
; SH=0 MAPS CKERR TO CK5
KW01675> CK5: CKSUMRW<-L,:XFLP;
KW01673> CK4: MAR<-KNMARW, :CK6;
; SH=0 MAPS CK6 TO CK6
KW01703> CK6: CKSUMRW<-L,L<-0+T;
KW01755> MTEMP<-L,TASK;
KW01756> MD<-MTEMP,:XFLP;
KW01671> CK2: L<-CKSUMRW-T,:R2;
; BUS=0 MAPS R2 TO R2
KW01667> RW2: CKSUMRW<-L;
KW01757> T<-KDATA<-CKSUMRW,RWC; THIS CODE HANDLES THE FINAL CHECKSUM
KW01760> L<-KDATA-T,BLOCK,:R2;
; RWC=CHECK NEVER GETS HERE
; RWC=WRITE MAPS R2 TO W2
; RWC=INIT MAPS R2 AND W2 TO KWD
KW01731> R2: L<-MRPAL, SH=0; SET READ POSTAMBLE LENGTH, CHECK CKSUM
KW01761> KCOMM<-TOTUWC, :CKSMERR;
; SH=0 MAPS CKSMERR TO PXFLP0
KW01733> W2: L<-MWPAL, TASK; SET WRITE POSTAMBLE LENGTH
KW01762> CKSUMRW<-L, :PXFLP;
KW01720> CKSMERR: KSTAT<-0,:PXFLP0; 0 MEANS CHECKSUM ERROR .. CONTINUE
KW01676> PXFLP: L<-CKSUMRW+1, INIT, BLOCK;
KW01721> PXFLP0: CKSUMRW<-L, TASK, SH=0, :PXFLP1;
; INIT MAPS PXFLP1 TO KWD
KW01711> PXFLP1: KDATA<-0,:PXFLP;
; SH=0 MAPS PXFLP TO PXF2
KW01677> PXF2: RECNO, BLOCK; DISPATCH BASED ON RECORD NUMBER
KW01763> :REC1;
; RECNO=2 MAPS REC1 INTO REC2
; RECNO=3 MAPS REC1 INTO REC3
; RECNO=INIT MAPS REC1 INTO KWD
KW01717> REC3: KSTAT<-4,:PXFLP; 4 MEANS SUCCESS!!!
KW01674> CKERR: KCOMM<-TOTUWC; TURN OFF DATA TRANSFER
KW01764> L<-KSTAT<-6, :PXFLP1; SHOW CHECK ERROR AND LOOP
;The Parity Error Task
;Its label predefinition is way earlier
;It dumps the following interesting registers:
;614/ DCBR Disk control block
;615/ KNMAR Disk memory address
;616/ DWA Display memory address
;617/ CBA Display control block
;620/ PC Emulator program counter
;621/ SAD Emulator temporary register for indirection
PA00015> PART: T<- 10;
PA01765> L<- ALLONES; TURN OFF MEMORY INTERRUPTS
PA01766> MAR<- ERRCTRL, :PX1;
PA00450> PR8: L<- SAD, :PX;
PA00447> PR7: L<- PC, :PX;
PA00446> PR6: L<- CBA, :PX;
PA00445> PR5: L<- DWA, :PX;
PA00444> PR4: L<- KNMAR, :PX;
PA00443> PR3: L<- DCBR, :PX;
PA00442> PR2: L<- NWW OR T, TASK; T CONTAINS 1 AT THIS POINT
PA00440> PR0: NWW<- L, :PART;
PA01767> PX: MAR<- 612+T;
PA01770> PX1: MTEMP<- L, L<- T;
PA01771> MD<- MTEMP;
PA01772> CURDATA<- L; THIS CLOBBERS THE CURSOR FOR ONE
PA01773> T<- CURDATA-1, BUS; FRAME WHEN AN ERROR OCCURS
PA01774> :PR0;
AltoIIMRT4K.mu:
;
; last modified December 1, 1977 1:14 AM
;
; This is the part of the Memory Refresh Task which
; is specific to Alto IIs WITHOUT Extended memory.
;
; Copyright Xerox Corporation 1979
$EngNumber $20000; ALTO 2 WITHOUT EXTENDED MEMORY
MRT: SINK_ MOUSE, BUS; MOUSE DATA IS ANDED WITH 17B
MRTA: L<- T<- -2, :TX0; DISPATCH ON MOUSE CHANGE
TX0: L_ T_ R37 AND NOT T; UPDATE REFRESH ADDRESS
T_ 3+T+1, SH=0;
L_ REFIIMSK ANDT, :DOTIMER;
NOTIMER:R37_ L; STORE UPDATED REFRESH ADDRESS
TIMERTN:L_ REFZERO AND T;
SH=0; TEST FOR CLOCK TICK
:NOCLK;
NOCLK: MAR_ R37; FIRST FEFRESH CYCLE
L_ CURX;
T_ 2, SH=0;
MAR_ R37 XORT, :DOCUR; SECOND REFRESH CYCLE
NOCUR: CURDATA_ L, TASK;
MRTLAST:CURDATA_ L, :MRT;
DOTIMER:R37_ L; SAVE REFRESH ADDRESS
MAR_EIALOC; INTERVAL TIMER/EIA INTERFACE
L_2 AND T;
SH=0, L_T_REFZERO.T; ***V3 CHANGE (USED TO BE BIAS)
CURDATA_L, :SPCHK; CURDATA_CURRENT TIME WITHOUT CONTROL BITS
SPCHK: SINK_MD, BUS=0, TASK; CHECK FOR EIA LINE SPACING
SPIA: :NOTIMERINT, CLOCKTEMP_L;
NOSPCHK:L_MD; CHECK FOR TIME=NOW
MAR_TRAPDISP-1; CONTAINS TIME AT WHICH INTERRUPT SHOULD HAPPEN
MTEMP_L; IF INTERRUPT IS CAUSED,
L_ MD-T; LINE STATE WILL BE STORED
SH=0, TASK, L_MTEMP, :SPIA;
TIMERINT:MAR_ ITQUAN; STORE THE THING IN CLOCKTEMP AT ITQUAN
L_ CURDATA;
R37_ L;
T_NWW; AND CAUSE AN INTERRUPT ON THE CHANNELS
MD_CLOCKTEMP; SPECIFIED BY ITQUAN+1
L_MD OR T, TASK;
NWW_L;
NOTIMERINT: T_R37, :TIMERTN;
;The rest of MRT, starting at the label CLOCK is unchanged
AltoIIMRT16K.mu:
;
; last modified December 1, 1977 1:13 AM
;
; This is the part of the Memory Refresh Task which
; is specific to Alto IIs with Extended memory.
;
; Copyright Xerox Corporation 1979
$EngNumber $30000; ALTO II WITH EXTENDED MEMORY
;
; This version assumes MRTACT is cleared by BLOCK, not MAR_ R37
; R37 [4-13] are the low bits of the TOD clock
; R37 [8-14] are the refresh address bits
; Each time MRT runs, four refresh addresses are generated, though
; R37 is incremented only once. Sprinkled throughout the execution
; of this code are the following operations having to do with refresh:
; MAR_ R37
; R37_ R37 +4 NOTE THAT R37 [14] DOES NOT CHANGE
; MAR_ R37 XOR 2 TOGGLES BIT 14
; MAR_ R37 XOR 200 TOGGLES BIT 8
; MAR_ R37 XOR 202 TOGGLES BITS 8 AND 14
MR00010> MRT: MAR<- R37; **FIRST REFRESH CYCLE**
MR00351> SINK<- MOUSE, BUS; MOUSE DATA IS ANDED WITH 17B
MR00360> MRTA: L<- T<- -2, :TX0; DISPATCH ON MOUSE CHANGE
MR00340> TX0: L<- R37 AND NOT T, T<- R37;INCREMENT CLOCK
MR00361> T<- 3+T+1, SH=0; IE. T<- T +4. IS INTV TIMER ON?
MR00362> L<- REFIIMSK AND T, :DOTIMER; [DOTIMER,NOTIMER] ZERO HIGH 4 BITS
MR00331> NOTIMER: R37<- L; STORE UPDATED CLOCK
MR00332> NOTIMERINT: T<- 2; NO STATE AT THIS POINT IN PUBLIC REGS
MR00363> MAR<- R37 XOR T,T<- R37; **SECOND REFRESH CYCLE**
MR00364> L<- REFZERO AND T; ONLY THE CLOKCK BITS, PLEASE
MR00365> SH=0, TASK; TEST FOR CLOCK OVERFLOW
MR00366> :NOCLK; [NOCLK,CLOCK]
MR00354> NOCLK: T <- 200;
MR00367> MAR<- R37 XOR T; **THIRD FEFRESH CYCLE**
MR00370> L<- CURX, BLOCK; CLEARS WAKEUP REQUEST FF
MR00371> T<- 2 OR T, SH=0; NEED TO CHECK CURSOR?
MR00372> MAR<- R37 XOR T, :DOCUR; **FOURTH REFRESH CYCLE**
MR00335> NOCUR: CURDATA<- L, TASK;
MR00327> MRTLAST:CURDATA<- L, :MRT; END OF MAIN LOOP
MR00330> DOTIMER:R37<- L; STORE UPDATED CLOCK
MR00373> MAR<- EIALOC; INTERVAL TIMER/EIA INTERFACE
MR00374> L<- 2 AND T;
MR00375> SH=0, L<- T<- REFZERO.T; ***V3 CHANGE (USED TO BE BIAS)
MR00376> CURDATA<-L, :SPCHK; CURDATA<- CURRENT TIME WITHOUT CONTROL BITS
MR00352> SPCHK: SINK<- MD, BUS=0, TASK; CHECK FOR EIA LINE SPACING
MR00377> SPIA: :NOTIMERINT, CLOCKTEMP<- L;
MR00353> NOSPCHK:L<-MD; CHECK FOR TIME = NOW
MR00400> MAR<-TRAPDISP-1; CONTAINS TIME AT WHICH INTERRUPT SHOULD HAPPEN
MR00401> MTEMP<-L; IF INTERRUPT IS CAUSED,
MR00402> L<- MD-T; LINE STATE WILL BE STORED
MR00403> SH=0, TASK, L<-MTEMP, :SPIA;
MR00333> TIMERINT:MAR<- ITQUAN; STORE THE THING IN CLOCKTEMP AT ITQUAN
MR00404> L<- CURDATA;
MR00405> R37<- L;
MR00406> T<-NWW; AND CAUSE AN INTERRUPT ON THE CHANNELS
MR00407> MD<-CLOCKTEMP; SPECIFIED BY ITQUAN+1
MR00410> L<-MD OR T, TASK;
MR00411> NWW<-L,:NOTIMERINT;
;The rest of MRT, starting at the label CLOCK is unchanged