From 7488f69ec28b2d061d6a25538769a2b6e77626ce Mon Sep 17 00:00:00 2001 From: Ivan Tatarinov Date: Sat, 12 Jun 2021 14:09:56 +0300 Subject: [PATCH] software/loadpzx: added `Makefile` --- software/Makefile | 3 +- software/loadpzx/.gitignore | 5 + software/loadpzx/Makefile | 81 ++ software/loadpzx/loadpzx.c | 1478 ++++++++++++++++++----------------- 4 files changed, 841 insertions(+), 726 deletions(-) create mode 100644 software/loadpzx/.gitignore create mode 100644 software/loadpzx/Makefile diff --git a/software/Makefile b/software/Makefile index 31f2fe0..603b388 100644 --- a/software/Makefile +++ b/software/Makefile @@ -32,7 +32,8 @@ SUBDIRS=\ esxdos\ iwconfig\ joyconf\ - keymap + keymap\ + loadpzx .PHONY: all all: build diff --git a/software/loadpzx/.gitignore b/software/loadpzx/.gitignore new file mode 100644 index 0000000..82e29a6 --- /dev/null +++ b/software/loadpzx/.gitignore @@ -0,0 +1,5 @@ +# SPDX-FileCopyrightText: 2021 Ivan Tatarinov +# +# SPDX-License-Identifier: CC0-1.0 + +build diff --git a/software/loadpzx/Makefile b/software/loadpzx/Makefile new file mode 100644 index 0000000..cc7a37e --- /dev/null +++ b/software/loadpzx/Makefile @@ -0,0 +1,81 @@ +# SPDX-FileCopyrightText: 2021 Ivan Tatarinov +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# Supported environments: +# * GNU on Linux, FreeBSD etc. +# * GNU on Windows NT (using MinGW/MSYS/Cygwin/WSL) +# +# Build: +# make [ ...] +# Install / Uninstall: +# make [prefix=] install | uninstall +# Clean: +# make clean | distclean +# +# where: +# is one of values for `BINS' variable prefixed with "build/" +# (see target `all' below). +# is a prefix directory to install files into. + +include ../../sdk/common.mk + +srcdir = . +# Use uppercase for FAT filesystem +prefix ?= . +exec_prefix ?= $(prefix) +bindir ?= $(exec_prefix)/BIN + +INSTALL ?= install +INSTALL_PROGRAM ?= $(INSTALL) +RM = rm -f + +BINS=\ + LOADPZX + +CC = sdcc +CFLAGS = -mz80 --reserve-regs-iy --opt-code-size --max-allocs-per-node 30000 +ESXDOS_ORG = 8192 +TMPS = + +.PHONY: all +all: $(foreach t,$(BINS),build/$(t)) + +build\ +$(DESTDIR)$(bindir): + mkdir -p $@ + +build/loadpzx.ihx: $(srcdir)/loadpzx.c | build + $(CC) $(CFLAGS) --nostdlib --nostdinc --no-std-crt0 --code-loc $(ESXDOS_ORG) --data-loc 12288 -o $@ $< +TMPS += $(foreach s,ihx asm lk lst map noi rel sym,build/loadpzx.$(s)) + +build/loadpzx.bin: build/loadpzx.ihx + makebin -p $< $@ +TMPS += build/loadpzx.bin + +build/LOADPZX: build/loadpzx.bin + dd if=$< of=$@ bs=1 skip=$(ESXDOS_ORG) status=noxfer + +# $1 = target +# No need in execution mode for FAT filesystem +define install_bin_rule = +$$(DESTDIR)$$(bindir)/$1: build/$1 | $$(DESTDIR)$$(bindir) + $$(INSTALL_PROGRAM) -m 644 $$< $$@ +endef + +$(foreach t,$(BINS),$(eval $(call install_bin_rule,$(t)))) + +.PHONY: install +install: $(foreach t,$(BINS),$(DESTDIR)$(bindir)/$(t)) + +.PHONY: uninstall +uninstall: + $(RM) $(foreach t,$(BINS),$(DESTDIR)$(bindir)/$(t)) + +.PHONY: clean +clean: + rm -f $(TMPS) $(foreach t,$(BINS),build/$(t)) + +.PHONY: distclean +distclean: + rm -rf build diff --git a/software/loadpzx/loadpzx.c b/software/loadpzx/loadpzx.c index a83db0f..a550313 100644 --- a/software/loadpzx/loadpzx.c +++ b/software/loadpzx/loadpzx.c @@ -1,725 +1,753 @@ -/* -Compilar con: -sdcc -mz80 --reserve-regs-iy --opt-code-size --max-allocs-per-node 10000 ---nostdlib --nostdinc --no-std-crt0 --code-loc 8192 loadpzx.c -*/ - -typedef unsigned char BYTE; -typedef unsigned short WORD; - -enum {IBLACK=0, IBLUE, IRED, IMAG, IGREEN, ICYAN, IYELLOW, IWHITE}; -enum {PBLACK=0, PBLUE=8, PRED=16, PMAG=24, PGREEN=32, PCYAN=40, PYELLOW=48, PWHITE=56}; -#define BRIGHT 64 -#define FLASH 128 - -__sfr __at (0xfe) ULA; -__sfr __at (0xff) ATTR; -__sfr __at (0x1f) KEMPSTONADDR; -__sfr __at (0x7f) FULLERADDR; - -__sfr __banked __at (0xf7fe) SEMIFILA1; -__sfr __banked __at (0xeffe) SEMIFILA2; -__sfr __banked __at (0xfbfe) SEMIFILA3; -__sfr __banked __at (0xdffe) SEMIFILA4; -__sfr __banked __at (0xfdfe) SEMIFILA5; -__sfr __banked __at (0xbffe) SEMIFILA6; -__sfr __banked __at (0xfefe) SEMIFILA7; -__sfr __banked __at (0x7ffe) SEMIFILA8; - -#define ATTRP 23693 -#define ATTRT 23695 -#define BORDR 23624 -#define LASTK 23560 - -#define WAIT_VRETRACE __asm halt __endasm -#define WAIT_HRETRACE while(ATTR!=0xff) -#define SETCOLOR(x) *(BYTE *)(ATTRP)=(x) -#define LASTKEY *(BYTE *)(LASTK) -#define ATTRPERMANENT *((BYTE *)(ATTRP)) -#define ATTRTEMPORARY *((BYTE *)(ATTRT)) -#define BORDERCOLOR *((BYTE *)(BORDR)) - -#define MAKEWORD(d,h,l) { ((BYTE *)&(d))[0] = (l) ; ((BYTE *)&(d))[1] = (h); } - -__sfr __banked __at (0xfc3b) ZXUNOADDR; -__sfr __banked __at (0xfd3b) ZXUNODATA; - -#define MASTERCONF 0 -#define SCANCODE 4 -#define KEYBSTAT 5 -#define JOYCONF 6 -#define SRAMDATA 0xf2 -#define SRAMADDRINC 0xf1 -#define SRAMADDR 0xf0 -#define COREID 0xff - -/* Some ESXDOS system calls */ -#define HOOK_BASE 128 -#define MISC_BASE (HOOK_BASE+8) -#define FSYS_BASE (MISC_BASE+16) -#define M_GETSETDRV (MISC_BASE+1) -#define F_OPEN (FSYS_BASE+2) -#define F_CLOSE (FSYS_BASE+3) -#define F_READ (FSYS_BASE+5) -#define F_WRITE (FSYS_BASE+6) -#define F_SEEK (FSYS_BASE+7) -#define F_GETPOS (FSYS_BASE+8) -#define M_TAPEIN (MISC_BASE+3) -#define M_AUTOLOAD (MISC_BASE+8) - -#define FMODE_READ 0x1 // Read access -#define FMODE_WRITE 0x2 // Write access -#define FMODE_OPEN_EX 0x0 // Open if exists, else error -#define FMODE_OPEN_AL 0x8 // Open if exists, if not create -#define FMODE_CREATE_NEW 0x4 // Create if not exists, if exists error -#define FMODE_CREATE_AL 0xc // Create if not exists, else open and truncate - -#define SEEK_START 0 -#define SEEK_CUR 1 -#define SEEK_BKCUR 2 - -#define BUFSIZE 2048 -BYTE errno; -char buffer[BUFSIZE]; - -void __sdcc_enter_ix (void) __naked; -void cls (BYTE); - -void puts (BYTE *); -void u16tohex (WORD n, char *s); -void u8tohex (BYTE n, char *s); -void print8bhex (BYTE n); -void print16bhex (WORD n); - -void memset (BYTE *, BYTE, WORD); -void memcpy (BYTE *, BYTE *, WORD); - -BYTE open (char *filename, BYTE mode); -void close (BYTE handle); -WORD read (BYTE handle, BYTE *buffer, WORD nbytes); -WORD write (BYTE handle, BYTE *buffer, WORD nbytes); -void seek (BYTE handle, WORD hioff, WORD looff, BYTE from); - -/* --------------------------------------------------------------------------------- */ -/* --------------------------------------------------------------------------------- */ -/* --------------------------------------------------------------------------------- */ -BYTE main (char *p); -void getcoreid(BYTE *s); -void usage (void); -BYTE commandlinemode (char *p); -void getfilename (char *p, char *fname); -BYTE printheader (BYTE handle); -void readpzx (BYTE handle); -WORD readblocktag (BYTE handle); -WORD readword (BYTE handle); -void convertpaus2puls (BYTE handle); -void skipblock (BYTE handle, WORD hiskip, WORD loskip); -void copyblock (BYTE handle, WORD hicopy, WORD locopy); -void rewindsram (void); -void writesram (BYTE v); -void incaddrsram (void); -void copysram (BYTE *p, WORD l); - -void init (void) __naked -{ - __asm - xor a - ld (#_errno),a - push hl - call _main - inc sp - inc sp - ld a,l - or a - jr z,preparaload - cp #255 - jr z,noload - scf - ret -noload: - or a - ret -preparaload: - ;Cierra TAPE.IN - ld b,#1 - rst #8 - .db #M_TAPEIN - - ;Auto LOAD "" - xor a - rst #8 - .db #M_AUTOLOAD - - or a - ret - -;Codigo antiguo para hacer LOAD "" -; ld bc,#3 -; ld hl,(#23641) -; push hl -; rst #0x18 -; .dw 0x1655 -; ld hl,#comando_load -; pop de -; ld bc,#3 -; ldir -; ld hl,#0x12cf -; .db 0xc3, 0xfb, 0x1f - -;comando_load: -; .db 239,34,34 - __endasm; -} - -BYTE main (char *p) -{ - if (!p) - { - usage(); - return 255; - } - else - return commandlinemode(p); -} - -BYTE commandlinemode (char *p) -{ - char fname[32]; - BYTE handle, res; - BYTE noautoload; - - noautoload = 0; - while (*p==' ') - p++; - if (*p=='-') - { - p++; - if (*p=='n') - { - noautoload = 255; - p++; - } - } - while (*p==' ') - p++; - - getfilename (p, fname); - handle = open (fname, FMODE_READ); - if (handle==0xff) - return errno; - - res = printheader(handle); - if (res) - readpzx(handle); - - close (handle); - - if (noautoload == 255) - puts ("\xd\xdType LOAD \"\" and press PLAY\xd"); - else - { - ZXUNOADDR = 0xf3; - ZXUNODATA = 0x1; // software assisted PLAY press - ZXUNODATA = 0x0; - } - - return noautoload; -} - -void usage (void) -{ - // 01234567890123456789012345678901 - puts (" LOADPZX [-n] file.pzx\xd\xd" - "Loads a PZX file into the PZX\xd" - "player.\xd" - "-n : do not autoplay.\xd"); -} - -void getfilename (char *p, char *fname) -{ - while (*p!=':' && *p!=0xd && *p!=' ') - *fname++ = *p++; - *fname = '\0'; -} - -BYTE printheader (BYTE handle) -{ - WORD lblock; - - readblocktag (handle); - if (buffer[0]!='P' || - buffer[1]!='Z' || - buffer[2]!='X' || - buffer[3]!='T') - { - puts ("This is not a PZX valid file\xd"); - return 0; - } - - MAKEWORD(lblock,buffer[5],buffer[4]); - read (handle, buffer, lblock); - if (buffer[0]!=1 || buffer[1]!=0) - { - puts ("PZX format not supported\xd"); - return 0; - } - if (lblock>3) - { - puts ("Loading: "); - puts(buffer+2); - puts ("\xd"); - } - return 1; -} - -void readpzx (BYTE handle) -{ - WORD hi,lo,res; - BYTE scandblctrl; - - ZXUNOADDR = 0xb; - scandblctrl = ZXUNODATA; - ZXUNODATA = scandblctrl | 0xc0; - - rewindsram(); - while(1) - { - *((BYTE *)(23692)) = 0xff; // para evitar el mensaje de scroll - res = readblocktag (handle); - if (!res) - break; - - if (buffer[0]=='P' && - buffer[1]=='U' && - buffer[2]=='L' && - buffer[3]=='S') - { - puts ("P"); - MAKEWORD(lo,buffer[5],buffer[4]); - MAKEWORD(hi,buffer[7],buffer[6]); - writesram(0x2); - incaddrsram(); - copysram(&buffer[4],4); - copyblock (handle,hi,lo); - } - else if (buffer[0]=='D' && - buffer[1]=='A' && - buffer[2]=='T' && - buffer[3]=='A') - { - puts ("D"); - MAKEWORD(lo,buffer[5],buffer[4]); - MAKEWORD(hi,buffer[7],buffer[6]); - writesram(0x3); - incaddrsram(); - copysram(&buffer[4],4); - copyblock (handle,hi,lo); - } - else if (buffer[0]=='P' && - buffer[1]=='A' && - buffer[2]=='U' && - buffer[3]=='S') - { - puts ("A"); - MAKEWORD(lo,buffer[5],buffer[4]); - MAKEWORD(hi,buffer[7],buffer[6]); - convertpaus2puls (handle); - //writesram(0x4); - //incaddrsram(); - //copysram(&buffer[4],4); - //copyblock (handle,hi,lo); - } - else if (buffer[0]=='S' && - buffer[1]=='T' && - buffer[2]=='O' && - buffer[3]=='P') - { - puts ("S"); - res = readword (handle); - //MAKEWORD(lo,buffer[5],buffer[4]); - //MAKEWORD(hi,buffer[7],buffer[6]); - writesram(0x1); - incaddrsram(); - copysram (&res, 2); - writesram(0); - incaddrsram(); - writesram(0); - incaddrsram(); - //skipblock(handle,hi,lo); - } - else if (buffer[0]=='B' && - buffer[1]=='R' && - buffer[2]=='W' && - buffer[3]=='S') - { - puts ("B"); - writesram(0x4); - incaddrsram(); - writesram(0); - incaddrsram(); - writesram(0); - incaddrsram(); - writesram(0); - incaddrsram(); - writesram(0); - incaddrsram(); - MAKEWORD(lo,buffer[5],buffer[4]); - MAKEWORD(hi,buffer[7],buffer[6]); - skipblock(handle,hi,lo); - } - else // skip unsupported block - { - puts ("x"); - MAKEWORD(lo,buffer[5],buffer[4]); - MAKEWORD(hi,buffer[7],buffer[6]); - skipblock(handle,hi,lo); - } - } - // pequeña pausa de 20ms para evitar errores de carga - // a causa de la conmutación brusca de la señal de EAR - // del player virtual a la entrada real - - // Add full stop mark to the tape - writesram(0); - incaddrsram(); - writesram(0); - incaddrsram(); - writesram(0); - incaddrsram(); - writesram(0); - incaddrsram(); - writesram(0); - incaddrsram(); - - ZXUNOADDR = 0xb; - ZXUNODATA = scandblctrl; -} - -WORD readblocktag (BYTE handle) -{ - return read (handle, buffer, 8); -} - -WORD readword (BYTE handle) -{ - WORD res; - read (handle, &res, 2); - return res; -} - -void skipblock (BYTE handle, WORD hiskip, WORD loskip) -{ - seek (handle, hiskip, loskip, SEEK_CUR); -} - -void copyblock (BYTE handle, WORD hicopy, WORD locopy) -{ - //print16bhex(hicopy); - //print16bhex(locopy); puts("\xd"); - while (hicopy!=0 || locopy>=BUFSIZE) - { - read (handle, buffer, BUFSIZE); - copysram (buffer, BUFSIZE); - if ((locopy-BUFSIZE)>locopy) - hicopy--; - locopy -= BUFSIZE; - //print16bhex(hicopy); - //print16bhex(locopy); puts("\xd"); - } - if (locopy>0) - { - //print16bhex(hicopy); - //print16bhex(locopy); puts("\xd"); - read (handle, buffer, locopy); - copysram (buffer, locopy); - } -} - -void convertpaus2puls (BYTE handle) -{ - BYTE pausa[10] = {0x6,0,0,0,0x1,0x80,0,0,0,0}; - - writesram(0x2); - incaddrsram(); - read (handle, buffer, 4); - pausa[6] = buffer[2]; - pausa[7] = buffer[3] | 0x80; - pausa[8] = buffer[0]; - pausa[9] = buffer[1]; - copysram (pausa,10); -} - -void rewindsram (void) -{ - ZXUNOADDR = SRAMADDR; - ZXUNODATA = 0; - ZXUNODATA = 0; - ZXUNODATA = 0; -} - -void writesram (BYTE v) -{ - ZXUNOADDR = SRAMDATA; - ZXUNODATA = v; -} - -void incaddrsram (void) -{ - ZXUNOADDR = SRAMADDRINC; - ZXUNODATA = 0; -} - -void copysram (BYTE *p, WORD l) -{ - while (l--) - { - ZXUNOADDR = SRAMDATA; - ZXUNODATA = *p++; - ZXUNOADDR = SRAMADDRINC; - ZXUNODATA = 0; - } -} - -void getcoreid(BYTE *s) -{ - BYTE cont; - volatile BYTE letra; - - ZXUNOADDR = COREID; - cont=0; - - do - { - letra = ZXUNODATA; - *(s++) = letra; - cont++; - } - while (letra!=0 && cont<32); - *s='\0'; -} - - -/* --------------------------------------------------------------------------------- */ -/* --------------------------------------------------------------------------------- */ -/* --------------------------------------------------------------------------------- */ -#pragma disable_warning 85 -#pragma disable_warning 59 -void memset (BYTE *dir, BYTE val, WORD nby) -{ - __asm - push bc - push de - ld l,4(ix) - ld h,5(ix) - ld a,6(ix) - ld c,7(ix) - ld b,8(ix) - ld d,h - ld e,l - inc de - dec bc - ld (hl),a - ldir - pop de - pop bc - __endasm; -} - -void memcpy (BYTE *dst, BYTE *fue, WORD nby) -{ - __asm - push bc - push de - ld e,4(ix) - ld d,5(ix) - ld l,6(ix) - ld h,7(ix) - ld c,8(ix) - ld b,9(ix) - ldir - pop de - pop bc - __endasm; -} - -void puts (BYTE *str) -{ - __asm - push bc - push de - ld a,(#ATTRT) - push af - ld a,(#ATTRP) - ld (#ATTRT),a - ld l,4(ix) - ld h,5(ix) -buc_print: - ld a,(hl) - or a - jp z,fin_print - cp #4 - jr nz,no_attr - inc hl - ld a,(hl) - ld (#ATTRT),a - inc hl - jr buc_print -no_attr: - rst #16 - inc hl - jp buc_print - -fin_print: - pop af - ld (#ATTRT),a - pop de - pop bc - __endasm; -} - -// void u16tohex (WORD n, char *s) -// { -// u8tohex((n>>8)&0xFF,s); -// u8tohex(n&0xFF,s+2); -// } -// -// void u8tohex (BYTE n, char *s) -// { -// BYTE i=1; -// BYTE resto; -// -// resto=n&0xF; -// s[1]=(resto>9)?resto+55:resto+48; -// resto=n>>4; -// s[0]=(resto>9)?resto+55:resto+48; -// s[2]='\0'; -// } -// -// void print8bhex (BYTE n) -// { -// char s[3]; -// -// u8tohex(n,s); -// puts(s); -// } -// -// void print16bhex (WORD n) -// { -// char s[5]; -// -// u16tohex(n,s); -// puts(s); -// } - - -void __sdcc_enter_ix (void) __naked -{ - __asm - pop hl ; return address - push ix ; save frame pointer - ld ix,#0 - add ix,sp ; set ix to the stack frame - jp (hl) ; and return - __endasm; -} - -BYTE open (char *filename, BYTE mode) -{ - __asm - push bc - push de - xor a - rst #8 - .db #M_GETSETDRV ;Default drive in A - ld l,4(ix) ;Filename pointer - ld h,5(ix) ;in HL - ld b,6(ix) ;Open mode in B - rst #8 - .db #F_OPEN - jr nc,open_ok - ld (#_errno),a - ld a,#0xff -open_ok: - ld l,a - pop de - pop bc - __endasm; -} - -void close (BYTE handle) -{ - __asm - push bc - push de - ld a,4(ix) ;Handle - rst #8 - .db #F_CLOSE - pop de - pop bc - __endasm; -} - -WORD read (BYTE handle, BYTE *buffer, WORD nbytes) -{ - __asm - push bc - push de - ld a,4(ix) ;File handle in A - ld l,5(ix) ;Buffer address - ld h,6(ix) ;in HL - ld c,7(ix) - ld b,8(ix) ;Buffer length in BC - rst #8 - .db #F_READ - jr nc,read_ok - ld (#_errno),a - ld bc,#65535 -read_ok: - ld h,b - ld l,c - pop de - pop bc - __endasm; -} - -WORD write (BYTE handle, BYTE *buffer, WORD nbytes) -{ - __asm - push bc - push de - ld a,4(ix) ;File handle in A - ld l,5(ix) ;Buffer address - ld h,6(ix) ;in HL - ld c,7(ix) - ld b,8(ix) ;Buffer length in BC - rst #8 - .db #F_WRITE - jr nc,write_ok - ld (#_errno),a - ld bc,#65535 -write_ok: - ld h,b - ld l,c - pop de - pop bc - __endasm; -} - -void seek (BYTE handle, WORD hioff, WORD looff, BYTE from) -{ - __asm - push bc - push de - ld a,4(ix) ;File handle in A - ld c,5(ix) ;Hiword of offset in BC - ld b,6(ix) - ld e,7(ix) ;Loword of offset in DE - ld d,8(ix) - ld l,9(ix) ;From where: 0: start, 1:forward current pos, 2: backwards current pos - rst #8 - .db #F_SEEK - pop de - pop bc - __endasm; -} - +/* + * loadpzx - loads a PZX file into the PZX player. + * + * Copyright (C) 2016-2021 Antonio Villena + * + * 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, version 3. + * + * 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, see . + * + * SPDX-FileCopyrightText: Copyright (C) 2016-2021 Antonio Villena + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#define PROGRAM "loadpzx" +#define VERSION "0.1" +#define DESCRIPTION "Loads a PZX file into the PZX" "\r" "player." +#define COPYRIGHT "\x7f 2016-2021 Antonio Villena" +#define LICENSE "License: GNU GPL 3.0" + +typedef unsigned char BYTE; +typedef unsigned short WORD; + +enum {IBLACK=0, IBLUE, IRED, IMAG, IGREEN, ICYAN, IYELLOW, IWHITE}; +enum {PBLACK=0, PBLUE=8, PRED=16, PMAG=24, PGREEN=32, PCYAN=40, PYELLOW=48, PWHITE=56}; +#define BRIGHT 64 +#define FLASH 128 + +__sfr __at (0xfe) ULA; +__sfr __at (0xff) ATTR; +__sfr __at (0x1f) KEMPSTONADDR; +__sfr __at (0x7f) FULLERADDR; + +__sfr __banked __at (0xf7fe) SEMIFILA1; +__sfr __banked __at (0xeffe) SEMIFILA2; +__sfr __banked __at (0xfbfe) SEMIFILA3; +__sfr __banked __at (0xdffe) SEMIFILA4; +__sfr __banked __at (0xfdfe) SEMIFILA5; +__sfr __banked __at (0xbffe) SEMIFILA6; +__sfr __banked __at (0xfefe) SEMIFILA7; +__sfr __banked __at (0x7ffe) SEMIFILA8; + +#define ATTRP 23693 +#define ATTRT 23695 +#define BORDR 23624 +#define LASTK 23560 + +#define WAIT_VRETRACE __asm halt __endasm +#define WAIT_HRETRACE while(ATTR!=0xff) +#define SETCOLOR(x) *(BYTE *)(ATTRP)=(x) +#define LASTKEY *(BYTE *)(LASTK) +#define ATTRPERMANENT *((BYTE *)(ATTRP)) +#define ATTRTEMPORARY *((BYTE *)(ATTRT)) +#define BORDERCOLOR *((BYTE *)(BORDR)) + +#define MAKEWORD(d,h,l) { ((BYTE *)&(d))[0] = (l) ; ((BYTE *)&(d))[1] = (h); } + +__sfr __banked __at (0xfc3b) ZXUNOADDR; +__sfr __banked __at (0xfd3b) ZXUNODATA; + +#define MASTERCONF 0 +#define SCANCODE 4 +#define KEYBSTAT 5 +#define JOYCONF 6 +#define SRAMDATA 0xf2 +#define SRAMADDRINC 0xf1 +#define SRAMADDR 0xf0 +#define COREID 0xff + +/* Some ESXDOS system calls */ +#define HOOK_BASE 128 +#define MISC_BASE (HOOK_BASE+8) +#define FSYS_BASE (MISC_BASE+16) +#define M_GETSETDRV (MISC_BASE+1) +#define F_OPEN (FSYS_BASE+2) +#define F_CLOSE (FSYS_BASE+3) +#define F_READ (FSYS_BASE+5) +#define F_WRITE (FSYS_BASE+6) +#define F_SEEK (FSYS_BASE+7) +#define F_GETPOS (FSYS_BASE+8) +#define M_TAPEIN (MISC_BASE+3) +#define M_AUTOLOAD (MISC_BASE+8) + +#define FMODE_READ 0x1 // Read access +#define FMODE_WRITE 0x2 // Write access +#define FMODE_OPEN_EX 0x0 // Open if exists, else error +#define FMODE_OPEN_AL 0x8 // Open if exists, if not create +#define FMODE_CREATE_NEW 0x4 // Create if not exists, if exists error +#define FMODE_CREATE_AL 0xc // Create if not exists, else open and truncate + +#define SEEK_START 0 +#define SEEK_CUR 1 +#define SEEK_BKCUR 2 + +#define BUFSIZE 2048 +BYTE errno; +char buffer[BUFSIZE]; + +void __sdcc_enter_ix (void) __naked; +void cls (BYTE); + +void puts (BYTE *); +void u16tohex (WORD n, char *s); +void u8tohex (BYTE n, char *s); +void print8bhex (BYTE n); +void print16bhex (WORD n); + +void memset (BYTE *, BYTE, WORD); +void memcpy (BYTE *, BYTE *, WORD); + +BYTE open (char *filename, BYTE mode); +void close (BYTE handle); +WORD read (BYTE handle, BYTE *buffer, WORD nbytes); +WORD write (BYTE handle, BYTE *buffer, WORD nbytes); +void seek (BYTE handle, WORD hioff, WORD looff, BYTE from); + +/* --------------------------------------------------------------------------------- */ +/* --------------------------------------------------------------------------------- */ +/* --------------------------------------------------------------------------------- */ +BYTE main (char *p); +void getcoreid(BYTE *s); +void show_usage (void); +BYTE commandlinemode (char *p); +void getfilename (char *p, char *fname); +BYTE printheader (BYTE handle); +void readpzx (BYTE handle); +WORD readblocktag (BYTE handle); +WORD readword (BYTE handle); +void convertpaus2puls (BYTE handle); +void skipblock (BYTE handle, WORD hiskip, WORD loskip); +void copyblock (BYTE handle, WORD hicopy, WORD locopy); +void rewindsram (void); +void writesram (BYTE v); +void incaddrsram (void); +void copysram (BYTE *p, WORD l); + +void init (void) __naked +{ + __asm + xor a + ld (#_errno), a + push hl + call _main + inc sp + inc sp + ld a, l + or a + jr z, prepare_load + cp #255 + jr z, no_load + scf + ret +no_load: + or a + ret +prepare_load: + ; close TAPE.IN + ld b, #1 + rst #8 + .db #M_TAPEIN + + ; auto LOAD "" + xor a + rst #8 + .db #M_AUTOLOAD + + or a + ret + __endasm; + // old code to do LOAD "" + /* + ld bc, #3 + ld hl, (#23641) + push hl + rst #0x18 + .dw 0x1655 + ld hl, #command_load + pop de + ld bc, #3 + ldir + ld hl, #0x12cf + jp #0x1ffb + +command_load: + .db 239, 34, 34 + */ +} + +BYTE main (char *p) +{ + if (!p) + { + show_usage(); + return 255; + } + else + return commandlinemode(p); +} + +BYTE commandlinemode (char *p) +{ + char fname[32]; + BYTE handle, res; + BYTE noautoload; + + noautoload = 0; + while (*p==' ') + p++; + if (*p=='-') + { + p++; + if (*p=='n') + { + noautoload = 255; + p++; + } + } + while (*p==' ') + p++; + + getfilename (p, fname); + handle = open (fname, FMODE_READ); + if (handle==0xff) + return errno; + + res = printheader(handle); + if (res) + readpzx(handle); + + close (handle); + + if (noautoload == 255) + puts ("\r\rType LOAD \"\" and press PLAY\r"); + else + { + ZXUNOADDR = 0xf3; + ZXUNODATA = 0x1; // software assisted PLAY press + ZXUNODATA = 0x0; + } + + return noautoload; +} + +void show_usage (void) +{ + // 01234567890123456789012345678901 + puts ( + PROGRAM " version " VERSION "\r" + DESCRIPTION "\r" + COPYRIGHT "\r" + LICENSE "\r" + "\r" + "Usage:\r" + " ." PROGRAM " [-n] file.pzx\r" + "\r" + "-n : do not autoplay.\r" + ); +} + +void getfilename (char *p, char *fname) +{ + while (*p!=':' && *p!=0xd && *p!=' ') + *fname++ = *p++; + *fname = '\0'; +} + +BYTE printheader (BYTE handle) +{ + WORD lblock; + + readblocktag (handle); + if (buffer[0]!='P' || + buffer[1]!='Z' || + buffer[2]!='X' || + buffer[3]!='T') + { + puts ("This is not a PZX valid file\r"); + return 0; + } + + MAKEWORD(lblock,buffer[5],buffer[4]); + read (handle, buffer, lblock); + if (buffer[0]!=1 || buffer[1]!=0) + { + puts ("PZX format not supported\r"); + return 0; + } + if (lblock>3) + { + puts ("Loading: "); + puts(buffer+2); + puts ("\r"); + } + return 1; +} + +void readpzx (BYTE handle) +{ + WORD hi,lo,res; + BYTE scandblctrl; + + ZXUNOADDR = 0xb; + scandblctrl = ZXUNODATA; + ZXUNODATA = scandblctrl | 0xc0; + + rewindsram(); + while(1) + { + *((BYTE *)(23692)) = 0xff; // to avoid scrolling message + res = readblocktag (handle); + if (!res) + break; + + if (buffer[0]=='P' && + buffer[1]=='U' && + buffer[2]=='L' && + buffer[3]=='S') + { + puts ("P"); + MAKEWORD(lo,buffer[5],buffer[4]); + MAKEWORD(hi,buffer[7],buffer[6]); + writesram(0x2); + incaddrsram(); + copysram(&buffer[4],4); + copyblock (handle,hi,lo); + } + else if (buffer[0]=='D' && + buffer[1]=='A' && + buffer[2]=='T' && + buffer[3]=='A') + { + puts ("D"); + MAKEWORD(lo,buffer[5],buffer[4]); + MAKEWORD(hi,buffer[7],buffer[6]); + writesram(0x3); + incaddrsram(); + copysram(&buffer[4],4); + copyblock (handle,hi,lo); + } + else if (buffer[0]=='P' && + buffer[1]=='A' && + buffer[2]=='U' && + buffer[3]=='S') + { + puts ("A"); + MAKEWORD(lo,buffer[5],buffer[4]); + MAKEWORD(hi,buffer[7],buffer[6]); + convertpaus2puls (handle); + //writesram(0x4); + //incaddrsram(); + //copysram(&buffer[4],4); + //copyblock (handle,hi,lo); + } + else if (buffer[0]=='S' && + buffer[1]=='T' && + buffer[2]=='O' && + buffer[3]=='P') + { + puts ("S"); + res = readword (handle); + //MAKEWORD(lo,buffer[5],buffer[4]); + //MAKEWORD(hi,buffer[7],buffer[6]); + writesram(0x1); + incaddrsram(); + copysram (&res, 2); + writesram(0); + incaddrsram(); + writesram(0); + incaddrsram(); + //skipblock(handle,hi,lo); + } + else if (buffer[0]=='B' && + buffer[1]=='R' && + buffer[2]=='W' && + buffer[3]=='S') + { + puts ("B"); + writesram(0x4); + incaddrsram(); + writesram(0); + incaddrsram(); + writesram(0); + incaddrsram(); + writesram(0); + incaddrsram(); + writesram(0); + incaddrsram(); + MAKEWORD(lo,buffer[5],buffer[4]); + MAKEWORD(hi,buffer[7],buffer[6]); + skipblock(handle,hi,lo); + } + else // skip unsupported block + { + puts ("x"); + MAKEWORD(lo,buffer[5],buffer[4]); + MAKEWORD(hi,buffer[7],buffer[6]); + skipblock(handle,hi,lo); + } + } + // small pause of 20ms to avoid loading errors + // due to abrupt switching of the EAR signal + // from the virtual player to the real input + + // Add full stop mark to the tape + writesram(0); + incaddrsram(); + writesram(0); + incaddrsram(); + writesram(0); + incaddrsram(); + writesram(0); + incaddrsram(); + writesram(0); + incaddrsram(); + + ZXUNOADDR = 0xb; + ZXUNODATA = scandblctrl; +} + +WORD readblocktag (BYTE handle) +{ + return read (handle, buffer, 8); +} + +WORD readword (BYTE handle) +{ + WORD res; + read (handle, &res, 2); + return res; +} + +void skipblock (BYTE handle, WORD hiskip, WORD loskip) +{ + seek (handle, hiskip, loskip, SEEK_CUR); +} + +void copyblock (BYTE handle, WORD hicopy, WORD locopy) +{ + //print16bhex(hicopy); + //print16bhex(locopy); puts("\r"); + while (hicopy!=0 || locopy>=BUFSIZE) + { + read (handle, buffer, BUFSIZE); + copysram (buffer, BUFSIZE); + if ((locopy-BUFSIZE)>locopy) + hicopy--; + locopy -= BUFSIZE; + //print16bhex(hicopy); + //print16bhex(locopy); puts("\r"); + } + if (locopy>0) + { + //print16bhex(hicopy); + //print16bhex(locopy); puts("\r"); + read (handle, buffer, locopy); + copysram (buffer, locopy); + } +} + +void convertpaus2puls (BYTE handle) +{ + BYTE pause[10] = {0x6, 0, 0, 0, 0x1, 0x80, 0, 0, 0, 0}; + + writesram(0x2); + incaddrsram(); + read (handle, buffer, 4); + pause[6] = buffer[2]; + pause[7] = buffer[3] | 0x80; + pause[8] = buffer[0]; + pause[9] = buffer[1]; + copysram (pause,10); +} + +void rewindsram (void) +{ + ZXUNOADDR = SRAMADDR; + ZXUNODATA = 0; + ZXUNODATA = 0; + ZXUNODATA = 0; +} + +void writesram (BYTE v) +{ + ZXUNOADDR = SRAMDATA; + ZXUNODATA = v; +} + +void incaddrsram (void) +{ + ZXUNOADDR = SRAMADDRINC; + ZXUNODATA = 0; +} + +void copysram (BYTE *p, WORD l) +{ + while (l--) + { + ZXUNOADDR = SRAMDATA; + ZXUNODATA = *p++; + ZXUNOADDR = SRAMADDRINC; + ZXUNODATA = 0; + } +} + +void getcoreid(BYTE *s) +{ + BYTE len; + volatile BYTE c; + + ZXUNOADDR = COREID; + len=0; + + do + { + c = ZXUNODATA; + *(s++) = c; + len++; + } + while (c!=0 && len<32); + *s='\0'; +} + + +/* --------------------------------------------------------------------------------- */ +/* --------------------------------------------------------------------------------- */ +/* --------------------------------------------------------------------------------- */ +#pragma disable_warning 85 +#pragma disable_warning 59 +void memset (BYTE *dir, BYTE val, WORD nby) +{ + __asm + push bc + push de + ld l, 4(ix) + ld h, 5(ix) + ld a, 6(ix) + ld c, 7(ix) + ld b, 8(ix) + ld d, h + ld e, l + inc de + dec bc + ld (hl), a + ldir + pop de + pop bc + __endasm; +} + +void memcpy (BYTE *dst, BYTE *fue, WORD nby) +{ + __asm + push bc + push de + ld e, 4(ix) + ld d, 5(ix) + ld l, 6(ix) + ld h, 7(ix) + ld c, 8(ix) + ld b, 9(ix) + ldir + pop de + pop bc + __endasm; +} + +void puts (BYTE *str) +{ + __asm + push bc + push de + ld a, (#ATTRT) + push af + ld a, (#ATTRP) + ld (#ATTRT), a + ld l, 4(ix) + ld h, 5(ix) +print_loop: + ld a, (hl) + or a + jp z, end_print + cp #4 + jr nz, no_attr + inc hl + ld a, (hl) + ld (#ATTRT), a + inc hl + jr print_loop +no_attr: + rst #16 + inc hl + jp print_loop + +end_print: + pop af + ld (#ATTRT), a + pop de + pop bc + __endasm; +} + +// void u16tohex (WORD n, char *s) +// { +// u8tohex((n>>8)&0xFF,s); +// u8tohex(n&0xFF,s+2); +// } +// +// void u8tohex (BYTE n, char *s) +// { +// BYTE i=1; +// BYTE rest; +// +// rest=n&0xF; +// s[1]=(rest>9)?rest+55:rest+48; +// rest=n>>4; +// s[0]=(rest>9)?rest+55:rest+48; +// s[2]='\0'; +// } +// +// void print8bhex (BYTE n) +// { +// char s[3]; +// +// u8tohex(n,s); +// puts(s); +// } +// +// void print16bhex (WORD n) +// { +// char s[5]; +// +// u16tohex(n,s); +// puts(s); +// } + +void __sdcc_enter_ix (void) __naked +{ + __asm + pop hl ; return address + push ix ; save frame pointer + ld ix, #0 + add ix, sp ; set ix to the stack frame + jp (hl) ; and return + __endasm; +} + +BYTE open (char *filename, BYTE mode) +{ + __asm + push bc + push de + xor a + rst #8 + .db #M_GETSETDRV ; A = default drive + ld l, 4(ix) ; HL = pointer to filename (ASCIIZ) + ld h, 5(ix) ; + ld b, 6(ix) ; B = file open mode + rst #8 + .db #F_OPEN + jr nc, open_ok + ld (#_errno), a + ld a, #0xff +open_ok: + ld l, a + pop de + pop bc + __endasm; +} + +void close (BYTE handle) +{ + __asm + push bc + push de + ld a, 4(ix) ; A = file handle + rst #8 + .db #F_CLOSE + pop de + pop bc + __endasm; +} + +WORD read (BYTE handle, BYTE *buffer, WORD nbytes) +{ + __asm + push bc + push de + ld a, 4(ix) ; A = file handle + ld l, 5(ix) ; HL = buffer address + ld h, 6(ix) ; + ld c, 7(ix) ; BC = buffer length + ld b, 8(ix) ; + rst #8 + .db #F_READ + jr nc, read_ok + ld (#_errno), a + ld bc, #65535 +read_ok: + ld h, b + ld l, c + pop de + pop bc + __endasm; +} + +WORD write (BYTE handle, BYTE *buffer, WORD nbytes) +{ + __asm + push bc + push de + ld a, 4(ix) ; A = file handle + ld l, 5(ix) ; HL = buffer address + ld h, 6(ix) ; + ld c, 7(ix) ; BC = buffer length + ld b, 8(ix) ; + rst #8 + .db #F_WRITE + jr nc, write_ok + ld (#_errno),a + ld bc, #65535 +write_ok: + ld h, b + ld l, c + pop de + pop bc + __endasm; +} + +void seek (BYTE handle, WORD hioff, WORD looff, BYTE from) +{ + __asm + push bc + push de + ld a, 4(ix) ; A = file handle + ld c, 5(ix) ; BC = MSW offset + ld b, 6(ix) ; + ld e, 7(ix) ; DE = LSW offset + ld d, 8(ix) ; + ld l, 9(ix) ; L = whence (0: start, 1: forward current pos, 2: backwards current pos) + rst #8 + .db #F_SEEK + pop de + pop bc + __endasm; +}