
; **********************************************
; **                                          **
; **  OPERATING SYSTEM ROM PART 2: E400-FFFF  **
; **                                          **
; **********************************************

		.org $E400
		.segment "E400FFFF"
	
		.include "atari.inc"
		.include "gtia.inc"
		.include "antic.inc"
		.include "pokey.inc"
		.include "pia.inc"

		.import C02C,C2AA,C018,C000,C0CE
		.import CHARSET1,CHARSET2
		.import C7E4,CB56,CA29,C90C
		.import C745,C9AA,C9A5,C9A0
		.import C99B,C996,C991
		.import SLFTST,COLDS,WARMS,INTIN,VBLKD
		.import VBLKI,SETVBL,SIO,DISKIN,DISKI
	
		.export	EDITRV,SCRENV ,KEYBDV,PRINTV,CASETV
		.export	DISKIV,DISKINV,CIOV  ,SIOV  ,SETVBV,SYSVBV,XITVBV
		.export	SIOINV,SENDEV ,INTINV,CIOINV,SELFSV,WARMSV,COLDSV
		.export	RBLOKV,CSOPIV ,PUPDIV,SLFTSV,PENTV ,PHUNLV,PHINIV
		.export	GPDVV
		.export	KIR
		.export	VFR,VSR
		.export	E40C,E41C,E42C,E43C,E44C
		.export	E49B,E510,E55C,E716,E7DE,E89E,E971
		.export	ISRODN,ISRTD,ISRSIR
		.export	PHR
		.export	SELFS

; E000-E3FF	1024	character set 1
; E400-E44F	  80	device handlers:
; -> E400		editor   E:
; -> E410		screen   S:
; -> E420		keyboard K:
; -> E430		printer  P:
; -> E440		cassette C:
; E450-E48E	  63	jump vectors (21)
; E48F-E49E	  16	device handler for parallel bus
; E49F-E4C0	  34	unused (zero, followed by RTS)
; E4C1-E738	 632	CIO code
; E739-E95B	 547	peripheral handler code
; E95C-EE1C	1217	SIO code
; EE1D-EEBB	 159	tables (presumably for screen handler)
; EEBC-EF6D	 176	peripheral handler code (special CIO case)
; EF6C-FCDA	3439	screen/editor/keyboard handler
; FCDB-FE98	 446	cassette handler
; FE99-FF72	 218	printer handler
; FF73-FFEA	 120	rom checksum routine
; FFEB-FFED	   3	unused (zero) bytes
; FFEE-FFF9	  12	ROM identification bytes
; FFFA-FFFF	   6	6502 exception handler vectors

; ***********************
; **                   **
; **  DEVICE HANDLERS  **
; **                   **
; ***********************

	; Device Handler "E:"

EDITRV:		.word	EF94-1	; Open    E:
		.word	F22E-1	; Close   E:
		.word	F24A-1	; Get     E:
		.word	F2B0-1	; Put     E:
		.word	F21E-1	; Status  E:
		.word	F22D-1	; Special E: [RTS]
E40C:		jmp	SIN	; Init    E:
		.byte	0

	; Device Handler "S:"

SCRENV:		.word	EF8E-1	; Open    S:
		.word	F22E-1	; Close   S:
		.word	F180-1	; Get     S:
		.word	F1A4-1	; Put     S:
		.word	F21E-1	; Status  S:
		.word	F9AF-1	; Special S:
E41C:		jmp	SIN	; Init    S:
		.byte	0

	; Device Handler "K:"

KEYBDV:		.word	F21E-1	; Open    K:
		.word	F21E-1	; Close   K:
E424:		.word	F2FD-1	; Get     K:
		.word	F22D-1	; Put     K: [RTS]
		.word	F21E-1	; Get     K:
		.word	F22D-1	; Special K: [RTS]
E42C:		jmp	SIN	; Init    K:
		.byte	0

	; Device Handler "P:"

PRINTV:		.word	FEC2-1	; Open    P:
		.word	FF07-1	; Close   P:
		.word	FEC1-1	; Get     P: [RTS]
		.word	FECB-1	; Put     P:
		.word	FEA3-1	; Status  P:
		.word	FEC1-1	; Special P: [RTS]
E43C:		jmp	PIN	; Init    P:
		.byte	0

	; Device Handler "C:"

CASETV:		.word	FCE6-1	; Open    C:
		.word	FDCF-1	; Close   C:
		.word	FD7A-1	; Get     C:
		.word	FDB4-1	; Put     C:
		.word	FDCC-1	; Status  C:
		.word	FCE5-1	; Special C: [RTS]
E44C:		jmp	CIN	; Init    C: !!! Patched by XL-IT! !!!
		.byte	0

; ********************
; **                **
; **  Jump Vectors  **
; **                **
; ********************

DISKIV:		jmp	DISKI
DISKINV:	jmp	DISKIN
CIOV:		jmp	CIO		; Central I/O
SIOV:		jmp	SIO		; Serial  I/O
SETVBV:		jmp	SETVBL
SYSVBV:		jmp	VBLKI
XITVBV:		jmp	VBLKD
SIOINV:		jmp	SIOINT
SENDEV:		jmp	SENDEN
INTINV:		jmp	INTIN
CIOINV:		jmp	ICIO
SELFSV:		jmp	SELFS
WARMSV:		jmp	WARMS
COLDSV:		jmp	COLDS
RBLOKV:		jmp	RBLOK
CSOPIV:		jmp	CSOPI
PUPDIV:		jmp	SELFS
SLFTSV:		jmp	SLFTST
PENTV:		jmp	PHE
PHUNLV:		jmp	PHUNL
PHINIV:		jmp	PHINI

	; Device Handler Parallel Bus

GPDVV:		.word	C991-1
		.word	C996-1
		.word	C99B-1
		.word	C9A0-1
		.word	C9A5-1
		.word	C9AA-1
E49B:		jmp	C90C
		.byte	0

	; Weird stuff

		.byte	0,0,0,0,0,0,0,0,0,0,0	; 33 bytes wasted
		.byte	0,0,0,0,0,0,0,0,0,0,0
		.byte	0,0,0,0,0,0,0,0,0,0,0

		rts				; 1 byte wasted

; ************************
; **                    **
; **  INIT CENTRAL I/O  **
; **                    **
; ************************

	; CIO initialization (called by monitor at power up)
	
ICIO:		ldx	#0
@1:		lda	#$FF		; set all IOCB's to free
		sta	ICHID,X		; by setting handler ID's=$FF
		lda	#<(IIN-1)
		sta	ICPTL,X		; point PUT to error routine
		lda	#>(IIN-1)
		sta	ICPTH,X
		txa
		clc
		adc	#$10		; bump index by size
		tax
		cmp	#$80		; done?
		bcc	@1		; no
		rts			; yes, return

	; error routine for illegal PUT
	
IIN:		ldy	#133		; IOCB not open
		rts

; *******************************
; **                           **
; **  CENTRAL I/O (602 bytes)  **
; **                           **
; *******************************

	; CIO interfaces between user and input/output device
	
CIO:		sta	ICAX6Z		; save possible output character
		stx	ICAX5Z		; save IOCB number * N

	; check for legal IOCB
	
		txa
		and	#%00001111	; is IOCB multiple of 16? 
		bne	@1		; no, error
		cpx	#$80		; is index too large?
		bcc	@2		; no

	; invalid IOCB number -- return error
	
@1:		ldy	#134		; error code
		jmp	E670		; return

	; move user IOCB to zero page
	
@2:		ldy	#0
@3:		lda	IOCB,X		; user IOCB
		sta	ZIOCB,Y		; to zero page
		inx
		iny
		cpy	#12		; 12 bytes
		bcc	@3

	; new stuff...
	
		lda	ICHIDZ
		cmp	#$7F
		bne	L6
		lda	ICCOMZ		; Handler Index Number == $7F
		cmp	#12
		beq	CICLOS		; Close command?
		lda	HNDLOD
		bne	L5		; Should we do a peripheral command?

E510:		ldy	#130		; ERROR: Nonexistent Device
L4:		jmp	E670

L5:		jsr	CA29		; Do peripheral command
		bmi	L4

	; Compute CIO internal vector for command
	
L6:		ldy	#132		; assume invalid code
		lda	ICCOMZ		; command code to index
		cmp	#3		; is command legal?
		bcc	E670_2		; no
		tay

	; move command to zero base for index
	
		cpy	#14		; is command special?
		bcc	@7		; no
		ldy	#14		; yes, set special offset index
@7:		sty	ICCOMT		; save command for vector
		lda	COMTAB-3,Y	; get vector offset from table
		beq	CIOPEN		; go if OPEN command
		cmp	#2		; is it CLOSE?
		beq	CICLOS		; yes
		cmp	#8		; is it STATUS or SPECIAL?
		bcs	CISTSP		; yes
		cmp	#4		; is it READ?
		beq	CIREAD		; yes
		jmp	CIWRIT		; else, must be WRITE

	; OPEN command
	; find device handler in handler address table
	
CIOPEN:		lda	ICHIDZ		; get handler ID
		cmp	#$FF		; is this IOCB closed?
		beq	W1		; yes

	; error -- IOCB already open
	
	ldy	#129			; error code
E670_2:	jmp	E670			; return

	; new stuff...
	
W1:		lda	HNDLOD
		bne	W2

	; go find device
	
		jsr	DEVSRC		; call device search
		bcs	W2		; go if device not found

	; device found, initialize IOCB for open

		lda	#0		; reserve 0 bytes
		sta	DVSTAT
		sta	DVSTAT+1

	; compute handler entry point

E55C:		jsr	COMENT
		bcs	E670_2		; go if error in compute

	; go to handler for initialization
	
		jsr	GOHAND		; use indirect jump

	; store PUT BYTE address-1 into IOCB
		
		lda	#11		; simulate put character
		sta	ICCOMT
		jsr	COMENT		; compute entry point
		lda	ICAX3Z		; move computed value
		sta	ICPTLZ		; to PUT BYTE address
		lda	ICAX4Z
		sta	ICPTHZ
		jmp	E672		; return to user

	; new stuff...
	
W2:		jsr	EEF9
		jmp	E670

	; CLOSE command

CICLOS:		ldy	#1		; assume good CLOSE
		sty	ICSTAZ 
		jsr	COMENT		; compute handler entry point
		bcs	@1		; go if error in compute
		jsr	GOHAND		; go to handler to close device
@1:		lda	#$FF		; get IOCB "free" value
		sta	ICHIDZ		; set handler ID
		lda	#>(IIN-1)
		sta	ICPTHZ		; set PUT BYTE to point to error
		lda	#<(IIN-1)
		sta	ICPTLZ
		jmp	E672		; return

	; STATUS and SPECIAL requests

	; do implied open if necessary and go to device

CISTSP:		lda	ICHIDZ		; is there a handler ID?
		cmp	#$FF
		bne	@1		; yes

	; IOCB is free, do implied open

		jsr	DEVSRC		; find device in table
		bcs	E670_2		; go if error in compute

	; compute and go to entry point in handler

@1:		jsr	COMENT		; compute handler entry vector
		jsr	GOHAND		; go to handler

	; restore handler index (do implied close)

		ldx	ICAX5Z		; IOCB index
		lda	ICHID,X		; get original handler ID
		sta	ICHIDZ		; restore zero page
		jmp	E672		; return

	; read -- do GET commands
	
CIREAD:		lda	ICCOMZ		; get command byte
		and	ICAX1Z		; is this read legal?
		bne	rlegal		; yes

	; illegal read -- IOCB opened for write only
	
		ldy	#131		; error code
E670_3:		jmp	E670		; return

	; compute and check entry point
	
rlegal:		jsr	COMENT		; compute entry point
		bcs	E670_3		; go if error in compute

	; get record or characters
	
		lda	ICBLLZ
		ora	ICBLHZ		; is buffer length zero?
		bne	@2		; no
		jsr	GOHAND
		sta	ICAX6Z
		jmp	E672

	; loop to fill buffer or end record
	
@2:		jsr	GOHAND		; go to handler to get byte
		sta	ICAX6Z		; save byte
		bmi	@6		; end transfer if error
		ldy	#0
		sta	(ICBALZ),Y	; put byte in user buffer
		jsr	INCBFP		; increment buffer pointer
		lda	ICCOMZ		; get command code
		and	#2		; is it GET RECORD?
		bne	@3		; no

	; check for EOL on text records
	
		lda	ICAX6Z		; get byte
		cmp	#$9B		; is it an EOL?
		bne	@3		; no
		jsr	DECBFL		; yes, decrement buffer length
		jmp	@6		; end transfer

	; check buffer full

@3:		jsr	DECBFL		; decrement buffer length
		bne	@2		; continue if non zero

	; buffer full, record not ended
	; discard bytes until end of record
	
		lda	ICCOMZ		; get command byte
		and	#2		; is it GET CHARACTER? 
		bne	@6		; yes, end transfer
	
	; loop to wait for EOL

@4:		jsr	GOHAND		; get byte from handler
		sta	ICAX6Z		; save character
		bmi	@5		; go if error

	; text record, wait for EOL
	
		lda	ICAX6Z		; get got byte
		cmp	#$9B		; is it EOL?
		bne	@4		; no, continue

	; end of record, buffer full -- send truncated record message
	
		lda	#137		; ERROR: truncated record
		sta	ICSTAZ		; store in IOCB

	; new stuff...
	
@5:		jsr	DECBFA
		ldy	#0
		lda	#$9B
		sta	(ICBALZ),Y
		jsr	INCBFP

	; transfer done
	
@6:		jsr	SUBBFL		; set final buffer length
		jmp	E672		; return

	; write -- do PUT commands
	
CIWRIT:		lda	ICCOMZ		; get command byte
		and	ICAX1Z		; is this write legal?
		bne	Z1		; yes

	; illegal write -- device opened for read only
	
		ldy	#135		; error code
E670_4:		jmp	E670		; return

	; compute and check entry point

Z1:		jsr	COMENT		; compute handler entry point
		bcs	E670_4		; go if error in compute

	; put record or characters
	
		lda	ICBLLZ
		ora	ICBLHZ		; is buffer length zero?
		bne	@2		; no
		lda	ICAX6Z		; get character
		inc	ICBLLZ		; set buffer length=1
		bne	@3		; then just transfer one byte

	; loop to transfer bytes from buffer to handler
	
@2:		ldy	#0
		lda	(ICBALZ),Y	; get byte from buffer
		sta	ICAX6Z		; save
@3:		jsr	GOHAND		; go put byte

	; new stuff...
	
		php			; save N flag
		jsr	INCBFP		; increment buffer pointer
		jsr	DECBFL		; decrement buffer length
		plp			; restore N flag

		bmi	@5		; end if error
	
		lda	ICCOMZ		; get command byte
		and	#2		; is it PUT RECORD?
		bne	@4		; no

	; text record -- check for EOL transfer
	
		lda	ICAX6Z		; get last character
		cmp	#$9B		; is it an EOL?
		beq	@5		; no

	; new stuff..
	
@4:		lda	ICBLLZ
		ora	ICBLHZ		; check buffer length
		bne	@2		; continue if non-zero

	; buffer empty, record not filled
	; check type of transfer
	
		lda	ICCOMZ		; get command code
		and	#2		; is it PUT CHARACTER?
		bne	@5		; yes, end transfer

	; put record (text), buffer empty, send EOL
	
		lda	#$9B
		jsr	GOHAND		; go to handler

	; end PUT transfer
		
@5:		jsr	SUBBFL		; set actual PUT buffer length
		jmp	E672		; return

	; CIO returns
	; returns with Y=status
	
E670:		sty	ICSTAZ

	; returns with status stored in ICSTAZ

	; move IOCB in zero page back to user area
	
E672:		ldy	ICAX5Z		; get IOCB index
		lda	ICBAL,Y
		sta	ICBALZ		; restore user buffer pointer
		lda	ICBAH,Y
		sta	ICBAHZ
		ldx	#0		; loop count and index
		stx	HNDLOD
@1:		lda	ZIOCB,X		; zero page
		sta	ICHID,Y		; to user area
		inx
		iny
		cpx	#12		; 12 bytes
		bcc	@1

	; restore A, X & Y
	
		lda	ICAX6Z		; get last character
		ldx	ICAX5Z		; IOCB index
		ldy	ICSTAZ		; get STATUS and set flags
		rts			; return to user

; ***********************
; **  CIO SUBROUTINES  **
; ***********************

	; COMENT -- check and compute handler entry point
	
COMENT:		ldy	ICHIDZ		; get handler index
		cpy	#34		; is it a legal index?
		bcc	@1		; yes

	; illegal handler index means device not open for operation
	
		ldy	#133		; error code
		bcs	@2		; return

	; use handler address table and command table to get vector
	
@1:		lda	HATABS+1,Y	; get low byte of address
		sta	ICAX3Z		; and save in pointer
		lda	HATABS+2,Y	; get hi byte of address
		sta	ICAX4Z
		ldy	ICCOMT		; get command code
		lda	COMTAB-3,Y	; get command offset
		tay
		lda	(ICAX3Z),Y	; get low byte of vector from
		tax			; handler itself and save
		iny
		lda	(ICAX3Z),Y	; get hi byte of vector
		sta	ICAX4Z
		stx	ICAX3Z		; set lo byte 
		clc			; show no error
@2:		rts

	; DECBFL -- decrement buffer length double byte
	; Z-flag = 0 on return if length = 0 after decrement
	
DECBFL:		lda	ICBLLZ		; will low byte go below?
		bne	@1		; no
		dec	ICBLHZ		; decrement hi byte
@1:		dec	ICBLLZ		; decrement low byte
		lda	ICBLLZ
		ora	ICBLHZ		; set Z if both are zero
		rts

	; DECBFA -- decrement buffer address diuble byte
	
DECBFA:		lda	ICBALZ		; will low byte go below?
		bne	@1		; no
		dec	ICBAHZ		; decrement hi byte
@1:		dec	ICBALZ		; decrement lo byte
		rts

	; INCBFP -- increment working buffer pointer
	
INCBFP:		inc	ICBALZ		; bump low byte
		bne	@1		; go if not zero
		inc	ICBAHZ		; else, bump hi byte
@1:		rts

	; SUBBFL -- set buffer length = buffer length - working byte count
	
SUBBFL:		ldx	ICAX5Z		; get IOCB index
		sec
		lda	$348,X		; get low byte of initial length
		sbc	ICBLLZ		; subtract final low byte
		sta	ICBLLZ		; and save back
		lda	$349,X		; get hi byte
		sbc	ICBLHZ
		sta	ICBLHZ
		rts

	; GOHAND -- go indirect to a device handler
	; Y = status on return, N flag=1 if error on return
	
GOHAND:		ldy	#146		; "no function" status for handler RTS
		jsr	@1		; use the indirect jump
		sty	ICSTAZ		; save status
		cpy	#0		; and set N flag
		rts

	; indirect jump to handler by Paul's method
	
@1:		tax			; save A
		lda	ICAX4Z		; get jump address hi byte
		pha			; put on stack
		lda	ICAX3Z		; get jump address lo byte
		pha			; put on stack
		txa			; restore A
		ldx	ICAX5Z		; get IOCB index
		rts			; go to handler indirectly

	; DEVSRC -- device search, find device in handler address table

	;  set ICDNO
	
DEVSRC:		SEC 
		ldy	#1
		lda	(ICBALZ),Y	; get device number (drive number)
		sbc	#'1'		; subtract ASCII one
		bmi	@1
		cmp	#9		; is number in range?
		bcc	@2		; yes

@1:		lda	#0		; no, default to one
@2:		sta	ICDNOZ		; save device number+1
		inc	ICDNOZ
	
	; loop to find device
		
		ldy	#0		; get device name from user
		lda	(ICBALZ),Y
	
E716:		beq	@4
		ldy	#33		; initial compare index
@3:		cmp	HATABS,Y	; is this the device?
		beq	@5		; yes
		dey
		dey			; else, point to next device
		dey
		bpl	@3		; continue for all devices

	; no device found, declare non-existent device error
	
@4:		ldy	#130		; error code
		sec			; show error
		rts			; and return

	; found device, set ICHID
	
@5:		tya
		sta	ICHIDZ		; save handler index
		clc			; show no error
		rts			; return

COMTAB:		.byte	0,4,4,4,4,6,6,6,6,2,8,10

; ********************************
; **                            **
; ** PERIPHERAL HANDLER LOADER  **
; **                            **
; ********************************

PHR:		lda	WARMST
		beq	@2
		lda	#<$3E9		; ZCHAIN = $3E9
		sta	ZCHAIN
		lda	#>$3E9
		sta	ZCHAIN+1
@1:		ldy	#$12
		clc
		lda	(ZCHAIN),Y
		tax
		iny
		adc	(ZCHAIN),Y
		beq	@4		; RTS
		lda	(ZCHAIN),Y
		sta	ZCHAIN+1
		stx	ZCHAIN
		jsr	CB56
		bne	@4		; RTS
		jsr	E894
		bcs	@4		; RTS
		bcc	@1
@2:		lda	#0
		sta	CHLINK
		sta	CHLINK+1
		lda	#$4F
		bne	@7
@3:		lda	#0
		tay
		jsr	E7BE
		bpl	@5
@4:		rts

@5:		clc
		lda	MEMLO		; HIMEM>=(MEMLO+DVSTAT) ?
		adc	DVSTAT
		sta	TEMP1
		lda	MEMLO+1
		adc	DVSTAT+1
		sta	TEMP1+1
		sec
		lda	HIMEM
		sbc	TEMP1
		lda	HIMEM+1
		sbc	TEMP1+1
		bcs	@8

@6:		lda	#$4E
@7:		tay
		jsr	E7BE
		jmp	@3

@8:		lda	DVSTAT+2	; device SIO address used for loading
		ldx	MEMLO
		stx	DVSTAT+2
		ldx	MEMLO+1
		stx	DVSTAT+3
		jsr	E7DE
		bmi	@6
		sec
		jsr	E89E
		bcs	@6
		bcc	@3

E7BE:		pha
		ldx	#$9
@1:		lda	E7D4,X
		sta	$300,X
		dex
		bpl	@1
		sty	DAUX2
		pla
		sta	DAUX1
		jmp	SIOV

	; a table area

E7D4:		.byte	$4F		; DDEVIC
		.byte	1		; DUNIT
		.byte	$40		; DCOMND
		.byte	%01000000	; DSTATS
		.word	$2EA		; DBUFLO/HI
		.byte	30		; DTIMLO
		.byte	0		; DUNUSE
		.word	4		; DBYTLO/HI

E7DE:		sta	TEMP2
		ldx	#0
		stx	TEMP1
		dex
		stx	TEMP3
		lda	$2EC
		ror	A
		bcc	@1
		inc	$2EC
		bne	@1
		inc	$2ED
@1:		lda	DVSTAT+2
		sta	LOADAD
		lda	DVSTAT+3
		sta	LOADAD+1
		lda	#<E816
		sta	GBYTEA
		lda	#>E816
		sta	GBYTEA+1
		lda	#$80
		sta	$2D3
		jmp	C745

E816:		ldx	TEMP3
		inx
		stx	TEMP3
		beq	@2
@1:		ldx	TEMP3
		lda	$37D,X
		clc
		rts
@2:		lda	#$80
		sta	TEMP3
		jsr	E833
		bpl	@1
		sec
		rts

E833:		ldx	#11
@1:		lda	E851,X
		sta	$300,X
		dex
		bpl	@1
		ldx	TEMP1
		stx	DAUX1
		inx
		stx	TEMP1
		lda	TEMP2
		sta	DDEVIC
		jmp	SIOV

	; Device Control Block

E851:		.byte	0		; DDEVIC
		.byte	1		; DUNIT
		.byte	$26		; DCOMND
		.byte	%01000000	; DSTATS
		.word	CASBUF		; DBUFLO/HI
		.byte	30		; DTIMLO
		.byte	0		; DUNUSE
		.word	$80		; DBYTLO/HI
		.word	0		; DAUX1/2

E85D:		sty	TEMP1
		sta	TEMP1+1
		lda	#<$3E9		; ZCHAIN = $3E9
		sta	ZCHAIN
		lda	#>$3E9
		sta	ZCHAIN+1
@1:		ldy	#$12
		lda	(ZCHAIN),Y
		tax
		iny
		lda	(ZCHAIN),Y
		cmp	TEMP1+1
		bne	@2
		cpx	TEMP1
		bne	@2
		clc
		rts
@2:		cmp	#0
		bne	@4
		cpx	#0
		bne	@4
@3:		sec
		rts
@4:		stx	ZCHAIN
		sta	ZCHAIN+1
		jsr	CB56
		bne	@3
		beq	@1
E894:		sec
		php
		bcs	E8C0		; JMP E8C0

PHINI:		sta	$2ED
		sty	$2EC

E89E:		php
		lda	#0
		tay
		jsr	E85D
		bcs	E8CE
		ldy	#$12
		lda	$2EC
		sta	(ZCHAIN),Y
		tax
		iny
		lda	$2ED
		sta	(ZCHAIN),Y
		stx	ZCHAIN
		sta	ZCHAIN+1
		lda	#0
		sta	(ZCHAIN),Y
		dey
		sta	(ZCHAIN),Y

E8C0:		jsr	E900
		bcc	E8D1
		lda	$2ED
		ldy	$2EC
		jsr	PHUNL
E8CE:		plp
		sec
		rts

E8D1:		plp
		bcs	E8DD
		lda	#0
		ldy	#$10
		sta	(ZCHAIN),Y
		iny
		sta	(ZCHAIN),Y
E8DD:		clc
		ldy	#$10
		lda	MEMLO
		adc	(ZCHAIN),Y
		sta	MEMLO
		iny
		lda	MEMLO+1
		adc	(ZCHAIN),Y
		sta	MEMLO+1
		ldy	#15
		lda	#0
		sta	(ZCHAIN),Y
		jsr	CB56
		ldy	#15
		sta	(ZCHAIN),Y
		clc
		rts

E900:		clc
		lda	ZCHAIN
		adc	#12
		sta	TEMP1
		lda	$4B
		adc	#0
		sta	TEMP1+1
		jmp	(TEMP1)
		jmp	SETVBL

PHUNL:		jsr	E85D
		bcs	@3
		tay
		lda	ZCHAIN
		pha
		lda	ZCHAIN+1
		pha
		stx	ZCHAIN
		sty	ZCHAIN+1
		lda	COLDST
		bne	@1
		ldy	#$10
		clc
		lda	(ZCHAIN),Y
		iny
		adc	(ZCHAIN),Y
		bne	@2
		jsr	CB56
		bne	@2
@1:		ldy	#18
		lda	(ZCHAIN),Y
		tax
		iny
		lda	(ZCHAIN),Y
		tay
		pla
		sta	ZCHAIN+1
		pla
		sta	ZCHAIN
		tya
		ldy	#19
		sta	(ZCHAIN),Y
		dey
		txa
		sta	(ZCHAIN),Y
		clc
		rts
@2:		pla
		pla
@3:		sec
		rts

	; weird stuff...

		.byte	0,0
		jmp	SIO

; ****************************************
; **                                    **
; ** END OF: PERIPHERAL HANDLER LOADER  **
; **                                    **
; ****************************************

; **********************
; **                  **
; ** SERIAL I/O INIT  **
; **                  **
; **********************

	; SIO initialization subroutine
	
SIOINT:		lda	#%00111100
		sta	PACTL		; turn off motor
		lda	#%00111100
		sta	PBCTL		; raise not command line
		lda	#3
		sta	$232		; get POKEY out of initialize mode
		sta	SOUNDR		; init poke address for quiet I/O
		sta	SKCTL
		rts

; ***********************
; **                   **
; ** SIO MAIN ROUTINE  **
; **                   **
; ***********************

E971:		tsx
		stx	STACKP		; save stack pointer
		lda	#1
		sta	CRITIC
		lda	DDEVIC
		cmp	#$60
		bne	@1		; branch if not cassette
		jmp	CASENT		; otherwise jump to cassette enter

	; all devices except cassette are intelligent
	
@1:		lda	#0
		sta	CASFLG		; init cassette flag to no cassette
	
		lda	#1		; set number of device retries
		sta	DRETRY
@2:		lda	#13		; set number of command frame retries
		sta	CRETRY

	; send a command frame
	
@3:		lda	#$28		; set baud rate to 19200
		sta	$D204
		lda	#0
		sta	$D206
	
		clc			; set up command buffer
		lda	DDEVIC
		adc	DUNIT
		adc	#$FF		; subtract 1
		sta	CDEVIC		; set bus ID number
	
		lda	DCOMND		; set bus command
		sta	CCOMND
	
		lda	DAUX1		; store command frame aux bytes 1 and 2
		sta	CAUX1
		lda	DAUX2
		sta	CAUX2		; done setting up command buffer
	
		clc			; set buffer pointer to cmd frame buf
		lda	#$3A
		sta	BUFRLO		; and buffer end address
		adc	#4
		sta	BFENLO
		lda	#2
		sta	BUFRHI
		sta	BFENHI		; done setting up buffer pointer
	
		lda	#%00110100	; lower not command line
		sta	PBCTL
	
		jsr	SENDIN		; send command frame to a smart device
	
		lda	ERRFLG
		bne	@4		; branch if an error received
	
		tya
		bne	@5		; branch if ACK received
	
@4:		dec	CRETRY		; NACK or TIME OUT occured
		bpl	@3		; so branch if any retries left 

		jmp	@10		; otherwise, jump to return section
	
@5:		lda	DSTATS		; new stuff...
		bpl	@6

	; send a data frame to a peripheral
	
		lda	#13		; set number of retries
		sta	CRETRY
		jsr	LDPNTR		; load buffer pointer with DCB info
		jsr	SENDIN		; send data frame to smart device
		beq	@10		; branch if bad

	; wait for complete signal from peripheral
	
@6:		jsr	STTMOT		; set device time out values in Y,X
	
		lda	#0
		sta	ERRFLG		; clear error flag
	
		jsr	WAITER		; set up timer and wait
		beq	@8		; branch if time out

	; device did not time out
	 
		bit	DSTATS
		bvs	@7		; branch if more data follows
	
		lda	ERRFLG
		bne	@10		; branch if an error occured
		beq	EA2A		; otherwise return

	; receive a data frame from peripheral
	
@7:		jsr	LDPNTR		; load buffer pointer with DCB info
		jsr	RECEIV		; go receive a data frame
@8:		lda	ERRFLG
		beq	@9		; branch if no error preceeded data
	
		lda	TSTAT		; get temp status
		sta	STATUS		; store in real status
	
@9:		lda	STATUS
		cmp	#1
		beq	EA2A		; branch if completely successful
@10:		dec	DRETRY
		bmi	EA2A		; branch if out of device retries
		jmp	@2		; otherwise, one more time

EA2A:		jsr	SENDDS		; disable POKEY interrupts
		lda	#0
		sta	CRITIC
		ldy	STATUS		; return status in Y
		sty	DSTATS		; and the DCB status word
		rts

	; wait subroutine
	; waits for COMPLETE or ACK
	; returns Y=$FF if successfull, Y=$00 if not

WAIT:		lda	#0
		sta	ERRFLG		; clear error flag
	
		clc			; load buffer pointer with address
		lda	#$3E		; of temporary RAM cell
		sta	BUFRLO
		adc	#1
		sta	BFENLO		; also set buffer end +1 address
		lda	#2
		sta	BUFRHI
		sta	BFENHI		; done loading pointer
	
		lda	#$FF
		sta	NOCKSM		; set no checksum follows data flag
	
		jsr	RECEIV		; go receive a byte
	
		ldy	#$FF		; assume success
		lda	STATUS
		cmp	#1
		bne	@2		; branch if it did not work ok
	
		lda	TEMP		; make sure the byte successfully rec'd
		cmp	#'A'		; was actually an ACK or COMPLETE
		beq	@4
		cmp	#'C'
		beq	@4
	
		cmp	#'E'		; branch if device did not send back
		bne	@1
	
		lda	#144
		sta	STATUS		; set device error status
		bne	@2
	
@1:		lda	#139		; otherwise set NACK status
		sta	STATUS
	
@2:		lda	STATUS
		cmp	#138
		beq	@3		; branch if time out
	
		lda	#$FF
		sta	ERRFLG		; set some error flag 
		bne	@4		; return with out setting Y = 0
	
@3:		ldy	#0
	
@4:		lda	STATUS
		sta	TSTAT
		rts			; return

	; send subroutine
	; sends a buffer of bytes out over the serial bus

SEND:		lda	#1		; assume success 
		sta	STATUS
	
		jsr	SENDEN		; enable sending
	
		ldy	#0
		sty	CHKSUM		; clear check sum
		sty	CHKSNT		; checksum sent flag
		sty	XMTDON		; transmission done flag
	
		lda	(BUFRLO),Y	; put first byte from buffer
		sta	SEROUT		; into the serial output register
	
		sta	CHKSUM		; put it in checksum
	
@1:		lda	BRKKEY
		bne	@2
		jmp	BROKE		; jump if break key pressed
	
@2:		lda	XMTDON		; loop until transmission done
		beq	@1
		jsr	SENDDS		; disable sending
		rts			; return

	; output data needed interrupt service routine
	
ISRODN:		tya
		pha			; save Y reg on stack

		inc	BUFRLO		; increment buffer pointer
		bne	@1
		inc	BUFRHI
	
@1:		lda	BUFRLO		; check if past end buffer
		cmp	BFENLO
		lda	BUFRHI		; high part
		sbc	BFENHI
		bcc	@4		; branch if not pas end of buffer
	
		lda	CHKSNT
		bne	@2
	
		lda	CHKSUM
		sta	SEROUT		; send check sum
		lda	#$FF
		sta	CHKSNT		; set checksum sent flag
		bne	@3
	
@2:		lda	POKMSK		; enable transmit done interrupt
		ora	#%00001000
		sta	POKMSK
		sta	IRQEN
	
@3:		pla
		tay			; restore Y reg
		pla			; return from interrupt
		rti

@4:		ldy	#0
		lda	(BUFRLO),Y	; put next byte from buffer
		sta	SEROUT		; into the serial output register
	
		clc
		adc	CHKSUM		; add it to checksum
		adc	#0
		sta	CHKSUM
	
		jmp	@3		; go return

	; transmit done interrupt service routine
	
ISRTD:		lda	CHKSNT
		beq	@1		; branch if checksum not yet sent
	
		sta	XMTDON		; otherwise set transmission done flag
	
		lda	POKMSK		; disable transmit done interrupt
		and	#%11110111
		sta	POKMSK
		sta	IRQEN
	
@1:		pla			; return from interrupt
		rti

RECEIV:		lda	#0
	
		ldy	CASFLG		; branch if cassette
		bne	@1
	
		sta	CHKSUM		; clear checksum
	
@1:		sta	BUFRFL		; buffer full flag
		sta	RECVDN		; receive done flag
	
		lda	#1
		sta	STATUS		; set good status for default case
		jsr	RECVEN		; do receive enable
		lda	#%00111100	; command frame hi command
		sta	PBCTL		; store in PIA
@2:		lda	BRKKEY
		bne	@3
		jmp	BROKE		; jump if break key pressed
	
@3:	 	lda	TIMFLG		; no,
		beq	TOUT		; if timeout, go set error status
		lda	RECVDN
		beq	@2		; done?
		rts
	
TOUT:		lda	#138		; yes,
		sta	STATUS		; set timeout status
		rts

ISRSIR:		tya
		pha			; save Y reg on stack
	
		lda	SKSTAT
		sta	SKRES		; reset status register
		bmi	@1		; branch if no framing error
		ldy	#140
		sty	STATUS		; set frame error status
	
@1:		and	#%00100000
		bne	@2		; branch if no overrun error
	
		ldy	#142
		sty	STATUS		; set overrun error status
	
@2:		lda	BUFRFL
		beq	@5		; branch if buffer was not yet filled
	
		lda	SERIN		; this input byte is the checksum
		cmp	CHKSUM
		beq	@3		; branch if checksums match
	
		ldy	#143
		sty	STATUS		; set checksum error status
	
@3:		lda	#$FF
		sta	RECVDN		; set receive done flag
	
@4:		pla
		tay			; restore Y reg
		pla			; return from interrupt
		rti

@5:		lda	SERIN
		ldy	#0
		sta	(BUFRLO),Y	; store input register into buffer
	
		clc			; add it to checksum
		adc	CHKSUM
		adc	#0
		sta	CHKSUM
	
		inc	BUFRLO		; increment buffer pointer
		bne	@6
		inc	BUFRHI
	
@6:		lda	BUFRLO
		cmp	BFENLO
		lda	BUFRHI
		sbc	BFENHI
		bcc	@4		; branch if new bufadr is in buffer L
	
		lda	NOCKSM
		beq	@7		; branch if a checksum will follow data
	
		lda	#0
		sta	NOCKSM		; clear no checksum flag
	
		beq	@3		; go return and set receive done flag
	
@7:		lda	#$FF
		sta	BUFRFL		; set buffer full flag
	
		bne	@4		; go return

	; load buffer pointer subroutine
	; load DCB buffer pointer with DCB buffer information
	
LDPNTR:		clc
		lda	DBUFLO
		sta	BUFRLO
		adc	DBYTLO
		sta	BFENLO		; also set buffer end + 1 address
	
		lda	DBUFHI
		sta	BUFRHI
		adc	DBYTHI
		sta	BFENHI
	
		rts			; return

	; cassette handling code
	
CASENT:		lda	DSTATS
		bpl	@3		; branch if input from cassette
	
		lda	#<1484		; set baud rate to 600
		sta	AUDF3
		lda	#>1484
		sta	AUDF4
	
		jsr	SENDEN		; turn on POKEY mark tone
	
		ldx	PALNTS
		ldy	EE11+4,X	; load short write interrecord gap time
		lda	DAUX2
		bmi	@1		; branch if short gap is desired
		ldy	EE11,X
	
@1:		ldx	#0		; set write IRG time
		jsr	SETVBX
	
		lda	#%00110100
		sta	PACTL		; turn on motor
	
@2:		lda	TIMFLG		; loop until done
		bne	@2
	
		jsr	LDPNTR		; load buffer pointer with DCB info
	
		jsr	SEND		; send a buffer
	
		jmp	@6		; go return

	; receive a record
	
@3:		lda	#$FF
		sta	CASFLG		; set cassette flag
	
		ldx	PALNTS
		ldy	EE11+6,X	; load short read interrecord gap time
		lda	DAUX2
		bmi	@4		; branch if short gap is desired
		ldy	EE11+2,X
@4:		ldx	#0
		jsr	SETVBX
	
		lda	#%00110100
		sta	PACTL		; turn on motor
	
@5:		lda	TIMFLG		; loop until done
		bne	@5
	
		jsr	LDPNTR		; load buffer pointer with DCB info
	
		jsr	STTMOT		; set device time out in Y,X
		jsr	SETVBX
	
		jsr	BEGIN		; set initial baud rate
	
		jsr	RECEIV		; go receive a block
	
@6:		lda	DAUX2
		bmi	@7		; branch if doing short IRG's

		lda	#%00111100
		sta	PACTL		; turn off motor
@7:		jmp	EA2A

JTIMER:		lda	#0
		sta	TIMFLG		; set time out flag
		rts

	; send enable subroutine
	
SENDEN:		lda	#%00000111	; mask off prev serial bus control bits
		and	SSKCTL
		ora	#%00100000	; set transmit mode
	
		ldy	DDEVIC
		cpy	#$60
		bne	@1		; branch if not cassette
	
		ora	#%00001000	; set the FSK output bit
	
		ldy	#7		; set FSK tome frequencies
		sty	AUDF2
		ldy	#5
		sty	AUDF1
	
@1:		sta	SSKCTL		; store new value to system mask
		sta	SKCTL		; store to actual register
	
		lda	#%11000111	; mask off prev serial bus intr bits
		and	POKMSK
		ora	#%00010000	; enable output data needed interrupt
	
		jmp	EC56		; continue in receive enable subroutine

	; receive enable subroutine
	
RECVEN:		lda	#%00000111	; mask off prev serial bus control bits
		and	SSKCTL
		ora	#%00010000	; set receive mode asynchronous
		sta	SSKCTL		; store new value to system mask
		sta	SKCTL		; store to actual register
	
		sta	SKRES		; reset serial port/keyboard status reg
	
		lda	#%11000111	; mask off prev serial bus intr bits
		and	POKMSK
		ora	#%00100000	; enable receive interrupt

EC56:		sta	POKMSK		; store new value to system mask
		sta	IRQEN		; store to actual register
	
		lda	#%00101000	; clock CH@3 with 1@79 MHz
		sta	AUDCTL		; clock CH@4 with CH@3
	
		ldx	#6		; set pure tones, no volume
		lda	#%10101000
		ldy	SOUNDR		; test quiet I/O flag
		bne	@1		; NE is normal (noisy)
	
		lda	#%10100000
@1:		sta	AUDC1,X
		dex
		dex
		bpl	@1
	
		lda	#%10100000
		sta	AUDC3		; turn off sound on channel 3
		ldy	DDEVIC
		cpy	#$60
		beq	@2		; branch if cassette is desired
		sta	AUDC1		; otherwise turn off channels 1 and 2
		sta	AUDC2
	
@2:		rts			; return

SENDDS:		nop			; ?huh?
	
		lda	#%11000111	; mask off serial bus interrupts
		and	POKMSK
		sta	POKMSK		; store new value to system mask
		sta	IRQEN		; store to actual register
	
		ldx	#6
		lda	#0
@1:		sta	AUDC1,X
		dex
		dex
		bpl	@1		; turn off audio volume
		rts			; return

	; set ddevice time out values in Y,X subroutine
	
STTMOT:		lda	DTIMLO		; get device time out in 1 second incr
		ror	A		; put 6 hi bits in X, lo 2 bits in Y
		ror	A
		tay			; temp save
		and	#%00111111	; mask off hi 2 bits
		tax			; this is hi byte of time out
	
		tya
		ror	A
		and	#%11000000	; mask off all but 2 hi bits
		tay			; this is lo byte of time out
	
		rts

	; these are called INTTBL in the OS source, but are not used!

		.word	ISRSIR		; serial input ready
		.word	ISRODN		; output data needed
		.word	ISRTD		; transmission done

	; send a data frame to an intelligent peripheral subroutine

SENDIN:		ldx	#1		; wait a short time...
@1:		ldy	#$FF
@2:		dey
		bne	@2
		dex
		bne	@1
	
		jsr	SEND		; go send the data frame
	
		ldy	#2		; set ack time out
		ldx	#0
WAITER:		jsr	SETVBX
	
		jsr	WAIT		; wait for ack
	
		tya			; if Y=0, a TIME OUT or NACK occured
	
		rts			; return

	; compute value for POKEY freq regs for the baud rate as
	; measured by an interval of the 'VCOUNT' timer.
	
COMPUT:		sta	TIMER2
		sty	TIMER2+1	; save final timer value
		jsr	ADJUST		; adjust VCOUNT value
		sta	TIMER2		; save adjusted value
		lda	TIMER1
		jsr	ADJUST		; adjust
		sta	TIMER1		; save adjusted TIMER1 value
		lda	TIMER2
		sec
		sbc	TIMER1
		sta	TEMP1		; find VCOUNT difference
		lda	TIMER2+1
		sec
		sbc	TIMER1+1
		tay			; find VBLANK count difference
		ldx	PALNTS
		lda	#0
		sec
		sbc	EE11+8,X
@1:		clc
		adc	EE11+8,X	; accumulate multiplication
		dey
		bpl	@1		; done?
		clc
		adc	TEMP1		; total VCOUNT difference
		tay			; save accum
		lsr	A
		lsr	A
		lsr	A
		asl	A
		sec
		sbc	#22		; adjust table index
		tax			; div interval by 4 to get table index
		tya			; restore accum
		and	#%00000111
		tay			; pull off 3 lo bits of interval
		lda	#$F5	        ;  -11
@2:		clc
		adc	#11		; accumulate interpolation constant
		dey
		bpl	@2		; interp constant computation done?
	
		ldy	#0
		sec
		sbc	#7		; adjust interpolation constant
		bpl	@3
		dey
@3:		clc
		adc	POKTAB,X	; add constant to lo byte table value
		sta	CBAUDL
		tya
		adc	POKTAB+1,X	; add carry to hi byte table value
		sta	CBAUDH
		rts

ADJUST:		cmp	#$7C
		bmi	@1		; larger than '7C' ?
		sec			; yes
		sbc	#$7C
		rts
@1:		clc
		ldx	PALNTS
		adc	EE11+10,X
		rts

	; initial baud rate measurement -- used to set the
	; baud rate at the start of a record

	; it is assumed that the first two bytes of every record are 'AA' hex
	
BEGIN:		lda	BRKKEY
		bne	@1
		jmp	BROKE		; jump if break key pressed
	
@1:		sei
	
		lda	TIMFLG
		bne	@2		; branch if not timed out
		beq	@4		; branch if time out
	
@2:		lda	SKSTAT
		and	#%00010000	; read serial port
		bne	BEGIN		; start bit?
		sta	SAVIO		; save ser. data in
		ldx	VCOUNT		; read vertical line counter
		ldy	RTCLOK+2	; read lo byte of VBLANK counter
		stx	TIMER1
		sty	TIMER1+1	; save initial timer value
	
		ldx	#1		; set mode flag
		stx	TEMP3
		ldy	#10		; set bit counter for 10 bits
@3:		lda	BRKKEY
		beq	BROKE		; branch if break key pressed
	
		lda	TIMFLG
		bne	@5		; branch if not timed out
@4:		cli
		jmp	TOUT		; branch if time out

@5:		lda	SKSTAT
		and	#%00010000	; read serial port
		cmp	SAVIO		; data in changed yet?
		beq	@3
		sta	SAVIO		; yes, save ser. data in
		dey			; decr. bit counter
		bne	@3		; done?
	
		dec	TEMP3		; yes,
		bmi	@6		; done with both modes?
		lda	VCOUNT
		ldy	RTCLOK+2	; read timer lo & hi bytes
		jsr	COMPUT		; no, compute baud rate
		ldy	#9		; set bit counter for 9 bits
		bne	@3

@6:		lda	CBAUDL
		sta	AUDF3
		lda	CBAUDH
		sta	AUDF4		; set POKEY freq regs for baud rate
		lda	#0
		sta	SKCTL
		lda	SSKCTL
		sta	SKCTL		; init POKEY serial port
		lda	#%01010101
		sta	(BUFRLO),Y	; store '$55' as first rcv. buffer
		iny
		sta	(BUFRLO),Y
		lda	#%10101010
		sta	CHKSUM		; store checksum for 2 bytes of '$AA'
		clc
		lda	BUFRLO
		adc	#2
		sta	BUFRLO
		lda	BUFRHI
		adc	#0
		sta	BUFRHI		; incr. buffer pointer by 1
		cli
		rts

BROKE:		jsr	SENDDS		; break key was pressed, so prepare
		lda	#%00111100	; to return
		sta	PACTL		; turn off motor
		lda	#%00111100
		sta	PBCTL		; raise not command line
	
		lda	#128
		sta	STATUS		; store break abort status code
	
		ldx	STACKP
		txs			; restore stack pointer
	
		dec	BRKKEY		; set break key flag to nonzero
		cli			; allow IRQ's
	
		jmp	EA2A		; go return

SETVBX:		lda	#<JTIMER	; store time out routine address
		sta	CDTMA1
		lda	#>JTIMER
		sta	CDTMA1+1
	
		lda	#1		; set for timer 1
	
		sei			; the SETVBL needs this to cut short
		jsr	SETVBV		; any VBLANKs that occur
		lda	#1		; set for timer 2
		sta	TIMFLG		; set flag to not timed out
		cli
		rts

	; 'VCOUNT' interval timer measurement -- TO -- POKEY freq reg value
	;               conversion table
	; The values stored in the table are 'AUDF+7'
	; The followinf formulas were used to determine the table values:
	; F OUT = F IN/(2*(AUDF+M)) , where F IN=1@78979 MHz & M=7
	; From this was derived a formula used to compute the table values
	; based on a measurement of the period by an interval of the VCOUNT
	; timer.
	;   AUDF+7=(11@365167)*T OUT, where T OUT=# of counts
	;   (127 usec. resolution) of VCOUNT for 1 character time
	;   (10 bit times).

	;		AUDF+7		  BAUD RATE	VCOUNT INTERVAL
	;               ------            -----------   ----------------
POKTAB:		.word	$3E8		;  895          88
		.word	$443		;  820          96
		.word	$49E		;  757          104
		.word	$4F9		;  703          112
		.word	$554		;  656          120
		.word	$5AF		;  615          128
		.word	$60A		;  579          136
		.word	$665		;  547          144
		.word	$6C0		;  518          152
		.word	$71A		;  492          160
		.word	$775		;  469          168
		.word	$7D0		;  447          176

	; PAL / NTSC timing values

EE11:		.byte	$B4,$96
		.byte	$78,$64
		.byte	$0F,$0D
		.byte	$0A,$08
		.byte	$83,$9C
		.byte	$07,$20

; *********************
; **  SIO ENDS HERE  **
; *********************

EE1D:		.byte	$18,$10,$0A,$0A,$10,$1C,$34,$64
		.byte	$C4,$C4,$C4,$C4,$1C,$10,$64,$C4
EE2D:		.byte	$17,$17,$0B,$17,$2F,$2F,$5F,$5F
		.byte	$61,$61,$61,$61,$17,$0B,$BF,$61
		.byte	$13,$13,$09,$13,$27,$27,$4F,$4F
		.byte	$41,$41,$41,$41,$13,$09,$9F,$41
EE4D:		.byte	$02,$06,$07,$08,$09,$0A,$0B,$0D
		.byte	$0F,$0F,$0F,$0F,$04,$05,$0C,$0E
EE5D:		.byte	$00,$00,$00,$00,$00,$00,$00,$01
		.byte	$01,$01,$01,$01,$00,$00,$01,$01
EE6D:		.byte	$03,$02,$02,$01,$01,$02,$02,$03
		.byte	$03,$03,$03,$03,$03,$03,$02,$03
EE7D:		.byte	$28,$14,$14,$28,$50,$50,$A0,$A0
		.byte	$40,$50,$50,$50,$28,$28,$A0,$A0
EE8D:		.byte	$18,$18,$0C,$18,$30,$30,$60,$60
		.byte	$C0,$C0,$C0,$C0,$18,$0C,$C0,$C0
EE9D:		.byte	$00,$00,$00,$02,$03,$02,$03,$02
		.byte	$03,$01,$01,$01,$00,$00,$03,$02
EEAD:		.byte	$FF,$F0,$0F,$C0,$30,$0C,$03

EEB4:		.byte	%10000000	; yet another barrel shifter!
		.byte	%01000000
		.byte	%00100000
		.byte	%00010000
		.byte	%00001000
		.byte	%00000100
		.byte	%00000010
		.byte	%00000001

PHE:		pha			; peripheral handler entry
		tya
		pha
		txa
		ldx	#0
@1:		cmp	HATABS,X
		beq	@3
		inx
		inx
		inx
		cpx	#$22
		bmi	@1
		ldx	#0
		tay
		lda	#0
@2:		cmp	HATABS,X
		beq	@4
		inx
		inx
		inx
		cpx	#$22
		bmi	@2
		pla
		pla
		ldy	#$FF
		sec
		rts

@3:		pla
		tay
		pla
		inx
		sec
		rts

@4:		tya
		sta	HATABS,X
		pla
		sta	HATABS+1,X
		pla
		sta	HATABS+2,X
		clc
		rts

EEF9:		ldy	#0
		lda	(ICBALZ),Y
		ldy	ICDNOZ
		jsr	E7BE
		bpl	EF07
		ldy	#130
		rts

EF07:		lda	#$7F
		sta	ICHIDZ
		lda	#<(EF26-1)
		sta	ICPTLZ
		lda	#>(EF26-1)
		sta	ICPTHZ
		lda	$2EC

		.byte	$AE		; absolute addr. mode for LDX ICAX5Z
		.word	ICAX5Z

		sta	$34D,X
		ldy	#0
		lda	(ICBALZ),Y
		sta	$34C,X
		ldy	#1
		rts

EF26:		pha
		txa
		pha
		and	#%00001111
		bne	EF3D
		cpx	#$80
		bpl	EF3D
		lda	HNDLOD
		bne	EF41
		ldy	#$82

EF38:		pla
		pla
		cpy	#0
		rts
EF3D:		ldy	#134
		bmi	EF38

EF41:		.byte	$8E		; absolute addr. mode for STX ICAX5Z
		.word	ICAX5Z

		ldy	#0
EF46:		lda	IOCB,X
		sta	ZIOCB,Y
		inx
		iny
		cpy	#12
		bmi	EF46

		jsr	CA29
		bmi	EF38
		pla
		tax
		pla
		tay
		lda	ICPTHZ
		pha
		lda	ICPTLZ
		pha
		tya
		ldy	#146
		rts

		.byte	0,0,0,0,0,0

		jmp	FD05

; ***************************************************************
; **                                                           **
; **  Device Handler Initialisation Code for devices E: S: K:  **
; **                                                           **
; ***************************************************************

SIN:		lda	#$FF
		sta	CH
		lda	RAMSIZ
		sta	RAMTOP
		lda	#$40
		sta	$2BE
		lda	#<KEYMAP
		sta	KEYDEF
		lda	#>KEYMAP
		sta	KEYDEF+1
		lda	#<FKYMAP
		sta	FKDEF
		lda	#>FKYMAP
		sta	FKDEF+1
		rts

; ***************
; **           **
; **  Open S:  **
; **           **
; ***************

EF8E:		lda	ICAX2Z	; perform screen OPEN
		and	#%00001111
		bne	EF9C

; ***************
; **           **
; **  Open E:  **
; **           **
; ***************

EF94:		lda	ICAX1Z	; perform editor OPEN
		and	#%00001111
		sta	ICAX1Z
		lda	#0

EF9C:		sta	$57	; complete OPEN command
		cmp	#$10
		bcc	EFA7
		lda	#$91
		jmp	F154

EFA7:		lda	#>CHARSET1
		sta	CHBAS
		lda	#>CHARSET2
		sta	CHSALT
		lda	#2
		sta	CHACT
		sta	SDMCTL
		lda	#1
		sta	$4C
		lda	#%11000000
		ora	POKMSK
		sta	POKMSK
		sta	IRQEN
		lda	#%01000000
		sta	NMIEN
		bit	$26E
		bpl	EFDC
		lda	#<FCC4		; gimme a DLI!
		sta	VDSLST
		lda	#>FCC4
		sta	VDSLST+1
		lda	#%11000000
EFDC:		sta	NMIEN
		lda	#0
		sta	TINDEX
		sta	ADRESS
		sta	$7B
		sta	CRSINH
		ldy	#14
		lda	#1
EFEF:		sta	TABMAP,Y
		dey
		bpl	EFEF

		ldx	#4	; init color 0-3
EFF7:		lda	FB08,X
		sta	$2C4,X
		dex
		bpl	EFF7

		ldy	RAMTOP
		dey
		sty	TXTMSC+1
		lda	#$60
		sta	TXTMSC
		ldx	$57
		lda	EE4D,X
		sta	$51
		lda	RAMTOP
		sta	ADRESS+1
		ldy	EE1D,X
F019:		lda	#$28
		jsr	F57A
		dey
		bne	F019
		lda	GPRIOR
		and	#%00111111
		sta	$67
		tay
		cpx	#8
		bcc	F04C
		cpx	#15
		beq	F03E
		cpx	#12
		bcs	F04C
		txa
		ror	A
		ror	A
		ror	A
		and	#%11000000
		ora	$67
		tay
F03E:		lda	#$10
		jsr	F57A
		cpx	#11
		bne	F04C
		lda	#6	; gray
		sta	COLOR4
F04C:		sty	GPRIOR
		lda	ADRESS
		sta	$58
		lda	ADRESS+1
		sta	$59
F057:		lda	$D40B
		cmp	#$7A
		bne	F057
		jsr	F578
		lda	EE5D,X
		beq	F06C
		lda	#$FF
		sta	ADRESS
		dec	ADRESS+1
F06C:		jsr	F565
		lda	ADRESS
		sta	$68
		lda	ADRESS+1
		sta	$69
		lda	#$41
		jsr	F570
		stx	$66
		lda	#$18
		sta	$2BF
		lda	$57
		cmp	#12
		bcs	F08D
		cmp	#9
		bcs	F0C6
F08D:		lda	ICAX1Z
		and	#%00010000
		beq	F0C6
		lda	#4
		sta	$2BF
		ldx	#2
		lda	$26E
		beq	F0A2
		jsr	F5A0
F0A2:		lda	#2
		jsr	F569
		dex
		bpl	F0A2
		ldy	RAMTOP
		dey
		tya
		jsr	F570
		lda	#$60
		jsr	F570
		lda	#$42
		jsr	F569
		clc
		lda	#$10
		adc	$66
		tay
		ldx	EE2D,Y
		bne	F0DB
F0C6:		ldy	$66
		ldx	EE2D,Y
		lda	$57
		bne	F0DB
		lda	$26E
		beq	F0DB
		jsr	F5A0
		lda	#$22
		sta	$51
F0DB:		lda	$51
		jsr	F570
		dex
		bne	F0DB
		lda	$57
		cmp	#8
		bcc	F10F
		cmp	#15
		beq	F0F1
		cmp	#12
		bcs	F10F
F0F1:		ldx	#$5D
		lda	RAMTOP
		sec
		sbc	#$10
		jsr	F570
		lda	#0
		jsr	F570
		lda	$51
		ora	#$40
		jsr	F570
F107:		lda	$51
		jsr	F570
		dex
		bne	F107
F10F:		lda	$59
		jsr	F570
		lda	$58
		jsr	F570
		lda	$51
		ora	#$40
		jsr	F570
		lda	#$70
		jsr	F570
		lda	#$70
		jsr	F570
		lda	ADRESS
		sta	SDLSTL
		lda	ADRESS+1
		sta	SDLSTH
		lda	#$70
		jsr	F570
		lda	ADRESS
		sta	HIMEM
		lda	ADRESS+1
		sta	HIMEM+1
		ldy	#1
		lda	SDLSTL
		sta	($68),Y
		iny
		lda	SDLSTH
		sta	($68),Y
		lda	$4C
		bpl	F164
F154:		sta	DERRF
		jsr	EF94
		lda	DERRF
		ldy	#0
		sty	DERRF
		tay
		rts

F164:		lda	ICAX1Z
		and	#%00100000
		bne	F175
		jsr	F420
		sta	TXTROW
		lda	LMARGN
		sta	TXTCOL
F175:		lda	#%00100010
		ora	SDMCTL
		sta	SDMCTL
		jmp	F20B

; *******************
; **               **
; **  Get Byte S:  **
; **               **
; *******************

F180:		jsr	F6CA	; screen get-byte routine
		jsr	F18F
		jsr	F76A
		jsr	F60A
		jmp	F21E

F18F:		jsr	F5AC	; get data under cursor
		lda	(ADRESS),Y
		and	$2A0
F197:		lsr	$6F
		bcs	F19E
		lsr	A
		bpl	F197
F19E:		sta	$2FA
		cmp	#0
F1A3:		rts

; *******************
; **               **
; **  Put Byte S:  **
; **               **
; *******************

F1A4:		sta	$2FB
		cmp	#$7D
		bne	F1B1
		jsr	F420
		jmp	F20B
F1B1:		jsr	F6CA
F1B4:		lda	$2FB
		cmp	#$9B
		bne	F1C1
		jsr	F661
		jmp	F20B
F1C1:		jsr	F1CA
		jsr	F60E
		jmp	F20B

F1CA:		lda	SSFLAG	; plot point
		bne	F1CA
		ldx	#2
F1D1:		lda	$54,X
		sta	$5A,X
		dex
		bpl	F1D1
		lda	$2FB
		tay
		rol	A
		rol	A
		rol	A
		rol	A
		and	#$3
		tax
		tya
		and	#$9F
		ora	FB49,X
F1E9:		sta	$2FA	; display
		jsr	F5AC
		lda	$2FA
F1F2:		lsr	$6F
		bcs	F1FA
		asl	A
		jmp	F1F2
F1FA:		and	$2A0
		sta	$50
		lda	$2A0
		eor	#$FF
		and	(ADRESS),Y
		ora	$50
		sta	(ADRESS),Y
		rts

F20B:		jsr	F18F
		sta	$5D
		ldx	$57
		bne	F21E
		ldx	CRSINH
		bne	F21E
		eor	#$80
		jsr	F1E9

; ********************************************
; **                                        **
; **  Open K: Close K: Get Status E: S: K:  **
; **                                        **
; ********************************************

F21E:		ldy	$4C
		jmp	F226

SELFS:		jmp	$C8FC

F226:		lda	#1
		sta	$4C
		lda	$2FB

; *********************************
; **                             **
; **  Special E: K: Put Byte K:  **
; **                             **
; *********************************

F22D:		rts

; *******************
; **               **
; **  Close E: S:  **
; **               **
; *******************

F22E:		bit	$26E
		bpl	F21E
		lda	#$40
		sta	NMIEN
		lda	#0
		sta	$26E
		lda	#<C0CE
		sta	$200
		lda	#>C0CE
		sta	$201
		jmp	EF94

; *******************
; **               **
; **  Get Byte E:  **
; **               **
; *******************

F24A:		jsr	F962
		jsr	F6BC
		lda	$6B
		bne	F288
		lda	$54
		sta	$6C
		lda	$55
		sta	$6D

F25C:		jsr	F2FD
		sty	$4C
		lda	$2FB
		cmp	#$9B
		beq	F27A
		jsr	F2BE
		jsr	F962
		lda	$63
		cmp	#$71
		bne	F277
		jsr	F556
F277:		jmp	F25C
F27A:		jsr	F718
		jsr	F8B1
		lda	$6C
		sta	$54
		lda	$6D
		sta	$55
F288:		lda	$6B
		beq	F29D
F28C:		dec	$6B
		beq	F29D
		lda	$4C
		bmi	F28C
		jsr	F180
		sta	$2FB
		jmp	F962

F29D:		jsr	F661
		lda	#$9B
		sta	$2FB
		jsr	F20B
		sty	$4C
		jmp	F962

F2AD:		jmp	(ADRESS)

; ******************
; **              **
; ** Put Byte E:  **
; **              **
; ******************

F2B0:		sta	$2FB
		jsr	F962
		jsr	F6BC
		lda	#0
		sta	SUPERF
F2BE:		jsr	F718
		jsr	F93C
		beq	F2CF
F2C6:		asl	ESCFLG
		jsr	F1B4
		jmp	F962
F2CF:		lda	$2FE
		ora	ESCFLG
		bne	F2C6
		asl	ESCFLG
		inx
		lda	SUPERF
		beq	F2E5
		txa
		clc
		adc	#$2D
		tax
F2E5:		lda	FB0D,X
		sta	ADRESS
		lda	FB0E,X
		sta	ADRESS+1
		jsr	F2AD	; JSR (ADRESS)
		jsr	F20B
		jmp	F962

F2F8:		lda	#$FF
		sta	CH

; *******************
; **               **
; **  Get Byte K:  **
; **               **
; *******************

F2FD:		lda	#0
		sta	SUPERF
		lda	ICAX1Z
		lsr	A
		bcs	@10
		lda	#$80
		ldx	BRKKEY
		beq	@9
		lda	CH
		cmp	#$FF
		beq	F2FD
		sta	$7C
		ldx	#$FF
		stx	CH
		ldx	$2DB
		bne	@1
		jsr	F983
@1:		tay
		cpy	#$C0
		bcs	F2F8
		lda	($79),Y
@2:		sta	$2FB
		tax
		bmi	@3
		jmp	@16
@3:		cmp	#$80
		beq	F2F8
		cmp	#$81
		bne	@4
		lda	$2B6
		eor	#$80
		sta	$2B6
		bcs	F2F8
@4:		cmp	#$82
		bne	@5
		lda	$2BE
		beq	@6
		lda	#0
		sta	$2BE
		beq	F2F8
@5:		cmp	#$83
		bne	@7
@6:		lda	#$40
		sta	$2BE
		bne	F2F8
@7:		cmp	#$84
		bne	@8
		lda	#$80
		sta	$2BE
		jmp	F2F8
@8:		cmp	#$85
		bne	@11
		lda	#$88
@9:		sta	$4C
		sta	BRKKEY
@10:		lda	#$9B
		jmp	@18
@11:		cmp	#$89
		bne	@13
		lda	$2DB
		eor	#$FF
		sta	$2DB
		bne	@12		; JMP $F2F8
		jsr	F983
@12:		jmp	F2F8

@13:		cmp	#$8E
		bcs	@15
		cmp	#$8A
		bcc	@12
		sbc	#$8A
		asl	$7C
		bpl	@14
		ora	#4
@14:		tay
		lda	(FKDEF),Y
		jmp	@2
@15:		cmp	#$92
		bcs	@16
		cmp	#$8E
		bcc	@12		; JMP $F2F8
		sbc	#$72
		inc	SUPERF
		bne	@18
@16:		lda	$7C
		cmp	#$40
		bcs	@17
		lda	$2FB
		cmp	#$61
		bcc	@17
		cmp	#$7B
		bcs	@17
		lda	$2BE
		beq	@17
		ora	$7C
		jmp	@1
@17:		jsr	F93C
		beq	@19		; JMP $F21E
		lda	$2FB
		eor	$2B6
@18:		sta	$2FB
@19:		jmp	F21E

; *******************************
; ** KEYBOARD HANDLER ROUTINES **
; *******************************
	
F3E0:		lda	#$80		; keyboard handler 27
		sta	ESCFLG
		rts

F3E6:		dec	$54		; keyboard handler 28
		bpl	F3F0
		ldx	$2BF
		dex
F3EE:		stx	$54
F3F0:		jmp	F90C

F3F3:		inc	$54		; keyboard handler 29
		lda	$54
		cmp	$2BF
		bcc	F3F0
		ldx	#0
		beq	F3EE

F400:		dec	$55		; keyboard handler $1E
		lda	$55
		bmi	F40A
		cmp	LMARGN
		bcs	F40E

F40A:		lda	RMARGN		; keyboard handler $1F
F40C:		sta	$55
F40E:		jmp	F88E

F411:		inc	$55		; keyboard handler $1F
		lda	$55
		cmp	RMARGN
		bcc	F40E
		beq	F40E

F41B:		lda	LMARGN		; keyboard handler $1E
		jmp	F40C

F420:		jsr	F9A6		; keyboard handler $7D
		ldy	ADRESS
		lda	#0
		sta	ADRESS
F429:		sta	(ADRESS),Y
		iny
		bne	F429
		inc	ADRESS+1
		ldx	ADRESS+1
		cpx	RAMTOP
		bcc	F429
		lda	#$FF
F438:		sta	$2B2,Y
		iny
		cpy	#4
		bcc	F438

F440:		jsr	F997		; keyboard handler $1C
		sta	$63
		sta	$6D
		lda	#0
		sta	$54
		sta	$56
		sta	$6C
		rts

F450:		lda	$63		; keyboard handler $7E
		cmp	LMARGN
		beq	F477
		lda	$55
		cmp	LMARGN
		bne	F45F
		jsr	F923
F45F:		jsr	F400
		lda	$55
		cmp	RMARGN
		bne	F46F
		lda	$54
		beq	F46F
		jsr	F3E6
F46F:		lda	#$20
		sta	$2FB
		jsr	F1CA
F477:		jmp	F88E

F47A:		jsr	F411		; keyboard handler $7F
		lda	$55
		cmp	LMARGN
		bne	F48B
		jsr	F665
		jsr	F758
		bcs	F492
F48B:		lda	$63
		jsr	F75D
		bcc	F47A
F492:		jmp	F88E

F495:		lda	$63		; keyboard handler $9F
		jmp	F73E

F49A:		lda	$63		; keyboard handler $9E
		jmp	F74A

F49F:		jsr	F94C		; keyboard handler $FF
		jsr	F18F
		sta	$7D
		lda	#0
		sta	$2BB
F4AC:		jsr	F1E9
		lda	$63
		pha
		jsr	F612
		pla
		cmp	$63
		bcs	F4C6
		lda	$7D
		pha
		jsr	F18F
		sta	$7D
		pla
		jmp	F4AC

F4C6:		jsr	F957
F4C9:		dec	$2BB
		bmi	F4D2
		dec	$54
		bne	F4C9
F4D2:		jmp	F88E

F4D5:		jsr	F94C		; keyboard handler $FE
F4D8:		jsr	F5AC
		lda	ADRESS
		sta	$68
		lda	ADRESS+1
		sta	$69
		lda	$63
		pha
		jsr	F60A
		pla
		cmp	$63
		bcs	F4FE
		lda	$54
		cmp	$2BF
		bcs	F4FE
		jsr	F18F
		ldy	#0
		sta	($68),Y
		beq	F4D8
F4FE:		ldy	#0
		tya
		sta	($68),Y
		jsr	F918
		jsr	F957
		jmp	F88E

F50C:		sec			; keyboard handler $9D
F50D:		jsr	F7C2
		lda	LMARGN
		sta	$55
		jsr	F5AC
		jsr	F78E
		jsr	F7E2
		jmp	F88E

F520:		jsr	F88E		; keyboard handler $9C
		ldy	$51
		sty	$54
F527:		ldy	$54
F529:		tya
		sec
		jsr	F75B
		php
		tya
		clc
		adc	#$78
		plp
		jsr	F73C
		iny
		cpy	#$18
		bne	F529
		lda	$2B4
		ora	#1
		sta	$2B4
		lda	#0
		sta	$55
		jsr	F5AC
		jsr	F82A
		jsr	F758
		bcc	F527
		jmp	F41B

F556:		ldy	#$20		; keyboard handler $FD
F558:		jsr	F983
		dey
		bpl	F558
		rts

F55F:		jsr	F440		; keyboard handler $1D
		jmp	F3E6

F565:		lda	#2
		bne	F57A
F569:		ldy	$26E
		beq	F570
		ora	#$20
F570:		ldy	$4C
		bmi	F59F
		ldy	#0
		sta	(ADRESS),Y
F578:		lda	#1
F57A:		sta	$29E
		lda	$4C
		bmi	F59F
		lda	ADRESS
		sec
		sbc	$29E
		sta	ADRESS
		bcs	F58D
		dec	ADRESS+1
F58D:		lda	APPMHI+1
		cmp	ADRESS+1
		bcc	F59F
		bne	F59B
		lda	APPMHI
		cmp	ADRESS
		bcc	F59F
F59B:		lda	#$93
		sta	$4C
F59F:		rts
F5A0:		lda	#2
		jsr	F570
		lda	#$A2
		jsr	F570
		dex
		rts
F5AC:		ldx	#1
		stx	$66
		dex
		stx	ADRESS+1
		lda	$54
		asl	A
		rol	ADRESS+1
		asl	A
		rol	ADRESS+1
		adc	$54
		sta	ADRESS
		bcc	F5C3
		inc	ADRESS+1
F5C3:		ldy	$57
		ldx	EE6D,Y
F5C8:		asl	ADRESS
		rol	ADRESS+1
		dex
		bne	F5C8
		lda	$56
		lsr	A
		lda	$55
		ldx	EE9D,Y
		beq	F5DF
F5D9:		ror	A
		asl	$66
		dex
		bne	F5D9
F5DF:		adc	ADRESS
		bcc	F5E5
		inc	ADRESS+1
F5E5:		clc
		adc	$58
		sta	ADRESS
		sta	$5E
		lda	ADRESS+1
		adc	$59
		sta	ADRESS+1
		sta	$5F

		ldx	EE9D,Y
		lda	FB04,X
		and	$55
		adc	$66
		tay
		lda	EEAD-1,Y
		sta	$2A0
		sta	$6F
		ldy	#0
F609:		rts
F60A:		lda	#0
		beq	F610
F60E:		lda	#$9B
F610:		sta	$7D
F612:		inc	$63
		inc	$55
		bne	F61A
		inc	$56
F61A:		lda	$55
		ldx	$57
		cmp	EE7D,X
		beq	F62D
		cpx	#0
		bne	F609
		cmp	RMARGN
		beq	F609
		bcc	F609
F62D:		cpx	#8
		bne	F635
		lda	$56
		beq	F609
F635:		lda	$57
		bne	F665
		lda	$63
		cmp	#$51
		bcc	F649
		lda	$7D
		beq	F665
		jsr	F661
		jmp	F6AB
F649:		jsr	F665
		lda	$54
		clc
		adc	#$78
		jsr	F75D
		bcc	F65E
		lda	$7D
		beq	F65E
		clc
		jsr	F50D
F65E:		jmp	F88E

F661:		lda	#$9B		; keyboard handler $9B
		sta	$7D
F665:		jsr	F997
		lda	#0
		sta	$56
		inc	$54
		ldx	$57
		ldy	#$18
		bit	$7B
		bpl	F67B
		ldy	#4
		tya
		bne	F67E
F67B:		lda	EE8D,X
F67E:		cmp	$54
		bne	F6AB
		sty	$29D
		txa
		bne	F6AB
		lda	$7D
		beq	F6AB
		cmp	#$9B
		beq	F691
		clc
F691:		jsr	F7F7
		inc	$2BB
		dec	$6C
		bpl	F69D
		inc	$6C
F69D:		dec	$29D
		lda	$2B2
		sec
		bpl	F691
		lda	$29D
		sta	$54
F6AB:		jmp	F88E

F6AE:		sec
		lda	$70,X
		sbc	$74
		sta	$70,X
		lda	$71,X
		sbc	$75
		sta	$71,X
		rts
F6BC:		lda	$2BF
		cmp	#4
		beq	F6CA
		lda	$57
		beq	F6CA
		jsr	EF94
F6CA:		lda	#39		; column 39 ?
		cmp	RMARGN
		bcs	F6D2
		sta	RMARGN
F6D2:		ldx	$57
		lda	EE8D,X
		cmp	$54
		bcc	F705
		beq	F705
		cpx	#8
		bne	F6EB
		lda	$56
		beq	F6F8
		cmp	#1
		bne	F705
		beq	F6EF
F6EB:		lda	$56
		bne	F705
F6EF:		lda	EE7D,X
		cmp	$55
		bcc	F705
		beq	F705
F6F8:		lda	#1
		sta	$4C
		lda	#$80
		ldx	BRKKEY
		sta	BRKKEY
		beq	F70A
		rts

F705:		jsr	F440
		lda	#$8D
F70A:		sta	$4C
		pla
		pla
		lda	$7B
		bpl	F715
		jmp	F962
F715:		jmp	F21E

F718:		ldy	#0
		lda	$5F
		beq	F722
		lda	$5D
		sta	($5E),Y
F722:		rts

F723:		pha
		and	#%00000111
		tax
		lda	EEB4,X
		sta	$6E
		pla
		lsr	A
		lsr	A
		lsr	A
		tax
		rts

F732:		rol	$2B4
		rol	$2B3
		rol	$2B2
		rts

F73C:		bcc	F74A
F73E:		jsr	F723
		lda	TABMAP,X
		ora	$6E
		sta	TABMAP,X
		rts

F74A:		jsr	F723
		lda	$6E
		eor	#$FF
		and	TABMAP,X
		sta	TABMAP,X
		rts

F758:		lda	$54
F75A:		clc
F75B:		adc	#$78
F75D:		jsr	F723
		clc
		lda	TABMAP,X
		and	$6E
		beq	F769
		sec
F769:		rts
F76A:		lda	$2FA
		ldy	$57
		cpy	#14
		bcs	F78A
		cpy	#12
		bcs	F77B
		cpy	#3
		bcs	F78A
F77B:		rol	A
		rol	A
		rol	A
		rol	A
		and	#3
		tax
		lda	$2FA
		and	#$9F
		ora	FB4D,X
F78A:		sta	$2FB
F78D:		rts
F78E:		ldx	RAMTOP
		dex
		stx	$69
		stx	$67
		lda	#$B0
		sta	$68
		lda	#$D8
		sta	$66
		ldx	$54
F79F:		inx
		cpx	$2BF
		beq	F78D
		ldy	#$27
F7A7:		lda	($68),Y
		sta	($66),Y
		dey
		bpl	F7A7
		sec
		lda	$68
		sta	$66
		sbc	#$28
		sta	$68
		lda	$69
		sta	$67
		sbc	#0
		sta	$69
		jmp	F79F

F7C2:		php
		ldy	#$16
F7C5:		tya
		jsr	F75A
		php
		tya
		clc
		adc	#$79
		plp
		jsr	F73C
		dey
		bmi	F7D9
		cpy	$54
		bcs	F7C5
F7D9:		lda	$54
		clc
		adc	#$78
		plp
		jmp	F73C
F7E2:		lda	LMARGN
		sta	$55
		jsr	F5AC
		sec
		lda	RMARGN
		sbc	LMARGN
		tay
		lda	#0
F7F1:		sta	(ADRESS),Y
		dey
		bpl	F7F1
		rts
F7F7:		jsr	F732
		lda	$26E
		beq	F827
F7FF:		lda	VSFLAG		; busy waiting (fine scroll)
		bne	F7FF
		lda	#8
		sta	VSFLAG
F809:		lda	VSFLAG		; busy waiting (fine scroll)
		cmp	#1
		bne	F809
F810:		lda	$D40B
		cmp	#$40
		bcs	F810		; busy waiting
		ldx	#$D
		lda	$2BF
		cmp	#4
		bne	F822
		ldx	#$70
F822:		cpx	$D40B
		bcs	F822
F827:		jsr	F9A6
F82A:		lda	ADRESS
		ldx	ADRESS+1
F82E:		inx
		cpx	RAMTOP
		beq	F839
		sec
		sbc	#$10
		jmp	F82E
F839:		adc	#39
		bne	F847
		ldx	ADRESS+1
		inx
		cpx	RAMTOP
		beq	F87C
		clc
		adc	#$10
F847:		tay
		sta	$7E
		sec
		lda	ADRESS
		sbc	$7E
		sta	ADRESS
		bcs	F855
		dec	ADRESS+1
F855:		lda	ADRESS
		clc
		adc	#40
		sta	$7E
		lda	ADRESS+1
		adc	#0
		sta	$7F
F862:		lda	($7E),Y
		sta	(ADRESS),Y
		iny
		bne	F862
		ldy	#$10
		lda	ADRESS
		cmp	#$D8
		beq	F87C
		clc
		adc	#240
		sta	ADRESS
		bcc	F855
		inc	ADRESS+1
		bne	F855
F87C:		ldx	RAMTOP
		dex
		stx	$7F
		ldx	#$D8
		stx	$7E
		lda	#0
		ldy	#$27
F889:		sta	($7E),Y
		dey
		bpl	F889
F88E:		lda	#0
		sta	$63
		lda	$54
		sta	$51
F896:		lda	$51
		jsr	F75A
		bcs	F8A9
		lda	$63
		clc
		adc	#$28
		sta	$63
		dec	$51
		jmp	F896
F8A9:		clc
		lda	$63
		adc	$55
		sta	$63
		rts

F8B1:		jsr	F94C
		lda	$63
		pha
		lda	$6C
		sta	$54
		lda	$6D
		sta	$55
		lda	#1
		sta	$6B
F8C3:		ldx	#$17
		lda	$7B
		bpl	F8CB
		ldx	#3
F8CB:		cpx	$54
		bne	F8DA
		lda	$55
		cmp	RMARGN
		bne	F8DA
		inc	$6B
		jmp	F8EA
F8DA:		jsr	F60A
		inc	$6B
		lda	$63
		cmp	LMARGN
		bne	F8C3
		dec	$54
		jsr	F400
F8EA:		jsr	F18F
		bne	F906
		dec	$6B
		lda	$63
		cmp	LMARGN
		beq	F906
		jsr	F400
		lda	$55
		cmp	RMARGN
		bne	F902
		dec	$54
F902:		lda	$6B
		bne	F8EA
F906:		pla
		sta	$63
		jmp	F957
F90C:		jsr	F88E
		lda	$51
		sta	$6C
		lda	LMARGN
		sta	$6D
F917:		rts

F918:		lda	$63
		cmp	LMARGN
		bne	F920
		dec	$54
F920:		jsr	F88E
F923:		lda	$63
		cmp	LMARGN
		beq	F917
		jsr	F5AC
		lda	RMARGN
		sec
		sbc	LMARGN
		tay
F932:		lda	(ADRESS),Y
		bne	F917
		dey
		bpl	F932
		jmp	F527

F93C:		ldx	#$2D
F93E:		lda	FB0D,X
		cmp	$2FB
		beq	F94B
		dex
		dex
		dex
		bpl	F93E
F94B:		rts

F94C:		ldx	#2
F94E:		lda	$54,X
		sta	$2B8,X
		dex
		bpl	F94E
		rts

F957:		ldx	#2
F959:		lda	$2B8,X
		sta	$54,X
		dex
		bpl	F959
		rts

F962:		lda	$2BF
		cmp	#$18
		beq	F980	; BEQ F21E

		ldx	#11	; swap $54.@5F with $290.@29B
F96B:		lda	$54,X
		pha
		lda	$290,X
		sta	$54,X
		pla
		sta	$290,X
		dex
		bpl	F96B

		lda	$7B
		eor	#$FF
		sta	$7B

F980:		jmp	F21E

F983:		ldx	#$7E
		pha
F986:		stx	CONSOL
		lda	$D40B
F98C:		cmp	$D40B	; busy waiting
		beq	F98C
		dex
		dex
		bpl	F986
		pla
		rts
F997:		lda	#0
		ldx	$7B
		bne	F9A1
		ldx	$57
		bne	F9A3
F9A1:		lda	LMARGN
F9A3:		sta	$55
		rts
F9A6:		lda	$58
		sta	ADRESS
		lda	$59
		sta	ADRESS+1
F9AE:		rts

; ******************
; **              **
; **  Special S:  **
; **              **
; ******************

F9AF:		ldx	#0
		lda	ICCOMZ
		cmp	#17
		beq	@2
		cmp	#18
		beq	@1
		ldy	#132		; ERROR: Invalid Handler Command
		rts

@1:		inx
@2:		stx	$2B7
		lda	$54
		sta	$2F5
		lda	$55
		sta	$2F6
		lda	$56
		sta	$2F7
		lda	#1
		sta	$2F8
		sta	$2F9
		sec
		lda	$2F5
		sbc	$5A
		sta	$76
		bcs	@3
		lda	#$FF
		sta	$2F8
		lda	$76
		eor	#$FF
		clc
		adc	#1
		sta	$76
@3:		sec
		lda	$2F6
		sbc	$5B
		sta	$77
		lda	$2F7
		sbc	$5C
		sta	$78
		bcs	@4
		lda	#$FF
		sta	$2F9
		lda	$77
		eor	#$FF
		sta	$77
		lda	$78
		eor	#$FF
		sta	$78
		inc	$77
		bne	@4
		inc	$78
@4:		ldx	#2
		ldy	#0
		sty	$73
@5:		tya
		sta	$70,X
		lda	$5A,X
		sta	$54,X
		dex
		bpl	@5
		lda	$77
		inx
		tay
		lda	$78
		sta	$7F
		sta	$75
		bne	@6
		lda	$77
		cmp	$76
		bcs	@6
		lda	$76
		ldx	#2
		tay
@6:		tya
		sta	$7E
		sta	$74
		pha
		lda	$75
		lsr	A
		pla
		ror	A
		sta	$70,X
@7:		lda	$7E
		ora	$7F
		bne	@8
		jmp	@19		; JMP $F21E
@8:		clc
		lda	$70
		adc	$76
		sta	$70
		bcc	@9
		inc	$71
@9:		lda	$71
		cmp	$75
		bcc	@11
		bne	@10
		lda	$70
		cmp	$74
		bcc	@11
@10:		clc
		lda	$54
		adc	$2F8
		sta	$54
		ldx	#0
		jsr	F6AE
@11:		clc
		lda	$72
		adc	$77
		sta	$72
		lda	$73
		adc	$78
		sta	$73
		cmp	$75
		bcc	@15
		bne	@12
		lda	$72
		cmp	$74
		bcc	@15
@12:		bit	$2F9
		bpl	@13
		dec	$55
		lda	$55
		cmp	#$FF
		bne	@14
		lda	$56
		beq	@14
		dec	$56
		bpl	@14
@13:		inc	$55
		bne	@14
		inc	$56
@14:		ldx	#2
		jsr	F6AE
@15:		jsr	F6CA
		jsr	F1CA
		lda	$2B7
		beq	@18
		jsr	F94C
		lda	$2FB
		sta	$2BC
@16:		lda	$54
		pha
		jsr	F612
		pla
		sta	$54
		jsr	F6CA
		jsr	F18F
		bne	@17
		lda	$2FD
		sta	$2FB
		jsr	F1CA
		jmp	@16
@17:		lda	$2BC
		sta	$2FB
		jsr	F957
@18:		sec
		lda	$7E
		sbc	#1
		sta	$7E
		lda	$7F
		sbc	#0
		sta	$7F
		bmi	@19			;  JMP $F21E
		jmp	@7
@19:		jmp	F21E

	; some tables

FB04:		.byte	0,1,3,7
FB08:		.byte	$28,$CA,$94,$46,$00	; Default colors 0-4

FB0D:		.byte	$1B
FB0E:		.word	F3E0
		.byte	$1C
		.word	F3E6
		.byte	$1D
		.word	F3F3
		.byte	$1E
		.word	F400
		.byte	$1F
		.word	F411
		.byte	$7D
		.word	F420
		.byte	$7E
		.word	F450
		.byte	$7F
		.word	F47A
		.byte	$9B
		.word	F661
		.byte	$9C
		.word	F520
		.byte	$9D
		.word	F50C
		.byte	$9E
		.word	F49A
		.byte	$9F
		.word	F495
		.byte	$FD
		.word	F556
		.byte	$FE
		.word	F4D5
		.byte	$FF
		.word	F49F
		.byte	$1C
		.word	F440
		.byte	$1D
		.word	F55F
		.byte	$1E
		.word	F41B
		.byte	$1F
		.word	F40A

FB49:		.byte	$40,$00,$20,$60
FB4D:		.byte	$20,$40,$00,$60

KEYMAP:		.byte	$6C,$6A,$3B,$8A,$8B,$6B,$2B,$2A
		.byte	$6F,$80,$70,$75,$9B,$69,$2D,$3D
		.byte	$76,$80,$63,$8C,$8D,$62,$78,$7A
		.byte	$34,$80,$33,$36,$1B,$35,$32,$31
		.byte	$2C,$20,$2E,$6E,$80,$6D,$2F,$81
		.byte	$72,$80,$65,$79,$7F,$74,$77,$71
		.byte	$39,$80,$30,$37,$7E,$38,$3C,$3E
		.byte	$66,$68,$64,$80,$82,$67,$73,$61
		.byte	$4C,$4A,$3A,$8A,$8B,$4B,$5C,$5E
		.byte	$4F,$80,$50,$55,$9B,$49,$5F,$7C
		.byte	$56,$80,$43,$8C,$8D,$42,$58,$5A
		.byte	$24,$80,$23,$26,$1B,$25,$22,$21
		.byte	$5B,$20,$5D,$4E,$80,$4D,$3F,$81
		.byte	$52,$80,$45,$59,$9F,$54,$57,$51
		.byte	$28,$80,$29,$27,$9C,$40,$7D,$9D
		.byte	$46,$48,$44,$80,$83,$47,$53,$41
		.byte	$0C,$0A,$7B,$80,$80,$0B,$1E,$1F
		.byte	$0F,$80,$10,$15,$9B,$09,$1C,$1D
		.byte	$16,$80,$03,$89,$80,$02,$18,$1A
		.byte	$80,$80,$85,$80,$1B,$80,$FD,$80
		.byte	$00,$20,$60,$0E,$80,$0D,$80,$81
		.byte	$12,$80,$05,$19,$9E,$14,$17,$11
		.byte	$80,$80,$80,$80,$FE,$80,$7D,$FF
		.byte	$06,$08,$04,$80,$84,$07,$13,$01

FKYMAP:		.byte	$1C,$1D,$1E,$1F,$8E,$8F,$90,$91

; **********************************
; **                              **
; **  KEYBOARD INTERRUPT ROUTINE  **
; **                              **
; **********************************

KIR:		txa
		pha
		tya
		pha
		ldy	PORTB
		lda	KBCODE
		cmp	CH1
		bne	@1
		ldx	KEYDEL
		bne	@8
@1:		ldx	KEYDIS
		cmp	#$83
		bne	@4
		txa
		eor	#$FF
		sta	KEYDIS
		bne	@2
		tya
		ora	#%00000100
		bne	@3
@2:		tya
		and	#%11111011
@3:		tay
		bcs	@7
@4:		txa
		bne	@9
		lda	KBCODE
		tax
		cmp	#$9F
		bne	@5
		lda	SSFLAG
		eor	#%11111111
		sta	SSFLAG
		bcs	@7
@5:		and	#%00111111
		cmp	#17
		bne	@10
		stx	$2DC
		beq	@7
@6:		stx	CH
		stx	CH1
@7:		lda	#3
		sta	KEYDEL
		lda	#0
		sta	ATRACT
@8:		lda	KRPDEL
		sta	SRTIMR
		lda	SDMCTL
		bne	@9
		lda	DMASAV
		sta	SDMCTL
@9:		sty	PORTB
		pla
		tay
		pla
		tax
		pla
		rti

@10:		cpx	#$84
		beq	@12
		cpx	#$94
		bne	@6
		lda	$2F4
		ldx	$26B
		sta	$26B
		stx	$2F4
		cpx	#>CHARSET2
		beq	@11
		tya
		ora	#%00001000
		tay
		bne	@7
@11:		tya
		and	#%11110111
		tay
		jmp	@7

@12:		lda	SDMCTL
		beq	@9
		sta	DMASAV
		lda	#0
		sta	SDMCTL
		beq	@9

	; smooth scroll DLI

FCC4:		pha
		lda	COLOR2

		.byte	$4D	; force absolute addressing mode for EOR $4F
		.word	$4F
		.byte	$2D	; force absolute addressing mode for AND $4E
		.word	$4E

		sta	WSYNC
		sta	COLPF1
		pla
		rti

		.byte	0,0		; waste 2 bytes
		jmp	F983		; waste 3 bytes

; ********************************************************
; **                                                    **
; **  Device Handler Initialization Code for device C:  **
; **                                                    **
; ********************************************************

CIN:		lda	#<1484		; 1484 <--> 600 baud
		sta	CBAUDL
		lda	#>1484
		sta	CBAUDH

; *****************
; **             **
; ** Special C:  **
; **             **
; *****************

FCE5:		rts			; patched by XL-IT!

; ***************
; **           **
; **  Open C:  **
; **           **
; ***************

FCE6:		lda	ICAX2Z		; patched by XL-IT!
		sta	$3E
		lda	ICAX1Z
		and	#12
		cmp	#4
		beq	CSOPI
		cmp	#8
		beq	FD34
		rts

CSOPI:		lda	#0
		sta	WMODE		; 'read'
		sta	$3F
		lda	#1
		jsr	FDFC
		bmi	FD2E
FD05:		lda	#$34
		sta	PACTL
		ldx	PALNTS
		ldy	FE93,X
		lda	FE91,X
		tax
		lda	#3
		sta	$22A
		jsr	SETVBV
FD1B:		lda	$22A
		bne	FD1B
		lda	#$80
		sta	$3D
		sta	$28A
		jmp	FD77
FD2A:		ldy	#$80
		dec	BRKKEY
FD2E:		lda	#0		; 'read'
		sta	WMODE
		rts

FD34:		lda	#$80		; 'write'
		sta	WMODE
		lda	#2
		jsr	FDFC
		bmi	FD2E

		lda	#<1484		; set baudrate
		sta	$D204
		lda	#>1484
		sta	$D206
		lda	#$60
		sta	DDEVIC
		jsr	SENDEV
		lda	#$34
		sta	PACTL
		ldx	PALNTS
		ldy	FE8F,X
		lda	FE8D,X
		tax
		lda	#3
		jsr	SETVBV
		lda	#$FF
		sta	$22A
FD6A:		lda	BRKKEY
		beq	FD2A
		lda	$22A
		bne	FD6A
		lda	#0
		sta	$3D
FD77:		ldy	#1
FD79:		rts

; **************
; **          **
; **  Get C:  **
; **          **
; **************

FD7A:		lda	$3F		; PATCHED BY XL-IT!
		bmi	FDB1		; LDY #136; RTS
		ldx	$3D
		cpx	$28A
		beq	RBLOK
		lda	$400,X
		inc	$3D
		ldy	#1
FD8C:		rts

RBLOK:		lda	#'R'		; read command
		jsr	FE3F
		tya
		bmi	FD8C
		lda	#0
		sta	$3D
		ldx	#$80
		lda	$3FF
		cmp	#$FE
		beq	@2
		cmp	#$FA
		bne	@1
		ldx	$47F
@1:		stx	$28A
		jmp	FD7A
@2:		dec	$3F
FDB1:		ldy	#$88
		rts

; **************
; **          **
; **  Put C:  **
; **          **
; **************

FDB4:		ldx	$3D	; PATCHED BY XL-IT!
		sta	$400,X
		inc	$3D
		ldy	#1
		cpx	#$7F
		beq	@1
		rts

@1:		lda	#$FC
		jsr	FE7C
		lda	#0
		sta	$3D
		rts

; ****************
; **            **
; ** Status C:  **
; **            **
; ****************

FDCC:		ldy	#1		; PATCHED BY XL-IT!
FDCE:		rts

; ****************
; **            **
; **  Close C:  **
; **            **
; ****************

FDCF:		lda	$289		; PATCHED BY XL-IT!
		bmi	FDDC
		ldy	#1
FDD6:		lda	#%00111100
		sta	PACTL
		rts

FDDC:		ldx	$3D
		beq	@1
		stx	$47F
		lda	#$FA
		jsr	FE7C
		bmi	FDD6
@1:		ldx	#$7F
		lda	#0
@2:		sta	$400,X
		dex
		bpl	@2
		lda	#$FE
		jsr	FE7C
		jmp	FDD6

FDFC:		sta	$40
@1:		lda	$14
		clc
		ldx	PALNTS
		adc	FE95,X
		tax
@2:		lda	#$FF
		sta	CONSOL
		lda	#0
		ldy	#$F0	; wait a bit ...
@3:		dey
		bne	@3
		sta	CONSOL
		ldy	#$F0	; wait a bit ...
@4:		dey
		bne	@4
		cpx	$14
		bne	@2
		dec	$40
		beq	@6
		txa
		clc
		ldx	PALNTS
		adc	FE97,X
		tax
@5:		cpx	$14	; busy waiting
		bne	@5
		beq	@1

@6:		jsr	@7
		tya
		rts

@7:		lda	E424+1	; JMP ($E424)+1 --> JMP $F2FD.
		pha
		lda	E424
		pha
		rts

FE3F:		sta	DCOMND
		lda	#>131		; 131 bytes per record
		sta	DBYTHI
		lda	#<131
		sta	DBYTLO
		lda	#>CASBUF	; cassette buffer
		sta	DBUFHI
		lda	#<CASBUF
		sta	DBUFLO
		lda	#$60
		sta	DDEVIC
		lda	#0
		sta	DUNIT
		lda	#$23
		sta	DTIMLO
		lda	DCOMND
		ldy	#$40
		cmp	#$52
		beq	@1
		ldy	#$80
@1:		sty	DSTATS
		lda	$3E
		sta	DAUX2
		jsr	SIOV
		rts

FE7C:		sta	$3FF
		lda	#%01010101	; bit pattern!
		sta	CASBUF
		sta	CASBUF+1
		lda	#'W'		; write command
		jsr	FE3F
		rts

	; Timing stuff

FE8D:		.byte	$04,$03
FE8F:		.byte	$80,$C0
FE91:		.byte	$02,$01
FE93:		.byte	$40,$E0
FE95:		.byte	$1E,$19
FE97:		.byte	$0A,$08

; ********************************************************
; **                                                    **
; **  Device Handler Initialisation Code for device P:  **
; **                                                    **
; ********************************************************

PIN:		lda	#30
		sta	PTIMOT
		rts

FE9F:		.word	$2EA
FEA1:		.word	$3C0

; status P:

FEA3:		lda	#4
		sta	$2DF
		ldx	FE9F
		ldy	FE9F+1
		lda	#'S'		; status
		sta	DCOMND
		sta	DAUX1
		jsr	FF14
		jsr	SIOV
		bmi	FEC1
		jsr	FF44
FEC1:		rts

; open P:

FEC2:		jsr	FEA3
		lda	#0
		sta	PBPNT
FECA:		rts

; put P:

FECB:		pha
		lda	ICDNO,X
		sta	ICDNOZ
		jsr	FF4B
		ldx	PBPNT
		pla
		sta	$3C0,X
		inx
		cpx	PBUFSZ
		beq	FEF6
		stx	PBPNT
		cmp	#$9B
		beq	FEEB
		ldy	#1
		rts

FEEB:		lda	#$20
FEED:		sta	$3C0,X
		inx
		cpx	PBUFSZ
		bne	FEED
FEF6:		lda	#0
		sta	PBPNT
		ldx	FEA1
		ldy	FEA1+1
		jsr	FF14
		jmp	SIOV

; close P:

FF07:		jsr	FF4B
		lda	#$9B
		ldx	PBPNT
		bne	FEED
		ldy	#1
		rts

FF14:		stx	DBUFLO
		sty	DBUFHI
		lda	#$40	; printer 1 ID
		sta	DDEVIC
		lda	ICDNOZ
		sta	DUNIT
		lda	#$80
		ldx	DCOMND
		cpx	#'S'	; COMMAND == STATUS ?
		bne	@1
		lda	#$40	; yes!
@1:		sta	DSTATS
		lda	PBUFSZ
		sta	DBYTLO
		lda	#0
		sta	DBYTHI
		lda	PTIMOT
		sta	DTIMLO
		rts

FF44:		lda	DVSTAT+2
		sta	PTIMOT
		rts

FF4B:		ldy	#'W'
		lda	ICAX2Z
@1:		cmp	#'N'
		bne	@2
		ldx	#'('
		bne	@4
@2:		cmp	#'D'
		bne	@3
		ldx	#$14
		bne	@4
@3:		cmp	#'S'
		bne	@5
		ldx	#29
@4:		stx	PBUFSZ
		sty	DCOMND
		sta	DAUX1
		rts
@5:		lda	#$4E
		bne	@1

; **********************
; **                  **
; **  Checksum Stuff  **
; **                  **
; **********************

VFR:		ldx	#0		; clear checksum value
		stx	$8B
		stx	$8C
@1:		jsr	FFA9		; calculate checksum of 1st 8K ROM:
		cpx	#12		; C000-CFFF + 5000-57FF + D800-DFFF
		bne	@1
		lda	C000		; checksum of first ROM
		ldx	C000+1

	; patched by XL-IT! to: CLC/RTS

FF86:		cmp	$8B		; carry = ( A==$8B && X==$8C )
		bne	@1
		cpx	$8C
		bne	@1
		clc			; clear carry means OK
		rts
@1:		sec			; set carry means ERROR
		rts

VSR:		ldx	#0		; clear checksum value
		stx	$8B
		stx	$8C
		ldx	#12
		jsr	FFA9		; calculate checksum of 2nd 8K ROM:
		jsr	FFA9		; E000-FFF7 + FFFA-FFFF
		lda	FFF8
		ldx	FFF8+1
		jmp	FF86	; carry = ( A==$8B && X==$8C )

FFA9:		ldy	#0	; copy 4 checksum-specifier bytes -> $9E..$9A1
@1:		lda	FFD7,X
		sta	$9E,Y
		inx		; advance to next checksum
		iny
		cpy	#4
		bne	@1
		ldy	#0	; add ($9E) -> $8B
@2:		clc
		lda	($9E),Y
		adc	$8B
		sta	$8B
		bcc	@3
		inc	$8C	; advance ($9E)
@3:		inc	$9E
		bne	@4
		inc	$9F
@4:		lda	$9E
		cmp	$A0	; repeat until $9E-ptr == $A0-ptr
		bne	@2
		lda	$9F
		cmp	$A1
		bne	@2
		rts		; return

	; checksums

FFD7:		.word	$C002,$D000
		.word	$5000,$5800
		.word	$D800,$E000
		.word	$E000,$FFF8
		.word	$FFFA,$0000

		.byte	0,0,0

	; ROM identification

		.byte	$10,$05,$83	; revision date: October 5th, 1983
		.byte	$02		; option byte
		.byte	'B','B',0,0,1	; part number: BB001
		.byte	$02		; revision number
FFF8:		.word	$6C8C		; checksum

; ***************************************
; **                                   **
; **  6502 HARDWARE INTERRUPT VECTORS  **
; **                                   **
; ***************************************

FFFA:		.word	C018	; address of 6502 Non-Maskable Interrupt (NMI) handler
FFFC:		.word	C2AA	; address of 6502 Reset (RST) handler
FFFE:		.word	C02C	; address of 6502 Interrupt Request (IRQ) handler

; **********************************
; **                              **
; ** END OF OPERATING SYSTEM ROM  **
; **                              **
; **********************************

		.end
