; ***************************************************
;   6801 slot control
;May 14, 1982  12:24 PM
;****************************************************
;ram equates
;****************************************************
.getnolist "m6801predefs.sr"
.getnolist "lsepdefs.bca"
datadir1 = 00000 ; 6801 data direction register 1
datadir2 = 00001 ; 6801 data direction register 2
ipoprt1  = 00002 ; 6801 ipo port 1 
ipoprt2  = 00003 ; 6801 ipo port 2
datadir3 = 00004 ; 6801 data direction register 4
datadir4 = 00005 ; 6801 data direction register 5
ipoprt3  = 00006 ; 6801 ipo port 3 
ipoprt4  = 00007 ; 6801 ipo port 4
tcsr     = 00008 ; timer control status register
cntrhi   = 00009 ; counter high byte
cntrlo   = 0000a ; counter low byte
outcmphi = 0000b ; output compare high byte
outcmplo = 0000c ; output compare low byte
inpcaphi = 0000d ; input capture high byte
inpcaplo = 0000e ; input capture low byte
ipoprt3cs= 0000f ; ipo port 3 control,status register
serate   = 00010 ; serial rate and mode register (say what?)
sercon   = 00011 ; serial control and status register
serrx    = 00012 ; serial receiver data register
sertx    = 00013 ; serial transmit data register
ramcon   = 00014 ; rampeprom control register
;**************************************************
;15 to 1f hex reserved (don't ask)
;**************************************************
altoi = 00080  ; input byte from alto
altoo = 00081  ; output byte to alto

;N.B.,  All bits but one of this port are output direction
UartOUT = 00082  ; output byte to uart.
uarti = 00083  ; input byte from uart
inbyte = 00084 ; input byte from slot card
OutToSlot = 00085; output byte to slot card
stcntr = 00086 ; system state counter
;*********************************************
;some ram assignments
;*********************************************
uartflgs = 00087; flag byte for uart communications
MultiPage = 00088; flag for multi-feed sequences
PageTimer = 0089; two-byte quantity for doing page sync timing
 PageTimer1 = 0090;
PageSyncHigh = 0091

; input byte equates
prntreq = 01 ; print request bit from slot
; output byte equates
pgsync = 080  ; page sync bit to slot
online = 040  ; online bit to slot I.E. the printer is ready
 onlineCpl = 0BF; compliment of online
addpaper = 20 ; add paper bit to slot [active low]
 addpaperCpl = 0DF; compliment of addpaper
clrpprpth = 10 ; clear paper path bit to slot [active low]
 clrpprpthCpl = 0EF; compliment of clrpprpth
allOK = 070	  ;status word that tells slot that all is ok.

prombase = 0F800 ; base of the 2716 
prt1msk = 0fe
wait = 2400		;2400 = ~8mSec
terminalWait = 0F000;
uartOutResetWait = 000FF
pageDuration = 024B;  i.e., 024<HEX> * 2400<HEX> =  ~ 4.62 seconds
;125(decimal) in the high multiplier =~1 second So for 4.62 seconds, need 587(decimal)
;587 decimal = 024B (hex)
;****************************************************
; Uart equates 
combit = 01
recfull = 80		;this is the "uart receiver full" bit


;****************************************************
; interupt vector equates
;****************************************************
restrtms = 0fffe
restrtls = 0ffff ; restart vector
nmims    = 0fffc 
nmils    = 0fffd ; nonmaskable interupt
swims    = 0fffa
swils    = 0fffb ; software interupt
irq1ms   = 0fff8 
irq1ls   = 0fff9 ; irq1 interupt
tcapms   = 0fff6
tcapls   = 0fff7 ; timer input capture or irq 2 interupt
tcompms  = 0fff4 
tcompls  = 0fff5 ; timer output compare or irq 2 interupt
tovms    = 0fff2 
tovls    = 0fff3 ; timer overflow or irq 2 interupt 
serinms  = 0fff0 
serinls  = 0fff1 ; serial ipo interupt
;****************************************************
; INIT the machine
;****************************************************
.loc 0f800
start:
  ldsi 000FF;	stack grows down from here
  clra
  staae altoi
  staae altoo
  staae uarti
  staae UartOUT   ; clear all the working registers
  staae inbyte
  staae OutToSlot
  staae stcntr
  staae uartflgs
  staae MultiPage
  staae PageTimer
  staae PageTimer1	;zero out low order byte too
  staae PageSyncHigh
  ldaai prt1msk
  staae datadir1 ; set up the port for ipo
  ldaai prntreq 
  andae ipoprt1   ; init the input byte
  staae inbyte
  ldaai 009 ; 
  staae serate ;     set rate to 9600 baud CC1 1 CC0 0 S1 0 S0 1  
  ldaai 00a ; 
  staae sercon ;        set tx and rx enable
  ldaai allOK;	 for now, say all's ok
  staae ipoprt1;	 send to SLOT
  lddi uartOutResetWait;	don't send anything out the uart for awhile
  jsr TimerWait;

  ldaai readStatus
  staae UartOut	;ask the Raven for its status
  ldaai combit	;don't bother to OR into this reg for now
  staae uartflgs;
;  ldxi RunningStr;
;  jsr OutString
  jsr SetTimer	;set interrupts			

;***************************************************
; start  outer loop:
;
; read and update inputs from the slot card & set status for Raven
;***************************************************
ReadSlot:
;	ldxi MainLoopStr;
;	jsr OutString
	ldaai prntreq ; mask the raw input from port 1
	andae ipoprt1   ; 
	tab;			;save a copy
	eorae inbyte   ; has it changed since last time?
	beq NoInput     ; no change so don't change anything
	tba;
	beq NoInput     ; is this a 1 to 0 transition? If so then skip.
	ldaai feedBottomNoOffset
	staae UartOUT
	ldaai combit  ; set the flag that will cause output reg to be sent
	oraae uartflgs	;to the raven
	staae uartflgs

NoInput:			;update outputs to the slot card
	stabe inbyte;
	ldaae OutToSlot	;remember to not destroy bits already there
	staae ipoprt1
	jmp ReadSlot	;end of outer loop

;***************************************************
; Interrupt Level!!!   Timer interupt and uart communications.
;***************************************************
readuart:
	ldaai recfull 
	andae sercon		; mask and test the receiver full bit 
	beq NothingWaiting	;skip read if it isn't set
	ldaae serrx
	andai 7F;			;mask the parity bit off
	staae uarti
;*** For debugging, type received char from terminal <i.e., Raven> back on terminal
;	ldxi ShowCharString
;	jsr OutString
;	ldabe uarti
;	jsr OutByteVal
;	ldxi StrCRT;
;	jsr OutString

;call status parsing routine here to take appropriate action, given input.
	ldabe uarti
	jsr StatusDispatch;	;for now, sets up OutToSlot

NothingWaiting:

;If pagesync is high, decrement timer and drop signal if timer=0
	ldaae PageSyncHigh;
	beq NoPageSync;
	ldde PageTimer;
	subdi 01;
	stde PageTimer
	bne NoPageSync;
	clre PageSyncHigh;		here if page timer just expired
	ldaae OutToSlot;
	eorai pgsync;		drop page sync signal
	staae OutToSlot;
NoPageSync:				;write UART if have something to send
	ldaai combit;		mask and test the communications flag
	andae uartflgs
	beq NothingToSend;		don't send any thing if it's not set
	ldaae UartOUT
	ldabe sercon
	staae sertx
	ldaai combit;		clear the flag cause we just send the character
	coma
	andae uartflgs
	staae uartflgs

NothingToSend:	
	jsr SetTimer
	rti 

;***************************************************
; status parsing routine: expects the command to be in acc B  and
; returns a dispatch address in the IX register.  This stuff processes only the
; status from the printer at the moment.
;***************************************************
StatusDispatch:
	subbi PSkey0;		subtract the lowest command value from the command in ACb
	bcs CmdErrorRtn;	the command passed in is less than the lowest command
	cmpbi PSillegalTop;	now see if the command is greater than any we have.
	bcc CmdErrorRtn;

	ldxi  PSTable;	put the base address into the index register
	aslb;			multiply the B register by two by shifting.
	abx;			and add in the contents of AC b
	ldxx 00;		load the memory location pointed to by IX reg.
	jsrx 00;		call the procedure pointed to by the index register
	rts;  done

CmdErrorRtn:
	ldxi 000;
	rts;  done <with error!>

;the procs that are dispatched to:
PSkey0Proc:
	rts;
PSkey1Proc:
	rts;
PSkey2Proc:
	rts;
PSkey3Proc:
	rts;
PSkey4Proc:
	rts;
PSkey5Proc:
	rts;
PSkey6Proc:
	rts;
PSkey7Proc:
	rts;
PSkey8Proc:
	rts; 
PSkey9Proc:
	rts;
PSclearKeyProc:
	rts;
PStestKeyProc:
	rts;
PSonLineKeyProc:
	ldaae OutToSlot	;turn on "OnLine" signal to SLOT
	oraai online
	staae OutToSlot
	rts;

PSoffLineKeyProc:
	ldaae OutToSlot	;turn off "OnLine" signal to SLOT
	andai onlineCpl
	staae OutToSlot
	rts;
noopProc:
	rts;
PSwaitProc:
	ldaae OutToSlot	;make "clrpprpth" signal to SLOT TRUE
	andai clrpprpthCpl	;(remember it's active low)
	staae OutToSlot
	rts;
PSstandbyProc:
	ldaae OutToSlot;
	oraai allOK; [clearPaperPath=F, addPaper=F, OnLine=T, PageSync unaffected]
	staae OutToSlot;
	rts;
PSfeederFaultProc:
	ldaae OutToSlot	;make "addpaper" signal to SLOT TRUE
	andai addpaperCpl	;(remember it's active low)
	staae OutToSlot
	rts;
PShardStop1Proc:
	jmp PSwaitProc
	rts;
PShardStop2Proc:
	jmp PSwaitProc
	rts;
PShardStop3Proc:
	jmp PSwaitProc
	rts;
PSsorterJamProc:
	jmp PSwaitProc
	rts;
PSinterlockOpenProc:
	jmp PSwaitProc
	rts;
PSfuserUnderTempProc:
	jmp PSwaitProc
	rts;
PSrunFeedingProc:
	rts;
PSrunReadyProc:
	rts;
PSstatusDisplayedProc:
	rts;
PScmdRejParityProc:
	ldaai combit;	resend the last command and hope it's the right one
	oraae uartflgs	;to the raven
	staae uartflgs
	rts;
PScmdRejUnrecogProc:
	rts;
PScmdRejIllSeqProc:
	rts;
PScmdRejSorterDownProc:
	rts;
PSnoFeedTrayProc:
	jmp PSwaitProc
	rts;
PSpageSyncProc:
	ldaae OutToSlot;
	oraai pgsync;	;will cause slot to relay this to uCode
	staae OutToSlot;	on next cycle through main loop
;SET A TIMER FOR DROPPING PAGE SYNC HERE!!!
	lddi pageDuration;
	stde PageTimer;
	ince PageSyncHigh;	set this boolean true for checking by the timer routine

;The idea here will be to eventually handle the case of multiple feeding
; If this is the result of a previous feed and there is another print request
; coming from the SLOT, feed another sheet here.
;	tst MultiPage;
;	beq PgSync1;	not multi page if zero
;	ldaai feedBottomNoOffset
;	staae UartOUT;	cause another feed if we're multi feeding
;	ldaai combit;	set the flag that will cause output reg to be sent
;	oraae uartflgs	;to the raven
;	staae uartflgs
; Think about decrementing the MultiPage word here OR at the beginning of the
;  proc so as not to do one too many feeds
PgSync1:
	rts;

PSpageDeliveredProc:
;	ldaae OutToSlot;	this is now done at the expiration of the page timer
;	eorai pgsync;
;	staae OutToSlot;
	rts;
PSpageDelveredSorterProc:
	jmp PSpageDeliveredProc;
	rts;
PScycleOffLIneProc:
	jmp PSoffLineKeyProc
	rts;
PSoffLineProc:
	jmp PSoffLineKeyProc
	rts;
PSonLineProc:
	jmp PSonLineKeyProc
	rts;
PSoutTrayFullProc:
	jmp PSwaitProc
	rts;
PSstackerFullProc:
	jmp PSwaitProc
	rts;

PSTable:
	.ADR PSkey0Proc;			--"30"
	.ADR PSkey1Proc;
	.ADR PSkey2Proc;
	.ADR PSkey3Proc;
	.ADR PSkey4Proc;
	.ADR PSkey5Proc;
	.ADR PSkey6Proc;
;	.ADR PSkey7Proc;		"37"
	.ADR PSonLineKeyProc;	"37" also!
;	.ADR PSkey8Proc;		"38"
	.ADR PSoffLineKeyProc;	"38" also!
	.ADR PSkey9Proc;		"39"
	.ADR PSclearKeyProc;	"3A"
	.ADR PStestKeyProc;	"3B"
	.ADR noopProc;	
	.ADR noopProc;	
	.ADR noopProc;	
	.ADR noopProc;		"3F"
	.ADR PSwaitProc;		"40"
	.ADR PSstandbyProc;
	.ADR PSfeederFaultProc;
	.ADR noopProc;		"43"
	.ADR PShardStop1Proc;	"44"
	.ADR PShardStop2Proc;
	.ADR PShardStop3Proc;
	.ADR PSsorterJamProc;	"47"
	.ADR PSinterlockOpenProc;
	.ADR PSfuserUnderTempProc;
	.ADR PSrunFeedingProc;	"4A"
	.ADR PSrunReadyProc;
	.ADR PSstatusDisplayedProc;
	.ADR PScmdRejParityProc;	"4D"
	.ADR PScmdRejUnrecogProc;
	.ADR PScmdRejIllSeqProc;	"4F"
	.ADR PScmdRejSorterDownProc;
	.ADR PSnoFeedTrayProc;
	.ADR PSpageSyncProc;	"52"
	.ADR PSpageDeliveredProc;"53"
	.ADR PSpageDelveredSorterProc;
	.ADR PScycleOffLIneProc;
	.ADR PSoffLineProc;	"56"
	.ADR PSonLineProc;
	.ADR PSoutTrayFullProc;
	.ADR PSstackerFullProc;		--"59"

SetTimer:				;this routine sets timer interrupt
	lddi wait			; load D with wait count
	addde cntrhi		; add D to counter
	clre tcsr			; clear timer control status reg
	stde outcmphi		; set output compare
	ldaai 008 ; 
	staae tcsr
	cli;				;clear interrupt disable!
	rts;

;NB, if this routine is called from code that can be interrupted, it's a good
; idea to change this routine to turn off interrupts then reenable them
; when done.  OR, to disable the interrupts before calling.
TimerWait:				;this routine doesn't set timer interrupt
;this routine now expects d to be loaded before call
;;	lddi terminalWait			; load D with wait count
	addde cntrhi		; add counter to D
	clre tcsr			; clear timer control status reg
	stde outcmphi	; set output compare
	ldaai 040 ; 
TimerWait1:
	bitae tcsr		; now wait for output compare flag
	beq TimerWait1	; not yet
	rts;

;call OutString by putting the address of the string into IX
OutString:
	ldabx 00;			pick up the length into b
AnotherChar:
	inx;				increment IX to point to first char of string
	ldaax 00;			pick up char using index reg as addressor
	pshb;				save b
	jsr OutPutChar
	pulb;
	decb;
	bgt AnotherChar;	branch if gt zero, i.e., more characters there
	rts;

OutPutChar:			;doesn't destroy a
	psha;
	lddi terminalWait
	jsr TimerWait;
	pula;
	ldabe sercon;   read serial controller reg into b
	staae sertx;		send arg
	rts;

OutByteVal:		;takes argument in B, prints it as two hex chars
	pshb;
	lsrb;
	lsrb;
	lsrb;
	lsrb;
	ldxi ByteValTab;
	abx;
	ldaax 00;		;get the ascii rep for left byte
	jsr OutPutChar;
	pulb;
	andbi 00F;
	ldxi ByteValTab;
	abx;
	ldaax 00;		;get the ascii rep for right byte
	jsr OutPutChar;
	rts;

ByteValTab:
	$0;
	$1;
	$2;
	$3;
	$4;
	$5;
	$6;
	$7;
	$8;
	$9;
	$A;
	$B;
	$C;
	$D;
	$E;
	$F;


;Literals here
ShowCharString:
	.TXT "Here's the char: ";
StrCRT:
	.TXT "*n*l";
RunningStr:
	.TXT "We're Running!*n*l";
AtInterruptStr:
	.TXT "At Interrupt Level*n*l";
MainLoopStr:
	.TXT "Main Loop*n*l";
.loc 0fff0
0f8
00
.loc 0fff4
.ADR readuart
.loc 0fffe
0f8
00