;-------------------------------------------------------------------------------
; FATware - firmware and file system driver for ZX Spectrum divIDE interface
; Copyright (c) 2005-2009 Milos Bazelides (baze)
;-------------------------------------------------------------------------------
; This software is provided "as is" without warranties or conditions of any
; kind, either express or implied. In no event shall the author(s) be held
; liable for any damages arising from the use of this software.
; See accompanying "licence.txt" file for copyright and terms of use.
;-------------------------------------------------------------------------------

	; common system variables

	extern	SysTemp1
	extern	SysBootOK
	extern	SysNumVolumes
	extern	SysCurrVolume
	extern	SysCursor
	extern	SysColour

	; common buffers

	extern	SysAY
	extern	SysNumber

	; core utility functions

	extern	SaveAY;
	extern	LoadAY;
	extern	Num32ToASCII;
	extern	PrintString;
	extern	PrintChar;

	; filesystem driver calls

	extern	FileOpen
	extern	FileClose;
	extern	FileRead;
	extern	FileWrite
	extern	FileSeek;
	extern	IsEOF;

	extern	FindVolume;		; TODO: also GetCurrentVolume?

	extern	OpenDir;
	extern	OpenCurrentDir;

	extern	FindDirEntry;		; TODO: GetNext?
	extern	ReadDirEntry;		; TODO: GetVolumeLabel
	extern	FileOpenRaw;

	; driver system variables (should be abstracted)

	extern	VolDesc
	extern	FileName
	extern	DirEntry


	include "z80_undoc.inc"
	include "zx_spectrum.inc"
	include "ata.inc"
	include "fat.inc"
	include "fat_driver.inc"

	define	BANK3			; RAM bank 3 (second "ROM") image
	segment	BANK3

;-------------------------------------------------------------------------------
; ROM ENTRY POINT: RST 0 (RESET)
;-------------------------------------------------------------------------------

	org	0

	di
	ld	a,80h
	out	(DIV_CTRL),a

	; the code continues in EEPROM from now on ;)

	jp	Startup			; jump to cold reset for bank 3

;-------------------------------------------------------------------------------
; ROM ENTRY POINT: RST 8
;-------------------------------------------------------------------------------

	org	8

	; jump to Rst8 when paged in, otherwise perform dummy LD HL,(...)

	ld	hl,(5C5Dh)

	; this code gets executed if we get here from ZX ROM

In8h	push	hl
	ld	hl,In8h
	ex	(sp),hl
	jp	OutRET

;-------------------------------------------------------------------------------
; IM 1 HANDLER
;-------------------------------------------------------------------------------

	org	1Fh

	; is the interlaced screen viewer active?

	push	af
	ld	a,(SysViewerFlag)
	rra
	jp	c,ImageViewer
	pop	af
	ei
	ret

;-------------------------------------------------------------------------------
; RST 30 HANDLER: Call MAPRAM/EEPROM routine
;-------------------------------------------------------------------------------

	org	30h

	ex	(sp),hl
	ld	(SysTemp1),de
	jp	CallBank

;-------------------------------------------------------------------------------
; ROM ENTRY POINT: IM 1
;-------------------------------------------------------------------------------

	org	38h

	; jump to 1Fh if we get here while divIDE ROM is mapped

	db	24		; JR to 1Fh (38h - 19h)
	push	hl

	; check SS + ENTER shortcut to enter NMI menu

Im1Cont	ld	a,127
	in	a,(254)
	and	2
	jr	nz,$f

	ld	a,191
	in	a,(254)
	rra
	jr	c,$f

	; invoke NMI handler

	pop	hl
	ei
	jr	67h

	; if we get here from ZX ROM just return back

$$	ld	hl,39h
	ex	(sp),hl
	jp	OutRET

;-------------------------------------------------------------------------------
; ROM ENTRY POINT: NMI
;-------------------------------------------------------------------------------

	org	66h

	ret				; prevent nested NMI calls
	xor	a
	out	(DIV_CTRL),a

	ld	a,r
	rlca
	sub	12
	rrca
	ld	(NmiR),a

	ld	a,i
	ld	(NmiI),a
	ld	a,0
	jp	po,$f
	inc	a
$$	ld	(NmiIFF),a

	di				; just for the case we jump here from the IM 1 handler
	pop	af
	ld	(NmiSP),sp

	ld	sp,NmiIY + 20
	push	af
	push	bc
	push	de
	push	hl
	ex	af,af'
	exx
	push	af
	push	bc
	push	de
	push	hl
	push	ix
	push	iy

	; soft reset if user holds 'R'

	ld	a,0FBh
	in	a,(254)
	and	8
	jp	z,0

	; save AY registers and mute sound

	ld	sp,4000h
	rst	30h
	dw	SaveAY

	; backup videoram

	ld	a,2
	di
	out	(DIV_CTRL),a

	ld	hl,4000h
	ld	de,2400h
	ld	bc,6912
	ldir

	xor	a
	ei
	out	(DIV_CTRL),a

	; only show browser if there are any volumes detected

	ld	a,(SysNumVolumes)
	or	a
	jr	z,NmiRet

	; detect interrupt mode (0 - IM0 or IM1, 1 - IM2)

	ld	a,3Dh
	ld	i,a
	xor	a
	ei
	halt
;	di				; useless, interrupt will set DI
	ld	(NmiIM),a

	im	1
	ei

	; display browser window

	call	BrowserRedraw

	; restore videoram

NmiRet	ld	a,2
	di
	out	(DIV_CTRL),a

	ld	hl,2400h
	ld	de,4000h
	ld	bc,6912
	ldir

	xor	a
	ei
	out	(DIV_CTRL),a

	halt				; interrupt sync
	di

	; restore AY registers

	ld	hl,SysAY
	rst	30h
	dw	LoadAY

	; restore context

	ld	a,(NmiI)
	ld	i,a
	ld	a,(NmiIM)
	im	1
	or	a
	jr	z,NmiInt
	im	2

NmiInt	ld	a,(NmiIFF)
	or	a
	ld	hl,OutEI
	jr	nz,NmiJP
	inc	l

NmiJP	ld	a,0C3h
	ld	(SysTemp1),a
	ld	(SysTemp1 + 1),hl

	; TO DO: R register stuff

	ld	sp,NmiIY
	pop	iy
	pop	ix
	pop	hl
	pop	de
	pop	bc
	pop	af
	ex	af,af'
	exx
	pop	hl
	pop	de
	pop	bc
	pop	af
	ld	sp,(NmiSP)
	jp	SysTemp1

;-------------------------------------------------------------------------------
; SMALL UTILITY FUNCTIONS TO EFFICIENTLY FILL UP ROM SPACE
;-------------------------------------------------------------------------------

;-------------------------------------------------------------------------------
StrCmpNoCase:
;-------------------------------------------------------------------------------
; DE - address of string 1
; HL - address of string 2 (this string must be already upper cased!)
;-------------------------------------------------------------------------------
; Output:
; z = 1        - string 1 == string 2
; z = 0, c = 1 - string 1 <= string 2
; z = 0, c = 0 - string 1 >= string 2
;-------------------------------------------------------------------------------

	ld	a,(de)
	or	a
	jr	z,$f
	inc	de
	call	UpperCase
	cp	(hl)
	inc	hl
	jr	z,StrCmpNoCase
	ret
$$	cp	(hl)
	ret

;-------------------------------------------------------------------------------
UpperCase:
;-------------------------------------------------------------------------------

	ld	c,a
	sub	'a'
	cp	26
	sbc	a,a
	and	20h
	xor	c
	ret

;-------------------------------------------------------------------------------
; ROM ENTRY POINT: SAVE
;-------------------------------------------------------------------------------

	org	4C6h

	ld	hl,1F80h		; ZX ROM instrucion
In4C6h	push	hl
	ld	hl,In4C6h
	ex	(sp),hl
	jp	OutRET

;-------------------------------------------------------------------------------
; ROM ENTRY POINT: LOAD
;-------------------------------------------------------------------------------
; IX - input address
; DE - number of bytes to read
; A - flag byte
; c = 1 / c = 0 - load / verify
;-------------------------------------------------------------------------------

	org	562h

	; TODO: interrupt mode detection and setting IM 1

	in	a,(254)			; ZX ROM instruction

	ld	a,(BORDCR)		; attempt to restore border colour
	rra
	rra
	rra
	and	7
	out	(254),a

	; TODO: check mode (real tape, from TAP, as raw etc.)

	; is there a TAP file descriptor opened?

	ld	hl,(SysTapFD)
	ld	a,h
	or	l
	jr	nz,TapVerf

	; no, fall back to ZX ROM loading routine

	ld	hl,564h
	push	hl
	in	a,(254)
	jp	OutRET

	; if it's VERIFY just return OK

TapVerf	ex	af,af'
	jr	c,TapCont

	add	ix,de
	ld	de,0
	scf
	jp	OutRET

	; save important input values

TapCont	ld	(SysTapIX),ix
	ld	(SysTapDE),de
	ld	(SysTapA),a

	; test for BREAK (prevent infinite tape looping)

TapBrk	ld	a,127
	in	a,(254)
	rra
	jr	nc,TapRet

	; load block length and flag byte

	ld	iy,(SysTapFD)
	ld	hl,SysTapLength
	ld	de,3
	rst	30h
	dw	FileRead
	jr	c,TapErr

	; less than 3 bytes read means end of TAP file

	ld	a,l
	cp	3
	jr	nc,TapZero

	; rewind tape on EOF (this doesn't cause disc access)

	xor	a
TapRwnd	ld	b,a
	ld	c,a
	ld	d,a
	ld	e,a
	rst	30h
	dw	FileSeek
	jr	TapBrk

	; some ugly TAP files have zero padding, rewind them

TapZero	ld	de,(SysTapLength)
	ld	a,d
	or	e
	dec	de
	jr	z,TapRwnd

	; check the flag byte

	ld	a,(SysTapA)
	ld	hl,SysTapFlag
	cp	(hl)
	jr	z,TapLoad

	; wrong flag byte, seek to the next tape block and return error

	xor	a
	ld	b,a
	ld	c,a
	inc	a
	rst	30h
	dw	FileSeek
	jr	nc,TapRet

	; close TAP file because file pointer will likely be inconsistent

TapErr	rst	30h
	dw	FileClose
	xor	a
	ld	h,a
	ld	l,a
	ld	(SysTapFD),hl

TapRet	ld	hl,107Fh
	exx
	ld	ix,(SysTapIX)
	ld	de,(SysTapDE)
	ld	iy,5C3Ah
	jp	OutRET

	; flag byte OK, load min(DE, TapeLength - 2) bytes

TapLoad	dec	de
	ld	hl,(SysTapDE)
	sbc	hl,de
	jr	nc,TapMin
	add	hl,de
	ex	de,hl

TapMin	ld	hl,(SysTapIX)
	rst	30h
	dw	FileRead
	jr	c,TapErr

	; read block checksum

	push	hl			; save number of bytes actually read
	ld	hl,SysTapChecksum
	ld	de,1
	rst	30h
	dw	FileRead
	pop	de
	jr	c,TapErr

	; advance emulated counters

	ld	hl,(SysTapDE)
	sbc	hl,de
	ld	(SysTapDE),hl
	ld	hl,(SysTapIX)
	push	hl
	add	hl,de
	ld	(SysTapIX),hl

	; move to the next tape block (skip possible trailing bytes)

	ld	hl,(SysTapLength)
	dec	hl			; skip flagbyte we already read
	scf				; skip also checksum
	sbc	hl,de

	push	de
	xor	a
	ld	b,a
	ld	c,a
	ex	de,hl
	inc	a
	rst	30h
	dw	FileSeek		; we may seek even 0 bytes
	pop	bc
	pop	hl
	jr	c,TapErr

	; now that file pointer is OK, calculate block checksum

	ld	a,(SysTapFlag)
TapSum	xor	(hl)
	cpi
	jp	pe,TapSum

	; return OK if checksums match

	ld	hl,SysTapChecksum
	xor	(hl)
	scf
	jr	z,TapRet

	; return error if block fits entirely in RAM

	dec	hl
	ld	a,h
	cp	64
	jr	nc,TapRet

	; part of block loaded to ROM - assume it was OK as we can't checksum

	scf
	jr	TapRet

;-------------------------------------------------------------------------------
ImageViewer:
;-------------------------------------------------------------------------------

	; delay so that scanline switch is somewhere in border

	pop	af
	ex	(sp),hl
	ex	(sp),hl
	ex	(sp),hl
	ex	(sp),hl

	; one iteration has 228 T (the length of one scanline on 128k machines)

ImgLoop	ex	de,hl
	out	(c),e
	ld	d,12
$$	dec	d
	jr	nz,$b
	nop
	dec	a
	jp	nz,ImgLoop
	ei
	ret

;-------------------------------------------------------------------------------
Startup:
;-------------------------------------------------------------------------------

	; DO WHATEVER GUI ETC. HAS TO DO ON INIT

	xor	a
	ld	(SysViewerFlag),a	; just for the case of reset during SCR viewer ???!????!?

	call	InitGui			; will be in bank 3

	; boot finished, perform ZX ROM reset

	ld	hl,1
	ld	a,l
	ld	(SysBootOK),a
	jp	OutJPHL

;-------------------------------------------------------------------------------
SnaRead:
;-------------------------------------------------------------------------------

	ld	hl,SnaI
	ld	de,27
	rst	30h
	dw	FileRead
	jr	c,SnaClos

	ld	hl,16384
	ld	de,49152
	rst	30h
	dw	FileRead

SnaClos	rst	30h
	dw	FileClose		; MUST NOT CHANGE CARRY !!!
	ret

;-------------------------------------------------------------------------------
LoadSNA:
;-------------------------------------------------------------------------------
; Input:
; IY - file descriptor address
;-------------------------------------------------------------------------------
; Output (if returns):
; c = 0 - wrong file format
; c = 1 - read error
;-------------------------------------------------------------------------------

	ld	e,(iy + fdSize + 0)
	ld	d,(iy + fdSize + 1)
	ld	c,(iy + fdSize + 2)
	ld	b,(iy + fdSize + 3)

	ld	a,b
	or	c
	jr	nz,SnaLong

	ld	hl,49179
	sbc	hl,de
	jr	z,Sna48k
SnaBad	or	a
	jr	SnaClos

SnaLong	dec	c
	dec	c
	ld	a,c
	or	b
	jr	nz,SnaClos

	ld	hl,401Fh
	sbc	hl,de
	add	hl,de
	jr	z,Sna128k
	xor	a
	ld	h,a
	sbc	hl,de
	jr	nz,SnaBad

	; load 128k snapshot

Sna128k	ld	de,49179		; BC = 0
	rst	30h
	dw	FileSeek
	jr	c,SnaClos

	ld	hl,SnaPC
	ld	de,4
	rst	30h
	dw	FileRead
	ret	c

	ld	bc,7FFDh
	ld	d,0
SnaLoop	ld	a,d
	cp	2
	jr	z,SnaNext
	cp	5
	jr	z,SnaNext
	ld	a,(SnaPage)
	and	7
	cp	d
	jr	z,SnaNext
	out	(c),d

	push	bc
	push	de
	ld	hl,49152
	ld	de,16384
	rst	30h
	dw	FileRead
	pop	de
	pop	bc
	jr	c,SnaClos

SnaNext	inc	d
	bit	3,d
	jr	z,SnaLoop

	ld	a,(SnaPage)
	out	(c),a

	; now read file from the start as usual 48k snapshot

	xor	a
	ld	b,a
	ld	c,a
	ld	d,a
	ld	e,a
	rst	30h
	dw	FileSeek

	call	SnaRead
	ret	c

	ei				; interrupt sync
	halt
	di

	; push PC on snapshot's stack

	ld	hl,(SnaPC)
	ld	sp,(SnaSP)
	push	hl
	ld	(SnaSP),sp
	jr	SnaRun

Sna48k	ld	bc,7FFDh
	ld	a,16
	out	(c),a

	call	SnaRead
	ret	c

	ei				; interrupt sync
	halt
	di

SnaRun	ld	a,(SnaBord)
	out	(254),a

	ld	a,(SnaI)
	ld	i,a
	ld	a,(SnaIM)
	im	0
	or	a
	jr	z,$f
	im	1
	dec	a
	jr	z,$f
	im	2

$$	ld	a,(SnaIFF)
	or	a
	ld	hl,OutEI
	jr	nz,$f
	inc	l
$$	ld	a,0C3h
	ld	(SysTemp1),a
	ld	(SysTemp1 + 1),hl

	ld	sp,SnaHL2
	pop	hl
	pop	de
	pop	bc
	pop	af
	ex	af,af'
	exx
	pop	hl
	pop	de
	pop	bc
	pop	iy
	pop	ix
	pop	af
	pop	af
	ld	sp,(SnaSP)
	jp	SysTemp1

;-------------------------------------------------------------------------------
Z80GetByte:
;-------------------------------------------------------------------------------
; c = 1 - read error
; c = 0, z = 1 - end of stream
; c = 0, z = 0 - byte is valid
;-------------------------------------------------------------------------------

	inc	l
	ret	nz

	push	bc
	push	de
	push	hl
	ld	de,256
	rst	30h
	dw	FileRead
	pop	hl
	pop	de
	pop	bc
	ret	nc

Z80Exit	ld	sp,(Z80SaveSP)
	rst	30h
	dw	FileClose
	ret

;-------------------------------------------------------------------------------
LoadZ80:
;-------------------------------------------------------------------------------
; Input:
; IY - file descriptor address
;-------------------------------------------------------------------------------
; Output (if returns):
; c = 0 - wrong file format
; c = 1 - read error
;-------------------------------------------------------------------------------

	ld	(Z80SaveSP),sp

	ld	hl,Z80Header
	ld	de,30
	rst	30h
	dw	FileRead
	jr	c,Z80Exit

	; correction 255 -> 1 (we ignore bit 0 as bit 7 of R though)

$$	ld	a,(Z80Header + 12)
	inc	a
	jr	z,$f
	dec	a
	rra
	and	7
$$	out	(254),a

	; determine Z80 version

	ld	hl,(Z80Header + 6)
	ld	a,h
	or	l
	jr	z,Z80v23

	; it's version 1 snapshot

	ld	bc,7FFDh
	ld	a,16
	out	(c),a
	ld	(Z80Header + 35),a	; hack header for 48k snap on 128k machine

	ld	hl,Z80Stream + 255
	ld	de,4000h
	ld	c,e
	call	Z80Depack
	jp	Z80Stat

	; version 2 and version 3 snapshots; read additional header

Z80v23	ld	hl,Z80Header + 30
	ld	de,2
	rst	30h
	dw	FileRead
	jr	c,Z80Exit

	ld	hl,Z80Header + 32
	ld	de,(Z80Header + 30)
	rst	30h
	dw	FileRead
	jr	c,Z80Exit

	; loop and read pages according to hardware mode

	ld	hl,Z80Stream + 255
Z80Loop	call	Z80GetByte
	ld	c,(hl)
	call	Z80GetByte
	ld	b,(hl)
	push	bc
	ld	bc,7FFDh

	; determine page number and address (depends on Z80 version)

	ld	a,(Z80Header + 30)
	cp	54			; sets NC for v3 snapshot
	sbc	a,a			; v2:-1, v3: 0
	add	a,4			; v2: 3, v3: 4
	ld	e,a
	ld	a,(Z80Header + 34)
	cp	2			; unsupported hardware mode (SamRAM)
	jr	z,Z80Exit		; Carry = 0
	cp	e
	jr	c,Z80k48
	cp	11			; Didaktik M / Kompakt
	jr	z,Z80k48
	cp	14			; Timex TC2048
	jr	z,Z80k48
	cp	15			; Timex TC2068
	jr	z,Z80k48
	cp	128			; Timex TS2068
	jr	nz,Z80k128

	; it's a 48k page, set address

Z80k48	ld	a,16
	out	(c),a
	ld	(Z80Header + 35),a	; hack header for 48k snap on 128k machine

	; skip other pages than 4, 5, 8 in 48k snapshot

	call	Z80GetByte
	ld	a,(hl)
	sub	4
	jr	c,Z80Skip

	ld	de,8000h
	ld	c,0C0h
	jr	z,Z80Page

	dec	a
	ld	d,c
	ld	c,e
	jr	z,Z80Page

	sub	3
	ld	d,40h
	ld	c,80h
	jr	z,Z80Page

Z80Skip	pop	bc
	ld	a,b
	and	c
	inc	a
	jr	nz,$f
	ld	bc,4000h

$$	call	Z80GetByte
	dec	bc
	ld	a,b
	or	c
	jr	nz,$b
	jr	Z80Next

	; it's a 128k page number (TODO: check if we are running on 128k machine)

Z80k128	call	Z80GetByte
	ld	a,(hl)
	sub	3			; TODO: check multiface ROM and skip to end
	jr	c,Z80Skip		; skip pages < 3
	cp	8
	jr	nc,Z80Skip		; skip pages > 10

	or	16
	out	(c),a
	ld	de,0C000h
	ld	c,e

	; we don't want to destroy C register here

Z80Page	ex	(sp),hl
	ld	a,h
	and	l
	inc	a
	pop	hl
	jr	nz,Z80Pack

	; read raw (uncompressed) block

$$	call	Z80GetByte
	ld	a,(hl)
	ld	(de),a
	inc	de
	ld	a,d
	cp	c
	jr	nz,$b
	jr	Z80Next

	; read compressed block

Z80Pack	call	Z80Depack
Z80Next	push	hl
	rst	30h
	dw	IsEOF
	pop	hl
	jp	nz,Z80Loop

	; restore machine state

Z80Stat	rst	30h
	dw	FileClose

	; interrupt sync

	ei
	halt
	di

	; restore AY state for v2 and v3 snapshots

	ld	hl,(Z80Header + 6)
	ld	a,h
	or	l
	jr	nz,$f

	ld	hl,Z80Header + 39
	rst	30h
	dw	LoadAY			; C = FDh
	ld	b,0FFh
	ld	a,(Z80Header + 38)
	out	(c),a

	; TODO: port 1FFDh

$$	ld	bc,7FFDh
	ld	a,(Z80Header + 35)
	out	(c),a			; this is why we hack 48k header

	ld	a,(Z80Header + 10)
	ld	i,a
	ld	a,(Z80Header + 29)
	and	3
	im	0
	jr	z,$f
	im	1
	dec	a
	jr	z,$f
	im	2

$$	ld	a,(Z80Header + 27)
	or	a
	ld	hl,OutEI
	jr	nz,$f
	inc	l
$$	ld	a,0C3h
	ld	(SysTemp1),a
	ld	(SysTemp1 + 1),hl

	; set registers

	ld	sp,Z80Header + 15
	pop	bc
	pop	de
	pop	hl
	exx
	pop	bc
	dec	sp
	pop	af
	dec	sp
	ld	a,c
	ex	af,af'
	pop	iy
	pop	ix

	; pick proper PC

	ld	de,(Z80Header + 6)
	ld	a,d
	or	e
	jr	nz,$f
	ld	de,(Z80Header + 32)

$$	ld	sp,Z80Header
	pop	bc
	dec	sp
	pop	af
	dec	sp
	ld	a,c
	pop	bc
	pop	hl

	ld	sp,(Z80Header + 8)
	push	de
	ld	de,(Z80Header + 13)
	jp	SysTemp1

;-------------------------------------------------------------------------------
Z80Depack:
;-------------------------------------------------------------------------------
; Input:
; DE = output address
; C = higher byte of address of the next 16k block
;-------------------------------------------------------------------------------

	ld	a,d
	cp	c
	ret	z

	call	Z80GetByte
	ld	a,(hl)
	cp	0EDh
	jr	z,$f

Z80Byte	ld	(de),a
	inc	de
	jr	Z80Depack

	; it might have been the last byte of input stream

$$	inc	de
	ld	a,d
	dec	de
	cp	c
	jr	z,$f

	call	Z80GetByte
	ld	a,0EDh
	cp	(hl)
	jr	z,Z80Run

	ld	(de),a
	inc	de
$$	ld	a,(hl)
	jr	Z80Byte

Z80Run	call	Z80GetByte
	ld	b,(hl)
	call	Z80GetByte
	ld	a,(hl)
$$	ld	(de),a
	inc	de
	djnz	$b
	jr	Z80Depack

;-------------------------------------------------------------------------------
LoadSCR:
;-------------------------------------------------------------------------------
; Input:
; IY - file descriptor address
;-------------------------------------------------------------------------------
; Output (if returns):
; c = 0 - OK
; c = 1 - read error or wrong file format
;-------------------------------------------------------------------------------

	ld	a,(iy + fdSize + 2)
	or	(iy + fdSize + 3)
	jr	nz,ScrClos

	ld	l,(iy + fdSize + 0)
	ld	h,(iy + fdSize + 1)
	ld	bc,6912
	sbc	hl,bc
	jr	z,Scr1
	sbc	hl,bc
	jr	z,Scr2
	scf
	jr	ScrClos

Scr1	call	ScrLoad
	ret	c
	jp	WaitForKey
;	call	WaitForKey
;	ret

Scr2	ld	bc,7FFDh
	ld	a,23
	out	(c),a

	ld	hl,49152
	ld	de,6912
	push	bc
	rst	30h
	dw	FileRead
	pop	bc
	jr	c,ScrClos

	ld	a,16
	out	(c),a
	push	bc
	call	ScrLoad
	pop	bc
	ret	c

	; show picture

	ld	e,16
	ld	l,24
$$	ld	a,255
	ld	(SysViewerFlag),a
	halt
	out	(c),e			; restore videoram 0 in case of key press
	exx
	call	ReadKey
	exx
	jr	z,$b

	ld	a,16
	out	(c),a
	ld	(SysViewerFlag),a
	ret

ScrLoad	ld	hl,16384
	ld	de,6912
	rst	30h
	dw	FileRead
ScrClos	rst	30h
	dw	FileClose		; MUST NOT CHANGE CARRY !!!
	ret

;-------------------------------------------------------------------------------
; GUI routines
;-------------------------------------------------------------------------------

	include	"gui.asm"

TxtNULL		db	0

	org	1FE1h			; calculated to fill up space at end

;-------------------------------------------------------------------------------
CallBank:
;-------------------------------------------------------------------------------

	ld	e,(hl)
	inc	hl	
	ld	d,(hl)
	inc	hl
	ex	(sp),hl
	call	PrepDE

PageOut	push	af
	ld	a,80h			; 40h in the EEPROM bank
	out	(DIV_CTRL),a
	pop	af
	ret

PrepDE	push	de
	ld	de,(SysTemp1)
	jr	PageOut

;-------------------------------------------------------------------------------
; ROM EXIT POINTS
;-------------------------------------------------------------------------------

	org	1FF7h

OutEI	ei
OutRET	ret
OutJPHL	jp	(hl)

	org	1FFEh

RomSign	db	0, 14			; ROM signature



;-------------------------------------------------------------------------------
; BANK 3 SYSTEM VARIABLES
;-------------------------------------------------------------------------------

	org	3800h

Z80Stream	ds	256		; Z80 snapshot stream cache
BrwPageHistory	ds	256		; browser page buffer
BrwEntryCache	ds	256		; browser dir entry cache

; NMI context structure

NmiIFF	db	0	; iff
NmiIM	db	0	; interrupt mode
NmiR	db	0	; R
NmiI	db	0	; I
NmiSP	dw	0	; SP
NmiIY	dw	0	; IY
	dw	0	; IX
	dw	0	; HL'
	dw	0	; DE'
	dw	0	; BC'
	dw	0	; AF'
	dw	0	; HL
	dw	0	; DE
	dw	0	; BC
	dw	0	; AF

SysTapFD	dw	0		; current tape file descriptor address
SysTapIX	dw	0
SysTapDE	dw	0
SysTapA		dw	0
SysTapLength	dw	0		; current tape block length
SysTapFlag	db	0		; current tape block flag byte
SysTapChecksum	db	0		; current tape block checksum

SysViewerFlag	db	0


; SNA snapshot structure

SnaI	db	0
SnaHL2	dw	0
SnaDE2	dw	0
SnaBC2	dw	0
SnaAF2	dw	0
SnaHL	dw	0
SnaDE	dw	0
SnaBC	dw	0
SnaIY	dw	0
SnaIX	dw	0
SnaIFF	db	0
SnaR	db	0
SnaAF	dw	0
SnaSP	dw	0
SnaIM	db	0
SnaBord	db	0
SnaPC	dw	0			; 128k snapshot specific values
SnaPage	db	0
SnaTRD	db	0

; Z80 header

Z80SaveSP	dw	0
Z80Header	ds	87		; (30 + 2 + 55) TODO: merge it with SNA?

; menu-related system variables

MnuRowAddr	dw	0
MnuColumnAddr	dw	0
MnuRowCount	db	0
MnuTextWidth	db	0
MnuAttrAddr	dw	0

MnuFirstItem	db	1
MnuLastItem	db	16

MnuPos		db	0
MnuCursorAddr	dw	0
MnuAttrBuf	dw	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0;, 0
MnuBuffer	ds	24		; buffer for dynamic menus

; GUI layer system variables

GuiPrevKey	db	0		; these 2 variables must be in this order
GuiKeyDelay	db	0
PokePrevKey	db 0
PokeKeyDelay	db	0
PokeAddr		dw 0
PokeVal		db 0
PokeCursor	dw 0
PokeOldCursor	dw 0
PokeAddrStr	db "00000",0
PokeValStr	db "000",0
TempStr	db	"                               "

; Disc Browser variables

BrwEntryAddr	dw	0
BrwPagePos	dw	0
SelVolPos	db	0

