Linked from RestoreAlto/index.html in Software in Sample Code Notes from e-mail by Josh Dersch < JoshD@LivingComputerMuseum.org > Mon, Jul 11, 2016 10:08 am - The code is below the ---------------------- See the attached. It's really not a question of *if* you need to trace the Alto on the LA, it's a question of *when* :). Unless you are exceptionally lucky and everything is working, debugging the hardware will likely require looking at the microcode, as the two are so tightly intertwined. Each source line is annotated with a prefix as in: XXYYYY> Where XX is a two letter prefix indicating the task the microcode belongs to, and YYYY is the microcode address (in octal) The prefixes are: EM - emulator SE - disk sector EN - ethernet MR - memory refresh DW - display word DH - display horizontal DV - display vertical PA - parity KW - disk word CU - cursor No microcode word is used by more than one task. This microcode listing matches up 100% with the PROMs in both of our Altos and the Alto II PROMs on Bitsavers (and included with Salto). As far as I know, this is the last revision of the Alto II microcode, you will want to verify that your PROMs match. - Josh --------- start of code ------------------------- ; 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 DV0014> DVT: MAR<- L<- DASTART+1; DV0001> CBA<- L, L<- 0; DV0005> CURDATA<- L; DV0006> SLC<- L; DV0017> T<- MD; CAUSE A VERTICAL FIELD INTERRUPT DV0023> L<- NWW OR T; DV0036> MAR<- CURLOC; SET UP THE CURSOR DV0046> NWW<- L, T<- 0-1; DV0047> L<- MD XOR T; HARDWARE EXPECTS X COMPLEMENTED DV0050> T<- MD, EVENFIELD; DV0051> CURX<- L, :DVT1; DV0002> DVT1: L<- BIAS-T-1, TASK, :DVT2; BIAS THE Y COORDINATE DV0003> DVT11: L<- BIAS-T, TASK; DV0052> DVT2: YPOS<- L, :DVT; ;Display Horizontal Task. ;11 cycles if no block change, 17 if new control block. DH0013> DHT: MAR<- CBA-1; DH0053> L<- SLC -1, BUS=0; DH0054> SLC<- L, :DHT0; DH0032> DHT0: T<- 37400; MORE TO DO IN THIS BLOCK DH0055> SINK<- MD; DH0056> L<- T<- MD AND T, SETMODE; DH0057> HTAB<- L LCY 8, :NORMODE; DH0034> NORMODE:L<- T<- 377 . T; DH0070> AECL<- L, :REST; DH0035> HALFMODE: L<- T<- 377 . T; DH0071> AECL<- L, :REST, T<- 0; DH0072> REST: L<- DWA + T,TASK; INCREMENT DWA BY 0 OR NWRDS DH0073> NDNX: DWA<- L, :DHT; DH0033> DHT1: L<- T<- MD+1, BUS=0; DH0074> CBA<- L, MAR<- T, :MOREB; DH0025> NOMORE: BLOCK, :DNX; DH0024> MOREB: T<- 37400; DH0075> L<- T<- MD AND T, SETMODE; DH0127> MAR<- CBA+1, :NORMX, EVENFIELD; DH0026> NORMX: HTAB<- L LCY 8, :NODD; DH0027> HALFX: HTAB<- L LCY 8, :NEVEN; DH0030> NODD: L<-T<- 377 . T; DH0130> AECL<- L, :XREST; ODD FIELD, FULL RESOLUTION DH0031> NEVEN: L<- 377 AND T; EVEN FIELD OR HALF RESOLUTION DH0131> AECL<-L, T<-0; DH0132> XREST: L<- MD+T; DH0133> T<-MD-1; DH0134> DNX: DWA<-L, L<-T, TASK; DH0135> SLC<-L, :DHT; ;Display Word Task DW0011> DWT: T<- DWA; DW0136> T<- -3+T+1; DW0137> L<- AECL+T,BUS=0,TASK; AECL CONTAINS NWRDS AT THIS TIME DW0140> AECL<-L, :DWTZ; DW0041> DWTY: BLOCK; DW0141> TASK, :DWTF; DW0040> DWTZ: L<-HTAB-1, BUS=0,TASK; DW0142> HTAB<-L, :DOTAB; DW0042> DOTAB: DDR<-0, :DWTZ; DW0043> NOTAB: MAR<-T<-DWA; DW0143> L<-AECL-T-1; DW0144> ALUCY, L<-2+T; DW0145> DWA<-L, :XNOMORE; DW0045> DOMORE: DDR<-MD, TASK; DW0146> DDR<-MD, :NOTAB; DW0144> XNOMORE:DDR<- MD, BLOCK; DW0147> DDR<- MD, TASK; DW0150> 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,,EOCDW,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 EN0007> EREST: L<- 0,ERBFCT; What's happening ? EN0152> EPNTR<- L,:ENOCMD; [ENOCMD,EOREST,EIREST,ERBRES] EN0203> ENOCMD: L<- ESNEVR,:EPOST; Shouldn't happen EN0217> 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. EN0237> EPOST: MAR<- EELOC; EN0220> EPNTR<- L,TASK; Save microcode status in EPNTR EN0222> MD<- ECNTR; Save ending count EN0224> MAR<- EPLOC; double word reference EN0230> T<- NWW; EN0240> MD<- EPNTR,EPFCT; BUS AND EPNTR with Status EN0260> L<- MD OR T,TASK; NWW OR c(EBLOC) EN0261> 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. EN0262> ESETUP: NOP; EN0263> L<- MD,BUS=0; check for zero length EN0264> T<- MD-1,:ECNTOK; [ECNTOK,ECNTZR] start-1 EN0253> ECNTZR: L<- ESCZER,:EPOST; Zero word count. Abort ;Ether Countdown Branch Function - ECBFCT. ;NEXT7 = Interface buffer not empty. EN0252> ECNTOK: ECNTR<- L,L<- T,ECBFCT,TASK; EN0265> 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. EN0213> 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 EN0153> EIFRST: MAR<- EHLOC; Get Ethernet address EN0266> T<- 377,EBFCT; What's happening? EN0267> L<- MD AND T,BUS=0,:EIFOK;[EIFOK,EIFBAD] promiscuous? EN0221> EIFOK: MTEMP<- LLCY8,:EIFCHK; [EIFCHK,EIFPRM] Data wakeup EN0225> EIFBAD: ERBFCT,TASK,:EIFB1; [EIFB1] POST wakeup; xCMD FF set? EN0151> EIFB1: :EIFB00; [EIFB00,EIFB01,EIFB10,EIFB11] EN0200> EIFB00: :EIFIGN; IDL or INGONE, restart rcvr EN0204> EIFB01: L<- ESABRT,:EPOST; OCMD, abort EN0210> EIFB10: L<- ESABRT,:EPOST; ICMD, abort EN0214> EIFB11: L<- ESABRT,:EPOST; ICMD and OCMD, abort EN0247> 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. EN0246> EIFCHK: L<- T<- 177400,EILFCT; Mask off src addr byte (BUS AND) EN0270> L<- MTEMP-T,SH=0; Broadcast? EN0271> SH=0,TASK,:EIFNBC; [EIFNBC,EIFBC] Our Address? EN0256> EIFNBC: :EIFIGN; [EIFIGN,EISET] EN0257> 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. EN0254> EIFIGN: SINK<- EPNTR,BUS=0,EPFCT;Reset; Called from output? EN0272> EISFCT,TASK,:EOCDWX; [EOCDWX,EIGO] Restart rcvr EN0226> EOCDWX: EWFCT,:EOCDWT; Return to countdown wait loop EN0255> 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 EN0236> EIDATA: T<- ECNTR-1, BUS=0; EN0273> MAR<- L<- EPNTR+1, EBFCT; [EIDMOR,EIDPST] What's happening EN0244> EIDMOR: EPNTR<- L, L<- T, ECBFCT; [EIDOK,EIDPST] Guaranteed to branch EN0241> EIDOK: MD<- EIDFCT, TASK; [EIDZ4] Read a word from the interface EN0234> 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". EN0245> EIDPST: L<- ESIDON, :EIDFUL; [EIDFUL,EPOST] Presumed to be INGONE EN0233> 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. EN0207> EOREST: MAR<- ELLOC; Get load EN0274> L<- R37; Use clock as random # gen EN0275> EPNTR<- LLSH1; Use bits [2:9] EN0276> L<- MD,EOSFCT; L<- current load EN0277> SH<0,ECNTR<- L; Overflowed? EN0300> MTEMP<- LLSH1,:EOLDOK; [EOLDOK,EOLDBD] EN0243> EOLDBD: L<- ESLOAD,:EPOST; Load overlow EN0242> EOLDOK: L<- MTEMP+1; Write updated load EN0301> MAR<- ELLOC; EN0302> MTEMP<- L,TASK; EN0303> MD<- MTEMP,:EORST1; New load = (old lshift 1) + 1 EN0304> EORST1: L<- EPNTR; Continue making random # EN0305> EPNTR<- LRSH1; EN0306> T<- 377; EN0307> L<- EPNTR AND T,TASK; EN0310> EPNTR<- L,:EORST2; ;At this point, EPNTR has 0,,random number, ENCTR has old load. EN0311> EORST2: MAR<- EICLOC; Has an input buffer been set up? EN0312> T<- ECNTR; EN0313> L<- EPNTR AND T; L<- Random & Load EN0314> SINK<- MD,BUS=0; EN0315> ECNTR<- L,SH=0,EPFCT,:EOINPR;[EOINPR,EOINPN] EN0154> EOINPR: EISFCT,:EOCDWT; [EOCDWT,EOCDGO] Enable in under out EN0155> 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. EN0250> EOCDWT: L<- 177400,EBFCT; What's happening? EN0316> EPNTR<- L,ECBFCT,:EOCDW;[EOCDW,EOCDRS] Packet coming in? EN0231> EOCDW: L<- ECNTR-1,BUS=0,TASK,:EOCDW1; [EOCDW1,EIGO] EN0223> EOCDW1: ECNTR<- L,EWFCT,:EOCDWT; [EOCDWT,EOCDGO] EN0235> EOCDRS: L<- ESABRT,:EPOST; [EPOST] POST event EN227> EIGO: :EIFRST; [EIFRST] Input under output ;Output main loop setup EN0251> EOCDGO: MAR<- EOCLOC; Double word reference EN0317> EPFCT; Reset interface EN0320> 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 EN0232> EODATA: L<- MAR<- EPNTR+1,EBFCT; What's happening? EN0321> T<- ECNTR-1,BUS=0,:EODOK; [EODOK,EODPST,EODCOL,EODUGH] EN0201> EODOK: EPNTR<- L,L<- T,:EODMOR; [EODMOR,EODEND] EN0156> EODMOR: ECNTR<- L,TASK; EN0322> EODFCT<- MD,:EODATA; Output word to transmitter EN0205> EODPST: L<- ESABRT,:EPOST; [EPOST] POST event EN0211> EODCOL: EPFCT,:EOREST; [EOREST] Collision EN0215> 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. EN0157> EODEND: EEFCT; Disable data wakeups EN0323> TASK; Wait for EEFCT to take EN0324> :EOEOT; Wait for Outgone ;Output completion. We are waiting for the interface buffer to ;empty, and the interface to generate an OUTGONE Post wakeup. EN0325> EOEOT: EBFCT; What's happening? EN0326> :EOEOK; [EOEOK,EOEPST,EOECOL,EOEUGH] EN0202> EOEOK: L<- ESNEVR,:EPOST; Runaway Transmitter. Never Never. EN0206> EOEPST: L<- ESODON,:EPOST; POST event. Output done EN0212> EOECOL: EPFCT,:EOREST; Collision EN0216> 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; MR0355> CLOCK: MAR<- CLOCKLOC; R37 OVERFLOWED. MR0412> NOP; MR0413> L<- MD+1; INCREMENT CLOCK IM MEMORY MR0414> MAR<- CLOCKLOC; MR0415> MTEMP<- L, TASK; MR0416> MD<- MTEMP, :NOCLK; MR0334> DOCUR: L<- T<- YPOS; CHECK FOR VISIBLE CURSOR ON THIS SCAN MR0417> SH<0, L<- 20-T-1; ***x13 change: the constant 20 was 17 MR0420> SH<0, L<- 2+T, :SHOWC; [SHOWC,WAITC] MR0337> WAITC: YPOS<- L, L<- 0, TASK, :MRTLAST; SQUASHES PENDING BRANCH MR0336> SHOWC: MAR<- CLOCKLOC+T+1, :CNOTLAST; MR0356> CNOTLAST: T<- CURX, :CURF; MR0357> CLAST: T<- 0; MR0421> CURF: YPOS<- L, L<- T; MR0422> CURX< L; MR0423> L<- MD, TASK; MR0424> CURDATA<- L, :MRT; ;AFTER THIS DISPATCH, T WILL CONTAIN XCHANGE, L WILL CONTAIN YCHANGE-1 MR0346> TX1: L<- T<- ONE +T, :M00; Y=0, X=1 MR0343> TX2: L<- T<- ALLONES, :M00; Y=0, X=-1 MR0342> TX3: L<- T<- 0, :M00; Y=1, X=0 MR0350> TX4: L<- T<- ONE AND T, :M00; Y=1, X=1 MR0345> TX5: L<- T<- ALLONES XOR T, :M00; Y=1, X=-1 MR0341> TX6: T<- 0, :M00; Y=-1, X=0 MR0347> TX7: T<- ONE, :M00; Y=-1, X=1 MR0344> TX8: T<- ALLONES, :M00; Y=-1, X=-1 MR0425> M00: MAR<- MOUSELOC; START THE FETCH OF THE COORDINATES MR0426> MTEMP<- L; YCHANGE -1 MR0427> L<- MD+ T; X+ XCHANGE MR0430> T<- MD; Y MR0431> T<- MTEMP+ T+1; Y+ (YCHANGE-1) + 1 MR0432> MTEMP<- L, L<- T; MR0433> MAR<- MOUSELOC; NOW RESTORE THE UPDATED COORDINATES MR0434> CLOCKTEMP<- L; MR0435> MD<- MTEMP, TASK; MR0436> MD<- CLOCKTEMP, :MRTA; ;CURSOR TASK ;Cursor task specific functions $XPREG $L026010,000000,124000; F2 = 10 $CSR $L026011,000000,124000; F2 = 11 CU0012> CURT: XPREG<- CURX, TASK; CU0437> 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. EM0000> NOVEM: IR<-L<-MAR<-0, :INXB,SAD<- L; LOAD SAD TO ZERO THE BUS. STORE PC AT 0 EM0460> Q0: L<- ONE, :INXA; EXECUTED TWICE EM0461> Q1: L<- TOTUWC, :INXA; EM0462> Q2: L<-402, :INXA; FIRST READ HEADER INTO 402, THEN EM0463> Q3: L<- 402, :INXA; STORE LABEL AT 402 EM0464> Q4: L<- ONE, :INXA; STORE DATA PAGE STARTING AT 1 EM0465> Q5: L<-377+1, :INXE; Store Ethernet Input Buffer Length ***X21. EM0466> Q6: L<-ONE, :INXE; Store Ethernet Input Buffer Pointer ***X21. EM0467> Q7: MAR<- DASTART; CLEAR THE DISPLAY POINTER EM0441> L<- 0; EM0451> R37<- L; EM0472> MD<- 0; EM0473> MAR<- 177034; FETCH KEYBOARD EM0474> L<- 100000; EM0475> NWW<- L, T<- 0-1; EM0476> L<- MD XOR T, BUSODD; *** X21 change. EM0477> MAR<- BDAD, :EtherBoot; [EtherBoot, DiskBoot] *** X21 change. ; BOOT DISK ADDRESS GOES IN LOCATION 12 EM0471> DiskBoot: SAD<- L, L<- 0+1; EM0500> MD<- SAD; EM0501> MAR<- KBLKADR, :FINSTO; ; Ethernet boot section added in X21. $NegBreathM1 $177175; $EthNovaGo $3; First data location of incoming packet EM0470> EtherBoot: L<-EthNovaGo, :EReRead; [EReRead, FINJMP] EM0454> EReRead:MAR<- EHLOC; Set the host address to 377 for breath packets EM0502> TASK; EM0503> MD<- 377; EM0504> MAR<- EPLOC; Zero the status word and start 'er up EM0505> SINK<- 2, STARTF; EM0506> MD <- 0; EM0457> EContRead: MAR<- EPLOC; See if status is still 0 EM0507> T<- 377; Status for correct read EM0510> L<- MD XOR T, TASK, BUS=0; EM0511> SAD<- L, :EReadDone; [EReadDone, EContRead] EM0456> EReadDone: MAR<- 2; Check the packet type EM0512> T<- NegBreathM1; -(Breath-of-life)-1 EM0513> T<-MD+T+1; EM0514> L<-SAD OR T; EM0515> SH=0, :EtherBoot; ; SUBROUTINE USED BY INITIALIZATION TO SET UP BLOCKS OF MEMORY $EIOffset $576; EM0516> INXA: T<-ONE, :INXCom; ***X21 change. EM0517> INXE: T<-EIOffset, :INXCom; ***X21 addition. EM0520> INXCom: MAR<-T<-IR<- SAD+T; *** X21 addition. EM0521> PC<- L, L<- 0+T+1; *** X21 change. EM0522> INXB: SAD<- L; **NB (JDersch 9/14 -- this is actually MD<-PC !) EM0523> SINK<- DISP, BUS,TASK; EM0524> 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 EM0020> START: T<- MAR<-PC+SKIP; EM0525> START1: L<- NWW, BUS=0; BUS# 0 MEANS DISABLED OR SOMETHING TO DO EM0576> :MAYBE, SH<0, L<- 0+T+1; SH<0 MEANS DISABLED EM0526> MAYBE: PC<- L, L<- T, :DOINT; EM0527> NOINT: PC<- L, :DIS0; EM0534> DOINT: MAR<- WWLOC, :INTCODE; TRY TO CAUSE AN INTERRUPT ;DISPATCH ON FUNCTION FIELD IF ARITHMETIC INSTRUCTION, ;OTHERWISE ON INDIRECT BIT AND INDEX FIELD EM0535> DIS0: L<- T<- IR<- MD; SKIP CLEARED HERE ;DISPATCH ON SHIFT FIELD IF ARITHMETIC INSTRUCTION, ;OTHERWISE ON THE INDIRECT BIT OR IR[3-7] EM0612> DIS1: T<- ACSOURCE, :GETAD; ;GETAD MUST BE 0 MOD 20 EM0540> GETAD: T<- 0, :DOINS; PAGE 0 EM0541> G1: T<- PC -1, :DOINS; RELATIVE EM0542> G2: T<- AC2, :DOINS; AC2 RELATIVE EM0543> G3: T<- AC3, :DOINS; AC3 RELATIVE EM0544> G4: T<- 0, :DOINS; PAGE 0 INDIRECT EM0545> G5: T<- PC -1, :DOINS; RELATIVE INDIRECT EM0546> G6: T<- AC2, :DOINS; AC2 RELATIVE INDIRECT EM0547> G7: T<- AC3, :DOINS; AC3 RELATIVE INDIRECT EM0550> G10: L<- 0-T-1, TASK, :SHIFT; COMPLEMENT EM0551> G11: L<- 0-T, TASK, :SHIFT; NEGATE EM0552> G12: L<- 0+T, TASK, :SHIFT; MOVE EM0553> G13: L<- 0+T+1, TASK, :SHIFT; INCREMENT EM0554> G14: L<- ACDEST-T-1, TASK, :SHIFT; ADD COMPLEMENT EM0555> G15: L<- ACDEST-T, TASK, :SHIFT; SUBTRACT EM0556> G16: L<- ACDEST+T, TASK, :SHIFT; ADD EM0557> G17: L<- ACDEST AND T, TASK, :SHIFT; EM0530> SHIFT: DNS<- L LCY 8, :START; SWAP BYTES EM0531> SH1: DNS<- L RSH 1, :START; RIGHT 1 EM0532> SH2: DNS<- L LSH 1, :START; LEFT 1 EM0533> SH3: DNS<- L, :START; NO SHIFT EM0060> DOINS: L<- DISP + T, TASK, :SAVAD, IDISP; DIRECT INSTRUCTIONS EM0061> DOIND: L<- MAR<- DISP+T; INDIRECT INSTRUCTIONS EM0613> XREG<- L; EM0614> L<- MD, TASK, IDISP, :SAVAD; EM0102> BRI: L<- MAR<- PCLOC ;INTERRUPT RETURN BRANCH EM0615> BRI0: T<- 77777; EM0616> L<- NWW AND T, SH < 0; EM0617> NWW<- L, :EIR0; BOTH EIR AND BRI MUST CHECK FOR INTERRUPT ; REQUESTS WHICH MAY HAVE COME IN WHILE ; INTERRUPTS WERE OFF EM0572> EIR0: L<- MD, :DOINT; EM0573> EIR1: L<- PC, :DOINT; ;***X21 addition ; DIRS - 61013 - Disable Interrupts and Skip if they were On EM0113> DIRS: T<-100000; EM0620> L<-NWW AND T; EM0621> L<-PC+1, SH=0; ; DIR - 61000 - Disable Interrupts EM0100> DIR: T<- 100000, :INTSOFF; EM0574> INTSOFF: L<- NWW OR T, TASK, :INTZ; EM0575> INTSON: PC<-L, :INTSOFF; ;EIR - 61001 - Enable Interrupts EM0101> EIR: L<- 100000, :BRI0; ;SIT - 61007 - Start Interval Timer EM0107> SIT: T<- AC0; EM0622> L<- R37 OR T, TASK; EM0623> R37<- L, :START; EM0624> FINJSR: L<- PC; EM0625> AC3<- L, L<- T, TASK; EM0455> FINJMP: PC<- L, :START; EM0626> 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 EM0064> JSRII: MAR<- DISP+T; FIRST LEVEL EM0627> IR<- JSRCX; EM0630> T<- MD, :DOIND; THE IR<- INSTRUCTION WILL NOT BRANCH ;TRAP ON UNIMPLEMENTED OPCODES. SAVES PC AT ;TRAPPC, AND DOES A JMP@ TRAPVEC ! OPCODE. EM0077> TRAP: XREG<- L LCY 8; THE INSTRUCTION EM0037> TRAP1: MAR<- TRAPPC;***X13 CHANGE: TAG 'TRAP1' ADDED EM0631> IR<- T<- 37; EM0632> MD<- PC; EM0633> T<- XREG.T; EM0634> T<- TRAPCON+T+1, :DOIND; T NOW CONTAINS 471+OPCODE ; THIS WILL DO JMP@ 530+OPCODE ;***X21 CHANGE: ADDED TAG RAMTRAP EM0076> RAMTRAP: SWMODE, :TRAP; ; Parameterless operations come here for dispatch. !1,2,NPNOTRAP,NPTRAP; EM0063> NOPAR: XREG<-L LCY 8; ***X21 change. Checks < 27. EM0635> T<-27; ***IIX3. Greatest defined op is 26. EM0640> L<-DISP-T; EM0641> ALUCY; EM0642> SINK<-DISP, SINK<-X37, BUS, TASK, :NPNOTRAP; EM0636> NPNOTRAP: :DIR; EM0637> NPTRAP: :TRAP1; ;***X21 addition for debugging w/ expanded DISP Prom EM0065> U5: :RAMTRAP; EM0066> U6: :RAMTRAP; EM0067> U7: :RAMTRAP; ;MAIN INSTRUCTION TABLE. GET HERE: ; (1) AFTER AN INDIRECTION ; (2) ON DIRECT INSTRUCTIONS EM0560> XCTAB: L<- SAD, TASK, :FINJMP; JMP EM0561> XJSR: T<- SAD, :FINJSR; JSR EM0562> XISZ: MAR<- SAD, :ISZ1; ISZ EM0563> XDSZ: MAR<- SAD, :DSZ1; DSZ EM0564> XLDA: MAR<- SAD, :FINLOAD; LDA 0-3 EM0565> XSTA: MAR<- SAD; /*NORMAL EM0643> XSTA1: L<- ACDEST, :FINSTO; /*NORMAL ; BOUNDS-CHECKING VERSION OF STORE ; SUBST ";**" TO ";**" 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; ;** EM0644> DSZ1: T<- ALLONES, :FINISZ; EM0645> ISZ1: T<- ONE, :FINISZ; EM0452> FINSTO: SAD<- L,TASK; EM0646> FINST1: MD<-SAD, :START; EM0647> FINLOAD: NOP; EM0650> LOADX: L<- MD, TASK; EM0651> LOADD: ACDEST<- L, :START; EM0652> FINISZ: L<- MD+T; EM0653> MAR<- SAD, SH=0; EM0654> SAD<- L, :FINSTO; EM0453> INCPC: MD<- SAD; EM0655> L<- PC+1, TASK; EM0656> 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; EM0121> DIV: T<- AC2; EM0657> DIVX: L<- AC0 - T; DO THE DIVIDE ONLY IF AC2>AC0 EM0672> ALUCY, TASK, SAD<- L, L<- 0+1; EM0673> :DODIV, SAD<- L LSH 1; SAD<- 2. COUNT THE LOOP BY SHIFTING EM0661> NODIV: :FINBLT; ***X21 change. EM0660> DODIV: L<- AC0, :DIV1; EM0662> DIVL: L<- AC0; EM0674> DIV1: SH<0, T<- AC1; WILL THE LEFT SHIFT OF THE DIVIDEND OVERFLOW? EM0675> :NOOVF, AC0<- L MLSH 1, L<- T<- 0+T; L<- AC1, T<- 0 EM0665> OVF: AC1<- L LSH 1, L<- 0+INCT, :NOV1; L<- 1. SHIFT OVERFLOWED EM0664> NOOVF: AC1<- L LSH 1 , L<- T; L<- 0. SHIFT OK EM0676> NOV1: T<- AC2, SH=0; EM0677> L<- AC0-T, :DX0; EM0667> 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. EM0700> :NOSUB, T<- AC1; EM0666> DX0: :DOSUB, T<- AC1; EM0671> DOSUB: AC0<- L, L<- 0+INCT; DO THE SUBTRACT EM0701> AC1<- L; AND PUT A 1 IN THE QUOTIENT EM0670> NOSUB: L<- SAD, BUS=0, TASK; EM0702> SAD<- L LSH 1, :DIVL; EM0663> 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; EM0120> MUL: L<- AC2-1, BUS=0; EM0703> MPYX: XREG<-L,L<- 0, :DOMUL; GET HERE WITH AC2-1 IN L. DON'T MUL IF AC2=0 EM0704> DOMUL: TASK, L<- -10+1; EM0720> SAD<- L; COUNT THE LOOP IN SAD EM0706> MPYL: L<- AC1, BUSODD; EM0721> T<- AC0, :NOADDIER; EM0710> NOADDIER: AC1<- L MRSH 1, L<- T, T<- 0, :NOSPILL; EM0711> ADDIER: L<- T<- XREG+INCT; EM0722> L<- AC1, ALUCY, :NOADDIER; EM0713> SPILL: T<- ONE; EM0712> NOSPILL: AC0<- L MRSH 1; EM0723> L<- AC1, BUSODD; EM0724> T<- AC0, :NOADDX; EM0714> NOADDX: AC1<- L MRSH 1, L<- T, T<- 0, :NOSPILLX; EM0715> ADDX: L<- T<- XREG+ INCT; EM0725> L<- AC1,ALUCY, :NOADDX; EM0717> SPILLX: T<- ONE; EM0716> NOSPILLX: AC0<- L MRSH 1; EM0726> L<- SAD+1, BUS=0, TASK; EM0727> SAD<- L, :MPYL; EM0705> NOMUL: T<- AC0; EM0730> AC0<- L, L<- T, TASK; CLEAR AC0 EM0731> AC1<- L; AND REPLACE AC1 WITH AC0 EM0707> 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; EM0062> EMCYCLE: L<- DISP, SINK<- X17, BUS=0; CONSTANT WITH BS=7 EM0734> CYCP: T<- AC0, :EMCYCX; EM0733> ACCYCLE: T<- AC1; EM0736> L<- 17 AND T, :CYCP; EM0732> EMCYCX: CYCOUT<-L, L<-0, :RETCYCX; EM0022> RAMCYCX: CYCOUT<-L, L<-0+1; EM0740> RETCYCX: CYRET<-L, L<-0+T; EM0742> SINK<-CYCOUT, BUS; EM0744> TASK, :L0; ;TABLE FOR CYCLE EM0174> R4: CYCOUT<- L MRSH 1; EM0741> Y3: L<- T<- CYCOUT, TASK; EM0175> R3X: CYCOUT<- L MRSH 1; EM0737> Y2: L<- T<- CYCOUT, TASK; EM0176> R2X: CYCOUT<- L MRSH 1; EM0735> Y1: L<- T<- CYCOUT, TASK; EM0177> R1X: CYCOUT<- L MRSH 1, :ENDCYCLE; EM0164> L4: CYCOUT<- L MLSH 1; EM0747> Z3: L<- T<- CYCOUT, TASK; EM0163> L3: CYCOUT<- L MLSH 1; EM0745> Z2: L<- T<- CYCOUT, TASK; EM0162> L2: CYCOUT<- L MLSH 1; EM0743> Z1: L<- T<- CYCOUT, TASK; EM0161> L1: CYCOUT<- L MLSH 1, :ENDCYCLE; EM0160> L0: CYCOUT<- L, :ENDCYCLE; EM0164> L8: CYCOUT<- L LCY 8, :ENDCYCLE; EM0165> L7: CYCOUT<- L LCY 8, :Y1; EM0166> L6: CYCOUT<- L LCY 8, :Y2; EM0165> L5: CYCOUT<- L LCY 8, :Y3; EM0171> R7: CYCOUT<- L LCY 8, :Z1; EM0172> R6: CYCOUT<- L LCY 8, :Z2; EM0173> R5: CYCOUT<- L LCY 8, :Z3; EM0746> ENDCYCLE: SINK<- CYRET, BUS, TASK; EM0750> :EMCYCRET; EM0600> EMCYCRET: L<-YCOUT, TASK, :LOADD; EM0601> 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; EM0566> CONVERT: MAR<-XREG+1; Got here via indirect mechanism which ; left first arg in SAD, its address in XREG. EM0751> T<-17; EM0760> L<-MD AND T; EM0761> T<-MAR<-AC3; EM0762> AC1<-L; AC1<-DBA EM0763> L<-MD+T, TASK; EM0764> AC3<-L; AC3<-Character descriptor block address(Char) EM0765> MAR<-AC3+1; EM0766> T<-177400; EM0767> IR<-L<-MD AND T; IR<-XH EM0770> XH<-L LCY 8, :ODDCX; XH register temporarily contains HD EM0577> ODDCX: L<-AC0, :HDENTER; EM0752> HDLOOP: T<-SAD; (really NWRDS) EM0771> L<-DWAX+T; EM0772> HDENTER: DWAX<-L; DWAX <- AC0+HD*NWRDS EM0773> L<-XH-1, BUS=0, TASK; EM0774> XH<-L, :HDLOOP; EM0753> HDEXIT: T<-MASKTAB; EM0775> MAR<-T<-AC1+T; Fetch the mask. EM1000> L<-DISP; EM1001> XH<-L; XH register now contains XH EM1002> L<-MD; EM1003> MASK<-L, L<-0+T+1, TASK; EM1004> AC1<-L; ***X21. AC1 <- (DBA)+1 EM1005> L<-5; ***X21. Calling conventions changed. EM1006> IR<-SAD, TASK; EM1007> CYRET<-L, :MOVELOOP; CYRET<-CALL5 EM0777> MOVELOOP: L<-T<-XH-1, BUS=0; EM1010> MAR<-AC3-T-1, :NFIN; Fetch next source word EM0756> NFIN: XH<-L; EM1011> T<-DISP; (really NWRDS) EM1012> L<-DWAX+T; Update destination address EM1013> T<-MD; EM1014> SINK<-AC1, BUS; EM1015> DWAX<-L, L<-T, TASK, :L0; Call Cycle subroutine EM0605> CONVCYCRET: MAR<-DWAX; EM1016> T<-MASK, BUS=0; EM1017> 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. EM0754> MERGE: L<-XREG AND NOT T; Data for second word. EM1020> T<-MD OR T; First word now merged, EM1021> XREG<-L, L<-T; EM1022> MTEMP<-L; EM1023> MAR<-DWAX; restore it. EM1024> SINK<-XREG, BUS=0, TASK; EM1025> MD<-MTEMP, :DOBOTH; XREG=0 means only one word ; is involved. EM0776> DOBOTH: MAR<-DWAX+1; EM1026> T<-XREG; EM1027> L<-MD OR T; EM1030> MAR<-DWAX+1; EM1031> XREG<-L, TASK; ***X21. TASK added. EM0755> STORE: MD<-XREG, :MOVELOOP; EM0757> FIN: L<-AC1-1; ***X21. Return AC1 to DBA. EM1032> AC1<-L; *** ... bletch ... EM1033> IR<-SH3CONST; EM1034> L<-MD, TASK, :SH1; ;RCLK - 61003 - Read the Real Time Clock into AC0,AC1 EM0103> RCLK: MAR<- CLOCKLOC; EM1035> L<- R37; EM1036> 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. EM0114> VERS: T<- EngNumber; ***V3 change EM1042> L<- 3+T, :LTOAC0; ***V3 change ;XMLDA - Extended Memory Load Accumulator. ; AC0 <- @AC1 in the alternate bank EM0125> XMLDA: XMAR<- AC1, :FINLOAD; ***V3 change ;XMSTA - Extended Memory Store Accumulator ; @AC1 <- AC0 in the alternate bank EM0126> 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; EM0105> BLT: L<- MAR<- AC0+1; EM1043> AC0<- L; EM1046> L<- MD, :BLKSA; EM0106> BLKS: L<- AC0; EM1047> BLKSA: T<- AC3+1, BUS=0; EM1050> MAR<- AC1+T, :MOREBLT; EM0606> MOREBLT: XREG<- L, L<- T; EM1051> AC3<- L, TASK; EM1052> MD<- XREG; STORE EM1053> L<- NWW, BUS=0; CHECK FOR INTERRUPT EM1054> SH<0, :PERHAPS, L<- PC-1; Prepare to back up PC. EM1045> NO: SINK<- DISP, SINK<- M7, BUS, :DISABLED; EM1044> PERHAPS: SINK<- DISP, SINK<- M7, BUS, :DOIT; EM0610> DOIT: PC<-L, :FINBLT; ***X21. Reset PC, terminate instruction. EM0611> DISABLED: :DIR; GOES TO BLT OR BLKS EM0607> FINBLT: T<-777; ***X21. PC in [177000-177777] means Ram return EM1055> L<-PC+T+1; EM1056> L<-PC AND T, TASK, ALUCY; EM1057> TOSTART: XREG<-L, :START; EM0021> RAMRET: T<-XREG, BUS, SWMODE; EM1060> TORAM: :NOVEM; ;PARAMETERLESS INSTRUCTIONS FOR DIDDLING THE WCS. ;JMPRAM - 61010 - JUMP TO THE RAM ADDRESS SPECIFIED BY AC1 EM0110> JMPR: T<-AC1, BUS, SWMODE, :TORAM; ;RDRAM - 61011 - READ THE RAM WORD ADDRESSED BY AC1 INTO AC0 EM0111> RDRM: T<- AC1, RDRAM; EM1061> L<- ALLONES, TASK, :LOADD; ;WRTRAM - 61012 - WRITE AC0,AC3 INTO THE RAM LOCATION ADDRESSED BY AC1 EM0112> WTRM: T<- AC1; EM1062> L<- AC0, WRTRAM; EM1063> L<- AC3, :FINBLT; ;DOUBLE WORD INSTRUCTIONS ;DREAD - 61015 ; AC0<- rv(AC3); AC1<- rv(AC3 xor 1) EM0115> DREAD: MAR<- AC3; START MEMORY CYCLE EM1064> NOP; DELAY EM1065> DREAD1: L<- MD; FIRST READ EM1066> T<-MD; SECOND READ EM1067> AC0<- L, L<-T, TASK; STORE MSW EM1070> AC1<- L, :START; STORE LSW ;DWRITE - 61016 ; rv(AC3)<- AC0; rv(AC3 xor 1)<- AC1 EM0116> DWRITE: MAR<- AC3; START MEMORY CYCLE EM1071> NOP; DELAY EM1072> MD<- AC0, TASK; FIRST WRITE EM1073> 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 EM0117> DEXCH: MAR<- AC3; START MEMORY CYCLE EM1074> NOP; DELAY EM1075> MD<- AC0; FIRST WRITE EM1076> MD<- AC1,:DREAD1; SECOND WRITE, GO TO READ ;DIOGNOSE INSTRUCTIONS ;DIOG1 - 61022 ; Hamming Code<- AC2 ; rv(AC3)<- AC0; rv(AC3 xor 1)<- AC1 EM0122> DIOG1: MAR<- ERRCTRL; START WRITE TO ERROR CONTROL EM1077> NOP; DELAY EM1100> MD<- AC2,:DWRITE; WRITE HAMMING CODE, GO TO DWRITE ;DIOG2 - 61023 ; rv(AC3)<- AC0 ; rv(AC3)<- AC0 xor AC1 EM0123> DIOG2: MAR<- AC3; START MEMORY CYCLE EM1101> T<- AC0; SETUP FOR XOR EM1102> L<- AC1 XORT; DO XOR EM1103> MD<- AC0; FIRST WRITE EM1104> MAR<- AC3; START MEMORY CYCLE EM1105> AC0<- L, TASK; STORE XOR WORD EM1106> 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 EM0567> INTCODE:PC<- L, IR<- 0; EM1107> T<- NWW; EM1110> T<- MD OR T; EM1111> L<- MD AND T; EM1112> SAD<- L, L<- T, SH=0; SAD HAD POTENTIAL INTERRUPTS EM1113> NWW<- L, L<- 0+1, :SOMEACTIVE; NWW HAS NEW WW EM0537> NOACTIVE: MAR<- WWLOC; RESTORE WW TO CORE EM1114> L<- SAD; AND REPLACE IT WITH SAD IN NWW EM1115> MD<- NWW, TASK; EM1116> INTZ: NWW<- L, :START; EM0536> SOMEACTIVE: MAR<- PCLOC; STORE PC AND SET UP TO FIND HIGHEST PRIORITY REQUEST EM1117> XREG<- L, L<- 0; EM1120> MD<- PC, TASK; EM1121> ILPA: PC<- L; EM1122> ILP: T<- SAD; EM1123> L<- T<- XREG AND T; EM1124> SH=0, L<- T, T<- PC; EM1125> :IEXIT, XREG<- L LSH 1; EM0571> NIEXIT: L<- 0+T+1, TASK, :ILPA; EM0570> IEXIT: MAR<- PCLOC+T+1; FETCH NEW PC. T HAS CHANNEL #, L HAS MASK EM1126> XREG<- L; EM1127> T<- XREG; EM1130> L<- NWW XOR T; TURN OFF BIT IN WW FOR INTERRUPT ABOUT TO HAPPEN EM1131> T<- MD; EM1132> NWW<- L, L<- T; EM1133> PC<- L, L<- T<- 0+1, TASK; EM1134> 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 EM0124> BITBLT: L<- 0; EM1135> SINK<-LREG, BUSODD; SINK<- -1 IFF NO RAM EM1142> L<- T<- DWOFF, :FDBL; EM1141> BBNORAM: TASK, :NPTRAP; TRAP IF NO RAM ; EM1166> FDW: T<- MD; PICK UP WIDTH, HEIGHT EM1143> WIDTH<- L, L<- T, TASK, :NZWID; EM1144> NZWID: NLINES<- L; EM1145> T<- AC1; EM1146> L<- NLINES-T; EM1147> NLINES<- L, SH<0, TASK; EM1150> :FDDX; ; EM1136> FDDX: L<- T<- DXOFF, :FDBL; PICK UP DEST X AND Y EM1164> FDX: T<- MD; EM1151> DESTX<- L, L<- T, TASK; EM1152> DESTY<- L; ; EM1153> L<- T<- SXOFF, :FDBL; PICK UP SOURCE X AND Y EM1172> FSX: T<- MD; EM1154> SRCX<- L, L<- T, TASK; EM1155> SRCY<- L, :CSHI; ; ; /* FETCH DOUBLEWORD FROM TABLE (L<- T<- OFFSET, :FDBL) EM1140> FDBL: MAR<- AC2+T; EM1156> SINK<- LREG, BUS; EM1160> FDBX: L<- MD, :FDBX; ; ; /* CALCULATE SKEW AND HINC !1,2,LTOR,RTOL; EM1157> CSHI: T<- DESTX; EM1161> L<- SRCX-T-1; EM1165> T<- LREG+1, SH<0; TEST HORIZONTAL DIRECTION EM1167> L<- 17.T, :LTOR; SKEW <- (SRCX - DESTX) MOD 16 EM1163> RTOL: SKEW<- L, L<- 0-1, :AH, TASK; HINC <- -1 EM0162> LTOR: SKEW<- L, L<- 0+1, :AH, TASK; HINC <- +1 EM1170> AH: HINC<- L; ; ; CALCULATE MASK1 AND MASK2 !1,2,IFRTOL,LNWORDS; !1,2,POSWID,NEGWID; EM1171> CMASKS: T<- DESTX; EM1173> T<- 17.T; EM1200> MAR<- LASTMASKP1-T-1; EM1201> L<- 17-T; STARTBITS <- 16 - (DESTX.17) EM1202> STARTBITSM1<- L; EM1203> L<- MD, TASK; EM1204> MASK1<- L; MASK1 <- @(MASKLOC+STARTBITS) EM1205> L<- WIDTH-1; EM1206> T<- LREG-1, SH<0; EM1207> T<- DESTX+T+1, :POSWID; EM1176> POSWID: T<- 17.T; EM1210> MAR<- LASTMASK-T-1; EM1211> T<- ALLONES; MASK2 <- NOT EM1212> L<- HINC-1; EM1213> L<- MD XOR T, SH=0, TASK; @(MASKLOC+(15-((DESTX+WIDTH-1).17))) EM1214> MASK2<- L, :IFRTOL; ; /* IF RIGHT TO LEFT, ADD WIDTH TO X'S AND EXCH MASK1, MASK2 EM1174> IFRTOL: T<- WIDTH-1; WIDTH-1 EM1215> L<- SRCX+T; EM1216> SRCX<- L; SRCX <- SCRX + (WIDTH-1) EM1217> L<- DESTX+T; EM1220> DESTX<- L; DESTX <- DESTX + (WIDTH-1) EM1221> T<- DESTX; EM1222> L<- 17.T, TASK; EM1223> STARTBITSM1<- L; STARTBITS <- (DESTX.17) + 1 EM1224> T<- MASK1; EM1225> L<- MASK2; EM1226> MASK1<- L, L<- T,TASK; EXCHANGE MASK1 AND MASK2 EM1227> MASK2<-L; ; ; /* CALCULATE NWORDS !1,2,LNW1,THIN; EM1175> LNWORDS:T<- STARTBITSM1+1; EM1232> L<- WIDTH-T-1; EM1233> T<- 177760, SH<0; EM1234> T<- LREG.T, :LNW1; EM1230> LNW1: L<- CALL4; NWORDS <- (WIDTH-STARTBITS)/16 EM1235> CYRET<- L, L<- T, :R4, TASK; CYRET<-CALL4 ; **WIDTH REG NOW FREE** EM0604> CYX4: L<- CYCOUT, :LNW2; EM1231> THIN: T<- MASK1; SPECIAL CASE OF THIN SLICE EM1236> L<-MASK2.T; EM1237> MASK1<- L, L<- 0-1; MASK1 <- MASK1.MASK2, NWORDS <- -1 EM1240> LNW2: NWORDS<- L; LOAD NWORDS ; **STARTBITSM1 REG NOW FREE** ; ; /* DETERMINE VERTICAL DIRECTION !1,2,BTOT,TTOB; T<- SRCY; EM1244> L<- DESTY-T; EM1245> T<- NLINES-1, SH<0; EM1246> L<- 0, :BTOT; VINC <- 0 IFF TOP-TO-BOTTOM EM1242> BTOT: L<- ALLONES; ELSE -1 EM1247> BTOT1: VINC<- L; EM1250> L<- SRCY+T; GOING BOTTOM TO TOP EM1251> SRCY<- L; ADD NLINES TO STARTING Y'S EM1252> L<- DESTY+T; EM1253> DESTY<- L, L<- 0+1, TASK; EM1254> TWICE<-L, :CWA; ; EM1243> 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 EM1255> CWA: L<- SRCY; Y HAS TO GO INTO AN R-REG FOR SHIFTING EM1256> YMUL<- L; EM1257> T<- SWAOFF; FIRST TIME IS FOR SWA, SRCX EM1260> L<- SRCX; ; **SRCX, SRCY REG NOW FREE** EM1261> DOSWA: MAR<- AC2+T; FETCH BITMAP ADDR AND RASTER EM1262> XREG<- L; EM1263> L<-CALL3; EM1264> CYRET<- L; CYRET<-CALL3 EM1265> L<- MD; EM1266> T<- MD; EM1267> DWAX<- L, L<-T, TASK; EM1270> RAST2<- L; EM1271> T<- 177760; EM1272> L<- T<- XREG.T, :R4, TASK; SWA <- SWA + SRCX/16 EM0603> CYX3: T<- CYCOUT; EM1273> L<- DWAX+T; EM1274> DWAX<- L; ; !1,2,NOADD,DOADD; !1,2,MULLP,CDELT; SWA <- SWA + SRCY*RAST1 EM1275> L<- RAST2; EM1302> SINK<- YMUL, BUS=0, TASK; NO MULT IF STARTING Y=0 EM1303> PLIER<- L, :MULLP; EM1300> MULLP: L<- PLIER, BUSODD; MULTIPLY RASTER BY Y EM1304> PLIER<- L RSH 1, :NOADD; EM1276> NOADD: L<- YMUL, SH=0, TASK; TEST NO MORE MULTIPLIER BITS EM1305> SHIFTB: YMUL<- L LSH 1, :MULLP; EM1277> DOADD: T<- YMUL; EM1306> L<- DWAX+T; EM1307> 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] EM1301> CDELT: L<- T<- HINC-1; (NOTE T<- -2 OR 0) EM1314> L<- T<- NWORDS-T, SH=0; (L<-NWORDS+2 OR T<-NWORDS) EM1315> CD1: SINK<- VINC, BUSODD, :HNEG; EM1310> HNEG: T<- RAST2, :VPOS; EM1311> HPOS: L<- -2-T, :CD1; (MAKES L<- -(NWORDS+2)) EM1312> VPOS: L<- LREG+T, :GDELT, TASK; BY NOW, LREG = +-(NWORDS+2) EM1313> VNEG: L<- LREG-T, :GDELT, TASK; AND T = RASTER EM1316> GDELT: RAST2<- L; ; ; /* END WORD ADDR LOOP !1,2,ONEMORE,CTOPL; EM1317> L<- TWICE-1; EM1322> TWICE<- L, SH<0; EM1323> L<- RAST2, :ONEMORE; USE RAST2 2ND TIME THRU EM1320> ONEMORE: RAST1<- L; EM1324> L<- DESTY, TASK; USE DESTY 2ND TIME THRU EM1325> YMUL<- L; EM1326> L<- DWAX; USE DWAX 2ND TIME THRU EM1327> T<- DESTX; CAREFUL - DESTX=SWA!! EM1330> SWA<- L, L<- T; USE DESTX 2ND TIME THRU EM1331> 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; EM1321> CTOPL: L<- SKEW, BUS=0, TASK; IF SKEW=0 THEN 0, ELSE EM1340> CTX: IR<- 0, :CTOP1; EM1332> CTOP1: T<- SRCX; (SKEW GR SRCX.17) XOR (HINC EQ 0) EM1341> L<- HINC-1; EM1342> T<- 17.T, SH=0; TEST HINC EM1343> L<- SKEW-T-1, :HM1; EM1335> H1: T<- HINC, SH<0; EM1344> L<- SWA+T, :NOTOPL; EM1334> HM1: T<- LREG; IF HINC=-1, THEN FLIP EM1345> L<- 0-T-1, :H1; THE POLARITY OF THE TEST EM1336> NOTOPL: SINK<- HINC, BUSODD, TASK, :CTX; HINC FORCES BUSODD EM1337> TOPL: SWA<- L, TASK; (DISP <- 100 FOR TOPLD) EM1346> IR<- 100, :CSKEW; ; **HINC REG NOW FREE** ; ; /* CALCULATE SKEW MASK !1,2,THINC,BCOM1; !1,2,COMSK,NOCOM; EM1333> CSKEW: T<- SKEW, BUS=0; IF SKEW=0, THEN COMP EM1347> MAR<- LASTMASKP1-T-1, :THINC; EM1350> THINC: L<-HINC-1; EM1354> SH=0; IF HINC=-1, THEN COMP EM1351> BCOM1: T<- ALLONES, :COMSK; EM1352> COMSK: L<- MD XOR T, :GFN; EM1353> NOCOM: L<- MD, :GFN; ; ; /* GET FUNCTION EM1355> GFN: MAR<- AC2; EM1356> SKMSK<- L; EM1357> T- MD; EM1360> L<- DISP+T, TASK; EM1361> 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; EM1363> VLOOP: T<- SWA; EM1364> L<- RAST1<-T; INC SWA BY DELTA EM1365> SWA<- L; EM1366> T<- DWAX; EM1367> L<- RAST2+T, TASK; INC DWAX BY DELTA EM1370> DWAX<- L; ; ; /* TEST FOR DONE, OR NEED GRAY !1,2,MOREV,DONEV; !1,2,BMAYBE,BNOINT; !1,2,BDOINT,BDIS0; !1,2,DOGRAY,NOGRAY; EM1371> BENTR: L<- T<- NLINES-1; DECR NLINES AND CHECK IF DONE EM1402> NLINES<- L, SH<0; EM1403> L<- NWW, BUS=0, :MOREV; CHECK FOR INTERRUPTS EM1372> MOREV: L<- 3.T, :BMAYBE, SH<0; CHECK DISABLED ***V3 change EM1375> BNOINT: SINK<- DISP, SINK<- lgm10, BUS=0, :BDIS0, TASK; EM1374> BMAYBE: SINK<- DISP, SINK<- lgm10, BUS=0, :BDOINT, TASK; TEST IF NEED GRAY(FUNC=8,12) EM1377> BDIS0: CONST<- L, :DOGRAY; ***V3 change ; ; /* INTERRUPT SUSPENSION (POSSIBLY) !1,1,DOI1; MAY GET AN OR-1 EM1376> BDOINT: :DOI1; TASK HERE EM1405> DOI1: T<- AC2; EM1404> MAR<- DHOFF+T; NLINES DONE = HT-NLINES-1 EM1406> T<- NLINES; EM1407> L<- PC-1; BACK UP THE PC, SO WE GET RESTARTED EM1410> PC<- L; EM1411> 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; EM1400> DOGRAY: T<- CONST-1; EM1414> T<- GRAYOFF+T+1; EM1415> MAR<- AC2+T; EM1416> NOP; UGH EM1417> L<- MD; EM1401> NOGRAY: SINK<- DISP, SINK<- lgm100, BUS=0, TASK; TEST TOPLD EM1420> CONST<- L, :PRELD; ; ; /* NORMAL COMPLETION EM1177> NEGWID: L<- 0, :BLITX, TASK; EM1373> DONEV: L<- 0, :BLITX, TASK; MAY BE AN OR-1 HERE! EM1137> BLITX: AC1<- L, :FINBLT; ; ; /* PRELOAD OF FIRST SOURCE WORD (DEPENDING ON ALIGNMENT) !1,2,AB1,NB1; EM1412> PRELD: SINK<- DISP, SINK<- lgm40, BUS=0; WHICH BANK EM1421> T<- HINC, :AB1; EM1423> NB1: MAR<- SWA-T, :XB1; (NORMAL BANK) EM1422> AB1: XMAR<- SWA-T, :XB1; (ALTERNATE BANK) EM1424> XB1: NOP; EM1425> L<- MD, TASK; EM1426> 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 EM1413> NOPLD: L<- 3, :FDISP; CALL #3 IS FIRST WORD EM1437> DON3: L<- NWORDS; EM1427> HCNT<- L, SH<0; HCNT COUNTS WHOLE WORDS EM1434> DON0: L<- HCNT-1, :DO0; IF NEG, THEN NO MIDDLE OR LAST EM1362> DO0: HCNT<- L, SH<0; CALL #0 (OR-14!) IS MIDDLE WORDS ; UGLY HACK SQUEEZES 2 INSTRS OUT OF INNER LOOP: EM1432> L<- DISP, SINK<- lgm14, BUS, TASK, :FDISPA; (WORKS LIKE L<-0) EM1431> LASTH: :LH1; TASK AND BUS PENDING EM1435> LH1: L<- 2, :FDISP; CALL #2 IS LAST WORD EM1436> 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; EM1433> FDISP: SINK<- DISP, SINK<-lgm14, BUS, TASK; EM1430> FDISPA: RETN<- L, :F0; EM1443> F0: SINK<- DISP, SINK<- lgm40, BUS=0, :WIND; FUNC 0 - WINDOW EM1447> F1: SINK<- DISP, SINK<- lgm40, BUS=0, :WIND; FUNC 1 - NOT WINDOW EM1467> F1A: T<- CYCOUT; EM1442> L<- ALLONES XOR T, TASK, :F3A; EM1453> F2: SINK<- DISP, SINK<- lgm40, BUS=0, :WIND; FUNC 2 - WINDOW .AND. GRAY EM1473> F2A: T<- CYCOUT; EM1444> L<- ALLONES XOR T; EM1445> SINK<- DISP, SINK<- lgm20, BUS=0; WHICH BANK EM1446> TEMP<- L, :AB2; TEMP <- NOT WINDOW EM1441> NB2: MAR<- DWAX, :XB2; (NORMAL BANK) EM1440> AB2: XMAR<- DWAX, :XB2; (ALTERNATE BANK) EM1450> XB2: L<- CONST AND T; WINDOW .AND. GRAY EM1451> T<- TEMP; EM1452> T<- MD .T; DEST.AND.NOT WINDOW EM1454> L<- LREG OR T, TASK, :F3A; (TRANSPARENT) EM1457> F3: L<- CONST, TASK, :F3A; FUNC 3 - CONSTANT (COLOR) ; ; ; /* AFTER GETTING SOURCE, START MEMORY AND DISPATCH ON OP !1,2,AB3,NB3; EM1455> F3A: CYCOUT<- L; (TASK HERE) EM1463> F0A: SINK<- DISP, SINK<- lgm20, BUS=0; WHICH BANK EM1456> SINK<- DISP, SINK<- lgm3, BUS, :AB3; DISPATCH ON OP EM1461> NB3: T<- MAR<- DWAX, :OP0; (NORMAL BANK) EM1460> 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 EM1474> OP0: SINK<- RETN, BUS; TEST IF UNMASKED EM1462> OP0A: L<- HINC+T, :STFULL; ELSE :STMSK EM1475> OP1: T<- CYCOUT; OP 1 - SOURCE .OR. DEST EM1464> L<- MD OR T, :OPN; EM1476> OP2: T<- CYCOUT; OP 2 - SOURCE .XOR. DEST EM1465> L<- MD XOR T, :OPN; EM1477> OP3: T<- CYCOUT; OP 3 - (NOT SOURCE) .AND. DEST EM1466> L<- 0-T-1; EM1470> T<- LREG; EM1471> L<- MD AND T, :OPN; EM1472> OPN: SINK<- DISP, SINK<- lgm20, BUS=0, TASK; WHICH BANK EM1500> CYCOUT<- L, :AB3; ; ; ; /* STORE MASKED INTO DESTINATION !1,2,STM2,STM1; !1,2,AB4,NB4; EM1517> STMSK: L<- MD; EM1501> SINK<- RETN, BUSODD, TASK; DETERMINE MASK FROM CALL INDEX EM1506> TEMP<- L, :STM2; STACHE DEST WORD IN TEMP EM1503> STM1: T<-MASK1, :STM3; EM1502> STM2: T<-MASK2, :STM3; EM1507> STM3: L<- CYCOUT AND T; ***X24. Removed TASK clause. EM1510> CYCOUT<- L, L<- 0-T-1; AND INTO SOURCE EM1511> T<- LREG; T<- MASK COMPLEMENTED EM1512> T<- TEMP .T; AND INTO DEST EM1513> L<- CYCOUT OR T; OR TOGETHER THEN GO STORE EM1514> SINK<- DISP, SINK<- lgm20, BUS=0, TASK; WHICH BANK EM1516> CYCOUT<- L, :AB4; EM1505> NB4: T<- MAR<- DWAX, :OP0A; (NORMAL BANK) EM1504> AB4: T<- XMAR<- DWAX, :OP0A; (ALTERNATE BANK) ; ; /* STORE UNMASKED FROM CYCOUT (L=NEXT DWAX) EM1515> STFULL: MD<- CYCOUT; EM1520> STFUL1: SINK<- RETN, BUS, TASK; EM1521> 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; EM1530> WIND: L<- T<- SKMSK, :AB5; ENTER HERE (8 INST TO TASK) EM1527> NB5: MAR<- SWA, :XB5; (NORMAL BANK) EM1526> AB5: XMAR<- SWA, :XB5; (ALTERNATE BANK) EM1531> XB5: L<- WORD2.T, SH=0; EM1532> CYCOUT<- L, L<- 0-T-1, :NZSK; CYCOUT<- OLD WORD .AND. MSK EM1525> ZESK: L<- MD, TASK; ZERO SKEW BYPASSES LOTS EM1533> CYCOUT<- L, :NOCY; EM1524> NZSK: T<- MD; EM1534> L<- LREG.T; EM1535> TEMP<- L, L<-T, TASK; TEMP<- NEW WORD .AND. NOTMSK EM1536> WORD2<- L; EM1540> T<- TEMP; EM1541> L<- T<- CYCOUT OR T; OR THEM TOGETHER EM1542> CYCOUT<- L, L<- 0+1, SH=0; DONT CYCLE A ZERO ***X21. EM1543> SINK<- SKEW, BUS, :DOCY; EM1522> DOCY: CYRET<- L LSH 1, L<- T, :L0; CYCLE BY SKEW ***X21. EM1523> NOCY: T<- SWA, :WIA; (MAY HAVE OR-17 FROM BUS) EM0602> CYX2: T<- SWA; EM1537> WIA: L<- HINC+T; EM1544> SINK<- DISP, SINK<- lgm14, BUS, TASK; DISPATCH TO CALLER EM1545> 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; SE0004> KSEC: MAR<- KBLKADR2; SE1574> KPOQ: CLRSTAT; RESET THE STORED DISK ADDRESS SE1575> MD<-L<-ALLONES+1, :GCOM2; ALSO CLEAR DCB POINTER SE1576> GETCOM: MAR<-KBLKADR; GET FIRST DCB POINTER SE1577> GCOM1: NOP; SE1600> L<-MD; SE1601> GCOM2: DCBR<-L,TASK; SE1602> KCOMM<-TOWTT; IDLE ALL DATA TRANSFERS SE1603> MAR<-KBLKADR3; GENERATE A SECTOR INTERRUPT SE1604> T<-NWW; SE1605> L<-MD OR T; SE1606> MAR<-KBLKADR+1; STORE THE STATUS SE1607> NWW<-L, TASK; SE1610> MD<-KSTAT; SE1611> MAR<-KBLKADR; WRITE THE CURRENT DCB POINTER SE1612> KSTAT<-5; INITIAL STATUS IS INCOMPLETE SE1613> L<-DCBR,TASK,BUS=0; SE1614> MD<-DCBR, :COMM; ; BUS=0 MAPS COMM TO NOCOMM SE1546> COMM: T<-2; GET THE DISK COMMAND SE1615> MAR<-DCBR+T; SE1616> T<-TOTUWC; SE1617> L<-MD XOR T, TASK, STROBON; SE1620> KWDCT<-L, :COMM2; ; STROBON MAPS COMM2 TO IDLE1 SE1550> COMM2: T<-10; READ NEW DISK ADDRESS SE1621> MAR<-DCBR+T+1; SE1622> T<-KWDCT; SE1623> L<-ONE AND T; SE1624> L<- -400 AND T, SH=0; SE1625> T<-MD, SH=0, :INVERT; ; SH=0 MAPS INVERT TO NOINVERT SE1572> INVERT: L<-2 XOR T, TASK, :BADCOMM; SE1573> NOINVERT: L<-T, TASK, :BADCOMM; ; SH=0 MAPS BADCOMM TO COMM3 SE1553> COMM3: KNMAR<-L; SE1626> MAR<-KBLKADR2; WRITE THE NEW DISK ADDRESS SE1627> T<-SECT2CM; CHECK FOR SECTOR > 13 SE1630> L<-T<-KDATA<-KNMAR+T; NEW DISK ADDRESS TO HARDWARE SE1631> KADR<-KWDCT,ALUCY; DISK COMMAND TO HARDWARE SE1632> L<-MD XOR T,TASK, :COMM4; COMPARE OLD AND NEW DISK ADDRESSES ; ALUCY MAPS COMM4 TO ILLSEC SE1554> COMM4: CKSUMR<-L; SE1633> MAR<-KBLKADR2; WRITE THE NEW DISK ADDRESS SE1634> T<-CADM,SWRNRDY; SEE IF DISK IS READY SE1635> L<-CKSUMR AND T, :COMM5; ; SWRNRDY MAPS COMM5 TO WHYNRDY SE1556> COMM5: MD<-KNMAR; COMPLETE THE WRITE SE1636> SH=0,TASK; SE1637> :STROB; ; SH=0 MAPS STROB TO CKSECT SE1561> CKSECT: T<-KNMAR,NFER; SE1640> L<-KSTAT XOR T, :STALL; ; NFER MAPS STALL TO CKSECT1 SE1563> CKSECT1: CKSUMR<-L,XFRDAT; SE1641> T<-CKSUMR, :KSFINI; ; XFRDAT MAPS KSFINI TO CKSECT2 SE1565> CKSECT2: L<-SECTMSK AND T; SE1642> KSLAST: BLOCK,SH=0; SE1571> GASP: TASK, :IDLE2; ; SH=0 MAPS IDLE2 TO TRANSFER SE1567> TRANSFER: KCOMM<-TOTUWC; TURN ON THE TRANSFER !1,2,ERRFND,NOERRFND; !1,2,EF1,NEF1; SE1643> DMPSTAT: T<-COMERR1; SEE IF STATUS REPRESENTS ERROR SE1650> L<-KSTAT AND T; SE1651> MAR<-DCBR+1; WRITE FINAL STATUS SE1652> KWDCT<-L,TASK,SH=0; SE1653> MD<-KSTAT,:ERRFND; ; SH=0 MAPS ERRFND TO NOERRFND SE1645> NOERRFND: T<-6; PICK UP NO-ERROR INTERRUPT WORD SE1654> INTCOM: MAR<-DCBR+T; SE1655> T<-NWW; SE1656> L<-MD OR T; SE1657> SINK<-KWDCT,BUS=0,TASK; SE1660> NWW<-L,:EF1; ; BUS=0 MAPS EF1 TO NEF1 SE1647> NEF1: MAR<-DCBR,:GCOM1; FETCH ADDRESS OF NEXT CONTROL BLOCK SE1644> ERRFND: T<-7,:INTCOM; PICK UP ERROR INTERRUPT WORD SE1646> EF1: :KSEC; SE1547> NOCOMM: L<-ALLONES,CLRSTAT,:KSLAST; SE1551> IDLE1: L<-ALLONES,:KSLAST; SE1566> IDLE2: KSTAT<-LOW14, :GETCOM; NO ACTIVITY THIS SECTOR SE1552> BADCOMM: KSTAT<-7; ILLEGAL COMMAND ONLY NOTED IN KBLK STAT SE1661> BLOCK; SE1662> TASK,:EF1; SE1557> WHYNRDY: NFER; SE1562> STALL: BLOCK, :STALL2; ; NFER MAPS STALL2 TO GASP SE1570> STALL2: TASK; SE1663> :DMPSTAT; SE1555> ILLSEC: KSTAT<-7, :STALL; ILLEGAL SECTOR SPECIFIED SE1560> STROB: CLRSTAT; SE1664> L<-ALLONES,STROBE,:CKSECT1; SE1564> 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; KW1737> KWD: BLOCK,:REC0; ; SH<0 MAPS REC0 TO REC0 ; ANYTHING=INIT MAPS REC0 TO KWD KW1735> REC0: L<-2, TASK; LENGTH OF RECORD 0 (ALLOW RELEASE IF BLOCKED) KW1665> KNMARW<-L; KW1702> T<-KNMARW, BLOCK, RWC; GET ADDR OF MEMORY BLOCK TO TRANSFER KW1710> MAR<-DCBR+T+1, :REC0RC; ; WRITE MAPS REC0RC TO REC0W ; INIT MAPS REC0RC TO KWD KW1722> REC0RC: T<-MFRRDL,BLOCK, :REC12A; FIRST RECORD READ DELAY KW1723> REC0W: T<-MFR0BL,BLOCK, :REC12A; FIRST RECORD 0'S BLOCK LENGTH KW1714> REC1: L<-10, INCRECNO; LENGTH OF RECORD 1 KW1715> T<-4, :REC12; KW1716> REC2: L<-PAGE1, INCRECNO; LENGTH OF RECORD 2 KW1725> T<-5, :REC12; KW1730> REC12: MAR<-DCBR+T, RWC; MEM BLK ADDR FOR RECORD KW1732> KNMARW<-L, :RDCK0; ; RWC=WRITE MAPS RDCK0 INTO WRT0 ; RWC=INIT MAPS RDCK0 INTO KWD KW1712> RDCK0: T<-MIRRDL, :REC12A; KW1713> WRT0: T<-MIR0BL, :REC12A; KW1734> REC12A: L<-MD; KW1736> KWDCTW<-L, L<-T; KW1740> COM1: KCOMM<- STUWC, :INPREF0; KW1701> INPREF: L<-CKSUMRW+1, INIT, BLOCK; KW1741> INPREF0: CKSUMRW<-L, SH<0, TASK, :INPREF1; ; INIT MAPS INPREF1 TO KWD KW1705> INPREF1: KDATA<-0, :PREFDONE; ; SH<0 MAPS PREFDONE TO INPREF KW1700> PREFDONE: T<-KNMARW; COMPUTE TOP OF BLOCK TO TRANSFER KW0016> KWDX: L<-KWDCTW+T,RWC; (ALSO USED FOR RESET) KW1742> 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 KW1704> RP0: KCOMM<-STRCWFS,:WP1; KW1706> CKP0: L<-KWDCTW-1; ADJUST FINISHING CONDITION BY 1 FOR CHECKING ONLY KW1743> KWDCTW<-L,:RP0; KW1707> WP0: KDATA<-ONE; WRITE THE SYNC PATTERN KW1744> WP1: L<-KBLKADR,TASK,:RW1; INITIALIZE THE CHECKSUM AND ENTER XFER LOOP KW1745> XFLP: T<-L<-KNMARW-1; BEGINNING OF MAIN XFER LOOP KW1746> KNMARW<-L; KW1747> MAR<-KNMARW,RWC; KW1750> 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 KW1724> R0: T<-CKSUMRW,SH=0,BLOCK; KW1751> MD<-L<-KDATA XOR T,TASK,:RW1; ; SH=0 MAPS RW1 TO RW2 KW1666> RW1: CKSUMRW<-L,:XFLP; KW1727> W0: T<-CKSUMRW,BLOCK; KW1752> KDATA<-L<-MD XOR T,SH=0; KW1753> TASK,:RW1; ; AS ALREADY NOTED, SH=0 MAPS RW1 TO RW2 KW1726> CK0: T<-KDATA,BLOCK,SH=0; KW1754> L<-MD XOR T,BUS=0,:CK1; ; SH=0 MAPS CK1 TO CK2 KW1670> CK1: L<-CKSUMRW XOR T,SH=0,:CK3; ; BUS=0 MAPS CK3 TO CK4 KW1672> CK3: TASK,:CKERR; ; SH=0 MAPS CKERR TO CK5 KW1675> CK5: CKSUMRW<-L,:XFLP; KW1673> CK4: MAR<-KNMARW, :CK6; ; SH=0 MAPS CK6 TO CK6 KW1703> CK6: CKSUMRW<-L,L<-0+T; KW1755> MTEMP<-L,TASK; KW1756> MD<-MTEMP,:XFLP; KW1671> CK2: L<-CKSUMRW-T,:R2; ; BUS=0 MAPS R2 TO R2 KW1667> RW2: CKSUMRW<-L; KW1757> T<-KDATA<-CKSUMRW,RWC; THIS CODE HANDLES THE FINAL CHECKSUM KW1760> L<-KDATA-T,BLOCK,:R2; ; RWC=CHECK NEVER GETS HERE ; RWC=WRITE MAPS R2 TO W2 ; RWC=INIT MAPS R2 AND W2 TO KWD KW1731> R2: L<-MRPAL, SH=0; SET READ POSTAMBLE LENGTH, CHECK CKSUM KW1761> KCOMM<-TOTUWC, :CKSMERR; ; SH=0 MAPS CKSMERR TO PXFLP0 KW1733> W2: L<-MWPAL, TASK; SET WRITE POSTAMBLE LENGTH KW1762> CKSUMRW<-L, :PXFLP; KW1720> CKSMERR: KSTAT<-0,:PXFLP0; 0 MEANS CHECKSUM ERROR .. CONTINUE KW1676> PXFLP: L<-CKSUMRW+1, INIT, BLOCK; KW1721> PXFLP0: CKSUMRW<-L, TASK, SH=0, :PXFLP1; ; INIT MAPS PXFLP1 TO KWD KW1711> PXFLP1: KDATA<-0,:PXFLP; ; SH=0 MAPS PXFLP TO PXF2 KW1677> PXF2: RECNO, BLOCK; DISPATCH BASED ON RECORD NUMBER KW1763> :REC1; ; RECNO=2 MAPS REC1 INTO REC2 ; RECNO=3 MAPS REC1 INTO REC3 ; RECNO=INIT MAPS REC1 INTO KWD KW1717> REC3: KSTAT<-4,:PXFLP; 4 MEANS SUCCESS!!! KW1674> CKERR: KCOMM<-TOTUWC; TURN OFF DATA TRANSFER KW1764> 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 PA0015> PART: T<- 10; PA1765> L<- ALLONES; TURN OFF MEMORY INTERRUPTS PA1766> MAR<- ERRCTRL, :PX1; PA0450> PR8: L<- SAD, :PX; PA0447> PR7: L<- PC, :PX; PA0446> PR6: L<- CBA, :PX; PA0445> PR5: L<- DWA, :PX; PA0444> PR4: L<- KNMAR, :PX; PA0443> PR3: L<- DCBR, :PX; PA0442> PR2: L<- NWW OR T, TASK; T CONTAINS 1 AT THIS POINT PA0440> PR0: NWW<- L, :PART; PA1767> PX: MAR<- 612+T; PA1770> PX1: MTEMP<- L, L<- T; PA1771> MD<- MTEMP; PA1772> CURDATA<- L; THIS CLOBBERS THE CURSOR FOR ONE PA1773> T<- CURDATA-1, BUS; FRAME WHEN AN ERROR OCCURS PA1774> :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 MR0010> MRT: MAR<- R37; **FIRST REFRESH CYCLE** MR0351> SINK<- MOUSE, BUS; MOUSE DATA IS ANDED WITH 17B MR0360> MRTA: L<- T<- -2, :TX0; DISPATCH ON MOUSE CHANGE MR0340> TX0: L<- R37 AND NOT T, T<- R37;INCREMENT CLOCK MR0361> T<- 3+T+1, SH=0; IE. T<- T +4. IS INTV TIMER ON? MR0362> L<- REFIIMSK AND T, :DOTIMER; [DOTIMER,NOTIMER] ZERO HIGH 4 BITS MR0331> NOTIMER: R37<- L; STORE UPDATED CLOCK MR0332> NOTIMERINT: T<- 2; NO STATE AT THIS POINT IN PUBLIC REGS MR0363> MAR<- R37 XOR T,T<- R37; **SECOND REFRESH CYCLE** MR0364> L<- REFZERO AND T; ONLY THE CLOKCK BITS, PLEASE MR0365> SH=0, TASK; TEST FOR CLOCK OVERFLOW MR0366> :NOCLK; [NOCLK,CLOCK] MR0354> NOCLK: T <- 200; MR0367> MAR<- R37 XOR T; **THIRD FEFRESH CYCLE** MR0370> L<- CURX, BLOCK; CLEARS WAKEUP REQUEST FF MR0371> T<- 2 OR T, SH=0; NEED TO CHECK CURSOR? MR0372> MAR<- R37 XOR T, :DOCUR; **FOURTH REFRESH CYCLE** MR0335> NOCUR: CURDATA<- L, TASK; MR0327> MRTLAST:CURDATA<- L, :MRT; END OF MAIN LOOP MR0330> DOTIMER:R37<- L; STORE UPDATED CLOCK MR0373> MAR<- EIALOC; INTERVAL TIMER/EIA INTERFACE MR0374> L<- 2 AND T; MR0375> SH=0, L<- T<- REFZERO.T; ***V3 CHANGE (USED TO BE BIAS) MR0376> CURDATA<-L, :SPCHK; CURDATA<- CURRENT TIME WITHOUT CONTROL BITS MR0352> SPCHK: SINK<- MD, BUS=0, TASK; CHECK FOR EIA LINE SPACING MR0377> SPIA: :NOTIMERINT, CLOCKTEMP<- L; MR0353> NOSPCHK:L<-MD; CHECK FOR TIME = NOW MR0400> MAR<-TRAPDISP-1; CONTAINS TIME AT WHICH INTERRUPT SHOULD HAPPEN MR0401> MTEMP<-L; IF INTERRUPT IS CAUSED, MR0402> L<- MD-T; LINE STATE WILL BE STORED MR0403> SH=0, TASK, L<-MTEMP, :SPIA; MR0333> TIMERINT:MAR<- ITQUAN; STORE THE THING IN CLOCKTEMP AT ITQUAN MR0404> L<- CURDATA; MR0405> R37<- L; MR0406> T<-NWW; AND CAUSE AN INTERRUPT ON THE CHANNELS MR0407> MD<-CLOCKTEMP; SPECIFIED BY ITQUAN+1 MR0410> L<-MD OR T, TASK; MR0411> NWW<-L,:NOTIMERINT; ;The rest of MRT, starting at the label CLOCK is unchanged