; refreshml.dsm
; L. Stewart, February 11, 1983  3:50 PM
; L. Stewart, February 14, 1983  12:25 PM, swab bug in refresh
; L. Stewart, February 16, 1983  10:26 PM, initial stack bug
; L. Stewart, February 18, 1983  9:46 AM, relocation
; L. Stewart, February 18, 1983  6:49 PM, boot switches & ref. bug.
; L. Stewart, February 24, 1983  1:48 PM, advice, bootSeal
; L. Stewart, February 24, 1983  1:48 PM, add monRelays..localNet

SPACE   SEGMENT

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

;	DB	2 DUP(?)

SPACE	ENDS

C←CODE	SEGMENT

$INCLUDE(Lark.d)

; numbers which affect relocation of this code
; stack initial value
SPIN		EQU	0DFF0H
OffRefA	EQU	0E010H
OffRefB	EQU	0E050H
OffRefC	EQU	0E090H
OffRefD	EQU	0E0D0H

triploc	EQU	004H
trcsloc	EQU	006H
nmiploc	EQU	008H
nmcsloc	EQU	00AH

; boot reasons
; interrupts of various sorts are of types 0 up through 255
cTRACE	EQU	1
cNMI		EQU	2
cWDTBoot	EQU	0FFF8H
cMainRet	EQU	0FFF9H
cTeleBoot	EQU	0FFFAH
cSSFAIL	EQU	0FFFBH
cMONRET	EQU	0FFFCH
cRUNERR	EQU	0FFFDH
cEXTINT	EQU	0FFFEH
cPwrOnBoot	EQU	0FFFFH
cRUNNING	EQU	0FF00H

C←DATA	SEGMENT

; save area for machine state
; the arrangement of the following statics is known
; to remote debuggers, so don't change it frivilously
←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	?
←bootReason	DW	00H
←rtcLow	DW	00H
←rtcHigh	DW	00H
←bootSwitches	DW	00H
←advice	DW	00H
←monRelays	DW	00H
←tlNet		DW	00H
←tlHost	DW	00H
←tlImHost	DW	00H
←localNet	DW	00H

; above state known to remote debuggers
←bootSeal	DW	00H
←lastIP	DW	?	; single step use
savea	DW	0
←lastNMI	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
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	JMP	runerr		; 3 bytes

;  address = E00A
	JMP	cstart		; 3 bytes

;  address = E00D
possnmi:
	JMP	pnmib		; 3 bytes

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

	DW	006C7H	; 2 bytes  DB 0C7H  DB 006H
	DW	nmiploc	; 2 bytes
	DW	OffRefB

	NOP			; drain IFU
	NOP
	NOP
	NOP			; total 14

	ADD	←rtcLow,1	; 5 bytes

	NOP			; drain IFU
	NOP
	NOP
	NOP			; total 23

	ADC	←rtcHigh,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	006C7H	; 2 bytes  DB 0C7H  DB 006H
	DW	nmiploc
	DW	OffRefC

	NOP			; drain IFU
	NOP
	NOP
	NOP
	NOP			; total 16

	ADD	←rtcLow,1

	NOP			; drain IFU
	NOP
	NOP
	NOP
	NOP			; total 26

	ADC	←rtcHigh,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	006C7H	; 2 bytes  DB 0C7H  DB 006H
	DW	nmiploc
	DW	OffRefD

	NOP			; drain IFU
	NOP
	NOP
	NOP
	NOP			; total 16

	ADD	←rtcLow,1

	NOP			; drain IFU
	NOP
	NOP
	NOP
	NOP			; total 26

	ADC	←rtcHigh,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	006C7H	; 2 bytes  DB 0C7H  DB 006H
	DW	nmiploc
	DW	OffRefA

	NOP			; drain IFU
	NOP
	NOP
	NOP
	NOP			; total 16

	ADD	←rtcLow,1

	NOP			; drain IFU
	NOP
	NOP
	NOP
	NOP			; total 26

	ADC	←rtcHigh,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

; P1A (output)
; P1A7 ResAlogInt' 1
; P1A6 Led' 1
; P1A5 SlaveReset 1
; P1A4 SlaveNMI 0
; P1A3 KickWDT 0
; P1A2 StopAudClock 0
; P1A1 P1A1 0
; P1A0 ResEncInt' 1

	DB	pioa
	DB	1
	DB	0E1H

; P1B Ethernet host address switches (input)

	DB	piob
	DB	1
	DB	000H

; P1C (0-3 input, 4-7 output)
; P1C7 Unused 0
; P1C6 Unused 0
; P1C5 SwitchHS' 1
; P1C4 ShuntA' 1
; P1C3 P1C3
; P1C2 BootMode
; P1C1 SynTSN
; P1C0 ManNMI

	DB	pioc
	DB	1
	DB	030H

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

; P2A (output)
; P2A7 Revert 1
; P2A6 GoOffHook' 1
; P2A5 CodecControlData 0
; P2A4 CodecControlClock 0
; P2A3 SenseSH 0
; P2A2 SenseRI 0
; P2A1 SenseSwitch 0
; P2A0 SenseCode 0

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

; P2B (output)
; P2B7 SwDataStrobe3 0
; P2B6 SwDataStrobe2 0
; P2B5 SwDataStrobe1 0
; P2B4 SwDataStrobe0 0
; P2B3 SwAddr3 0
; P2B2 SwAddr2 0
; P2B1 SwAddr1 0
; P2B0 SwAddr0 0

	DB	apiob
	DB	1
	DB	000H

; P2C (0-3 output, 4-7 input)
; P2C7 DTMFCode3
; P2C6 DTMFCode2
; P2C5 DTMFCode1
; P2C4 DTMFCode0
; P2C3 EnableRing' 1
; P2C2 SideTone' 1
; P2C1 Unused 0
; P2C0 SwData 0

	DB	apioc
	DB	1
	DB	00CH	; EnableRing and SideTone 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, free run
	DB	01BH		; no gate, F1
	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

; select one of the next two lines
;	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

; select one of the next two lines
;	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	; ICW1: level mode, single 8259, ICW4 needed

	DB	intdata
	DB	3
	DB	070H	; ICW2, base of vectors
	DB	001H	; ICW4, no nest, no buffer, no AEOI, 8088
	DB	0FFH	; OCW1, mask off all interrupts

; end of string
	DB	0FFH

; jump targets for jumps at top of this file

; runerr may catch sequential execution into EPROM space
runerr:
	PUSHF
	CLI
	PUSH	CS
	MOV	rbx,BX
	MOV	BX,08000H	; fake PUSH IP
	PUSH	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,←lastNMI
	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	AX,0F000H
	PUSH	AX		; push flags for monitor execution
	XOR	AX,AX
	PUSH	AX		; push cs for wasnmi
	MOV	AX,OFFSET wasnmi
	PUSH	AX		; push ip for wasnmi
	JMP	wasntnmi

; execution starts here on a system reset
; might be a WDTBoot, but we haven't checket yet
cstart:
	MOV	BX,cPwrOnBoot

; callable from C:  CStart(reason)
; initializes
←CStart:
	MOV	AL,0FFH		; timer master reset
	OUT	TimCtl,AL
	MOV	AL,083H		; Port A, C4-7 Out, Port B, C0-3 In, mode 0
	OUT	pioctl,AL
	MOV	AL,068H		; kick WDT, Alog reset
	OUT	pioa,AL
	MOV	AL,0E1H		; normal
	OUT	pioa,AL
	MOV	AL,000H		; input
	OUT	piob,AL
	MOV	AL,030H		; A and HS relays OFF
	OUT	pioc,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
	MOV	AL,000H		; crossbar
	OUT	apiob,AL
	MOV	AL,00CH		; EnableRing and SideTone OFF
	OUT	apioc,AL

; all traps, etc. come here with different codes in BX
←CRestart:
	MOV	AX,SPIN
	MOV	SP,AX
; CS better be 0
	XOR	AX,AX
	MOV	SS,AX
	MOV	ES,AX
	MOV	DS,AX
	MOV	BP,AX		; top of stack
	MOV	←bootReason,BX
	CMP	BX,cPwrOnBoot
	JNE	callMon
	CALL	←Setup
; might be a WDTBoot, so check it out
	MOV	AX,←bootSeal
	CMP	AX,0ABCDH
	JNE	pob
	MOV	BX,cWDTBoot
	MOV	←bootReason,BX
	JMP	callMon
pob:
	MOV	←advice,0
callMon:
	MOV	AX,0ABCDH
	MOV	←bootSeal,AX
	MOV	BX,←bootReason
	CALL	←MonMain
;
; if the monitor returns, start it again
;
	MOV	BX,cMONRET
	JMP	←CStart

←StartM LABEL	NEAR
	MOV	←bootReason,cRUNNING
	CMP	rsp,0300H
	JAE	sok
	MOV	rsp,03F0H
sok:
	MOV	AX,rip
	MOV	←lastIP,AX		; save current ip
	XOR	AX,AX			; zero segment regs
	MOV	SS,AX
	MOV	DS,AX
	MOV	ES,AX
	MOV	AX,rsp
	MOV	SP,AX
	PUSH	rfl
	XOR	AX,AX			; zero CS
	PUSH	AX
	PUSH	rip
	MOV	AX,rax
	MOV	BX,rbx
	MOV	CX,rcx
	MOV	DX,rdx
	MOV	SI,rsi
	MOV	DI,rdi
	MOV	BP,rbp
	IRET			; pops FL, CS, and IP

intcom:
	MOV	rax,AX
	MOV	rcx,CX
	MOV	rdx,DX
	MOV	rsi,SI
	MOV	rdi,DI
	MOV	rbp,BP
	POP	rip
	POP	rcs
	POP	rfl
	PUSH	DS
	POP	rds
	PUSH	ES
	POP	res
	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

; All other interrupts

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

; the monitor calls this to initialize the machine

←Setup	PROC	NEAR
;
; 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

; temporary refresh, to keep things going temporarily
	MOV	SI,0
	MOV	CX,128
	CLD
	REP	LODSW
; first fill in those in low memory
	MOV	CX,6
	MOV	DI,000H
	MOV	BX,000H
	MOV	DX,OFFSET UnkInt
	SUB	DX,000H
	CLD
suih1:
	MOV	AX,DX
	STOSW
	MOV	AX,BX
	STOSW
	INC	BX
	SUB	DX,010H
	LOOP	suih1
; assert that an NMI is not in progress
	MOV	←lastNMI,0
; set up single step
	XOR	AX,AX
	XOR	BX,BX
	MOV	[trcsloc+BX],AX
	MOV	[nmcsloc+BX],AX
	MOV	[triploc+BX],OFFSET trace
	MOV	[nmiploc+BX],OFFSET RefA
;
; initialize IO devices
;
	CALL	←InitIO
; set the rest of 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,250
	MOV	DI,018H
	MOV	BX,006H
	MOV	DX,OFFSET UnkInt
	SUB	DX,060H
	CLD
suih2:
	MOV	AX,DX
	STOSW
	MOV	AX,BX
	STOSW
	INC	BX
	SUB	DX,010H
	LOOP	suih2

; initialize save area
	MOV	rip,0400H
	MOV	rsp,0DFF0H
	XOR	AX,AX
	MOV	rcs,AX
	MOV	res,AX
	MOV	rds,AX
	MOV	rss,AX
	MOV	rfl,0F000H	 ; interrupts off
	RET
←Setup	ENDP

←InitIO	PROC	NEAR
	MOV	BX,OFFSET ←I9513
	CALL	←PortStr
	MOV	BX,OFFSET ←I8255
	CALL	←PortStr
	MOV	BX,OFFSET ←I8237
	CALL	←PortStr
	MOV	BX,OFFSET ←I8274
	CALL	←PortStr
	MOV	BX,OFFSET ←I8259
	CALL	←PortStr
	RET
←InitIO	ENDP

PUBLIC	←mState
PUBLIC	←bootReason
PUBLIC	←rtcLow
PUBLIC	←rtcHigh
PUBLIC	←bootSwitches
PUBLIC	←advice
PUBLIC	←monRelays
PUBLIC	←tlNet
PUBLIC	←tlHost
PUBLIC	←tlImHost
PUBLIC	←localNet
PUBLIC	←CStart
PUBLIC	←CRestart
PUBLIC	←StartM
PUBLIC	←Setup
PUBLIC	←InitIO
PUBLIC	←lastIP
PUBLIC	←lastNMI

C←CODE ENDS
	END