Service Manuals, User Guides, Schematic Diagrams or docs for : xerox alto microcode altoIIcode3.mu
<< Back |
HomeMost service manuals and schematics are PDF files, so You will need Adobre Acrobat Reader to view : Acrobat Download
Some of the files are DjVu format. Readers and resources available here : DjVu Resources
For the compressed files, most common are zip and rar. Please, extract files with Your favorite compression software ( WinZip, WinRAR ... ) before viewing.
If a document has multiple parts, You should download all, before extracting.
Good luck. Repair on Your own risk. Make sure You know what You are doing.
Image preview - the first page of the document
Preview not available!
Sorry, no preview image available for this document.
Possible reasons are : this is not a PDF document, it is password protected or the file is partially corrupted.
We are working to fix the issue.
You can still download the full file from the link below and it will be viewable.
>> Download altoIIcode3.mu documenatation <<Text preview - extract from the document; 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
;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
DVT: MAR_ L_ DASTART+1;
CBA_ L, L_ 0;
CURDATA_ L;
SLC_ L;
T_ MD; CAUSE A VERTICAL FIELD INTERRUPT
L_ NWW OR T;
MAR_ CURLOC; SET UP THE CURSOR
NWW_ L, T_ 0-1;
L_ MD XOR T; HARDWARE EXPECTS X COMPLEMENTED
T_ MD, EVENFIELD;
CURX_ L, :DVT1;
DVT1: L_ BIAS-T-1, TASK, :DVT2; BIAS THE Y COORDINATE
DVT11: L_ BIAS-T, TASK;
DVT2: YPOS_ L, :DVT;
;Display Horizontal Task.
;11 cycles if no block change, 17 if new control block.
DHT: MAR_ CBA-1;
L_ SLC -1, BUS=0;
SLC_ L, :DHT0;
DHT0: T_ 37400; MORE TO DO IN THIS BLOCK
SINK_ MD;
L_ T_ MD AND T, SETMODE;
HTAB_ L LCY 8, :NORMODE;
NORMODE:L_ T_ 377 . T;
AECL_ L, :REST;
HALFMODE: L_ T_ 377 . T;
AECL_ L, :REST, T_ 0;
REST: L_ DWA + T,TASK; INCREMENT DWA BY 0 OR NWRDS
NDNX: DWA_ L, :DHT;
DHT1: L_ T_ MD+1, BUS=0;
CBA_ L, MAR_ T, :MOREB;
NOMORE: BLOCK, :DNX;
MOREB: T_ 37400;
L_ T_ MD AND T, SETMODE;
MAR_ CBA+1, :NORMX, EVENFIELD;
NORMX: HTAB_ L LCY 8, :NODD;
HALFX: HTAB_ L LCY 8, :NEVEN;
NODD: L_T_ 377 . T;
AECL_ L, :XREST; ODD FIELD, FULL RESOLUTION
NEVEN: L_ 377 AND T; EVEN FIELD OR HALF RESOLUTION
AECL_L, T_0;
XREST: L_ MD+T;
T_MD-1;
DNX: DWA_L, L_T, TASK;
SLC_L, :DHT;
;Display Word Task
DWT: T_ DWA;
T_-3+T+1;
L_ AECL+T,BUS=0,TASK; AECL CONTAINS NWRDS AT THIS TIME
AECL_L, :DWTZ;
DWTY: BLOCK;
TASK, :DWTF;
DWTZ: L_HTAB-1, BUS=0,TASK;
HTAB_L, :DOTAB;
DOTAB: DDR_0, :DWTZ;
NOTAB: MAR_T_DWA;
L_AECL-T-1;
ALUCY, L_2+T;
DWA_L, :XNOMORE;
DOMORE: DDR_MD, TASK;
DDR_MD, :NOTAB;
XNOMORE:DDR_ MD, BLOCK;
DDR_ MD, TASK;
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
EREST: L_ 0,ERBFCT; What's happening ?
EPNTR_ L,:ENOCMD; [ENOCMD,EOREST,EIREST,ERBRES]
ENOCMD: L_ ESNEVR,:EPOST; Shouldn't happen
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.
EPOST: MAR_ EELOC;
EPNTR_ L,TASK; Save microcode status in EPNTR
MD_ ECNTR; Save ending count
MAR_ EPLOC; double word reference
T_ NWW;
MD_ EPNTR,EPFCT; BUS AND EPNTR with Status
L_ MD OR T,TASK; NWW OR c(EBLOC)
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.
ESETUP: NOP;
L_ MD,BUS=0; check for zero length
T_ MD-1,:ECNTOK; [ECNTOK,ECNTZR] start-1
ECNTZR: L_ ESCZER,:EPOST; Zero word count. Abort
;Ether Countdown Branch Function - ECBFCT.
;NEXT7 = Interface buffer not empty.
ECNTOK: ECNTR_ L,L_ T,ECBFCT,TASK;
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.
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
EIFRST: MAR_ EHLOC; Get Ethernet address
T_ 377,EBFCT; What's happening?
L_ MD AND T,BUS=0,:EIFOK;[EIFOK,EIFBAD] promiscuous?
EIFOK: MTEMP_ LLCY8,:EIFCHK; [EIFCHK,EIFPRM] Data wakeup
EIFBAD: ERBFCT,TASK,:EIFB1; [EIFB1] POST wakeup; xCMD FF set?
EIFB1: :EIFB00; [EIFB00,EIFB01,EIFB10,EIFB11]
EIFB00: :EIFIGN; IDL or INGONE, restart rcvr
EIFB01: L_ ESABRT,:EPOST; OCMD, abort
EIFB10: L_ ESABRT,:EPOST; ICMD, abort
EIFB11: L_ ESABRT,:EPOST; ICMD and OCMD, abort
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.
EIFCHK: L_ T_ 177400,EILFCT; Mask off src addr byte (BUS AND)
L_ MTEMP-T,SH=0; Broadcast?
SH=0,TASK,:EIFNBC; [EIFNBC,EIFBC] Our Address?
EIFNBC: :EIFIGN; [EIFIGN,EISET]
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.
EIFIGN: SINK_ EPNTR,BUS=0,EPFCT;Reset; Called from output?
EISFCT,TASK,:EOCDWX; [EOCDWX,EIGO] Restart rcvr
EOCDWX: EWFCT,:EOCDWT; Return to countdown wait loop
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
EIDATA: T_ ECNTR-1, BUS=0;
MAR_ L_ EPNTR+1, EBFCT; [EIDMOR,EIDPST] What's happening
EIDMOR: EPNTR_ L, L_ T, ECBFCT; [EIDOK,EIDPST] Guaranteed to branch
EIDOK: MD_ EIDFCT, TASK; [EIDZ4] Read a word from the interface
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".
EIDPST: L_ ESIDON, :EIDFUL; [EIDFUL,EPOST] Presumed to be INGONE
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.
EOREST: MAR_ ELLOC; Get load
L_ R37; Use clock as random # gen
EPNTR_ LRSH1; Use bits [6:13]
L_ MD,EOSFCT; L_ current load
SH<0,ECNTR_ L; Overflowed?
MTEMP_ LLSH1,:EOLDOK; [EOLDOK,EOLDBD]
EOLDBD: L_ ESLOAD,:EPOST; Load overlow
EOLDOK: L_ MTEMP+1; Write updated load
MAR_ ELLOC;
MTEMP_ L,TASK;
MD_ MTEMP,:EORST1; New load = (old lshift 1) + 1
EORST1: L_ EPNTR; Continue making random #
EPNTR_ LRSH1;
T_ 377;
L_ EPNTR AND T,TASK;
EPNTR_ L,:EORST2;
;At this point, EPNTR has 0,,random number, ENCTR has old load.
EORST2: MAR_ EICLOC; Has an input buffer been set up?
T_ ECNTR;
L_ EPNTR AND T; L_ Random & Load
SINK_ MD,BUS=0;
ECNTR_ L,SH=0,EPFCT,:EOINPR;[EOINPR,EOINPN]
EOINPR: EISFCT,:EOCDWT; [EOCDWT,EOCDGO] Enable in under out
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.
EOCDWT: L_ 177400,EBFCT; What's happening?
EPNTR_ L,ECBFCT,:EOCDW0;[EOCDW0,EOCDRS] Packet coming in?
EOCDW0: L_ ECNTR-1,BUS=0,TASK,:EOCDW1; [EOCDW1,EIGO]
EOCDW1: ECNTR_ L,EWFCT,:EOCDWT; [EOCDWT,EOCDGO]
EOCDRS: L_ ESABRT,:EPOST; [EPOST] POST event
EIGO: :EIFRST; [EIFRST] Input under output
;Output main loop setup
EOCDGO: MAR_ EOCLOC; Double word reference
EPFCT; Reset interface
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
EODATA: L_ MAR_ EPNTR+1,EBFCT; What's happening?
T_ ECNTR-1,BUS=0,:EODOK; [EODOK,EODPST,EODCOL,EODUGH]
EODOK: EPNTR_ L,L_ T,:EODMOR; [EODMOR,EODEND]
EODMOR: ECNTR_ L,TASK;
EODFCT_ MD,:EODATA; Output word to transmitter
EODPST: L_ ESABRT,:EPOST; [EPOST] POST event
EODCOL: EPFCT,:EOREST; [EOREST] Collision
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.
EODEND: EEFCT; Disable data wakeups
TASK; Wait for EEFCT to take
:EOEOT; Wait for Outgone
;Output completion. We are waiting for the interface buffer to
;empty, and the interface to generate an OUTGONE Post wakeup.
EOEOT: EBFCT; What's happening?
:EOEOK; [EOEOK,EOEPST,EOECOL,EOEUGH]
EOEOK: L_ ESNEVR,:EPOST; Runaway Transmitter. Never Never.
EOEPST: L_ ESODON,:EPOST; POST event. Output done
EOECOL: EPFCT,:EOREST; Collision
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;
CLOCK: MAR_ CLOCKLOC; R37 OVERFLOWED.
NOP;
L_ MD+1; INCREMENT CLOCK IM MEMORY
MAR_ CLOCKLOC;
MTEMP_ L, TASK;
MD_ MTEMP, :NOCLK;
DOCUR: L_ T_ YPOS; CHECK FOR VISIBLE CURSOR ON THIS SCAN
SH<0, L_ 20-T-1; ***x13 change: the constant 20 was 17
SH<0, L_ 2+T, :SHOWC; [SHOWC,WAITC]
WAITC: YPOS_ L, L_ 0, TASK, :MRTLAST; SQUASHES PENDING BRANCH
SHOWC: MAR_ CLOCKLOC+T+1, :CNOTLAST;
CNOTLAST: T_ CURX, :CURF;
CLAST: T_ 0;
CURF: YPOS_ L, L_ T;
CURX_ L;
L_ MD, TASK;
CURDATA_ L, :MRT;
;AFTER THIS DISPATCH, T WILL CONTAIN XCHANGE, L WILL CONTAIN YCHANGE-1
TX1: L_ T_ ONE +T, :M00; Y=0, X=1
TX2: L_ T_ ALLONES, :M00; Y=0, X=-1
TX3: L_ T_ 0, :M00; Y=1, X=0
TX4: L_ T_ ONE AND T, :M00; Y=1, X=1
TX5: L_ T_ ALLONES XOR T, :M00; Y=1, X=-1
TX6: T_ 0, :M00; Y=-1, X=0
TX7: T_ ONE, :M00; Y=-1, X=1
TX8: T_ ALLONES, :M00; Y=-1, X=-1
M00: MAR_ MOUSELOC; START THE FETCH OF THE COORDINATES
MTEMP_ L; YCHANGE -1
L_ MD+ T; X+ XCHANGE
T_ MD; Y
T_ MTEMP+ T+1; Y+ (YCHANGE-1) + 1
MTEMP_ L, L_ T;
MAR_ MOUSELOC; NOW RESTORE THE UPDATED COORDINATES
CLOCKTEMP_ L;
MD_ MTEMP, TASK;
MD_ CLOCKTEMP, :MRTA;
;CURSOR TASK
;Cursor task specific functions
$XPREG $L026010,000000,124000; F2 = 10
$CSR $L026011,000000,124000; F2 = 11
CURT: XPREG_ CURX, TASK;
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.
NOVEM: IR_L_MAR_0, :INXB,SAD_ L; LOAD SAD TO ZERO THE BUS. STORE PC AT 0
Q0: L_ ONE, :INXA; EXECUTED TWICE
Q1: L_ TOTUWC, :INXA;
Q2: L_402, :INXA; FIRST READ HEADER INTO 402, THEN
Q3: L_ 402, :INXA; STORE LABEL AT 402
Q4: L_ ONE, :INXA; STORE DATA PAGE STARTING AT 1
Q5: L_377+1, :INXE; Store Ethernet Input Buffer Length ***X21.
Q6: L_ONE, :INXE; Store Ethernet Input Buffer Pointer ***X21.
Q7: MAR_ DASTART; CLEAR THE DISPLAY POINTER
L_ 0;
R37_ L;
MD_ 0;
MAR_ 177034; FETCH KEYBOARD
L_ 100000;
NWW_ L, T_ 0-1;
L_ MD XOR T, BUSODD; *** X21 change.
MAR_ BDAD, :EtherBoot; [EtherBoot, DiskBoot] *** X21 change.
; BOOT DISK ADDRESS GOES IN LOCATION 12
DiskBoot: SAD_ L, L_ 0+1;
MD_ SAD;
MAR_ KBLKADR, :FINSTO;
; Ethernet boot section added in X21.
$NegBreathM1 $177175;
$EthNovaGo $3; First data location of incoming packet
EtherBoot: L_EthNovaGo, :EReRead; [EReRead, FINJMP]
EReRead:MAR_ EHLOC; Set the host address to 377 for breath packets
TASK;
MD_ 377;
MAR_ EPLOC; Zero the status word and start 'er up
SINK_ 2, STARTF;
MD _ 0;
EContRead: MAR_ EPLOC; See if status is still 0
T_ 377; Status for correct read
L_ MD XOR T, TASK, BUS=0;
SAD_ L, :EReadDone; [EReadDone, EContRead]
EReadDone: MAR_ 2; Check the packet type
T_ NegBreathM1; -(Breath-of-life)-1
T_MD+T+1;
L_SAD OR T;
SH=0, :EtherBoot;
; SUBROUTINE USED BY INITIALIZATION TO SET UP BLOCKS OF MEMORY
$EIOffset $576;
INXA: T_ONE, :INXCom; ***X21 change.
INXE: T_EIOffset, :INXCom; ***X21 addition.
INXCom: MAR_T_IR_ SAD+T; *** X21 addition.
PC_ L, L_ 0+T+1; *** X21 change.
INXB: MD_ PC;
SINK_ DISP, BUS,TASK;
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
START: T_ MAR_PC+SKIP;
START1: L_ NWW, BUS=0; BUS# 0 MEANS DISABLED OR SOMETHING TO DO
:MAYBE, SH<0, L_ 0+T+1; SH<0 MEANS DISABLED
MAYBE: PC_ L, L_ T, :DOINT;
NOINT: PC_ L, :DIS0;
DOINT: MAR_ WWLOC, :INTCODE; TRY TO CAUSE AN INTERRUPT
;DISPATCH ON FUNCTION FIELD IF ARITHMETIC INSTRUCTION,
;OTHERWISE ON INDIRECT BIT AND INDEX FIELD
DIS0: L_ T_ IR_ MD; SKIP CLEARED HERE
;DISPATCH ON SHIFT FIELD IF ARITHMETIC INSTRUCTION,
;OTHERWISE ON THE INDIRECT BIT OR IR[3-7]
DIS1: T_ ACSOURCE, :GETAD;
;GETAD MUST BE 0 MOD 20
GETAD: T_ 0, :DOINS; PAGE 0
G1: T_ PC -1, :DOINS; RELATIVE
G2: T_ AC2, :DOINS; AC2 RELATIVE
G3: T_ AC3, :DOINS; AC3 RELATIVE
G4: T_ 0, :DOINS; PAGE 0 INDIRECT
G5: T_ PC -1, :DOINS; RELATIVE INDIRECT
G6: T_ AC2, :DOINS; AC2 RELATIVE INDIRECT
G7: T_ AC3, :DOINS; AC3 RELATIVE INDIRECT
G10: L_ 0-T-1, TASK, :SHIFT; COMPLEMENT
G11: L_ 0-T, TASK, :SHIFT; NEGATE
G12: L_ 0+T, TASK, :SHIFT; MOVE
G13: L_ 0+T+1, TASK, :SHIFT; INCREMENT
G14: L_ ACDEST-T-1, TASK, :SHIFT; ADD COMPLEMENT
G15: L_ ACDEST-T, TASK, :SHIFT; SUBTRACT
G16: L_ ACDEST+T, TASK, :SHIFT; ADD
G17: L_ ACDEST AND T, TASK, :SHIFT;
SHIFT: DNS_ L LCY 8, :START; SWAP BYTES
SH1: DNS_ L RSH 1, :START; RIGHT 1
SH2: DNS_ L LSH 1, :START; LEFT 1
SH3: DNS_ L, :START; NO SHIFT
DOINS: L_ DISP + T, TASK, :SAVAD, IDISP; DIRECT INSTRUCTIONS
DOIND: L_ MAR_ DISP+T; INDIRECT INSTRUCTIONS
XREG_ L;
L_ MD, TASK, IDISP, :SAVAD;
BRI: L_ MAR_ PCLOC ;INTERRUPT RETURN BRANCH
BRI0: T_ 77777;
L_ NWW AND T, SH < 0;
NWW_ L, :EIR0; BOTH EIR AND BRI MUST CHECK FOR INTERRUPT
; REQUESTS WHICH MAY HAVE COME IN WHILE
; INTERRUPTS WERE OFF
EIR0: L_ MD, :DOINT;
EIR1: L_ PC, :DOINT;
;***X21 addition
; DIRS - 61013 - Disable Interrupts and Skip if they were On
DIRS: T_100000;
L_NWW AND T;
L_PC+1, SH=0;
; DIR - 61000 - Disable Interrupts
DIR: T_ 100000, :INTSOFF;
INTSOFF: L_ NWW OR T, TASK, :INTZ;
INTSON: PC_L, :INTSOFF;
;EIR - 61001 - Enable Interrupts
EIR: L_ 100000, :BRI0;
;SIT - 61007 - Start Interval Timer
SIT: T_ AC0;
L_ R37 OR T, TASK;
R37_ L, :START;
FINJSR: L_ PC;
AC3_ L, L_ T, TASK;
FINJMP: PC_ L, :START;
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
JSRII: MAR_ DISP+T; FIRST LEVEL
IR_ JSRCX;
T_ MD, :DOIND; THE IR_ INSTRUCTION WILL NOT BRANCH
;TRAP ON UNIMPLEMENTED OPCODES. SAVES PC AT
;TRAPPC, AND DOES A JMP@ TRAPVEC ! OPCODE.
TRAP: XREG_ L LCY 8; THE INSTRUCTION
TRAP1: MAR_ TRAPPC;***X13 CHANGE: TAG 'TRAP1' ADDED
IR_ T_ 37;
MD_ PC;
T_ XREG.T;
T_ TRAPCON+T+1, :DOIND; T NOW CONTAINS 471+OPCODE
; THIS WILL DO JMP@ 530+OPCODE
;***X21 CHANGE: ADDED TAG RAMTRAP
RAMTRAP: SWMODE, :TRAP;
; Parameterless operations come here for dispatch.
!1,2,NPNOTRAP,NPTRAP;
NOPAR: XREG_L LCY 8; ***X21 change. Checks < 27.
T_27; ***IIX3. Greatest defined op is 26.
L_DISP-T;
ALUCY;
SINK_DISP, SINK_X37, BUS, TASK, :NPNOTRAP;
NPNOTRAP: :DIR;
NPTRAP: :TRAP1;
;***X21 addition for debugging w/ expanded DISP Prom
U5: :RAMTRAP;
U6: :RAMTRAP;
U7: :RAMTRAP;
;MAIN INSTRUCTION TABLE. GET HERE:
; (1) AFTER AN INDIRECTION
; (2) ON DIRECT INSTRUCTIONS
XCTAB: L_ SAD, TASK, :FINJMP; JMP
XJSR: T_ SAD, :FINJSR; JSR
XISZ: MAR_ SAD, :ISZ1; ISZ
XDSZ: MAR_ SAD, :DSZ1; DSZ
XLDA: MAR_ SAD, :FINLOAD; LDA 0-3
XSTA: MAR_ SAD; /*NORMAL
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;
;**
DSZ1: T_ ALLONES, :FINISZ;
ISZ1: T_ ONE, :FINISZ;
FINSTO: SAD_ L,TASK;
FINST1: MD_SAD, :START;
FINLOAD: NOP;
LOADX: L_ MD, TASK;
LOADD: ACDEST_ L, :START;
FINISZ: L_ MD+T;
MAR_ SAD, SH=0;
SAD_ L, :FINSTO;
INCPC: MD_ SAD;
L_ PC+1, TASK;
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;
DIV: T_ AC2;
DIVX: L_ AC0 - T; DO THE DIVIDE ONLY IF AC2>AC0
ALUCY, TASK, SAD_ L, L_ 0+1;
:DODIV, SAD_ L LSH 1; SAD_ 2. COUNT THE LOOP BY SHIFTING
NODIV: :FINBLT; ***X21 change.
DODIV: L_ AC0, :DIV1;
DIVL: L_ AC0;
DIV1: SH<0, T_ AC1; WILL THE LEFT SHIFT OF THE DIVIDEND OVERFLOW?
:NOOVF, AC0_ L MLSH 1, L_ T_ 0+T; L_ AC1, T_ 0
OVF: AC1_ L LSH 1, L_ 0+INCT, :NOV1; L_ 1. SHIFT OVERFLOWED
NOOVF: AC1_ L LSH 1 , L_ T; L_ 0. SHIFT OK
NOV1: T_ AC2, SH=0;
L_ AC0-T, :DX0;
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.
:NOSUB, T_ AC1;
DX0: :DOSUB, T_ AC1;
DOSUB: AC0_ L, L_ 0+INCT; DO THE SUBTRACT
AC1_ L; AND PUT A 1 IN THE QUOTIENT
NOSUB: L_ SAD, BUS=0, TASK;
SAD_ L LSH 1, :DIVL;
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;
MUL: L_ AC2-1, BUS=0;
MPYX: XREG_L,L_ 0, :DOMUL; GET HERE WITH AC2-1 IN L. DON'T MUL IF AC2=0
DOMUL: TASK, L_ -10+1;
SAD_ L; COUNT THE LOOP IN SAD
MPYL: L_ AC1, BUSODD;
T_ AC0, :NOADDIER;
NOADDIER: AC1_ L MRSH 1, L_ T, T_ 0, :NOSPILL;
ADDIER: L_ T_ XREG+INCT;
L_ AC1, ALUCY, :NOADDIER;
SPILL: T_ ONE;
NOSPILL: AC0_ L MRSH 1;
L_ AC1, BUSODD;
T_ AC0, :NOADDX;
NOADDX: AC1_ L MRSH 1, L_ T, T_ 0, :NOSPILLX;
ADDX: L_ T_ XREG+ INCT;
L_ AC1,ALUCY, :NOADDX;
SPILLX: T_ ONE;
NOSPILLX: AC0_ L MRSH 1;
L_ SAD+1, BUS=0, TASK;
SAD_ L, :MPYL;
NOMUL: T_ AC0;
AC0_ L, L_ T, TASK; CLEAR AC0
AC1_ L; AND REPLACE AC1 WITH AC0
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;
EMCYCLE: L_ DISP, SINK_ X17, BUS=0; CONSTANT WITH BS=7
CYCP: T_ AC0, :EMCYCX;
ACCYCLE: T_ AC1;
L_ 17 AND T, :CYCP;
EMCYCX: CYCOUT_L, L_0, :RETCYCX;
RAMCYCX: CYCOUT_L, L_0+1;
RETCYCX: CYRET_L, L_0+T;
SINK_CYCOUT, BUS;
TASK, :L0;
;TABLE FOR CYCLE
R4: CYCOUT_ L MRSH 1;
Y3: L_ T_ CYCOUT, TASK;
R3X: CYCOUT_ L MRSH 1;
Y2: L_ T_ CYCOUT, TASK;
R2X: CYCOUT_ L MRSH 1;
Y1: L_ T_ CYCOUT, TASK;
R1X: CYCOUT_ L MRSH 1, :ENDCYCLE;
L4: CYCOUT_ L MLSH 1;
Z3: L_ T_ CYCOUT, TASK;
L3: CYCOUT_ L MLSH 1;
Z2: L_ T_ CYCOUT, TASK;
L2: CYCOUT_ L MLSH 1;
Z1: L_ T_ CYCOUT, TASK;
L1: CYCOUT_ L MLSH 1, :ENDCYCLE;
L0: CYCOUT_ L, :ENDCYCLE;
L8: CYCOUT_ L LCY 8, :ENDCYCLE;
L7: CYCOUT_ L LCY 8, :Y1;
L6: CYCOUT_ L LCY 8, :Y2;
L5: CYCOUT_ L LCY 8, :Y3;
R7: CYCOUT_ L LCY 8, :Z1;
R6: CYCOUT_ L LCY 8, :Z2;
R5: CYCOUT_ L LCY 8, :Z3;
ENDCYCLE: SINK_ CYRET, BUS, TASK;
:EMCYCRET;
EMCYCRET: L_CYCOUT, TASK, :LOADD;
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;
CONVERT: MAR_XREG+1; Got here via indirect mechanism which
; left first arg in SAD, its address in XREG.
T_17;
L_MD AND T;
T_MAR_AC3;
AC1_L; AC1_DBA
L_MD+T, TASK;
AC3_L; AC3_Character descriptor block address(Char)
MAR_AC3+1;
T_177400;
IR_L_MD AND T; IR_XH
XH_L LCY 8, :ODDCX; XH register temporarily contains HD
ODDCX: L_AC0, :HDENTER;
HDLOOP: T_SAD; (really NWRDS)
L_DWAX+T;
HDENTER: DWAX_L; DWAX _ AC0+HD*NWRDS
L_XH-1, BUS=0, TASK;
XH_L, :HDLOOP;
HDEXIT: T_MASKTAB;
MAR_T_AC1+T; Fetch the mask.
L_DISP;
XH_L; XH register now contains XH
L_MD;
MASK_L, L_0+T+1, TASK;
AC1_L; ***X21. AC1 _ (DBA)+1
L_5; ***X21. Calling conventions changed.
IR_SAD, TASK;
CYRET_L, :MOVELOOP; CYRET_CALL5
MOVELOOP: L_T_XH-1, BUS=0;
MAR_AC3-T-1, :NFIN; Fetch next source word
NFIN: XH_L;
T_DISP; (really NWRDS)
L_DWAX+T; Update destination address
T_MD;
SINK_AC1, BUS;
DWAX_L, L_T, TASK, :L0; Call Cycle subroutine
CONVCYCRET: MAR_DWAX;
T_MASK, BUS=0;
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.
MERGE: L_XREG AND NOT T; Data for second word.
T_MD OR T; First word now merged,
XREG_L, L_T;
MTEMP_L;
MAR_DWAX; restore it.
SINK_XREG, BUS=0, TASK;
MD_MTEMP, :DOBOTH; XREG=0 means only one word
; is involved.
DOBOTH: MAR_DWAX+1;
T_XREG;
L_MD OR T;
MAR_DWAX+1;
XREG_L, TASK; ***X21. TASK added.
STORE: MD_XREG, :MOVELOOP;
FIN: L_AC1-1; ***X21. Return AC1 to DBA.
AC1_L; *** ... bletch ...
IR_SH3CONST;
L_MD, TASK, :SH1;
;RCLK - 61003 - Read the Real Time Clock into AC0,AC1
RCLK: MAR_ CLOCKLOC;
L_ R37;
AC1_ L, :LOADX;
;SIO - 61004 - Put AC0 on the bus, issue STARTF to get device attention,
;Read Host address from Ethernet interface into AC0.
SIO: L_ AC0, STARTF;
T_ 77777; ***X21 sets AC0[0] to 0
L_ RSNF AND T;
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.
VERS: T_ EngNumber; ***V3 change
L_ 3+T, :LTOAC0; ***V3 change
;XMLDA - Extended Memory Load Accumulator.
; AC0 _ @AC1 in the alternate bank
XMLDA: XMAR_ AC1, :FINLOAD; ***V3 change
;XMSTA - Extended Memory Store Accumulator
; @AC1 _ AC0 in the alternate bank
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;
BLT: L_ MAR_ AC0+1;
AC0_ L;
L_ MD, :BLKSA;
BLKS: L_ AC0;
BLKSA: T_ AC3+1, BUS=0;
MAR_ AC1+T, :MOREBLT;
MOREBLT: XREG_ L, L_ T;
AC3_ L, TASK;
MD_ XREG; STORE
L_ NWW, BUS=0; CHECK FOR INTERRUPT
SH<0, :PERHAPS, L_ PC-1; Prepare to back up PC.
NO: SINK_ DISP, SINK_ M7, BUS, :DISABLED;
PERHAPS: SINK_ DISP, SINK_ M7, BUS, :DOIT;
DOIT: PC_L, :FINBLT; ***X21. Reset PC, terminate instruction.
DISABLED: :DIR; GOES TO BLT OR BLKS
FINBLT: T_777; ***X21. PC in [177000-177777] means Ram return
L_PC+T+1;
L_PC AND T, TASK, ALUCY;
TOSTART: XREG_L, :START;
RAMRET: T_XREG, BUS, SWMODE;
TORAM: :NOVEM;
;PARAMETERLESS INSTRUCTIONS FOR DIDDLING THE WCS.
;JMPRAM - 61010 - JUMP TO THE RAM ADDRESS SPECIFIED BY AC1
JMPR: T_AC1, BUS, SWMODE, :TORAM;
;RDRAM - 61011 - READ THE RAM WORD ADDRESSED BY AC1 INTO AC0
RDRM: T_ AC1, RDRAM;
L_ ALLONES, TASK, :LOADD;
;WRTRAM - 61012 - WRITE AC0,AC3 INTO THE RAM LOCATION ADDRESSED BY AC1
WTRM: T_ AC1;
L_ AC0, WRTRAM;
L_ AC3, :FINBLT;
;DOUBLE WORD INSTRUCTIONS
;DREAD - 61015
; AC0_ rv(AC3); AC1_ rv(AC3 xor 1)
DREAD: MAR_ AC3; START MEMORY CYCLE
NOP; DELAY
DREAD1: L_ MD; FIRST READ
T_MD; SECOND READ
AC0_ L, L_T, TASK; STORE MSW
AC1_ L, :START; STORE LSW
;DWRITE - 61016
; rv(AC3)_ AC0; rv(AC3 xor 1)_ AC1
DWRITE: MAR_ AC3; START MEMORY CYCLE
NOP; DELAY
MD_ AC0, TASK; FIRST WRITE
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
DEXCH: MAR_ AC3; START MEMORY CYCLE
NOP; DELAY
MD_ AC0; FIRST WRITE
MD_ AC1,:DREAD1; SECOND WRITE, GO TO READ
;DIOGNOSE INSTRUCTIONS
;DIOG1 - 61022
; Hamming Code_ AC2
; rv(AC3)_ AC0; rv(AC3 xor 1)_ AC1
DIOG1: MAR_ ERRCTRL; START WRITE TO ERROR CONTROL
NOP; DELAY
MD_ AC2,:DWRITE; WRITE HAMMING CODE, GO TO DWRITE
;DIOG2 - 61023
; rv(AC3)_ AC0
; rv(AC3)_ AC0 xor AC1
DIOG2: MAR_ AC3; START MEMORY CYCLE
T_ AC0; SETUP FOR XOR
L_ AC1 XORT; DO XOR
MD_ AC0; FIRST WRITE
MAR_ AC3; START MEMORY CYCLE
AC0_ L, TASK; STORE XOR WORD
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
INTCODE:PC_ L, IR_ 0;
T_ NWW;
T_ MD OR T;
L_ MD AND T;
SAD_ L, L_ T, SH=0; SAD HAD POTENTIAL INTERRUPTS
NWW_ L, L_0+1, :SOMEACTIVE; NWW HAS NEW WW
NOACTIVE: MAR_ WWLOC; RESTORE WW TO CORE
L_ SAD; AND REPLACE IT WITH SAD IN NWW
MD_ NWW, TASK;
INTZ: NWW_ L, :START;
SOMEACTIVE: MAR_ PCLOC; STORE PC AND SET UP TO FIND HIGHEST PRIORITY REQUEST
XREG_ L, L_ 0;
MD_ PC, TASK;
ILPA: PC_ L;
ILP: T_ SAD;
L_ T_ XREG AND T;
SH=0, L_ T, T_ PC;
:IEXIT, XREG_ L LSH 1;
NIEXIT: L_ 0+T+1, TASK, :ILPA;
IEXIT: MAR_ PCLOC+T+1; FETCH NEW PC. T HAS CHANNEL #, L HAS MASK
XREG_ L;
T_ XREG;
L_ NWW XOR T; TURN OFF BIT IN WW FOR INTERRUPT ABOUT TO HAPPEN
T_ MD;
NWW_ L, L_ T;
PC_ L, L_ T_ 0+1, TASK;
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
BITBLT: L_ 0;
SINK_LREG, BUSODD; SINK_ -1 IFF NO RAM
L_ T_ DWOFF, :FDBL;
BBNORAM: TASK, :NPTRAP; TRAP IF NO RAM
;
FDW: T_ MD; PICK UP WIDTH, HEIGHT
WIDTH_ L, L_ T, TASK, :NZWID;
NZWID: NLINES_ L;
T_ AC1;
L_ NLINES-T;
NLINES_ L, SH<0, TASK;
:FDDX;
;
FDDX: L_ T_ DXOFF, :FDBL; PICK UP DEST X AND Y
FDX: T_ MD;
DESTX_ L, L_ T, TASK;
DESTY_ L;
;
L_ T_ SXOFF, :FDBL; PICK UP SOURCE X AND Y
FSX: T_ MD;
SRCX_ L, L_ T, TASK;
SRCY_ L, :CSHI;
;
; /* FETCH DOUBLEWORD FROM TABLE (L_ T_ OFFSET, :FDBL)
FDBL: MAR_ AC2+T;
SINK_ LREG, BUS;
FDBX: L_ MD, :FDBX;
;
; /* CALCULATE SKEW AND HINC
!1,2,LTOR,RTOL;
CSHI: T_ DESTX;
L_ SRCX-T-1;
T_ LREG+1, SH<0; TEST HORIZONTAL DIRECTION
L_ 17.T, :LTOR; SKEW _ (SRCX - DESTX) MOD 16
RTOL: SKEW_ L, L_ 0-1, :AH, TASK; HINC _ -1
LTOR: SKEW_ L, L_ 0+1, :AH, TASK; HINC _ +1
AH: HINC_ L;
;
; CALCULATE MASK1 AND MASK2
!1,2,IFRTOL,LNWORDS;
!1,2,POSWID,NEGWID;
CMASKS: T_ DESTX;
T_ 17.T;
MAR_ LASTMASKP1-T-1;
L_ 17-T; STARTBITS _ 16 - (DESTX.17)
STARTBITSM1_ L;
L_ MD, TASK;
MASK1_ L; MASK1 _ @(MASKLOC+STARTBITS)
L_ WIDTH-1;
T_ LREG-1, SH<0;
T_ DESTX+T+1, :POSWID;
POSWID: T_ 17.T;
MAR_ LASTMASK-T-1;
T_ ALLONES; MASK2 _ NOT
L_ HINC-1;
L_ MD XOR T, SH=0, TASK; @(MASKLOC+(15-((DESTX+WIDTH-1).17)))
MASK2_ L, :IFRTOL;
; /* IF RIGHT TO LEFT, ADD WIDTH TO X'S AND EXCH MASK1, MASK2
IFRTOL: T_ WIDTH-1; WIDTH-1
L_ SRCX+T;
SRCX_ L; SRCX _ SCRX + (WIDTH-1)
L_ DESTX+T;
DESTX_ L; DESTX _ DESTX + (WIDTH-1)
T_ DESTX;
L_ 17.T, TASK;
STARTBITSM1_ L; STARTBITS _ (DESTX.17) + 1
T_ MASK1;
L_ MASK2;
MASK1_ L, L_ T,TASK; EXCHANGE MASK1 AND MASK2
MASK2_L;
;
; /* CALCULATE NWORDS
!1,2,LNW1,THIN;
LNWORDS:T_ STARTBITSM1+1;
L_ WIDTH-T-1;
T_ 177760, SH<0;
T_ LREG.T, :LNW1;
LNW1: L_ CALL4; NWORDS _ (WIDTH-STARTBITS)/16
CYRET_ L, L_ T, :R4, TASK; CYRET_CALL4
; **WIDTH REG NOW FREE**
CYX4: L_ CYCOUT, :LNW2;
THIN: T_ MASK1; SPECIAL CASE OF THIN SLICE
L_MASK2.T;
MASK1_ L, L_ 0-1; MASK1 _ MASK1.MASK2, NWORDS _ -1
LNW2: NWORDS_ L; LOAD NWORDS
; **STARTBITSM1 REG NOW FREE**
;
; /* DETERMINE VERTICAL DIRECTION
!1,2,BTOT,TTOB;
T_ SRCY;
L_ DESTY-T;
T_ NLINES-1, SH<0;
L_ 0, :BTOT; VINC _ 0 IFF TOP-TO-BOTTOM
BTOT: L_ ALLONES; ELSE -1
BTOT1: VINC_ L;
L_ SRCY+T; GOING BOTTOM TO TOP
SRCY_ L; ADD NLINES TO STARTING Y'S
L_ DESTY+T;
DESTY_ L, L_ 0+1, TASK;
TWICE_L, :CWA;
;
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
CWA: L_ SRCY; Y HAS TO GO INTO AN R-REG FOR SHIFTING
YMUL_ L;
T_ SWAOFF; FIRST TIME IS FOR SWA, SRCX
L_ SRCX;
; **SRCX, SRCY REG NOW FREE**
DOSWA: MAR_ AC2+T; FETCH BITMAP ADDR AND RASTER
XREG_ L;
L_CALL3;
CYRET_ L; CYRET_CALL3
L_ MD;
T_ MD;
DWAX_ L, L_T, TASK;
RAST2_ L;
T_ 177760;
L_ T_ XREG.T, :R4, TASK; SWA _ SWA + SRCX/16
CYX3: T_ CYCOUT;
L_ DWAX+T;
DWAX_ L;
;
!1,2,NOADD,DOADD;
!1,2,MULLP,CDELT; SWA _ SWA + SRCY*RAST1
L_ RAST2;
SINK_ YMUL, BUS=0, TASK; NO MULT IF STARTING Y=0
PLIER_ L, :MULLP;
MULLP: L_ PLIER, BUSODD; MULTIPLY RASTER BY Y
PLIER_ L RSH 1, :NOADD;
NOADD: L_ YMUL, SH=0, TASK; TEST NO MORE MULTIPLIER BITS
SHIFTB: YMUL_ L LSH 1, :MULLP;
DOADD: T_ YMUL;
L_ DWAX+T;
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]
CDELT: L_ T_ HINC-1; (NOTE T_ -2 OR 0)
L_ T_ NWORDS-T, SH=0; (L_NWORDS+2 OR T_NWORDS)
CD1: SINK_ VINC, BUSODD, :HNEG;
HNEG: T_ RAST2, :VPOS;
HPOS: L_ -2-T, :CD1; (MAKES L_-(NWORDS+2))
VPOS: L_ LREG+T, :GDELT, TASK; BY NOW, LREG = +-(NWORDS+2)
VNEG: L_ LREG-T, :GDELT, TASK; AND T = RASTER
GDELT: RAST2_ L;
;
; /* END WORD ADDR LOOP
!1,2,ONEMORE,CTOPL;
L_ TWICE-1;
TWICE_ L, SH<0;
L_ RAST2, :ONEMORE; USE RAST2 2ND TIME THRU
ONEMORE: RAST1_ L;
L_ DESTY, TASK; USE DESTY 2ND TIME THRU
YMUL_ L;
L_ DWAX; USE DWAX 2ND TIME THRU
T_ DESTX; CAREFUL - DESTX=SWA!!
SWA_ L, L_ T; USE DESTX 2ND TIME THRU
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;
CTOPL: L_ SKEW, BUS=0, TASK; IF SKEW=0 THEN 0, ELSE
CTX: IR_ 0, :CTOP1;
CTOP1: T_ SRCX; (SKEW GR SRCX.17) XOR (HINC EQ 0)
L_ HINC-1;
T_ 17.T, SH=0; TEST HINC
L_ SKEW-T-1, :HM1;
H1: T_ HINC, SH<0;
L_ SWA+T, :NOTOPL;
HM1: T_ LREG; IF HINC=-1, THEN FLIP
L_ 0-T-1, :H1; THE POLARITY OF THE TEST
NOTOPL: SINK_ HINC, BUSODD, TASK, :CTX; HINC FORCES BUSODD
TOPL: SWA_ L, TASK; (DISP _ 100 FOR TOPLD)
IR_ 100, :CSKEW;
; **HINC REG NOW FREE**
;
; /* CALCULATE SKEW MASK
!1,2,THINC,BCOM1;
!1,2,COMSK,NOCOM;
CSKEW: T_ SKEW, BUS=0; IF SKEW=0, THEN COMP
MAR_ LASTMASKP1-T-1, :THINC;
THINC: L_HINC-1;
SH=0; IF HINC=-1, THEN COMP
BCOM1: T_ ALLONES, :COMSK;
COMSK: L_ MD XOR T, :GFN;
NOCOM: L_ MD, :GFN;
;
; /* GET FUNCTION
GFN: MAR_ AC2;
SKMSK_ L;
T_ MD;
L_ DISP+T, TASK;
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;
VLOOP: T_ SWA;
L_ RAST1+T; INC SWA BY DELTA
SWA_ L;
T_ DWAX;
L_ RAST2+T, TASK; INC DWAX BY DELTA
DWAX_ L;
;
; /* TEST FOR DONE, OR NEED GRAY
!1,2,MOREV,DONEV;
!1,2,BMAYBE,BNOINT;
!1,2,BDOINT,BDIS0;
!1,2,DOGRAY,NOGRAY;
BENTR: L_ T_ NLINES-1; DECR NLINES AND CHECK IF DONE
NLINES_ L, SH<0;
L_ NWW, BUS=0, :MOREV; CHECK FOR INTERRUPTS
MOREV: L_ 3.T, :BMAYBE, SH<0; CHECK DISABLED ***V3 change
BNOINT: SINK_ DISP, SINK_ lgm10, BUS=0, :BDIS0, TASK;
BMAYBE: SINK_ DISP, SINK_ lgm10, BUS=0, :BDOINT, TASK; TEST IF NEED GRAY(FUNC=8,12)
BDIS0: CONST_ L, :DOGRAY; ***V3 change
;
; /* INTERRUPT SUSPENSION (POSSIBLY)
!1,1,DOI1; MAY GET AN OR-1
BDOINT: :DOI1; TASK HERE
DOI1: T_ AC2;
MAR_ DHOFF+T; NLINES DONE = HT-NLINES-1
T_ NLINES;
L_ PC-1; BACK UP THE PC, SO WE GET RESTARTED
PC_ L;
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;
DOGRAY: T_ CONST-1;
T_ GRAYOFF+T+1;
MAR_ AC2+T;
NOP; UGH
L_ MD;
NOGRAY: SINK_ DISP, SINK_ lgm100, BUS=0, TASK; TEST TOPLD
CONST_ L, :PRELD;
;
; /* NORMAL COMPLETION
NEGWID: L_ 0, :BLITX, TASK;
DONEV: L_ 0, :BLITX, TASK; MAY BE AN OR-1 HERE!
BLITX: AC1_ L, :FINBLT;
;
; /* PRELOAD OF FIRST SOURCE WORD (DEPENDING ON ALIGNMENT)
!1,2,AB1,NB1;
PRELD: SINK_ DISP, SINK_ lgm40, BUS=0; WHICH BANK
T_ HINC, :AB1;
NB1: MAR_ SWA-T, :XB1; (NORMAL BANK)
AB1: XMAR_ SWA-T, :XB1; (ALTERNATE BANK)
XB1: NOP;
L_ MD, TASK;
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
NOPLD: L_ 3, :FDISP; CALL #3 IS FIRST WORD
DON3: L_ NWORDS;
HCNT_ L, SH<0; HCNT COUNTS WHOLE WORDS
DON0: L_ HCNT-1, :DO0; IF NEG, THEN NO MIDDLE OR LAST
DO0: HCNT_ L, SH<0; CALL #0 (OR-14!) IS MIDDLE WORDS
; UGLY HACK SQUEEZES 2 INSTRS OUT OF INNER LOOP:
L_ DISP, SINK_ lgm14, BUS, TASK, :FDISPA; (WORKS LIKE L_0)
LASTH: :LH1; TASK AND BUS PENDING
LH1: L_ 2, :FDISP; CALL #2 IS LAST WORD
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;
FDISP: SINK_ DISP, SINK_lgm14, BUS, TASK;
FDISPA: RETN_ L, :F0;
F0: SINK_ DISP, SINK_ lgm40, BUS=0, :WIND; FUNC 0 - WINDOW
F1: SINK_ DISP, SINK_ lgm40, BUS=0, :WIND; FUNC 1 - NOT WINDOW
F1A: T_ CYCOUT;
L_ ALLONES XOR T, TASK, :F3A;
F2: SINK_ DISP, SINK_ lgm40, BUS=0, :WIND; FUNC 2 - WINDOW .AND. GRAY
F2A: T_ CYCOUT;
L_ ALLONES XOR T;
SINK_ DISP, SINK_ lgm20, BUS=0; WHICH BANK
TEMP_ L, :AB2; TEMP _ NOT WINDOW
NB2: MAR_ DWAX, :XB2; (NORMAL BANK)
AB2: XMAR_ DWAX, :XB2; (ALTERNATE BANK)
XB2: L_ CONST AND T; WINDOW .AND. GRAY
T_ TEMP;
T_ MD .T; DEST.AND.NOT WINDOW
L_ LREG OR T, TASK, :F3A; (TRANSPARENT)
F3: L_ CONST, TASK, :F3A; FUNC 3 - CONSTANT (COLOR)
;
;
; /* AFTER GETTING SOURCE, START MEMORY AND DISPATCH ON OP
!1,2,AB3,NB3;
F3A: CYCOUT_ L; (TASK HERE)
F0A: SINK_ DISP, SINK_ lgm20, BUS=0; WHICH BANK
SINK_ DISP, SINK_ lgm3, BUS, :AB3; DISPATCH ON OP
NB3: T_ MAR_ DWAX, :OP0; (NORMAL BANK)
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
OP0: SINK_ RETN, BUS; TEST IF UNMASKED
OP0A: L_ HINC+T, :STFULL; ELSE :STMSK
OP1: T_ CYCOUT; OP 1 - SOURCE .OR. DEST
L_ MD OR T, :OPN;
OP2: T_ CYCOUT; OP 2 - SOURCE .XOR. DEST
L_ MD XOR T, :OPN;
OP3: T_ CYCOUT; OP 3 - (NOT SOURCE) .AND. DEST
L_ 0-T-1;
T_ LREG;
L_ MD AND T, :OPN;
OPN: SINK_ DISP, SINK_ lgm20, BUS=0, TASK; WHICH BANK
CYCOUT_ L, :AB3;
;
;
; /* STORE MASKED INTO DESTINATION
!1,2,STM2,STM1;
!1,2,AB4,NB4;
STMSK: L_ MD;
SINK_ RETN, BUSODD, TASK; DETERMINE MASK FROM CALL INDEX
TEMP_ L, :STM2; STACHE DEST WORD IN TEMP
STM1: T_MASK1, :STM3;
STM2: T_MASK2, :STM3;
STM3: L_ CYCOUT AND T; ***X24. Removed TASK clause.
CYCOUT_ L, L_ 0-T-1; AND INTO SOURCE
T_ LREG; T_ MASK COMPLEMENTED
T_ TEMP .T; AND INTO DEST
L_ CYCOUT OR T; OR TOGETHER THEN GO STORE
SINK_ DISP, SINK_ lgm20, BUS=0, TASK; WHICH BANK
CYCOUT_ L, :AB4;
NB4: T_ MAR_ DWAX, :OP0A; (NORMAL BANK)
AB4: T_ XMAR_ DWAX, :OP0A; (ALTERNATE BANK)
;
; /* STORE UNMASKED FROM CYCOUT (L=NEXT DWAX)
STFULL: MD_ CYCOUT;
STFUL1: SINK_ RETN, BUS, TASK;
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;
WIND: L_ T_ SKMSK, :AB5; ENTER HERE (8 INST TO TASK)
NB5: MAR_ SWA, :XB5; (NORMAL BANK)
AB5: XMAR_ SWA, :XB5; (ALTERNATE BANK)
XB5: L_ WORD2.T, SH=0;
CYCOUT_ L, L_ 0-T-1, :NZSK; CYCOUT_ OLD WORD .AND. MSK
ZESK: L_ MD, TASK; ZERO SKEW BYPASSES LOTS
CYCOUT_ L, :NOCY;
NZSK: T_ MD;
L_ LREG.T;
TEMP_ L, L_T, TASK; TEMP_ NEW WORD .AND. NOTMSK
WORD2_ L;
T_ TEMP;
L_ T_ CYCOUT OR T; OR THEM TOGETHER
CYCOUT_ L, L_ 0+1, SH=0; DONT CYCLE A ZERO ***X21.
SINK_ SKEW, BUS, :DOCY;
DOCY: CYRET_ L LSH 1, L_ T, :L0; CYCLE BY SKEW ***X21.
NOCY: T_ SWA, :WIA; (MAY HAVE OR-17 FROM BUS)
CYX2: T_ SWA;
WIA: L_ HINC+T;
SINK_ DISP, SINK_ lgm14, BUS, TASK; DISPATCH TO CALLER
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;
KSEC: MAR_ KBLKADR2;
KPOQ: CLRSTAT; RESET THE STORED DISK ADDRESS
MD_L_ALLONES+1, :GCOM2; ALSO CLEAR DCB POINTER
GETCOM: MAR_KBLKADR; GET FIRST DCB POINTER
GCOM1: NOP;
L_MD;
GCOM2: DCBR_L,TASK;
KCOMM_TOWTT; IDLE ALL DATA TRANSFERS
MAR_KBLKADR3; GENERATE A SECTOR INTERRUPT
T_NWW;
L_MD OR T;
MAR_KBLKADR+1; STORE THE STATUS
NWW_L, TASK;
MD_KSTAT;
MAR_KBLKADR; WRITE THE CURRENT DCB POINTER
KSTAT_5; INITIAL STATUS IS INCOMPLETE
L_DCBR,TASK,BUS=0;
MD_DCBR, :COMM;
; BUS=0 MAPS COMM TO NOCOMM
COMM: T_2; GET THE DISK COMMAND
MAR_DCBR+T;
T_TOTUWC;
L_MD XOR T, TASK, STROBON;
KWDCT_L, :COMM2;
; STROBON MAPS COMM2 TO IDLE1
COMM2: T_10; READ NEW DISK ADDRESS
MAR_DCBR+T+1;
T_KWDCT;
L_ONE AND T;
L_-400 AND T, SH=0;
T_MD, SH=0, :INVERT;
; SH=0 MAPS INVERT TO NOINVERT
INVERT: L_2 XOR T, TASK, :BADCOMM;
NOINVERT: L_T, TASK, :BADCOMM;
; SH=0 MAPS BADCOMM TO COMM3
COMM3: KNMAR_L;
MAR_KBLKADR2; WRITE THE NEW DISK ADDRESS
T_SECT2CM; CHECK FOR SECTOR > 13
L_T_KDATA_KNMAR+T; NEW DISK ADDRESS TO HARDWARE
KADR_KWDCT,ALUCY; DISK COMMAND TO HARDWARE
L_MD XOR T,TASK, :COMM4; COMPARE OLD AND NEW DISK ADDRESSES
; ALUCY MAPS COMM4 TO ILLSEC
COMM4: CKSUMR_L;
MAR_KBLKADR2; WRITE THE NEW DISK ADDRESS
T_CADM,SWRNRDY; SEE IF DISK IS READY
L_CKSUMR AND T, :COMM5;
; SWRNRDY MAPS COMM5 TO WHYNRDY
COMM5: MD_KNMAR; COMPLETE THE WRITE
SH=0,TASK;
:STROB;
; SH=0 MAPS STROB TO CKSECT
CKSECT: T_KNMAR,NFER;
L_KSTAT XOR T, :STALL;
; NFER MAPS STALL TO CKSECT1
CKSECT1: CKSUMR_L,XFRDAT;
T_CKSUMR, :KSFINI;
; XFRDAT MAPS KSFINI TO CKSECT2
CKSECT2: L_SECTMSK AND T;
KSLAST: BLOCK,SH=0;
GASP: TASK, :IDLE2;
; SH=0 MAPS IDLE2 TO TRANSFER
TRANSFER: KCOMM_TOTUWC; TURN ON THE TRANSFER
!1,2,ERRFND,NOERRFND;
!1,2,EF1,NEF1;
DMPSTAT: T_COMERR1; SEE IF STATUS REPRESENTS ERROR
L_KSTAT AND T;
MAR_DCBR+1; WRITE FINAL STATUS
KWDCT_L,TASK,SH=0;
MD_KSTAT,:ERRFND;
; SH=0 MAPS ERRFND TO NOERRFND
NOERRFND: T_6; PICK UP NO-ERROR INTERRUPT WORD
INTCOM: MAR_DCBR+T;
T_NWW;
L_MD OR T;
SINK_KWDCT,BUS=0,TASK;
NWW_L,:EF1;
; BUS=0 MAPS EF1 TO NEF1
NEF1: MAR_DCBR,:GCOM1; FETCH ADDRESS OF NEXT CONTROL BLOCK
ERRFND: T_7,:INTCOM; PICK UP ERROR INTERRUPT WORD
EF1: :KSEC;
NOCOMM: L_ALLONES,CLRSTAT,:KSLAST;
IDLE1: L_ALLONES,:KSLAST;
IDLE2: KSTAT_LOW14, :GETCOM; NO ACTIVITY THIS SECTOR
BADCOMM: KSTAT_7; ILLEGAL COMMAND ONLY NOTED IN KBLK STAT
BLOCK;
TASK,:EF1;
WHYNRDY: NFER;
STALL: BLOCK, :STALL2;
; NFER MAPS STALL2 TO GASP
STALL2: TASK;
:DMPSTAT;
ILLSEC: KSTAT_7, :STALL; ILLEGAL SECTOR SPECIFIED
STROB: CLRSTAT;
L_ALLONES,STROBE,:CKSECT1;
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;
KWD: BLOCK,:REC0;
; SH<0 MAPS REC0 TO REC0
; ANYTHING=INIT MAPS REC0 TO KWD
REC0: L_2, TASK; LENGTH OF RECORD 0 (ALLOW RELEASE IF BLOCKED)
KNMARW_L;
T_KNMARW, BLOCK, RWC; GET ADDR OF MEMORY BLOCK TO TRANSFER
MAR_DCBR+T+1, :REC0RC;
; WRITE MAPS REC0RC TO REC0W
; INIT MAPS REC0RC TO KWD
REC0RC: T_MFRRDL,BLOCK, :REC12A; FIRST RECORD READ DELAY
REC0W: T_MFR0BL,BLOCK, :REC12A; FIRST RECORD 0'S BLOCK LENGTH
REC1: L_10, INCRECNO; LENGTH OF RECORD 1
T_4, :REC12;
REC2: L_PAGE1, INCRECNO; LENGTH OF RECORD 2
T_5, :REC12;
REC12: MAR_DCBR+T, RWC; MEM BLK ADDR FOR RECORD
KNMARW_L, :RDCK0;
; RWC=WRITE MAPS RDCK0 INTO WRT0
; RWC=INIT MAPS RDCK0 INTO KWD
RDCK0: T_MIRRDL, :REC12A;
WRT0: T_MIR0BL, :REC12A;
REC12A: L_MD;
KWDCTW_L, L_T;
COM1: KCOMM_ STUWC, :INPREF0;
INPREF: L_CKSUMRW+1, INIT, BLOCK;
INPREF0: CKSUMRW_L, SH<0, TASK, :INPREF1;
; INIT MAPS INPREF1 TO KWD
INPREF1: KDATA_0, :PREFDONE;
; SH<0 MAPS PREFDONE TO INPREF
PREFDONE: T_KNMARW; COMPUTE TOP OF BLOCK TO TRANSFER
KWDX: L_KWDCTW+T,RWC; (ALSO USED FOR RESET)
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
RP0: KCOMM_STRCWFS,:WP1;
CKP0: L_KWDCTW-1; ADJUST FINISHING CONDITION BY 1 FOR CHECKING ONLY
KWDCTW_L,:RP0;
WP0: KDATA_ONE; WRITE THE SYNC PATTERN
WP1: L_KBLKADR,TASK,:RW1; INITIALIZE THE CHECKSUM AND ENTER XFER LOOP
XFLP: T_L_KNMARW-1; BEGINNING OF MAIN XFER LOOP
KNMARW_L;
MAR_KNMARW,RWC;
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
R0: T_CKSUMRW,SH=0,BLOCK;
MD_L_KDATA XOR T,TASK,:RW1;
; SH=0 MAPS RW1 TO RW2
RW1: CKSUMRW_L,:XFLP;
W0: T_CKSUMRW,BLOCK;
KDATA_L_MD XOR T,SH=0;
TASK,:RW1;
; AS ALREADY NOTED, SH=0 MAPS RW1 TO RW2
CK0: T_KDATA,BLOCK,SH=0;
L_MD XOR T,BUS=0,:CK1;
; SH=0 MAPS CK1 TO CK2
CK1: L_CKSUMRW XOR T,SH=0,:CK3;
; BUS=0 MAPS CK3 TO CK4
CK3: TASK,:CKERR;
; SH=0 MAPS CKERR TO CK5
CK5: CKSUMRW_L,:XFLP;
CK4: MAR_KNMARW, :CK6;
; SH=0 MAPS CK6 TO CK6
CK6: CKSUMRW_L,L_0+T;
MTEMP_L,TASK;
MD_MTEMP,:XFLP;
CK2: L_CKSUMRW-T,:R2;
; BUS=0 MAPS R2 TO R2
RW2: CKSUMRW_L;
T_KDATA_CKSUMRW,RWC; THIS CODE HANDLES THE FINAL CHECKSUM
L_KDATA-T,BLOCK,:R2;
; RWC=CHECK NEVER GETS HERE
; RWC=WRITE MAPS R2 TO W2
; RWC=INIT MAPS R2 AND W2 TO KWD
R2: L_MRPAL, SH=0; SET READ POSTAMBLE LENGTH, CHECK CKSUM
KCOMM_TOTUWC, :CKSMERR;
; SH=0 MAPS CKSMERR TO PXFLP0
W2: L_MWPAL, TASK; SET WRITE POSTAMBLE LENGTH
CKSUMRW_L, :PXFLP;
CKSMERR: KSTAT_0,:PXFLP0; 0 MEANS CHECKSUM ERROR .. CONTINUE
PXFLP: L_CKSUMRW+1, INIT, BLOCK;
PXFLP0: CKSUMRW_L, TASK, SH=0, :PXFLP1;
; INIT MAPS PXFLP1 TO KWD
PXFLP1: KDATA_0,:PXFLP;
; SH=0 MAPS PXFLP TO PXF2
PXF2: RECNO, BLOCK; DISPATCH BASED ON RECORD NUMBER
:REC1;
; RECNO=2 MAPS REC1 INTO REC2
; RECNO=3 MAPS REC1 INTO REC3
; RECNO=INIT MAPS REC1 INTO KWD
REC3: KSTAT_4,:PXFLP; 4 MEANS SUCCESS!!!
CKERR: KCOMM_TOTUWC; TURN OFF DATA TRANSFER
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
PART: T_ 10;
L_ ALLONES; TURN OFF MEMORY INTERRUPTS
MAR_ ERRCTRL, :PX1;
PR8: L_ SAD, :PX;
PR7: L_ PC, :PX;
PR6: L_ CBA, :PX;
PR5: L_ DWA, :PX;
PR4: L_ KNMAR, :PX;
PR3: L_ DCBR, :PX;
PR2: L_ NWW OR T, TASK; T CONTAINS 1 AT THIS POINT
PR0: NWW_ L, :PART;
PX: MAR_ 612+T;
PX1: MTEMP_ L, L_ T;
MD_ MTEMP;
CURDATA_ L; THIS CLOBBERS THE CURSOR FOR ONE
T_ CURDATA-1, BUS; FRAME WHEN AN ERROR OCCURS
:PR0;
◦ Jabse Service Manual Search 2024 ◦ Jabse Pravopis ◦ onTap.bg ◦ Other service manual resources online : Fixya ◦ eServiceinfo