;    ZXZVM: Z-Code interpreter for the Z80 processor
;    Copyright (C) 1998-9,2006,2016  John Elliott <seasip.webmaster@gmail.com>
;
;    This program is free software; you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation; either version 2 of the License, or
;    (at your option) any later version.
;
;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.
;
;    You should have received a copy of the GNU General Public License
;    along with this program; if not, write to the Free Software
;    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

; 2006, Garry Lancaster: New file, refactored from zxp3dos.zsm and zxio.zsm
; 2018-03-02, Garry Lancaster: Changed Spectrum version detection
; 2018-03-02, Garry Lancaster: Don't do DOS_INIT at exit (messes drives/paths)
; 2018-03-06, Garry Lancaster: Bugfix: mark story file as open
; 2018-03-06, Garry Lancaster: Improve error reporting from dodos
; 2018-03-07, Garry Lancaster: Allow BASIC to continue after graceful exit

; +3-specific routines.

;Spectrum addresses between 4000h and 0BFFFh always refer to the same area
;of memory. Those above 0C000h can refer to one of eight memory banks, so
;I'll write them as 0:C000 to 7:C000. Memory banks 2 and 5 mirror what is
;in memory below 0C000h, so they aren't very useful. Addresses below 4000h
;can refer to one of four ROMS, so I'll write them as R0:0000 to R3:0000.
;
;The I/O subsystem lives in the Spectrum's screen RAM (so I can be sure that
;code which needs to bank switch is below 0BFE0h). Thus screen output goes
;to the shadow screen at 7:C000, which can be switched out when not needed.
;
;A bug in +3DOS necessitates the following workaround:
;
; - Despite what it says in the manual, it is necessary to have at least 
;  one buffer in the disc cache, or files are read incorrectly. So put the
;  cache at the top of Bank 6, and run the interpreter with Bank 6 paged. 
;  The game file then loads in the 1,3,4,0 environment.
;
; - Although this was forced on me by +3DOS, I might have done it anyway;
;  my previous plan (game in 1,3,4,6) would have meant implementing my own
;  cache manually, a nasty business.

	org	ZJT

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;Other source files
;
	include zxio.zsm	;ZX I/O - must come first
	include zxp3dos.zsm     ;+3DOS specific functions
	include zxvers.zsm	;Get Spectrum version
	include zx64.zsm	;64-column printing	
	include in_wrhex.inc	;Render numbers into hex or decimal

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;
;Spectrum system variables:
;
ONERR	EQU	5B3Ah	;Memory paging subroutine used in reporting errors
BANKM	EQU	5B5Ch	;Memory paging latch
OLDSP	EQU	5B6Ah	;Saved stack pointer used while BASIC is calling +3DOS
SYNRET  EQU     5B6Ch   ;Return address for ONERR
PRAMT	EQU	5CB4H	;Top of physical memory
BANKIO  EQU     7FFDh   ;I/O port for memory paging

SAVEPG 	EQU	6 ; memory page for savefile
HDRADDR	EQU	0C000h
SCRADDR	EQU	0C000h

typeset	EQU	070ffh	; poked by BASIC to 0 or 1

;
;Enter a filename
;
NAMEBUF:
	DEFS	20
FNBUF:	DEFS	20
FNAME$:	DEFB	13,10,'Filename> $'

GNAME:	
;
	LD	DE,FNAME$
	LD	C,9
	CALL	ZXFDOS
	LD	A,3	;Z-address 4000h
	CALL	SELMEM
	LD	DE,NAMEBUF
	LD	HL,0C000h
	LD	BC,20
	LDIR		;Backup Z-machine memory at 4000h
	LD	HL,0C000h
	LD	(HL),16	;Max. 16 characters in name
	INC	HL
	LD	(HL),0	;None provided
	LD	A,6
	CALL	SELMEM
	LD	DE,0
	LD	HL,4000h	;Filename buffer
	CALL	LINEINP
	LD	A,3
	CALL	SELMEM
	LD	DE,FNBUF
	LD	HL,0C000h
	LD	BC,20
	PUSH	BC
	PUSH	HL
	LDIR	
	POP	DE
	POP	BC		;Length of buffer
	LD	HL,NAMEBUF
	LD	DE,0C000h
	LDIR			;Original contents of buffer
	LD	HL,FNBUF+1
	LD	E,(HL)
	LD	D,0
	INC	HL
	ADD	HL,DE
	LD	(HL),0FFh	;FFh-terminated filename string
	LD	A,6
	CALL	SELMEM
	LD	HL,FNBUF+2
	LD	A,E		;<< v1.01  A = length of input
	OR	A
	SCF			; If it's 0, then no name was input.
	RET	NZ
	CCF			;>> v1.01
	RET

;
; Chime an error
;
CHIME:	CALL	PUSHA
	LD	DE,0E00H
	LD	HL,CHIMEBF
	LD	BC,0FFFDH
CHIME1:	LD	A,(HL)
	OUT	(C),E
	LD	B,0BFH
	OUT	(C),A
	LD	B,0FFH
	INC	HL
	INC	E
	DEC	D
	JP	Z,POPA
	JR	CHIME1
;
CHIMEBF:
	DEFW	01A6H,014FH,011AH
	DEFB	0,78H,10H,10H,10H,0,8,0,0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;Utility function to call +3DOS.
;This takes an inline word parameter, the address within +3DOS
;that should be called.
;
dodos:	ld	(dosde),de
	ex	(sp),hl
	ld	e,(hl)
	inc	hl
	ld	d,(hl)
	inc	hl
	ex	(sp),hl
	ld	(dosjmp + 1),de
	ld	de,(dosde)
	call	seldos
dosjmp:	call	0
	call	sel48
	ret	c
	pop	hl	;HL=address after call
	push	hl
	push	af	;Error no.
	ld	de,p3retm
	call	sphex4	;4-digit hex
	pop	af
	push	af	;Error no.
	ld	l,a
	ld	h,0
	ld	de,p3eno
	call	spdec2	;2-digit
	ex	de,hl
	dec	hl
	set	7,(hl)	 ;Set bit 7 on last character, since this is a 
	ld	hl,p3der ;fatal error message
	pop	af
	ret
;
;One message (not really very informative)
;
p3der:  defb    '(ret='
p3retm:	defb	'0000) +3DOS error '
p3eno:  defb    '00000'

;
;Bank-switching code to take us to/from the +3DOS environment
;
seldos:	push	af
	push	bc
	ld	a,(bankm)
	res	4,a
	or	7
	ld	bc,bankio
	di
	ld	(bankm),a
	out	(c),a
	ei	
	pop	bc
	pop	af
	ret
;
sel48:	push    af
        push    bc
        ld      a,(bankm)
	set	4,a
        and	0F8h
        ld      bc,bankio
        di
        ld      (bankm),a
        out     (c),a
        ei
        pop     bc
        pop     af
        ret
;
FLAGS3	equ	23398	;<< v1.03 >> System variable holding no. of drives

;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
dosinit:
;
;Disable the disc cache and the RAMdisc. We need the space for the 
;Z-machine's memory.
;
	call	dodos
	defw	GET_1346
	ld	(old_1346),de
	ld	(old_1346+2),hl
	ld	hl,7F00h	;No RAMdisc
;
;+3DOS bug workaround: Unless at least one cache buffer is allocated, the
;disc routines get directory data mixed up with file data. The cache also
;means faster access to the bits of the Z-code file not loaded in 1/3/4/0.
; 
	ld	de,6020h	;Allow 16k for disc cache. This should speed
	call	dodos		;up access of paged memory.
	defw	SET_1346
	ret	nc
	call	dodos
	defw	DOS_VERS
	ld	(p3dver),de
;
; << v1.03 Point the CHANGE DISK callback at us.
;
	ld	c,0		;One drive
	ld	a,(FLAGS3)
	bit	5,a
	jr	z,setcv
	inc	c		;Two drives
setcv:	ld	a,c
	ld	(unit_b),a
	ld	hl,chgsub
	call	dodos		;Map B: to whatever it's mapped to anyway.
	defw	DOS_MAPB
;
; >> v1.03
;
	scf
	ret
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
dosunit:
;
;Restore the cache and the RAMdisc.
;
	ld	hl,(old_1346+2)
	ld	de,(old_1346)
	call	dodos
	defw	SET_1346
	ld	a,(unit_b)	;<< v1.03 reverse CHANGE DISK code
	ld	c,a
	ld	hl,(chgdsk)	;+3BASIC "Change disk" routine
	call	dodos
	defw	DOS_MAPB	;>> v1.03
	ret
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Ask the user to change the disc
;
chgsub:
	ld	(chgms1),a

	call	sel48		;Switch to 48 BASIC ROM for keyboard input
	ld	de,chgmsg
	call	print
chgs1:	call	con6
	and	a
	jr	z,chgs1
	ld	e,0Dh
	call	opchar		;Carriage return
	ld	e,' '
	ld	b,63
	call	string$
	ld	e,0Dh
	call	opchar

	jp	seldos		;Go back to +3DOS 
;
chgmsg:	defb	13,10,'Please insert the disc for '
chgms1:	defb	'Z: and press ENTER',13,'$'

chgdsk:	defw	0	;Original CHANGE DISK routine
unit_b:	defb	0	;Drive B is unit 0 or 1?
old_1346:
	defw	0	;Original cache and RAMdisc settings
	defw	0
p3dver:	defw	0	;The version of +3DOS we are using
dosde:  defw    0	;Used to store DE while entering +3DOS

;
;Read/write BC bytes of z-machine memory at HL.
;
p3rmem:	ld	a,b
	or	c
	scf
	ret	z
	ld	d,b
	ld	e,c	;DE = no. of bytes to read
p3rm1:	push	hl
	push	de
	call	blkadd	;Returns HL = block base, DE = block lenth, C=bank
	push	de
	ld	b,SAVENO
	call	dodos
	defw	DOS_READ
	jr	nc,p3rend
	pop	bc	;BC = no. of bytes read
	pop	hl	;HL = total bytes to transfer
	and	a
	sbc	hl,bc	;HL = bytes left to transfer
	jr	c,p3re2
	jr	z,p3re2	;End of transfer
	ex	de,hl	;DE = no. of bytes left to transfer
	pop	hl
	add	hl,bc	;HL = new base address
	jr	p3rm1
;
p3wmem: ld	a,b
	or	c
	scf
	ret	z
	ld      d,b
        ld      e,c     ;DE = no. of bytes to write
p3wm1:  push    hl
        push    de
        call    blkadd  ;Returns HL = block base, DE = block lenth, C=bank
        push    de
        ld      b,SAVENO
        call    dodos
        defw    DOS_WRITE
        jr      nc,p3rend
        pop     bc      ;BC = no. of bytes read
        pop     hl      ;HL = total bytes to transfer
        and     a
        sbc     hl,bc   ;HL = bytes left to transfer
        jr      c,p3re2
        jr      z,p3re2 ;End of transfer
        ex      de,hl   ;DE = no. of bytes left to transfer
        pop     hl
        add     hl,bc   ;HL = new base address
        jr      p3wm1
;
p3re2:	pop	de
	scf
	ret
;
p3rend:	pop	de	;Read failed
	pop	de
	pop	de
	ret
;
blkadd:	ld	a,h	;Let HL = true address of block, C the bank it is in,
	rlca		;    DE = amount of block within this bank.
	rlca		;A = 0 - 3, bank number
	and	3
	inc	a	;A is 1, 2, 3, 4
	cp	1
	jr	z,blkad1
	inc	a	;A is 3, 4 or 5
	cp	5
	jr	nz,blkad1
	xor	a
blkad1:	ld	c,a	;C is bank - 1, 3, 4, 0
	push	hl
	ld	a,h
	and	03Fh	;Limit HL to 14 bits
	ld	h,a	;<< v0.02 >> arithmetic bug fix
	push	de	;DE = length of block
	ld	de,4000h
	and	a
	ex	de,hl	;<< v0.02 >> arithmetic bug fix
	sbc	hl,de	;HL = max length in this bank
	pop	de	;DE = length of block
	ld	a,h
	cp	d
	jr	nc,blkad2	;If HL >= DE, return DE
	ld	a,l
	cp	e
	jr	nc,blkad2
	ex	de,hl		;DE = length to read/write
blkad2:	pop	hl		;HL = base address
	ld	a,h
	or	0C0h
	ld	h,a
	ret	
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;Open the story file
;
st_open:
	ld	b,FILENO
	ld	c,05h	;Open read-only
	ld	de,2	;Open if exists, else complain
	call	dodos
	defw	DOS_OPEN
	ret	nc
	ld	a,1	;Mark story file as open
	ld	(STORY_FILE),a
	jr	st_op1
;
st_reload:
        ld      b,FILENO
        ld      de,0
	ld	hl,0
        call    dodos
        defw    SETPOS
st_op1:	ret	nc
	ld	c,1	;Load up to the first 64k of the file
	call	ldbank
	ret	nc
	ld	c,3
	call	ldbank
	ret	nc
	ld	c,4
	call	ldbank
	ret	nc
	ld	c,0
	call	ldbank
	ret
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Load 16k from the file into memory bank C
;
ldbank: ld	b,FILENO
	ld	de,4000h
	ld	hl,0C000h
	call	dodos
	defw	DOS_READ
	jr	c,rdok
	cp	25
	jr	z,rdok
	and	a
	ret
;
rdok:	scf
	ret

;
; Initialisation.
;
init1:	ld	(story),de
	ld	a,(typeset)	; choose typeset
	and	a
	ld	hl,set532
	jr	z,type32
	ld	hl,set564
type32:	ld	de,scrset5
	ld	bc,set564 - set532
	ldir
	call	vers
        ld      a,h
        cp      2               ; type 2: +3/+2a
	jr	z,init2
	ld	hl,reqp3
	xor	a
	ret

reqp3:	defb	'Spectrum +3 require'
	defb	0E4h	;'d'+80h

;
init2:	ld	hl,0FFFFh	;<< v1.12
	ld	(icpage),hl
	ld	(dcpage),hl	;>> v1.12 Init cache to empty 
	di
	ld	a,(bankm)
	and	0F8h		;Switch to bank 6 at the same time...
	or	0Eh		;Activate the shadow screen
	ld	bc,bankio
	di
	ld	(bankm),a
	out	(c),a
	ei
	call	dosinit		;Initialise +3DOS
	ret	nc
	call	erall		;Clear the screen
	ld	a,1
	ld	(cfont),a	;Set current font
	ld	de,signon
	call	print		;Sign on
	ld	hl,(story)
pslp:	ld	e,(hl)
	inc	e		;Print story name (FF-terminated)
	jr	z,pslend
	dec	e
	call	opchar
	inc	hl
	jr	pslp

pslend:	ld	de,sign1	;Second part of sign-on message
	call	print
	ld	hl,(story)
	call	st_open		;Load the story file
	ret	nc
	call	ZXCLS
	ld	a,6
	call	selmem
	scf
	ret
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
exit1:	push	af
	push	hl
	call	st_close	
	call	dosunit	;Undo anything we did to +3DOS
	pop	hl
	pop	af
	jp	nc,zxerr
	ld	hl,finished
	jp	zxret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
ICACHE	equ	6800h	; << v1.12 Instruction cache...
DCACHE	equ	6900h	;    ... and data cache 

icpage:	defw	0FFFFh
dcpage:	defw	0FFFFh
;
peek1:	jr	nc,peek2	;<< 1.12 Handle instruction fetches
	ld	a,e		;  a bit differently 
	and	a
	jr	z,peek64	; inst fetch in RAM = same
	ld	a,(icpage+1)
	cp	e
	jr	nz,icmiss
	ld	a,(icpage)
	cp	h
	jr	nz,icmiss
; Cache hit! Yay!
ichit:	push	de
	ld	de,ICACHE
chit:	push	hl
	ld	h,0	
	add	hl,de
	ld	a,(hl)
	pop	hl
	pop	de
	scf
	ret		;>> 1.12
;
peek2:	ld	a,e	;First 64k? If not, access file on disc
	and	a
	jr	z,peek64
peek3:	ld	a,(dcpage+1)
	cp	e
	jr	nz,dcmiss
	ld	a,(dcpage)
	cp	h
	jr	nz,dcmiss
dchit:	push	de
	ld	de,DCACHE
	jr	chit
	
peek64:	push	bc
	push	hl
;
; Inline zbank to save on pushes and pops
;
	ld	bc,bankio
	ld	a,h
        rlca
        rlca
        and     3       ;A = Z-machine bank, 0-3
        inc     a       ;A = 1-4
	cp	1
	jr	z,p64a
	inc	a	;A = 1, 3, 4 or 5
	cp	5
	jr	c,p64a
	xor	a 	;A = 1, 3, 4 or 0
p64a:	di
	or	8	;Shadow screen
	out	(c),a
	pop	hl
	push	hl
	ld	a,h
	or	0C0h
	ld	h,a	;HL = address
	ld	l,(hl)	; L = value
	ld	a,(bankm)
	out	(c),a
	ei
	ld	a,l
	pop	hl
	pop	bc	
	scf
	ret
;
; Cache miss. Load the cache with page EH.
;
icmiss:
        push    hl
	ld	hl,ICACHE
	ld	(CMADDR),HL
	pop	hl
	call	cmiss
	ld	a,e
	ld	(icpage+1),a
	ld	a,h
	ld	(icpage),a
	jr	ichit
;
dcmiss:
        push    hl
	ld	hl,DCACHE
	ld	(CMADDR),HL
	pop	hl
	call	cmiss
	ld	a,e
	ld	(dcpage+1),a
	ld	a,h
	ld	(dcpage),a
	jr	dchit
;
CMADDR:	defw	0
;
cmiss:	push	hl
        push    de
        push    ix
        push    bc
        ld      b,FILENO
        ld      d,0
	ld	l,0
        call    dodos
        defw    SETPOS
        jp      nc,st_err
        ld      b,FILENO
	ld	c,7	;Page doesn't matter, the cache is in low 48k.
	ld	de,256
	ld	hl,(CMADDR)
        call    dodos
        defw    DOS_READ
	jp	nc,st_err
	pop	bc
	pop	ix
	pop	de
	pop	hl
	ret
;
slowpw:	and	a
	call	peek1
	ld	b,a
	inc	hl
	ld	a,h
	or	l
	jr	nz,slowp1
	inc	e
slowp1:	and	a
	call	peek1
	inc	hl
	ld	c,a
	ld	a,h
	or	l
	jr	nz,slowp2
	inc	e
slowp2:	
	pop	af
	scf
	ret
;
peekw:	push	hl
	push	de
	call	ipeekw
	pop	de
	pop	hl
	ret
;
ipeekw:	push	af
	ld	a,e
	or	a	;Is the word in RAM?
	jr	nz,slowpw
	ld	a,l
	cp	0FFH	;Is there a chance the word might go across 2 pages?	
	jr	z,slowpw
;
;Read a word from the low 64k; we know it does not extend over a page boundary
;
        push    de
	push	hl
;
; Inline zbank to save on pushes and pops
;
	ld	bc,bankio
	ld	a,h
        rlca
        rlca
        and     3       ;A = Z-machine bank, 0-3
        inc     a       ;A = 1-4
	cp	1
	jr	z,p64wa
	inc	a	;A = 1, 3, 4 or 5
	cp	5
	jr	c,p64wa
	xor	a 	;A = 1, 3, 4 or 0
p64wa:	di
	or	8	;Shadow screen
	out	(c),a
	pop	hl
	push	hl
	ld	a,h
	or	0C0h
	ld	h,a	;HL = address
	ld	d,(hl)	
	inc	hl
	ld	e,(hl)	;DE = value
	ld	a,(bankm)
	out	(c),a
	ei
	ld	c,e
	ld	b,d	;Move value to BC
	pop	hl
	pop	de	;EHL = address
	inc	hl
	inc	hl
	ld	a,h	;<< v1.03 Check for rollover at FFFE -> 10000
	or	l
	jr	nz,fpw1
	inc	e
fpw1:			;>> v1.03
	pop	af
	scf
	ret
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
poke1:	push	hl
	push	de
	push	bc
	ld	d,a
	call	zbank
	ld	a,0c0h
	or	h
	ld	h,a	;HL |= 0C000h
	ld	(hl),d
	call	nbank
	pop	bc
	pop	de
	pop	hl
	scf
	ret

;
; Page header in and out.
;
headerin:
	ld	a,1
	jp	selmem

headerout:
	ld	a,6
	jp	selmem

;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
tmem1:	ld	hl,0bfffh	;Top of memory. The top 16k is a 
	ret			;disk cache; we may have to shrink this.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;Switch to the memory bank containing Z-address HL. Pushes the previous
;bank onto the stack.
;
zbank:	pop	bc	;Return address
	ld	a,(bankm)
	push	af
	push	bc
        and     0F8h    ;Only change the memory banking settings
        ld      c,a
        ld      a,h
        rlca
        rlca
        and     3       ;A = Z-machine bank, 0-3
        inc     a       ;A = 1-4
	cp	1
	jr	z,zbank1
	inc	a	;A = 1, 3, 4 or 5
	cp	5
	jr	c,zbank1
	xor	a 	;A = 1, 3, 4 or 0
zbank1:	or	c	
	ld	bc,bankio
	di
	ld	(bankm),a
	out	(c),a
	ret
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
nbank:	ld	l,a
	pop	bc	;Switch out of the Zmachine bank
	pop	af	;NOTE: pops 1 word off the stack
	push	bc
	ld	bc,bankio
	di
	ld	(bankm),a
	out	(c),a
	ei
	ld	a,l
	ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;Select memory bank in A
;
selmem:	push	af
	push	bc
	and	7
	ld	b,a
	ld	a,(bankm)
	and	0F8h	;Only change the bits we want to
	or	b
	ld	bc,bankio
	di
	ld	(bankm),a
	out	(c),a
	ei
	pop	bc
	pop	af
	ret
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
ZXERR:	ld	sp,(ERRSP)
ZXRET:	push	hl
	call	erall
	pop	de
	call	print7
	LD	IY,5C3AH	;Spectrum system veriables
	EI
	ld	a,$ff
	ld	(ERRNO),a
zxerr2:	call	con6
	or	a
	jr	z,zxerr2	; wait for a keypress
	di		;Switch back to the conventional screen
	ld	a,(bankm)
	and	0F0h
	ld	bc,bankio
	di
	ld	(bankm),a
	out	(c),a
	ei
	ret

	end

