
; **********************************************
; **                                          **
; **  OPERATING SYSTEM ROM PART 1: C000-CBFF  **
; **                                          **
; **********************************************

		.org	$C000
		.segment "C000CBFF"

		.include "atari.inc"
		.include "gtia.inc"
		.include "pokey.inc"
		.include "antic.inc"
		.include "pia.inc"

		.import E510,E55C,E716,E89E,E7DE,E971
		.import SLFTSV,SIOV,CSOPIV,RBLOKV,DISKINV
		.import E49B,DISKIV,INTIV,INTINV,SIOINV
		.import CIOINV,E40C,E41C,E42C,E43C,E44C
		.import BFF0,ISRTD,ISRODN,ISRSIR,KIR
		.import KEYBDV,SCRENV,EDITRV,CASETV,PRINTV
		.import BFFE,BFFA,PHR,CIOV,BFFC,V003,CHARSET1
		.import VSR,VFR,SELFS

		.export	C000,C018,C02C,C0CE,C2AA,C745,C90C,C991,C996
		.export	C99B,C9A0,C9A5,C9AA,CA29,CA57,CA61,CB56

		.export	DISKI,DISKIN,SIO,SETVBL,VBLKI,VBLKD,INTIN,WARMS,COLDS

; C000-C00C	  13	ROM identification
; C00D-C017	  11	init interrupys
; C018-C02B	  20	6502 NMI handler
; C02C-C02F	   4	6502 IRQ handler
; C030-C0DE	 175	default IRQ handler
; C0DF-C0E1	   3	halt computer
; C0E2-C271	 400	vblank stage 1
; C272-C289	  24	set vblank
; C28A-C28F	   6	end-vblank
; C290-C2A9	  26	warmstart code
; C2AA-C2C9	  32	6502 RESET handler: coldstart code
; C2CA-C42D	 356	warm/coldstart continuation
; C42E-C470	  67	boot process data
; C471-C6A2	 562	boot code
; C6A3-C932	 656	floppy disk code
; C933-C96D	  59	SIO code
; C96E-CA56	 233	parallel handler code
; CA57-CB55	 255	selftest data
; CB56-CB64	  15	checksum code
; CB65-CBFF	 155	unused (zeros)
; CC00-CFFF	1024    character set 2
; 5000-57FF	2048	selftest ROM
; D800-DFFF	2048	floating point package

; *************************************
; **                                 **
; **  Computer & ROM identification  **
; **                                 **
; *************************************

C000:		.word	$9211		; checksum
		.byte	$10,$05,$83	; revision date: October 5th, 1983
		.byte	0		; option byte
		.byte	'B','B',0,0,1	; part number: BB001
		.byte	2		; revision number

; **********************
; **                  **
; ** Init Interrupts  **
; **                  **
; **********************

INTIN:		lda	#%01000000	; enable VBI only
		sta	NMIEN
		lda	TRIG3
		sta	GINTLK
		rts

; *************************************************
; **                                             **
; **  6502 Non-Maskable Interrupt (NMI) handler  **
; **                                             **
; *************************************************

C018:		bit	NMIST		; check NMI status
		bpl	C020		; determine NMI type

		; display list interrupt detected

		jmp	(VDSLST)	; engage DLI handler

		; vertical blank interrupt detected

C020:		cld			; clear decimal flag
		pha			; save A register
		txa			; save X register
		pha
		tya			; save Y register
		pha
		sta	NMIRES		; reset NMI status
		jmp	(VVBLKI)	; engage VBLANK immediate handler

; ********************************************
; **                                        **
; **  6502 Interrupt Request (IRQ) handler  **
; **                                        **
; ********************************************

C02C:		cld			; clear decimal flag
		jmp	(VIMIRQ)	; engage immediate IRQ handler

; ************************************
; **                                **
; ** Default Immediate IRQ handler  **
; **                                **
; ************************************

IMIRQ:		pha			; save A register
		lda	IRQST		; check IRQ status
		and	#%00100000	; serial input data ready?
		bne	@1		; no - other IRQ!

		; serial input ready IRQ

		lda	#%11011111	; disable interrupt notification
		sta	IRQEN
		lda	POKMSK		; enable interrupts
		sta	IRQEN
		jmp	(VSERIN)	; engage SERIN IRQ handler

		; other IRQ

@1:		txa			; save X register
		pha
		lda	PDVS		; check parallel bus IRQ
		and	PDMSK
		beq	@2		; no - other IRQ!

		; parallel bus IRQ

		jmp	(VPIRQ)		; engage Parallel IRQ handler

		; other IRQ

@2:		ldx	#6
@3:		lda	IRQMSK,X
		cpx	#5
		bne	@4
		and	POKMSK
		beq	@5
@4:		bit	IRQST
		beq	@6
@5:		dex
		bpl	@3
		jmp	C0A0

@6:		eor	#$FF
		sta	IRQEN
		lda	POKMSK
		sta	IRQEN
		cpx	#0
		bne	@7
		lda	KEYDIS
		bne	C0A0
@7:		lda	IRQOFS,X	; setup correct handler jump vector
		tax
		lda	$200,X
		sta	JVECK
		lda	$201,X
		sta	JVECK+1
		pla			; restore X register
		tax
		jmp	(JVECK)

; *****************************
; **                         **
; **  break key IRQ Handler  **
; **                         **
; *****************************

BRKKY:		lda	#0
		sta	BRKKEY
		sta	SSFLAG
		sta	CRSINH
		sta	ATRACT
		pla
		rti

C0A0:		pla
		tax
		bit	PACTL
		bpl	@1
		lda	PORTA
		jmp	(VPRCED)

@1:		bit	PBCTL
		bpl	@2
		lda	PORTB
		jmp	(VINTER)

@2:		pla
		sta	JVECK
		pla
		pha
		and	#%00010000
		beq	@3
		lda	JVECK
		pha
		jmp	(VBREAK)

@3:		lda	JVECK
		pha

PLARTI:		pla
C0CE:		rti

; ***************************
; **                       **
; **  IRQ Dispatcher Data  **
; **                       **
; ***************************

		; Bit masks for IRQ interrupts

IRQMSK:		.byte	%10000000	; break key              LO PRIORITY
		.byte	%01000000	; keyboard               |
		.byte	%00000100	; timer 4                |
		.byte	%00000010	; timer 2                |
		.byte	%00000001	; timer 1                |
		.byte	%00001000	; serial output complete |
		.byte	%00010000	; serial output ready    |
		.byte	%00100000	; serial input ready     HI PRIORITY

		; Offsets from $200 of IRQ interrupt handler vectors

IRQOFS:		.byte	VBRKKY - $200	; break key              LO PRIORITY
		.byte	VKEYBD - $200	; keyboard               |
		.byte	VTIMR4 - $200	; timer 4                |
		.byte	VTIMR2 - $200	; timer 2                |
		.byte	VTIMR1 - $200	; timer 1                |
		.byte	VSEROC - $200	; serial output complete |
		.byte	VSEROR - $200	; serial output ready    |
		.byte	VSERIN - $200	; serial input ready     HI PRIORITY

; *********************
; **                 **
; ** HALT PROCESSOR  **
; **                 **
; *********************

HALT:		jmp	HALT

; **********************
; **                  **
; **  VBLANK STAGE 1  **
; **                  **
; **********************

VBLKI:		inc	RTCLOK+2	; increase RTCLOK
		bne	@1
		inc	ATRACT
		inc	RTCLOK+1
		bne	@1
		inc	RTCLOK

@1:		lda	#$FE		; manage ATRACT mode
		ldx	#0
		ldy	ATRACT
		bpl	@2
		sta	ATRACT
		ldx	RTCLOK+1
		lda	#%11110110
@2:		sta	DRKMSK
		stx	COLRSH
		lda	COLOR1
		eor	COLRSH
		and	DRKMSK
		sta	COLPF1

		ldx	#0		; decrement countdown timer 1
		jsr	C255
		bne	@3
		jsr	@16		; JSR (CDTMA1)

@3:		lda	CRITIC
		bne	@4		; BNE VBLKD
		tsx
		lda	$104,X
		and	#4
		beq	@5
@4:		jmp	VBLKD

@5:		lda	TRIG3		; crash purposely if (TRIG3!=GINTLK)
		cmp	GINTLK
		bne	HALT

		lda	PENV		; light pen hardware -> shadow
		sta	LPENV
		lda	PENH
		sta	LPENH	
		lda	SDLSTH		; dlist shadow -> hardware
		sta	DLISTH
		lda	SDLSTL
		sta	DLISTL
		lda	SDMCTL		; dma control shadow -> hardware
		sta	DMACTL
		lda	GPRIOR		; GTIA priority shadow -> hardware
		sta	PRIOR
		lda	VSFLAG		; do vertical scrolling
		beq	@6
		dec	VSFLAG
		lda	#8
		sec
		sbc	VSFLAG
		and	#%00000111
		sta	VSCROL
@6:		ldx	#8		; reset console keys
		stx	CONSOL

@7:		cli			; copy shadow colors -> GTIA
		lda	$2C0,X
		eor	COLRSH
		and	DRKMSK
		sta	$D012,X
		dex
		bpl	@7

		lda	CHBAS		; character base shadow -> hardware
		sta	CHBASE
		lda	CHACT		; character control shadow -> hardware
		sta	CHACTL

		ldx	#2		; decrement countdown timer 2
		jsr	C255
		bne	@8
		jsr	@17		; JSR (CDTMA2)

@8:		ldx	#2		; decrement timer 3,4,5 & set flags
@9:		inx
		inx
		lda	$218,X
		ora	$219,X
		beq	@10
		jsr	C255
		sta	$226,X
@10:		cpx	#8
		bne	@9

		lda	SKSTAT
		and	#%00000100
		beq	@11
		lda	KEYDEL
		beq	@11
		dec	KEYDEL
@11:		lda	SRTIMR
		beq	@13
		lda	SKSTAT
		and	#%00000100
		bne	@12
		dec	SRTIMR
		bne	@13
		lda	KEYDIS
		bne	@13
		lda	KEYREP
		sta	SRTIMR

		lda	KBCODE	; KBCODE in [$9F,$83,$84,$94,$11,$51,$91,$D1] ?
		cmp	#$9F	;  ... skip
		beq	@13
		cmp	#$83
		beq	@13
		cmp	#$84
		beq	@13
		cmp	#$94
		beq	@13
		and	#$3F
		cmp	#$11
		beq	@13

		lda	KBCODE
		sta	CH
		jmp	@13

@12:		lda	#0
		sta	SRTIMR

@13:		lda	PORTA		; set stick() values
		lsr	A
		lsr	A
		lsr	A
		lsr	A
		sta	STICK1
		sta	STICK3
		lda	PORTA
		and	#%00001111
		sta	STICK0
		sta	STICK2

		lda	TRIG0		; set STRIG() from TRIG() values
		sta	STRIG0
		sta	STRIG2
		lda	TRIG1
		sta	STRIG1
		sta	STRIG3

		ldx	#3		; set PADDLE() from POT() values
@14:		lda	$D200,X
		sta	$270,X
		sta	$274,X
		dex
		bpl	@14

		sta	POTGO	; paddles have been read; initiate new "POTGO"!

		ldx	#2		; set PTRIG() values
		ldy	#1
@15:		lda	$278,Y
		lsr	A
		lsr	A
		lsr	A
		sta	$27D,X
		sta	$281,X
		lda	#0
		rol	A
		sta	$27C,X
		sta	$280,X
		dex
		dex
		dey
		bpl	@15

		jmp	(VVBLKD)

@16:		jmp	(CDTMA1)
@17:		jmp	(CDTMA2)

; *********************************
; **                             **
; **  DECREMENT COUNTDOWN TIMER  **
; **                             **
; *********************************

C255:		ldy	$218,X
		bne	@1
		ldy	$219,X
		beq	@2
		dec	$219,X
@1:		dec	$218,X
		bne	@2
		ldy	$219,X
		bne	@2
		lda	#0
		rts
@2:		lda	#$FF
		rts

; ************************************
; **                                **
; **  SET VERTICAL BLANK INTERRUPT  **
; **                                **
; ************************************

	; subroutine to set vertical blank vectors and timers
	; entry X=hi, Y=lo byte to set
	;       A= 1-5 TIMERS 1-5
	;          6 IMM VBLANK
	;          7 DEF VBLANK

SETVBL:		asl	A		; mul by 2
		sta	INTEMP
		txa
		ldx	#5
		sta	WSYNC		; waste 20 CPU cycles
@1:		dex			; to allow VBLANK to happen
		bne	@1		; if this is line "7C"
		ldx	INTEMP
		sta	$217,X
		tya
		sta	$216,X
		rts

; ******************************************
; *                                       **
; *  END-VBLANK & DEFAULT VBLANK STAGE 2  **
; *                                       **
; ******************************************

	; exit rom vertical blank
	
VBLKD:		pla		; unstack Y
		tay
		pla		; unstack X
		tax
		pla		; unstack A
		rti		; and go back from whence

; ******************
; **              **
; **  WARM START  **
; **              **
; ******************

WARMS:		sei
		lda	TRIG3
		cmp	GINTLK
		bne	COLDS
		ror	A
		bcc	@1
		jsr	C4C9
		bne	COLDS
@1:		lda	COLDST
		bne	COLDS
		lda	#$FF
		bne	C2CA

; ********************************
; **                            **
; **  6502 Reset (RST) handler  **
; **                            **
; ********************************

C2AA:		sei			; disable interrupts

		ldx	#140		; wait about 0@1 second ...
@1:		dey
		bne	@1
		dex
		bne	@1

		lda	PUPBT1		; check $33D..$33F = $5C,$93,$25?
		cmp	#$5C
		bne	COLDS
		lda	PUPBT2
		cmp	#$93
		bne	COLDS
		lda	PUPBT3
		cmp	#$25
		beq	WARMS

COLDS:		lda	#0

		; Warm- and cold-start continuation

C2CA:		sta	WARMST
		sei
		cld
		ldx	#$FF
		txs
		jsr	C471

		lda	#1		; default: memory OK!
		sta	NGFLAG

		lda	WARMST
		bne	@6

		; This part: cold start only!

		lda	#0
		ldy	#8
		sta	RAMLO
		sta	RAMLO+1
@1:		lda	#$FF
		sta	(RAMLO),Y
		cmp	(RAMLO),Y
		beq	@2
		lsr	NGFLAG		; signal memory bad!
@2:		lda	#0
		sta	(RAMLO),Y
		cmp	(RAMLO),Y
		beq	@3
		lsr	NGFLAG		; signal memory bad!
@3:		iny
		bne	@1
		inc	RAMLO+1
		ldx	RAMLO+1
		cpx	TRAMSZ
		bne	@1
		lda	#<SELFS		; [$A:$B] = SELFTEST
		sta	DOSVEC
		lda	#>SELFS
		sta	DOSVEC+1

		lda	PORTB		; Verify ROMs
		and	#%01111111	; enable self test ROM
		sta	PORTB
		jsr	VFR
		bcs	@4
		jsr	VSR
		bcc	@5
@4:		lsr	NGFLAG
@5:		lda	PORTB		; disable self test ROM
		ora	#%10000000
		sta	PORTB

		lda	#$FF
		sta	COLDST
		bne	@10

		; this part: Warm start only!

@6:		ldx	#0
		lda	DERRF
		beq	@7

		.byte	$8E	; force absolute addr. mode for STX APPMHI
		.word	APPMHI
		.byte	$8E	; force absolute addr. mode for STX APPMHI+1
		.word	APPMHI+1

		txa			; clear $200-$33C
@7:		sta	$200,X
		cpx	#$ED
		bcs	@8
		sta	$300,X
@8:		dex
		bne	@7

		ldx	#$10		; reset $10..$7F to zero
@9:		sta	0,X
		inx
		bpl	@9

		; Warm- and cold-start continuation

@10:		ldx	#0		; init BASICF
		lda	PORTB
		and	#%00000010
		beq	@11
		inx
@11:		stx	BASICF

		lda	#$5C		; init power-up bytes
		sta	PUPBT1
		lda	#$93
		sta	PUPBT2
		lda	#$25
		sta	PUPBT3

		lda	#2		; init left margin
		sta	LMARGN
		lda	#39		; init right margin
		sta	RMARGN

		lda	PAL		; init keyboard timing & PALNTS flag
		and	#%00001110
		bne	@12
		lda	#5		; PAL
		ldx	#1
		ldy	#40
		bne	@13
@12:		lda	#6		; NTSC
		ldx	#0
		ldy	#48
@13:		sta	KEYREP
		stx	PALNTS
		sty	KRPDEL

		ldx	#$25		; init 19 vectors from $200 to $225
@14:		lda	C44B,X
		sta	$200,X
		dex
		bpl	@14

		ldx	#14		; init 5 3-byte device driver entries
@15:		lda	C42E,X
		sta	HATABS,X
		dex
		bpl	@15

		jsr	C535
		cli
		lda	NGFLAG		; check if memory is ok
		bne	@16

		lda	PORTB		; NO: enable SELFTEST ROM!
		and	#%01111111
		sta	PORTB

		lda	#2		; ...and go for self-test!
		sta	CHACT
		lda	#>CHARSET1
		sta	CHBAS
		jmp	V003

@16:		ldx	#0		; memory ok.
		stx	TRAMSZ
		ldx	RAMSIZ
		cpx	#>$B000
		bcs	@17
		ldx	BFFC
		bne	@17
		inc	TRAMSZ
		jsr	C4C9
		jsr	@22		; JSR ($BFFE)

@17:		lda	#3		; open #0,12,0,"E:"
		ldx	#0
		sta	ICCOM,X
		lda	#<EDITOR
		sta	ICBAL,X
		lda	#>EDITOR
		sta	ICBAH,X
		lda	#12
		sta	ICAX1,X
		jsr	CIOV
		bpl	@18
		jmp	C2AA		; no go -- hardware reset!

@18:		inx			; all ok -- settle down
		bne	@18
		iny
		bpl	@18

		jsr	C66E
		lda	TRAMSZ
		beq	@19
		lda	BFFC+1
		ror	A
		bcc	@20
@19:		jsr	C58B
		jsr	PHR
@20:		lda	#0
		sta	COLDST
		lda	TRAMSZ
		beq	@21		; BEQ (DOSVEC)
		lda	BFFC+1
		and	#%00000100
		beq	@21		; BEQ (BFFE)
		jmp	(BFFA)
@21:		jmp	(DOSVEC)
@22:		jmp	(BFFE)
		clc
		rts

		; BOOT PROCESS DATA!

C42E:		.byte	"P"		; initial device driver entries
		.word	PRINTV
		.byte	"C"
		.word	CASETV
		.byte	"E"
		.word	EDITRV
		.byte	"S"
		.word	SCRENV
		.byte	"K"
		.word	KEYBDV

BT_ERR:		.byte	"BOOT ERROR",$9B

EDITOR:		.byte	"E:",$9B	; Editor device specification

C44B:		.word	C0CE		; VDSLST ->     RTI
		.word	PLARTI		; VPRCED -> PLA,RTI
		.word	PLARTI		; VINTER -> PLA,RTI
		.word	PLARTI		; VBREAK -> PLA,RTI

		.word	KIR		; VKEYBD
		.word	ISRSIR		; VSERIN
		.word	ISRODN		; VSEROR
		.word	ISRTD		; VSEROC
		.word	PLARTI		; VTIMR1 -> PLA,RTI
		.word	PLARTI		; VTIMR2 -> PLA,RTI
		.word	PLARTI		; VTIMR4 -> PLA,RTI

		.word	IMIRQ		; VIMIRQ -> Immediate IRQ
		.word	0		; CDTMV1 -> 0
		.word	0		; CDTMV2 -> 0
		.word	0		; CDTMV3 -> 0
		.word	0		; CDTMV4 -> 0
		.word	0		; CDTMV5 -> 0
		.word	VBLKI		; VVBLKI -> VBLANK Immediate
		.word	VBLKD		; VVBLKD -> VBLANK Deferred

C471:		lda	TRIG3
		ror	A
		bcc	@1
		lda	BFFC
		bne	@1
		lda	BFFC+1
		bpl	@1
		jmp	(BFFE)
@1:		jsr	C4DA
		lda	PORTB
		ora	#%00000010
		sta	PORTB

		lda	WARMST
		beq	@2
		lda	BASICF
		bne	@4
		beq	@3
@2:		lda	CONSOL		; option key pressed?
		and	#%00000100
		beq	@4		; no -- skip enable BASIC
@3:		lda	PORTB		; enable BASIC
		and	#%11111101
		sta	PORTB

@4:		lda	#<$2800		; search 1st byte of ROM from $2800 up
		tay
		sta	RAMLO+1
		lda	#>$2800
		sta	TRAMSZ
@5:		lda	(TRAMSZ-1),Y
		eor	#$FF
		sta	(TRAMSZ-1),Y
		cmp	(TRAMSZ-1),Y
		bne	@6
		eor	#$FF
		sta	(TRAMSZ-1),Y
		cmp	(TRAMSZ-1),Y
		bne	@6
		inc	TRAMSZ
		bne	@5
@6:		rts

C4C9:		lda	#0
		tax
		clc
@1:		adc	BFF0,X
		inx
		bne	@1
		cmp	CARTCK
		sta	CARTCK
		rts

C4DA:		lda	#0	; clear all of $D000..$D4FF, except $D301.
		tax
		sta	PBCTL
@1:		sta	$D000,X
		sta	$D400,X
		sta	$D200,X
		cpx	#1
		beq	@2
		sta	$D300,X
@2:		inx
		bne	@1

		lda	#%00111100
		sta	PBCTL
		lda	#%11111111
		sta	PORTB
		lda	#%00111000
		sta	PACTL
		sta	PBCTL
		lda	#0
		sta	PORTA
		lda	#%11111111
		sta	PORTB
		lda	#%00111100
		sta	PACTL
		sta	PBCTL
		lda	PORTB
		lda	PORTA
		lda	#%00100010
		sta	SKCTL
		lda	#160
		sta	$D205
		sta	$D207
		lda	#%00101000
		sta	AUDCTL
		lda	#$FF
		sta	SEROUT
		rts

C535:		dec	BRKKEY

		lda	#<BRKKY		; init break key interrupt vector
		sta	VBRKKY
		lda	#>BRKKY
		sta	VBRKKY+1

		lda	TRAMSZ
		sta	RAMSIZ
		sta	HIMEM+1
		lda	#0
		sta	HIMEM

		lda	#<$700		; MEMLO = $700
		sta	MEMLO
		lda	#>$700
		sta	MEMLO+1

		jsr	E40C		; init devices
		jsr	E41C
		jsr	E42C
		jsr	E43C
		jsr	E44C

		jsr	CIOINV		; init cassette I/O
		jsr	SIOINV		; init serial I/O
		jsr	INTINV		; init ehhh...
		jsr	DISKIV		; init disk I/O

		lda	#<PIRQ
		sta	VPIRQ
		lda	#>PIRQ
		sta	VPIRQ+1

		jsr	E49B

		lda	CONSOL
		and	#1
		eor	#1
		sta	CKEY
		rts

C58B:		lda	WARMST
		beq	@1
		lda	BOOTQ
		and	#1
		beq	C5C8
		jmp	C63B		; JMP (DOSINI)

@1:		lda	#1
		sta	DUNIT
		lda	#'S'		; status
		sta	DCOMND
		jsr	DISKINV
		bmi	C5C8

C5A7:		lda	#0
		sta	DAUX2
		lda	#1
		sta	DAUX1
		lda	#<$400
		sta	DBUFLO
		lda	#>$400
		sta	DBUFHI

C5BB:		jsr	C659
		bpl	C5C9

C5C0:		jsr	C63E
		lda	CASSBT
		beq	C5A7
C5C8:		rts

C5C9:		ldx	#3
@1:		lda	$400,X
		sta	$240,X
		dex
		bpl	@1
		lda	BOOTAD
		sta	RAMLO
		lda	BOOTAD+1
		sta	RAMLO+1
		lda	$404
		sta	DOSINI
		lda	$405
		sta	DOSINI+1

C5E8:		ldy	#$7F		; copy lower half page 4
@1:		lda	$400,Y
		sta	(RAMLO),Y
		dey
		bpl	@1

		clc			; RAMLO += 128
		lda	RAMLO
		adc	#<$80
		sta	RAMLO
		lda	RAMLO+1
		adc	#>$80
		sta	RAMLO+1

		dec	DBSECT
		beq	@3		; we have read last sector!
		inc	DAUX1		; go for next sector...
@2:		jsr	C659
		bpl	C5E8
		jsr	C63E
		lda	CASSBT
		bne	C5C0
		beq	@2

@3:		lda	CASSBT
		beq	@4
		jsr	C659
@4:		jsr	@5
		bcs	C5C0
		jsr	C63B		; JSR (DOSINI)
		inc	BOOTQ
		rts

@5:		clc			; [RAMLO] = BOOTAD+6
		lda	BOOTAD
		adc	#6
		sta	RAMLO
		lda	BOOTAD+1
		adc	#0
		sta	RAMLO+1
		jmp	(RAMLO)

C63B:		jmp	(DOSINI)

		; display "BOOT ERROR" message

C63E:		ldx	#<BT_ERR
		ldy	#>BT_ERR
		txa
		ldx	#0
		sta	ICBAL,X
		tya
		sta	ICBAH,X
		lda	#9
		sta	ICCOM,X
		lda	#$FF
		sta	ICBLL,X
		jmp	CIOV

C659:		lda	CASSBT
		beq	@1
		jmp	RBLOKV
@1:		lda	#'R'		; read sector
		sta	DCOMND
		lda	#1
		sta	DUNIT
		jmp	DISKINV

C66E:		lda	WARMST
		beq	@1
		lda	BOOTQ
		and	#2
		beq	@2		; RTS
		jmp	@3		; JMP (CASINI)

@1:		lda	CKEY
		beq	@2		; RTS
		lda	#$80
		sta	FTYPE
		inc	CASSBT
		jsr	CSOPIV
		jsr	C5BB
		lda	#0
		sta	CASSBT
		sta	CKEY
		asl	BOOTQ
		lda	DOSINI		;  copy DOSINI -> CASINI
		sta	CASINI
		lda	DOSINI+1
		sta	CASINI+1
@2:		rts
@3:		jmp	(CASINI)

DISKI:		lda	#160		; 171-second timeout
		sta	DSKTIM
		lda	#<$80		; 128-byte disk sectors
		sta	DSCTLN
		lda	#>$80
		sta	DSCTLN+1
		rts

DISKIN:		lda	#'1'
		sta	DDEVIC
		lda	DSKTIM		; time-out for FORMAT
		ldx	DCOMND
		cpx	#'!'
		beq	@1
		lda	#7		; otherwise: 7 seconds
@1:		sta	DTIMLO

		ldx	#%01000000	; set bit 7 if WRITE, otherwise bit 6
		lda	DCOMND
		cmp	#'P'		; "put" command? (WRITE/NO VERIFY)
		beq	@2
		cmp	#'W'		; "write" command?
		bne	@3
@2:		ldx	#%10000000

@3:		cmp	#'S'		; "status" command?
		bne	@4

		; STATUS command:

		lda	#<DVSTAT
		sta	DBUFLO
		lda	#>DVSTAT
		sta	DBUFHI
		ldy	#<4
		lda	#>4
		beq	@5		; JMP @5

@4:		ldy	DSCTLN
		lda	DSCTLN+1

@5:		stx	DSTATS
		sty	DBYTLO
		sta	DBYTHI
		jsr	SIOV
		bpl	@6
		rts

@6:		lda	DCOMND
		cmp	#'S'
		bne	@7

		jsr	C73A
		ldy	#2
		lda	(BUFADR),Y
		sta	DSKTIM

@7:		lda	DCOMND
		cmp	#'!'
		bne	@10
		jsr	C73A
		ldy	#$FE
@8:		iny
		iny
@9:		lda	(BUFADR),Y
		cmp	#$FF
		bne	@8
		iny
		lda	(BUFADR),Y
		iny
		cmp	#$FF
		bne	@9
		dey
		dey
		sty	DBYTLO
		lda	#0
		sta	DBYTHI
@10:		ldy	DSTATS
		rts

C73A:		lda	DBUFLO
		sta	BUFADR
		lda	DBUFHI
		sta	BUFADR+1
		rts

C745:		ldx	#5
@1:		lda	#0
		sta	$2C9,X
		dex
		bpl	@1

@2:		lda	#0
		sta	LCOUNT
		jsr	C7CF		; JSR (GBYTEA)
		ldy	#$9C
		bcs	@4		; RTS
		sta	HIBYTE
		jsr	C7CF		; JSR (GBYTEA)
		ldy	#$9C
		bcs	@4		; RTS
		sta	RECLEN
		lda	HIBYTE
		cmp	#11
		beq	C795
		rol	A
		tax
		lda	C8E4,X
		sta	RUNADR
		lda	C8E4+1,X
		sta	RUNADR+1
@3:		lda	RECLEN
		cmp	LCOUNT
		beq	@2
		jsr	C7CF		; JSR (GBYTEA)
		ldy	#$9C
		bcs	@4		; RTS
		jsr	C7D2		; JSR (RUNADR)
		inc	LCOUNT
		bne	@3
@4:		rts

C795:		jsr	C7CF		; JSR (GBYTEA)
		ldy	#$9C
		bcs	@3
		sta	RUNADR
		jsr	C7CF		; JSR (GBYTEA)
		ldy	#$9C
		bcs	@3
		sta	RUNADR+1
		lda	RECLEN
		cmp	#1
		beq	@2
		bcc	@4
		clc
		lda	RUNADR
		adc	LOADAD
		tay
		lda	RUNADR+1
		adc	$2D2
@1:		sty	RUNADR
		sta	RUNADR+1
@2:		ldy	#1
@3:		rts
	
@4:		ldy	#0
		lda	#0
		beq	@1

C7CF:		jmp	(GBYTEA)
C7D2:		jmp	(RUNADR)

C7D5:		ldy	LCOUNT
		cpy	#1
		beq	@1
		bcs	@9
		sta	RELADR
		sta	NEWADR
		bcc	@8		; RTS
@1:		sta	RELADR+1
		sta	NEWADR+1
		ldx	#0
		lda	HIBYTE
		beq	@2
		cmp	#10
		beq	@3
		ldx	#2
@2:		clc
		lda	RELADR
		adc	$2D1,X
		sta	NEWADR
		lda	RELADR+1
		adc	$2D2,X
		sta	NEWADR+1
@3:		clc
		lda	NEWADR
		adc	RECLEN
		pha
		lda	#0
		adc	NEWADR+1
		tay
		pla
		sec
		sbc	#2
		bcs	@4
		dey
@4:		pha
		tya
		cmp	$2CC,X
		pla
		bcc	@6
		bne	@5
		cmp	$2CB,X
		bcc	@6
@5:		sta	$2CB,X
		pha
		tya
		sta	$2CC,X
		pla
@6:		ldx	HIBYTE
		cpx	#1
		beq	@8		; RTS
		cpy	HIMEM+1
		bcc	@8		; RTS
		bne	@7
		cmp	HIMEM
		bcc	@8		; RTS
@7:		pla
		pla
		ldy	#$9D
@8:		rts

@9:		sec
		pha
		lda	LCOUNT
		sbc	#2
		clc
		adc	NEWADR
		sta	LTEMP
		lda	#0
		adc	NEWADR+1
		sta	LTEMP+1
		pla
		ldy	#0
		sta	(LTEMP),Y
		jmp	@8		; RTS

C86D:		clc
		adc	NEWADR
		sta	LTEMP
		lda	#0
		adc	NEWADR+1
		sta	LTEMP+1
		ldy	#0
		lda	(LTEMP),Y
		clc
		adc	LOADAD
		sta	(LTEMP),Y
		inc	LTEMP
		bne	@1
		inc	LTEMP+1
@1:		lda	(LTEMP),Y
		adc	LOADAD+1
		sta	(LTEMP),Y
		rts

C892:		ldx	#0
		ldy	HIBYTE
		cpy	#4
		bcc	@1
		ldx	#2
@1:		clc
		adc	NEWADR
		sta	LTEMP
		lda	#0
		adc	NEWADR+1
		sta	LTEMP+1
		ldy	#0
		lda	(LTEMP),Y
		clc
		adc	LOADAD,X
		sta	(LTEMP),Y
		rts

C8B5:		pha
		lda	LCOUNT
		ror	A
		pla
		bcs	@2
		clc
		adc	NEWADR
		sta	LTEMP
		lda	#0
		adc	NEWADR+1
		sta	LTEMP+1
		ldy	#0
		lda	(LTEMP),Y
		sta	HIBYTE
@1:		rts

@2:		clc
		adc	LOADAD
		lda	#0
		adc	LOADAD+1
		adc	HIBYTE
		ldy	#0
		sta	(LTEMP),Y
		beq	@1		; RTS

		; Peripheral Device Handlers?

C8E4:		.word	C7D5,C7D5,C892,C892,C892,C892
		.word	C86D,C86D,C8B5,C8B5,C7D5,C795

		; Unused code?

		lda	#$FF	; start self test!
		sta	COLDST
		lda	PORTB
		and	#%01111111
		sta	PORTB
		jmp	SLFTSV

C90C:		lda	#1
		sta	SHPDVS
@1:		lda	SHPDVS
		sta	PDVS
		lda	$D803		; ID number
		cmp	#$80
		bne	@2
		lda	$D80B		; ID number
		cmp	#$91
		bne	@2
		jsr	$D819		; JMP addr
@2:		asl	SHPDVS
		bne	@1
		lda	#0
		sta	PDVS
		rts

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

		; !!! patched by XL-IT! !!!

SIO:		lda	#1		; start of critical timing region
		.byte	$8D		; STA CRITIC (absolute)
		.word	CRITIC

		lda	DUNIT		; save DUNIT
		pha
	
		lda	PDVMSK
		beq	@2

		ldx	#8
@1:		jsr	C9AF
		beq	@2
		txa			; save X
		pha
		jsr	$D805		; JMP instruction
		pla
		tax			; restore X
		bcc	@1
		lda	#0
		sta	SHPDVS
		sta	PDVS
		beq	@3		; skip to end-of-sio

	; "normal" SIO command
	
@2:		jsr	E971

@3:		pla			; restore DUNIT
		sta	DUNIT

		lda	#0		; end of critical timing region
		.byte	$8D		; STA CRITIC (absolute)
		.word	CRITIC

		sty	DSTATS
		ldy	DSTATS
		rts

; ****************************
; **                        **
; **  PARALLEL IRQ HANDLER  **
; **                        **
; ****************************

PIRQ:		ldx	#8
@1:		ror	A
		bcs	@2
		dex
		bne	@1
@2:		lda	SHPDVS
		pha
		lda	BARREL-1,X
		sta	SHPDVS
		sta	PDVS
		jsr	$D808		; 'JMP'
		pla
		sta	SHPDVS
		sta	PDVS
		pla
		tax
		pla
		rti

C991:		ldy	#1
		jmp	C9DC
C996:		ldy	#3
		jmp	C9DC
C99B:		ldy	#5
		jmp	C9DC
C9A0:		ldy	#7
		jmp	C9DC
C9A5:		ldy	#9
		jmp	C9DC
C9AA:		ldy	#11
		jmp	C9DC

C9AF:		dex
		bpl	@1
		lda	#0
		sta	SHPDVS
		sta	PDVS
		rts

@1:		lda	PDVMSK
		and	BARREL,X
		beq	C9AF
		sta	SHPDVS
		sta	PDVS
		rts

C9CA:		lda	$D80D,Y		; open vector
		pha
		dey
		lda	$D80D,Y		; open vector
		pha
		lda	PPTMPA
		ldx	PPTMPX
		ldy	#146
		rts

C9DC:		sta	PPTMPA
		stx	PPTMPX

		.byte	$AD		; absolute addr. mode for LDA CRITIC
		.word	CRITIC

		pha
		lda	#1

		.byte	$8D		; absolute addr. mode for STA CRITIC
		.word	CRITIC

		ldx	#8
@1:		jsr	C9AF
		beq	@2
		txa
		pha
		tya
		pha
		jsr	C9CA
		bcc	@4
		sta	PPTMPA
		pla
		pla
		jmp	@3

@2:		ldy	#130
@3:		lda	#0
		sta	SHPDVS
		sta	PDVS
		pla

		.byte	$8D		; absolute addr. mode for STA CRITIC
		.word	CRITIC

		lda	PPTMPA
		sty	PPTMPX
		ldy	PPTMPX
		rts

@4:		pla
		tay
		pla
		tax
		bcc	@1		; JMP @1

		; Barrel Shifter :-)

BARREL:		.byte	%10000000
		.byte	%01000000
		.byte	%00100000
		.byte	%00010000
		.byte	%00001000
		.byte	%00000100
		.byte	%00000010
		.byte	%00000001

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

		lda	$34D,X
		jsr	E7DE
		bcs	@1		; BCS E510
		clc
		jsr	E89E
		bcs	@1

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

		lda	$34C,X
		jsr	E716
		bcs	@1

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

		sta	IOCB,X
		sta	ICHIDZ
		lda	#3
		sta	ICCOMT
		jmp	E55C

@1:		jmp	E510

		; Some data, seems to be used by SELFTEST ROMS.

CA57:		.byte	$00,$13,$16,$D1,$E4,$E4,$E8,$29,$EB,$EE

CA61:		.byte	$00,$00,$2D,$25,$2D,$2F,$32,$39	; '  MEMORY TEST   '
		.byte	$00,$34,$25,$33,$34,$00,$00,$00
		.byte	$32,$2F,$2D			; 'ROM'
		.byte	$32,$21,$2D			; 'RAM'
		.byte	$00,$00,$2B,$25,$39,$22,$2F,$21	; '  KEYBOARD TEST '
		.byte	$32,$24,$00,$34,$25,$33,$34,$00

		.byte	$00,$00,$B2,$91,$00,$92,$00,$93
		.byte	$00,$94,$00,$A8,$00,$A1,$00,$A2
		.byte	$00,$00,$00,$5B,$00,$11,$00,$12
		.byte	$00,$13,$00,$14,$00,$15,$00,$16
		.byte	$00,$17,$00,$18,$00,$19,$00,$10
		.byte	$00,$1C,$00,$1E,$00,$A2,$80,$B3
		.byte	$00,$00,$00,$FF,$FF,$00,$31,$00
		.byte	$37,$00,$25,$00,$32,$00,$34,$00
		.byte	$39,$00,$35,$00,$29,$00,$2F,$00
		.byte	$30,$00,$0D,$00,$1D,$00,$B2,$B4
		.byte	$00,$00,$00,$80,$DC,$80,$00,$21
		.byte	$00,$33,$00,$24,$00,$26,$00,$27
		.byte	$00,$28,$00,$2A,$00,$2B,$00,$2C
		.byte	$00,$1B,$00,$0B,$00,$0A,$00,$A3
		.byte	$00,$00,$00,$80,$B3,$A8,$80,$00
		.byte	$3A,$00,$38,$00,$23,$00,$36,$00
		.byte	$22,$00,$2E,$00,$2D,$00,$0C,$00
		.byte	$0E,$00,$0F,$00,$80,$B3,$A8,$80
		.byte	$00,$00,$00,$00,$00,$00,$00,$00
		.byte	$80,$B3,$80,$B0,$80,$A1,$80,$A3
		.byte	$80,$A5,$80,$80,$80,$A2,$80,$A1
		.byte	$80,$B2,$80,$00,$33,$00,$30,$00
		.byte	$21,$00,$23,$00,$25,$00,$00,$00
		.byte	$22,$00,$21,$00,$32,$00,$00,$33
		.byte	$28,$00,$22,$00,$33,$00,$5C,$00
		.byte	$36,$2F,$29,$23,$25		; 'VOICE'
		.byte	$00,$03

		; 18-byte checksum!

CB56:		ldy	#17
		lda	#0
		clc
@1:		adc	(ZCHAIN),Y
		dey
		bpl	@1
		adc	#0
		eor	#$FF
		rts

		; 155 zero bytes:

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

