Service Manuals, User Guides, Schematic Diagrams or docs for : xerox alto microcode altocode24.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 altocode24.mu documenatation <<

Text preview - extract from the document
;	A L T O C O D E 2 4 . M U

;***Derived from ALTOCODE23.MU, as last modified by
;	Ingalls, August 11, 1976  10:39 PM
;***E. McCreight, editor
;***modified by McCreight, September 19, 1977  4:34 PM
;	removed STM3: dependence on saving R40 across tasks
;***modified by Boggs, September 20, 1977  8:02 PM
;	moved constants and symbols into AltoConsts23.mu

;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,V15,V16,V17,MUL,DIV,V22,V23,BITBLT,,,,,,,,,,,;

;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,EIDOK,EIFOK,,EOCDW1,EIDPST,EIFBAD,EOCDWX,EIGO;

;Miscellaenous address constraints
!7,10,,EOCDW0,EODATA,,,EOCDRS,EIDATA,EPOST;
!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,EIDMOR,EIDFUL;
!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, so this loop causes SysClk to stop for one cycle by
;referencing MD in cycle 4.

EIDATA:	L_ MAR_ EPNTR+1,EBFCT;	What's happening?
	T_ ECNTR-1,BUS=0,:EIDOK;[EIDOK,EIDPST] word count zero?
EIDOK:	EPNTR_ L,L_ T,:EIDMOR;	[EIDMOR,EIDFUL]
EIDMOR:	MD_ EIDFCT,TASK;	Read a word from interface
	ECNTR_ L,:EIDATA;

EIDPST:	L_ ESIDON,:EPOST;	[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_ LLSH1;		Use bits [2:9]
	L_ MD,EOSFCT;		L_ current load
	SH<0,ECNTR_ L;		Overflowed?
	MTEMP_ LLSH1,:EOLDOK;	[EOLDOK,EOLDBD]

EOLDBD:	L_ ESLOAD,:EPOST;	Load overlow

EOLDOK:	MAR_ ELLOC;		Write updated load
	L_ MTEMP+1;
	MTEMP_ L,TASK;
	MD_ MTEMP,:EORST1;	New load = (old lshift 1) + 1

EORST1:	L_ EPNTR;		Continue making random #
	EPNTR_ LLSH1;
	T_ 177400;
	L_ EPNTR AND T,TASK;
	EPNTR_ LLCY8,: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 wake 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,DTODD;
!1,1,MRTLAST;
!1,2,CNOTLAST,CLAST;

$CLOCKTEMP$R11;

MRT:	SINK_ MOUSE, BUS;	MOUSE DATA IS ANDED WITH 17B
MRTA:	L_ T_ -2, :TX0;		DISPATCH ON MOUSE CHANGE
TX0:	L_ T_ R37 AND NOT T;	CHECK FOR INTERVAL TIMER/EIA
	SH=0, L_T_ 77+T+1;	
	:DOTIMER, R37_ L, ALUCY;	
NOTIMER:L_ CURX, :NOCLK;
NOCLK:	T_ REFMSK, SH=0;
	MAR_ R37 AND T, :DOCUR;
NOCUR:	CURDATA_ L, TASK;
MRTLAST:CURDATA_ L, :MRT;	END OF MAIN LOOP


DOTIMER:MAR_EIALOC;		INTERVAL TIMER/EIA INTERFACE
DTODD:	L_2 AND T;
	SH=0, L_T_BIAS.T;
	CURDATA_L, :SPCHK;	CURDATA_CURRENT TIME WITHOUT CONTROL BITS

SPCHK:	SINK_MD, BUS=0, TASK;	CHECK FOR EIA LINE SPACING
SPIA:	:NOTIMERINT, CLOCKTEMP_L;

NOSPCHK:L_MD;			CHECK FOR TIME=NOW
	MAR_TRAPDISP-1;		CONTAINS TIME AT WHICH INTERRUPT SHOULD HAPPEN
	MTEMP_L;		IF INTERRUPT IS CAUSED, LINE STATE WILL BE STORED
	L_ MD-T;
	SH=0, TASK, L_MTEMP, :SPIA;

TIMERINT: MAR_ ITQUAN;		STORE THE THING IN CLOCKTEMP AT ITQUAN
	L_ CURDATA;
	R37_ L;
	T_NWW;			AND CAUSE AN INTERRUPT ON THE CHANNELS 
	MD_CLOCKTEMP;		SPECIFIED BY ITQUAN+1
	L_MD OR T, TASK;
	NWW_L;

NOTIMERINT: SINK_CURDATA, BUS=0, :NOTIMER;

CLOCK:	MAR_ CLOCKLOC;		R37 OVERFLOWED. UPDATE CLOCK
	NOP;
	L_ MD+1;
	MAR_ CLOCKLOC;
	MTEMP_ L, TASK;
	MD_ MTEMP, :NOTIMER;

DOCUR:	L_ T_ YPOS;		CHECK FOR VISIBLE CURSOR ON THIS SCAN
	SH < 0, L_ 20-T-1;
	SH<0, L_ 2+T, :SHOWC;

WAITC:	YPOS_ L, L_ 0, TASK, :MRTLAST;
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
	MAR_ MOUSELOC;			NOW RESTORE THE UPDATED COORDINATES
	T_ MTEMP+ T+1;			Y+ (YCHANGE-1) + 1
	MTEMP_ L, L_ T;
	MD_ MTEMP;
	MAR_ MOUSELOC+1;
	MTEMP_ L, TASK;
	MD_ MTEMP, :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
!7,10,PR0,,PR2,PR3,PR4,PR5,PR6,PR7;

;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
	T_ BIAS;
	L_ R37 AND T;
	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:	SAD_ L;
	SINK_ DISP, BUS,TASK;
	MD_ PC, :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 by ORing AC0 into R37
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;
	T_ XREG.T;
	T_ TRAPCON+T+1;		T NOW CONTAINS 471+OPCODE
	MD_ PC, :DOIND;		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 < 25.
	T_25;		***X21. Greatest defined op is 24.
	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;

;***X21 change. Traps numbered instead of lettered.
V15:	:TRAP1;		;Alto II DREAD
V16:	:TRAP1;		;Alto II DWRITE
V17:	:TRAP1;		;Alto II DEXCH
V22:	:TRAP1;		;Alto II DIOG1
V23:	:TRAP1;		;Alto II DIOG2

;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
	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:	L_ PC+1;
	PC_ L, TASK, :FINST1;

;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,
	MAR_DWAX;			restore it.
	XREG_L, L_T;
	MTEMP_L;
	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,
;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;


;ENGBUILD is a constant returned by VERS that contains a discription
;of the Alto and it's Microcode. The conposition of ENGBUILD 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.
$EngNumber	$1;	This is an Alto I

VERS:	T_ EngNumber;		***X21 addition
	L_ 3+T, :LTOAC0;	Altocode24 is called ucode version 3

;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;

;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 *
;	************************
;
;	/* 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), 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;
;	T_ 0+T+1;	**
;	MAR_ LASTMASKP1-T-1;	**REPLACE THESE 2 BY 1 BELOW IN #21
	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 _ 20 FOR TOPLD)
	IR_ 20, :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_ 17;	**THIS MASK IS ONLY FOR SAFETY
	T_ MD.T;
	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
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;
;
;	/* 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)
PRELD:	T_ HINC;
	MAR_ SWA-T;	PRELOAD SOURCE PRIOR TO MAIN LOOP
	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;
FDISP:	SINK_ DISP, SINK_lgm14, BUS, TASK;
FDISPA:	RETN_ L, :F0;
F0:	:WIND;			FUNC 0 - WINDOW
F1:	:WIND;			FUNC 1 - NOT WINDOW
F1A:	T_ CYCOUT;
	L_ ALLONES XOR T, TASK, :F3A;
F2:	:WIND;			FUNC 2 - WINDOW .AND. GRAY
F2A:	T_ CYCOUT;
	L_ ALLONES XOR T;
	TEMP_ L;		TEMP _ NOT WINDOW
	MAR_ DWAX;
	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;	FUNC 3 - CONSTANT (COLOR)
F3A:	CYCOUT_ L;
;
;
;	/* HERE ARE THE OPERATIONS - ENTER WITH SOURCE IN CYCOUT
	%16,17,15,STFULL,STMSK;	MASKED OR FULL STORE (LOOK AT 2-BIT)
F0A:	SINK_ DISP, SINK_ lgm3, BUS;	DISPATCH ON OP
OPX:	T_ MAR_ DWAX, :OP0;	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, TASK;
OP2:	T_ CYCOUT;		OP 2 - SOURCE .XOR. DEST
	L_ MD XOR T, :OPN, TASK;
OP3:	T_ CYCOUT;		OP 3 - (NOT SOURCE) .AND. DEST
	L_ 0-T-1;
	T_ LREG;
	L_ MD AND T, TASK;
OPN:	CYCOUT_ L, :OPX;
;
;
;	/* STORE MASKED INTO DESTINATION
	!1,2,STM2,STM1;
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, TASK;
	CYCOUT_ L;		OR TOGETHER THEN GO STORE
	T_ MAR_ DWAX, :OP0A;
;
;	/* 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;
WIND:	MAR_ SWA;		ENTER HERE (7 INST TO TASK)
	L_ T_ SKMSK;
	L_ WORD2.T, SH=0;
	CYCOUT_ L, L_ 0-T-1, :NZSK;	CYCOUT_ OLD WORD .AND. MSK
ZESK:	L_ MD;	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:	SH=0,TASK;
	MD_KNMAR, :STROB;	COMPLETE THE WRITE

;	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: MAR_DCBR+1;	WRITE FINAL STATUS
	T_COMERR1;	SEE IF STATUS REPRESENTS ERROR
	L_KSTAT AND T;
	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:	MAR_T_L_KNMARW-1;	BEGINNING OF MAIN XFER LOOP
	KNMARW_L,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_ 7;
	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;
	MTEMP_ L, L_ T;
	CURDATA_ L;		THIS CLOBBERS THE CURSOR FOR ONE 
	T_ CURDATA-1, BUS;	FRAME WHEN AN ERROR OCCURS
	MD_ MTEMP, :PR0;



◦ Jabse Service Manual Search 2024 ◦ Jabse PravopisonTap.bg ◦ Other service manual resources online : FixyaeServiceinfo