; refreshml.dsm
; L. Stewart, January 21, 1983  10:47 AM

SPACE   SEGMENT

C←GROUP GROUP SPACE, C←CODE, C←DATA

;	DB	2 DUP(?)

SPACE	ENDS

C←CODE	SEGMENT

$INCLUDE(Lark.d)

; stack initial value
SPIN	EQU	0DFF0H

deiploc	EQU	000H
decsloc	EQU	002H
triploc	EQU	004H
trcsloc	EQU	006H
nmiploc	EQU	008H
nmcsloc	EQU	00AH
bkiploc	EQU	00CH
bkcsloc	EQU	00EH
oviploc	EQU	010H
ovcsloc	EQU	012H

;  boot reasons
; interrupts of various sorts are of types 0 up through 255
cDIVERR	EQU	0
cTRACE	EQU	1
cNMI		EQU	2
cBREAK	EQU	3
cOVERR	EQU	4
cSWAT	EQU	5
cMONRET	EQU	0FFFCH
cRUNERR	EQU	0FFFDH
cEXTINT	EQU	0FFFEH
cRESET	EQU	0FFFFH

C←DATA	SEGMENT

; save area for machine state

←mstate	LABEL	BYTE
rax	DW	?
rbx	DW	?
rcx	DW	?
rdx	DW	?
rsp	DW	?
rbp	DW	?
rsi	DW	?
rdi	DW	?
rcs	DW	?
rds	DW	?
rss	DW	?
res	DW	?
rip	DW	?
rfl	DW	?
←lip	DW	?	; single step use
←cmklo	DW	00H
←cmkhi	DW	00H
savea	DW	0
←lnmi	DW	?
←eitype	DW	?

C←DATA ENDS

EXTRN	←MonMain:NEAR
EXTRN	←PortStr:NEAR

ASSUME CS:C←CODE, DS:C←DATA

; if code happens to execute into the monitor from lower
; addresses, a trap of type cRUNERR happens

;  address = E000
	JMP	runerr		; 3 bytes

;  address = E003
	JMP	cstart		; 3 bytes

;  address = E006
possnmi:
	JMP	pnmib		; 3 bytes

;  address = E009
RefA:
	NOP			; drain IFU
	NOP
	NOP
	NOP			; total 4

	DW	0C706H	; 2 bytes
	DW	nmiploc	; 2 bytes
	DW	0E049H	; OFFSET RefB

	NOP			; drain IFU
	NOP
	NOP
	NOP			; total 14

	ADD	←cmklo,1	; 5 bytes

	NOP			; drain IFU
	NOP
	NOP
	NOP			; total 23

	ADC	←cmkhi,0	; 5 bytes

	NOP			; drain IFU
	NOP
	NOP
	NOP			; total 32

	MOV	savea,AX	; 3 bytes

	NOP			; drain IFU
	NOP
	NOP
	NOP			; total 39

	IN	AL,pioc	; 2 bytes

	NOP			; drain IFU
	NOP
	NOP
	NOP			; total 45

	TEST	AL,1		; 2 bytes

	NOP			; drain IFU
	NOP
	NOP
	NOP			; total 51

	JZ	possnmi	; 2 bytes

wasntnmi:

	NOP			; drain IFU
	NOP
	NOP
	NOP			; total 57

	MOV	AX,savea	; 3 bytes

	NOP
	NOP
	NOP			; total 63

	IRET

RefB:
	NOP			; drain IFU
	NOP
	NOP
	NOP
	NOP			; total 5

	DW	0C706H
	DW	nmiploc
	DW	0E089H	; OFFSET RefC

	NOP			; drain IFU
	NOP
	NOP
	NOP
	NOP			; total 16

	ADD	←cmklo,1

	NOP			; drain IFU
	NOP
	NOP
	NOP
	NOP			; total 26

	ADC	←cmkhi,0

	NOP			; total 32

	NOP
	NOP
	NOP
	NOP
	NOP

	NOP
	NOP
	NOP
	NOP
	NOP			; total 42

	NOP
	NOP
	NOP
	NOP
	NOP

	NOP
	NOP
	NOP
	NOP
	NOP			; total 52

	NOP
	NOP
	NOP
	NOP
	NOP

	NOP
	NOP
	NOP
	NOP
	NOP			; total 62

	NOP

	IRET

RefC:
	NOP			; drain IFU
	NOP
	NOP
	NOP
	NOP			; total 5

	DW	0C706H
	DW	nmiploc
	DW	0E0C9H	; OFFSET RefD

	NOP			; drain IFU
	NOP
	NOP
	NOP
	NOP			; total 16

	ADD	←cmklo,1

	NOP			; drain IFU
	NOP
	NOP
	NOP
	NOP			; total 26

	ADC	←cmkhi,0

	NOP			; total 32

	NOP
	NOP
	NOP
	NOP
	NOP

	NOP
	NOP
	NOP
	NOP
	NOP			; total 42

	NOP
	NOP
	NOP
	NOP
	NOP

	NOP
	NOP
	NOP
	NOP
	NOP			; total 52

	NOP
	NOP
	NOP
	NOP
	NOP

	NOP
	NOP
	NOP
	NOP
	NOP			; total 62

	NOP

	IRET

RefD:
	NOP			; drain IFU
	NOP
	NOP
	NOP
	NOP			; total 5

	DW	0C706H
	DW	nmiploc
	DW	0E009H	; OFFSET RefA

	NOP			; drain IFU
	NOP
	NOP
	NOP
	NOP			; total 16

	ADD	←cmklo,1

	NOP			; drain IFU
	NOP
	NOP
	NOP
	NOP			; total 26

	ADC	←cmkhi,0

	NOP			; total 32

	NOP
	NOP
	NOP
	NOP
	NOP

	NOP
	NOP
	NOP
	NOP
	NOP			; total 42

	NOP
	NOP
	NOP
	NOP
	NOP

	NOP
	NOP
	NOP
	NOP
	NOP			; total 52

	NOP
	NOP
	NOP
	NOP
	NOP

	NOP
	NOP
	NOP
	NOP
	NOP			; total 62

	NOP

	IRET

; io device initialization strings

; The format of this stuff is <port address><byte count><bytes>
; port FF terminates the list

; first set up the 8255 and reset all its outputs
←I8255 LABEL BYTE
	DB	pioctl
	DB	1
	DB	083H	; Port A, C[4..7] output, B, C[0..3] input, all mode 0

	DB	pioa
	DB	1
	DB	0E1H

	DB	piob
	DB	1
	DB	000H

	DB	pioc
	DB	1
	DB	030H

	DB	apioctl
	DB	1
	DB	088H	; Port A, B, C0-3 Out, Port C4-7 In, mode 0

	DB	apioa
	DB	1
	DB	0C0H	; revert and off-hook relays OFF

	DB	0FFH

←I8237 LABEL BYTE
; reset DMA controller
	DB	dmamask
	DB	1
	DB	00FH

	DB	dmaclr
	DB	1
	DB	000H

; Set up SLC controller only in cascade mode

	DB	dmastat
	DB	1
	DB	020H

	DB	dmamode
	DB	1
	DB	0C1H

	DB	dmamask
	DB	1
	DB	00DH

	DB	0FFH

; See Lark9513.txt for explanations
←I9513 DB TimCtl
	DB	5
	DB	0FFH
	DB	05FH
	DB	001H
	DB	0E0H
	DB	017H

	DB	TimData
	DB	2
	DB	0C0H
	DB	088H

	DB	TimCtl
	DB	6
	DB	0E9H		; set SLCHoldoff' high (was E1)
	DB	0E2H		; everyone else low
	DB	0E3H
	DB	0E4H
	DB	0E5H

	DB	001H

; SLCHoldoff
	DB	TimData
	DB	30

;new
	DB	062H		; mode L, toggle
	DB	0DBH		; active high edge gate N, F1
	DB	059H		; delay 192/2 -7
	DB	000H
	DB	02EH		; low for 46
	DB	000H

;old
;	DB	062H		; mode J
;	DB	01BH
;	DB	02EH
;	DB	000H
;	DB	092H
;	DB	000H

; TSN
; new
	DB	062H		; mode J, free run
	DB	01BH		; no gate, F1
	DB	058H		; low for 88
	DB	000H
	DB	008H		; high for 8
	DB	000H
; old
;	DB	062H		; mode L
;	DB	0FBH
;	DB	007H		; delay 7
;	DB	000H
;	DB	008H		; high for 8
;	DB	000H

; Framesync
	DB	0A5H		; Mode R
	DB	0FBH		; active low edge gate N, F1
	DB	005H		; delay 5
	DB	000H
	DB	000H
	DB	000H

; 8274 ch. B baud rate, 1200 baud
	DB	062H		; Mode J
	DB	01BH
	DB	028H
	DB	000H
	DB	028H
	DB	000H

; Refresh generator
; Programmable timer, set up for toggling every 8 ticks of SynTSN
; It triggers nmi on the low to high transition of output
	DB	022H		; Mode D
	DB	014H
	DB	008H
	DB	000H
	DB	000H
	DB	000H

	DB	TimCtl
	DB	2
	DB	05FH
	DB	03FH

	DB	0FFH


←I8274 DB	sioctla
	DB	2
	DB	018H	; channel reset
	DB	0F0H	; reset Tx underrun, error reset

	DB	sioctlb
	DB	2
	DB	018H	; channel reset
	DB	0F0H	; reset Tx underrun, error reset

	DB	sioctla
	DB	14
	DB	004H	; WR 4 next
	DB	04CH	; 16 x clock, 2 stop, no parity
	DB	001H	; WR 1 next
	DB	004H	; no interrupts, variable vector
;	DB	01EH	; rx int all chars, variable vector, txint, no ext int
	DB	002H	; WR 2 next
	DB	014H	; 8088 mode, non-vector int. rx high pri., both int.
	DB	003H	; WR 3 next
	DB	0C0H	; 8 bits/rxchar
	DB	005H	; WR 5 next
	DB	060H	; 8 bits/txchar
	DB	006H	; WR 6 next
	DB	000H	; junk
	DB	007H	; WR 7 next
	DB	000H	; junk

	DB	sioctlb
	DB	14
	DB	004H	; WR 4 next
	DB	04CH	; 16 x clock, 2 stop, no parity
	DB	001H	; WR 1 next
	DB	004H	; no interrupts, variable vector
;	DB	01EH	; rx int all chars, variable vector, txint, no ext int
	DB	002H	; WR 2 next
	DB	000H	; base vector
	DB	003H	; WR 3 next
	DB	0C0H	; 8 bits/rxchar
	DB	005H	; WR 5 next
	DB	060H	; 8 bits/txchar
	DB	006H	; WR 6 next
	DB	000H	; junk
	DB	007H	; WR 7 next
	DB	000H	; junk

; now enable 8274
	DB	sioctla
	DB	4
	DB	003H
	DB	0C1H	; 8 bits/rxchar, rx enable
	DB	005H
	DB	068H	; 8 bits/txchar, tx enable

	DB	sioctlb
	DB	4
	DB	003H
	DB	0C1H	; 8 bits/rxchar, rx enable
	DB	005H
	DB	068H	; 8 bits/txchar, tx enable


	DB	0FFH

; set up 8259
; Mask all interrupts
←I8259	DB	intctl
	DB	1
	DB	01BH

	DB	intdata
	DB	3
	DB	070H
	DB	001H
	DB	0FFH

; end of string
	DB	0FFH

; jump targets for jumps at top of this file

; runerr may catch sequential execution into EPROM space
runerr:
	MOV	rbx,BX
	MOV	BX,cRUNERR
	JMP	intcom

; NMI button pushed
wasnmi:
	MOV	rbx,BX
	MOV	BX,cNMI
	JMP	intcom

; possible NMI button push
pnmib:		; if old, juggle stack
	MOV	AX,1
	XCHG	AX,←lnmi
	OR	AL,AL
	JZ	pnmic
	JMP	wasntnmi
pnmic:
; if we reach here, fix stack so IRET from refresh code
; "returns" to wasnmi, saving client state
	MOV	BX,0F000H
	PUSH	BX		; push flags for monitor execution
	XOR	BX,BX
	PUSH	BX		; push cs for this routine
	MOV	BX,OFFSET wasnmi
	PUSH	BX		; push ip for this routine
	JMP	wasntnmi

; execution starts here on a system reset
cstart:
	MOV	BX,cRESET

; callable from C:  CStart(reason)
; initializes
←CStart:
	MOV	AL,0FFH
	OUT	TimCtl,AL
	MOV	AL,083H		; Port A, C4-7 Out, Port B, C0-3 In, mode 0
	OUT	pioctl,AL
	MOV	AL,068H
	OUT	pioa,AL
	MOV	AL,0E1H
	OUT	pioa,AL
	MOV	AL,030H		; A and HS relays OFF
	OUT	pioc,AL
	MOV	AL,000H
	OUT	piob,AL
	MOV	AL,088H		; Port A, B, C0-3 Out, Port C4-7 In, mode 0
	OUT	apioctl,AL
	MOV	AL,0C0H		; revert and off-hook relays OFF
	OUT	apioa,AL

; all traps, etc. come here with different codes in BX
←CRestart:
	MOV	AX,SPIN
	MOV	SP,AX
	MOV	AX,CS
	MOV	SS,AX
	MOV	ES,AX
	MOV	DS,AX
	CALL	←MonMain
;
; if the monitor returns, start it again
;
	MOV	BX,cMONRET
	JMP	←CStart

←StartM LABEL	NEAR
	CMP	rsp,020H
	JAE	sok
	MOV	rsp,01F0H
sok:
	MOV	AX,rip
	MOV	←lip,AX		; save current ip
	MOV	AX,rss
	MOV	SS,AX
	MOV	AX,rsp
	MOV	SP,AX
	PUSH	rfl
	PUSH	rcs
	PUSH	rip
	MOV	BX,rbx
	MOV	CX,rcx
	MOV	DX,rdx
	MOV	SI,rsi
	MOV	DI,rdi
	MOV	BP,rbp
	MOV	AX,rax
	PUSH	res
	PUSH	rds
	POP	DS
	POP	ES
	IRET

brkpt	LABEL	NEAR
	MOV	rbx,BX
	MOV	BX,cBREAK
intcom:
	MOV	rax,AX
	MOV	rcx,CX
	MOV	rdx,DX
	MOV	rsi,SI
	MOV	rdi,DI
	MOV	rbp,BP
	PUSH	DS
	POP	rds
	PUSH	ES
	POP	res
	POP	rip
	POP	rcs
	POP	rfl
	MOV	AX,SS
	MOV	rss,AX
	MOV	AX,SP
	MOV	rsp,AX
	JMP	←CRestart

trace	LABEL	NEAR
; determine if interrupt happened first!
; if trace flag is off in the flags on the stack then reorder.

	MOV	rax,AX
	MOV	rbx,BX
	MOV	rcx,CX
	MOV	rdx,DX
	POP	DX		; pop ip
	POP	CX		; pop cs
	POP	AX		; pop flags
	PUSH	AX		; push them back
; note:	asm bug, TEST AH,1 doesn't work!
	TEST	AX,0100H	; tf set?
	JNZ	trok		; if so, this is the trace trap
	XOR	BX,BX		; otherwise
	PUSH	BX		; push cs for this routine
	MOV	BX,OFFSET trace	; push ip for this routine
	PUSH	BX
	PUSH	AX		; push original flags
	PUSH	CX		; push original cs
	PUSH	DX		; push original ip
	MOV	AX,rax		; restore registers
	MOV	BX,rbx
	MOV	CX,rcx
	MOV	DX,rdx
	IRET
trok:
	PUSH	CX		; push original cs
	PUSH	DX		; push original ip
	MOV	AX,rax		; restore registers
	MOV	CX,rcx		; except BX
	MOV	DX,rdx
	MOV	BX,cTRACE
	JMP	intcom

cmov	LABEL	NEAR
	MOV	rbx,BX
	MOV	BX,cOVERR
	JMP	intcom

cmde	LABEL	NEAR
	MOV	rbx,BX
	MOV	BX,cDIVERR
	JMP	intcom

; All other interrupts

UnkInt:
; in principle, CS contains the interrupt type and IP has 
; whatever it takes to get control here.
	PUSH	BX
	MOV	BX,CS
	MOV	←eitype,BX
	POP	BX
	MOV	AL,020H  ; 8259 eoi
	OUT	intctl,AL
	MOV	rbx,BX
	MOV	BX,cEXTINT
	DB	0EAH	; long jump to
	DW	OFFSET intcom	; intcom
	DW	0

; the monitor calls this to initialize the machine

←Setup	PROC	NEAR
;
; set up first refresh interrupt handler
	XOR	BX,BX
	XOR	AX,AX
	MOV	[nmcsloc+BX],AX
	MOV	AX,OFFSET RefA
	MOV	[nmiploc+BX],AX
;
; initialize IO devices
;
	MOV	BX,OFFSET ←I8255
	CALL	←PortStr
	MOV	BX,OFFSET ←I9513
	CALL	←PortStr
	MOV	BX,OFFSET ←I8237
	CALL	←PortStr
	MOV	BX,OFFSET ←I8274
	CALL	←PortStr
	MOV	BX,OFFSET ←I8259
	CALL	←PortStr
; now set up single step and breakpoint
	XOR	AX,AX
	XOR	BX,BX
	MOV	←lnmi,AX
	MOV	[trcsloc+BX],AX
	MOV	[bkcsloc+BX],AX
	MOV	[decsloc+BX],AX
	MOV	[ovcsloc+BX],AX
	MOV	[triploc+BX],OFFSET trace
	MOV	[bkiploc+BX],OFFSET brkpt
	MOV	[deiploc+BX],OFFSET cmde
	MOV	[oviploc+BX],OFFSET cmov

; set up all interrupts to point to UnkInt
; The idea is that the interrupt type is encoded in the CS:IP pair
; so that CS holds the type and IP holds UnkInt-16*CS
	MOV	CX,251
	MOV	DI,014H
	MOV	BX,5
	MOV	DX,OFFSET UnkInt
	SUB	DX,050H
	CLD
suih:
	MOV	AX,DX
	STOSW
	MOV	AX,BX
	STOSW
	INC	BX
	SUB	DX,010H
	LOOP	suih
; initialize save area
	MOV	rip,0200H
	MOV	rsp,01F0H
	XOR	AX,AX
	MOV	rcs,AX
	MOV	res,AX
	MOV	rds,AX
	MOV	rss,AX
	MOV	rfl,0F000H	 ; interrupts off
	RET
←Setup	ENDP

PUBLIC	←cmklo
PUBLIC	←cmkhi
PUBLIC	←mstate
PUBLIC	←CRestart
PUBLIC	←StartM
PUBLIC	←Setup
PUBLIC	←lip
PUBLIC	←lnmi
PUBLIC	←eitype

C←CODE ENDS
	END