Service Manuals, User Guides, Schematic Diagrams or docs for : xerox alto microcode altoIIcode3.mu

<< Back | Home

Most 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 PravopisonTap.bg ◦ Other service manual resources online : FixyaeServiceinfo