From 7488f69ec28b2d061d6a25538769a2b6e77626ce Mon Sep 17 00:00:00 2001 From: Ivan Tatarinov Date: Sat, 12 Jun 2021 14:09:56 +0300 Subject: [PATCH 1/4] 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; +} From 52b6f24794b5d1eec0322f77b888bf66786df91a Mon Sep 17 00:00:00 2001 From: Ivan Tatarinov Date: Sat, 12 Jun 2021 19:26:05 +0300 Subject: [PATCH 2/4] sdk/include: added `regs.mac` macros to operate on CPU registers --- sdk/include/regs.mac | 77 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 sdk/include/regs.mac diff --git a/sdk/include/regs.mac b/sdk/include/regs.mac new file mode 100644 index 0000000..09b1f0c --- /dev/null +++ b/sdk/include/regs.mac @@ -0,0 +1,77 @@ +; regs.mac - macros to assign values to CPU registers. +; +; SPDX-FileCopyrightText: Copyright (C) 2021 Ivan Tatarinov +; +; SPDX-License-Identifier: GPL-3.0-or-above + +; Compatible compilers: +; SJAsmPlus, + + ifndef regs_mac_included + define regs_mac_included + + ; Load (initialize) A register + macro ld_a value + if 0 = value + xor a ; 1 byte + else + ld a, value ; 2 bytes + endif +___a=value + endm + + ; Change A register + macro chg_a value + if ___a != value + if 0 = (value & $ff) + xor a ; 1 byte + elseif ((___a + 1) & $ff) = (value & $ff) + inc a ; 1 byte + elseif ((___a - 1) & $ff) = (value & $ff) + dec a ; 1 byte + elseif (((___a & $7f) << 1) + ((___a & $80) >> 7)) = (value & $ff) + rlca ; 1 byte + elseif (((___a & $fe) >> 1) + ((___a & $01) << 7)) = (value & $ff) + rrca ; 1 byte + elseif ((___a ^ $ff) & $ff) = (value & $ff) + cpl ; 1 byte + else + ld a, value & $ff ; 2 bytes + endif +___a=value + endif + endm + + ; Load (initialize) BC register + macro ld_bc value + ld bc, value +___bc=value + endm + + ; Change BC register + macro chg_bc value + if (___bc & $ffff) != (value & $ffff) + if (___bc & $ff) = (value & $ff) + if (((___bc >> 8) + 1) & $ff) = ((value >> 8) & $ff) + inc b + elseif (((___bc >> 8) - 1) & $ff) = ((value >> 8) & $ff) + dec b + else + ld b, value >> 8 + endif + elseif ((___bc >> 8) & $ff) = ((value >> 8) & $ff) + if (((___bc & $ff) + 1) & $ff) = (value & $ff) + inc c + elseif (((___bc & $ff) - 1) & $ff) = (value & $ff) + dec c + else + ld c, value & $ff + endif + else + ld bc, value + endif +___bc=value + endif + endm + + endif ; !regs_mac_included From 9eb8173ad94af8275ed52521edf756dc554b3346 Mon Sep 17 00:00:00 2001 From: Ivan Tatarinov Date: Sat, 12 Jun 2021 19:57:27 +0300 Subject: [PATCH 3/4] software/playrmov: added `Makefile` --- sdk/include/zxuno.def | 2 + software/Makefile | 3 +- software/playrmov/.gitignore | 5 + software/playrmov/Makefile | 83 +++++ software/playrmov/playrmov.asm | 489 +++++++++++++++------------ software/playrmov/playrmov.changelog | 7 + 6 files changed, 363 insertions(+), 226 deletions(-) create mode 100644 software/playrmov/.gitignore create mode 100644 software/playrmov/Makefile create mode 100644 software/playrmov/playrmov.changelog diff --git a/sdk/include/zxuno.def b/sdk/include/zxuno.def index b8d8908..71fe832 100644 --- a/sdk/include/zxuno.def +++ b/sdk/include/zxuno.def @@ -31,6 +31,7 @@ define dev_control 14 define dev_control2 15 define newreg 16 + define radas_ctrl $40 ; ZX-UNO register to activate Radastan mode define dma_ctrl $a0 ; ZX-UNO register to start/stop DMA define dma_src $a1 ; ZX-UNO register to set DMA source define dma_dst $a2 ; ZX-UNO register to set DMA destination @@ -47,6 +48,7 @@ ; Aliases ZXUNOADDR: equ zxuno_port ZXUNODATA: equ zxuno_data +RADASCTRL: equ radas_ctrl ; MMC/SDC interface: define SPI_PORT $eb diff --git a/software/Makefile b/software/Makefile index 603b388..3df1e9a 100644 --- a/software/Makefile +++ b/software/Makefile @@ -33,7 +33,8 @@ SUBDIRS=\ iwconfig\ joyconf\ keymap\ - loadpzx + loadpzx\ + playrmov .PHONY: all all: build diff --git a/software/playrmov/.gitignore b/software/playrmov/.gitignore new file mode 100644 index 0000000..82e29a6 --- /dev/null +++ b/software/playrmov/.gitignore @@ -0,0 +1,5 @@ +# SPDX-FileCopyrightText: 2021 Ivan Tatarinov +# +# SPDX-License-Identifier: CC0-1.0 + +build diff --git a/software/playrmov/Makefile b/software/playrmov/Makefile new file mode 100644 index 0000000..7a52781 --- /dev/null +++ b/software/playrmov/Makefile @@ -0,0 +1,83 @@ +# 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 + +INCLUDEDIR = ../../sdk/include +AS = sjasmplus +ifeq ($(USE_SJASMPLUS_VERSION),sjasmplus) +AFLAGS = --nobanner +else ifeq ($(USE_SJASMPLUS_VERSION),z00m128) +AFLAGS = --nologo +else +AFLAGS = +endif +AFLAGS += -I$(INCLUDEDIR) + +BINS=\ + PLAYRMOV + +.PHONY: all +all: $(foreach t,$(BINS),build/$(t)) + +build\ +$(DESTDIR)$(bindir): + mkdir -p $@ + +build/PLAYRMOV: $(srcdir)/playrmov.asm\ + $(INCLUDEDIR)/zxuno.def\ + $(INCLUDEDIR)/esxdos.def\ + $(INCLUDEDIR)/regs.mac\ + | build + $(AS) $(AFLAGS) --raw=$@ $< + +# $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 $(foreach t,$(BINS),build/$(t)) + +.PHONY: distclean +distclean: + rm -rf build diff --git a/software/playrmov/playrmov.asm b/software/playrmov/playrmov.asm index cc972cc..59488a3 100644 --- a/software/playrmov/playrmov.asm +++ b/software/playrmov/playrmov.asm @@ -1,225 +1,264 @@ -; API de ESXDOS. -include "esxdos.inc" -include "errors.inc" - -; PLAYRMOV : un comando para ESXDOS 0.8.5 que permite reproducir videos en formato -; Radastaniano (ficheros .RDM) usando DIVMMC en el ZX-Uno. - -; Video: secuencia lineal de frames. -; Cada frame: 6144 bytes con el bitmap en el formato radastaniano + -; 16 bytes para la paleta (entradas 0-15) - -; Version 0.2 : arreglado el problema del stack. Gracias a Miguel Ângelo Guerreiro -; Se borra la pantalla al terminar la reproducción -; Version 0.1 : necesita que el stack esté por debajo de 49152 -; (ej. CLEAR 49151 antes de ejecutar el comando) - -;Para ensamblar con PASMO como archivo binario (no TAP) - -BORDERCLR equ 23624 -PAPERCOLOR equ 23693 -ULAPLUSADDR equ 0bf3bh -ULAPLUSDATA equ 0ff3bh -ZXUNOADDR equ 0fc3bh -ZXUNODATA equ 0fd3bh -RADASCTRL equ 40h -BANKM equ 7ffdh -PILA equ 3deah ;valor sugerido por Miguel Ângelo para poner la pila en el área de comando - - org 2000h ;comienzo de la ejecución de los comandos ESXDOS. - -Main proc - ld a,h - or l - jr z,PrintUso ;si no se ha especificado nombre de fichero, imprimir uso - call RecogerNFile - - di - ld (BackupSP),sp - ld sp,PILA - ei - call PlayFichero - call Cls - - ld sp,(BackupSP) - ret - -PrintUso ld hl,Uso -BucPrintMsg ld a,(hl) - or a - ret z - rst 10h - inc hl - jr BucPrintMsg - endp - - -RecogerNFile proc ;HL apunta a los argumentos (nombre del fichero) - ld de,BufferNFich -CheckCaracter ld a,(hl) - or a - jr z,FinRecoger - cp " " - jr z,FinRecoger - cp ":" - jr z,FinRecoger - cp 13 - jr z,FinRecoger - ldi - jr CheckCaracter -FinRecoger xor a - ld (de),a - inc de ;DE queda apuntando al buffer este que se necesita en OPEN, no sé pa qué. - ret - endp - - -PlayFichero proc - xor a - rst 08h - db M_GETSETDRV ;A = unidad actual - ld b,FA_READ ;B = modo de apertura - ld hl,BufferNFich ;HL = Puntero al nombre del fichero (ASCIIZ) - rst 08h - db F_OPEN - ret c ;Volver si hay error - ld (FHandle),a - - call SetupVideoMemory - -BucPlayVideo ld hl,0c000h - ld bc,6144+16 ;Bitmap + paleta - ld a,(FHandle) - rst 08h - db F_READ - jr c,FinPlay ;si error, fin de lectura - ld a,b - or c - jr z,FinPlay ;si no hay más que leer, fin de lectura - - call SwitchScreens - ld bc,7ffeh - in a,(c) ;Detectar si se ha pulsado SPACE - and 1 - jr z,FinPlay - - jr BucPlayVideo - -FinPlay ld a,(FHandle) - rst 08h - db F_CLOSE - - call RestoreVideoMemory - - or a ;Volver sin errores a ESXDOS - ret - endp - - -SetupVideoMemory proc - di - - ld bc,ZXUNOADDR - ld a,RADASCTRL - out (c),a - ld bc,ZXUNODATA - ld a,3 ;modo radastaniano - out (c),a - - ld bc,BANKM - ld a,00010111b ;banco 7, pantalla normal, ROM 3 - ld (Banco),a - out (c),a - ei - ret - endp - - -RestoreVideoMemory proc - di - ld bc,BANKM - ld a,00010000b ;banco 0, pantalla normal, ROM 3 - out (c),a - - ld bc,ZXUNOADDR - ld a,RADASCTRL - out (c),a - ld bc,ZXUNODATA - ld a,0 ;modo ULA normal - out (c),a - - ei - ret - endp - - -SwitchScreens proc - halt - - ld ix,0c000h + 6144 ;apuntamos a donde está la paleta - ld d,0 ;D es el indice a la paleta que se está escribiendo - ld h,0ffh ;H contiene el color más oscuro, para poner en el borde después - ld l,0 ;L contiene el índice al color más oscuro -BucUpdPaleta ld bc,ULAPLUSADDR - out (c),d - ld b,0ffh - ld a,(ix) - out (c),a - ld a,d - cp 8 ;Solo hacemos el test para los indices 0-7 - jr nc,NoTestColorOscuro - ld a,(ix) - cp h - jr nc,NoTestColorOscuro - ld h,a - ld l,d -NoTestColorOscuro inc ix - inc d - ld a,16 - cp d - jr nz,BucUpdPaleta - - ld a,l - out (254),a ;El borde lo más oscuro posible - - ld a,(Banco) - xor 00001010b ;conmutamos de la pantalla normal a la shadow y de la 7 a la 5 - ld (Banco),a - ld bc,BANKM - out (c),a - ret - endp - - -Cls proc - ld a,(BORDERCLR) - sra a - sra a - sra a - and 7 - out (254),a - ld hl,16384 - ld de,16385 - ld bc,6143 - ld (hl),l - ldir - inc hl - inc de - ld bc,767 - ld a,(PAPERCOLOR) - ld (hl),a - ldir - ret - endp - - - ; 01234567890123456789012345678901 -Uso db " playrmov moviefile.rdm",13,13 - db "Plays a video file encoded for",13 - db "the ",34,"Radastan",34," video mode.",13,0 - -FHandle db 0 -Banco db 0 -BackupSP dw 0 - -BufferNFich equ $ ;resto de la RAM para el nombre del fichero \ No newline at end of file +; playrmov - a command for ESXDOS 0.8.5 and above that allows playing videos +; in Radastan format (.RDM files) using DivMMC on the ZX-Uno. +; +; Copyright (C) 2016-2021 Antonio Villena +; Contributors: +; Miguel Ângelo Guerreiro (fixed the stack problem) +; 2021 Ivan Tatarinov +; +; 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 3 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, see . +; +; SPDX-FileCopyrightText: Copyright (C) 2016-2021 Antonio Villena +; +; SPDX-FileContributor: Miguel Ângelo Guerreiro +; SPDX-FileContributor: 2021 Ivan Tatarinov +; +; SPDX-License-Identifier: GPL-3.0-only + +; Video: linear sequence of frames. +; Frame: 6144 bytes with the bitmap in Radastan format + +; 16 bytes for the palette (inputs 0-15) + +; output PLAYRMOV + + define PROGRAM "playrmov" + define VERSION "0.2" + define DESCRIPTION "Plays a video file encoded for", 13, "the ", 34, "Radastan", 34, " video mode." + define COPYRIGHT 127, " 2016-2021 Antonio Villena" + define LICENSE "License: GNU GPL 3.0" + + include zxuno.def + include esxdos.def + include regs.mac + +BORDERCLR: equ 23624 +PAPERCOLOR: equ 23693 +ULAPLUSADDR: equ $bf3b +ULAPLUSDATA: equ $ff3b +BANKM: equ $7ffd +PILA: equ $3dea ; value suggested by Miguel Ângelo to + ; put the stack in the command area + + org $2000 ; entry point of ESXDOS program + +;----------------------------------------------------------------------------- +; Subroutine +; In: HL = pointer to the command line arguments string (ASCIIZ) + +Main: ld a, h + or l + jr nz, Init ; If no filename specified, show usage +; jr ShowUsage ; No need, it follows + +;----------------------------------------------------------------------------- +; Subroutine + +ShowUsage: ld hl, aUsage +; jr Print ; No need, it follows + +;----------------------------------------------------------------------------- +; Subroutine +; In: HL = pointer to an ASCIIZ string + +Print: ld a, (hl) + or a + ret z ; Return on string end + rst $10 + inc hl + jr Print + +;----------------------------------------------------------------------------- +; Subroutine +; In: HL = pointer to the command line arguments string (ASCIIZ) + +Init: ld de, FileName +; call GetFileName ; inline + +;----------------------------------------------------------------------------- +; Subroutine +; In: HL = pointer to the command line arguments (filename) +; DE = pointer to the output ASCIIZ string (filename) +; Out: DE = pointer to terminating 0 character of output string + +.GetFileName: ld a, (hl) + or a + jr z, .End + cp " " + jr z, .End + cp ":" + jr z, .End + cp 13 + jr z, .End + ldi + jr .GetFileName +.End: xor a + ld (de), a +; ret ; skipped + +; continue Init() + inc de ; DE remains pointing to the buffer that is + ; needed in OPEN, I don't know what for + di + ld (BackupSP), sp + ld sp, PILA + ei + + call PlayFile + call Cls + + ld sp, (BackupSP) + ret + +;----------------------------------------------------------------------------- +; Subroutine + +PlayFile: xor a + esxdos M_GETSETDRV ; A = current drive + ld b, FA_READ ; B = file open mode + ld hl, FileName ; HL = pointer to file name (ASCIIZ) + esxdos F_OPEN + ret c ; Return on error + ld (FileHandle), a + + call SetupVideoMemory + +.Loop: ld hl, $c000 + ld bc, 6144 + 16 ; Bitmap + palette + ld a, (FileHandle) + esxdos F_READ + jr c, .Stop ; Stop on error + ld a,b + or c + jr z, .Stop ; Stop on end of data + call SwitchScreens + ld bc, $7ffe + in a, (c) ; Detect if SPACE has been pressed + and %00000001 + jr nz, .Loop +.Stop: ld a, (FileHandle) + esxdos F_CLOSE + + call RestoreVideoMemory + + or a ; Return to ESXDOS without errors (CY=0) + ret + +;----------------------------------------------------------------------------- +; Subroutine + +SetupVideoMemory: + di + ld_bc ZXUNOADDR + ld_a RADASCTRL + out (c), a + chg_bc ZXUNODATA + chg_a 3 ; "Radastan" mode + out (c), a + chg_bc BANKM + chg_a %00010111 ; Bank 7, normal display, ROM 3 + ld (Bank), a + out (c), a + ei + ret + +;----------------------------------------------------------------------------- +; Subroutine + +RestoreVideoMemory: + di + ld_bc BANKM + ld_a %00010000 ; Bank 0, normal display, ROM 3 + out (c), a + chg_bc ZXUNOADDR + chg_a RADASCTRL + out (c), a + chg_bc ZXUNODATA + chg_a 0 ; Normal ULA mode + out (c),a + ei + ret + +;----------------------------------------------------------------------------- +; Subroutine + +SwitchScreens: halt + + ld ix, $c000 + 6144 ; IX = pointer to palette + ld d, 0 ; D = index to the palette that is being written + ld h, $ff ; H = darkest color, to put on the edge afterwards + ld l, 0 ; L = index to the darkest color +PaletteUpdate: + ld_bc ULAPLUSADDR + out (c), d + chg_bc ULAPLUSDATA + ld a, (ix) + out (c), a + ld a, d + cp 8 ; Only do the test for indices 0-7 + jr nc, .NoDarkColor + ld a, (ix) + cp h + jr nc, .NoDarkColor + ld h, a + ld l, d +.NoDarkColor: inc ix + inc d + ld a, 16 + cp d + jr nz, PaletteUpdate + + ld a, l ; The edge is as dark as possible + out (254), a ; + + ld a, (Bank) ; Switch from the normal screen to + xor %00001010 ; the shadow screen and from 7 to 5 + ld (Bank), a ; + ld bc, BANKM ; + out (c), a ; + ret + +;----------------------------------------------------------------------------- +; Subroutine + +Cls: ld a, (BORDERCLR) + .3 sra a + and %00000111 + out (254), a + ld hl, ScreenAddr ; L = 0 + ld de, ScreenAddr+1 + ld bc, 6144-1 + ld (hl), l + ldir + inc hl + inc de + ld bc, 768-1 + ld a, (PAPERCOLOR) + ld (hl), a + ldir + ret + +; 01234567890123456789012345678901 +aUsage: db PROGRAM, " version ", VERSION, 13 + db DESCRIPTION, 13 + db COPYRIGHT, 13 + db LICENSE, 13 + db 13 + db "Usage:", 13 + db " .", PROGRAM, " moviefile.rdm", 13, 0 + +FileHandle db 0 +Bank db 0 +BackupSP dw 0 +FileName: ; Rest of RAM for filename +ScreenAddr: equ $4000 diff --git a/software/playrmov/playrmov.changelog b/software/playrmov/playrmov.changelog new file mode 100644 index 0000000..9bb1fe1 --- /dev/null +++ b/software/playrmov/playrmov.changelog @@ -0,0 +1,7 @@ +Version 0.2 + Fixed the stack problem. Thanks to Miguel Ângelo Guerreiro. + Screen clears when playback ends. + +Version 0.1 + Needs the stack to be below 49152. Ex. "CLEAR 49151" before executing the + command. From aae879818a4258ee14ae566da502e7c491073c52 Mon Sep 17 00:00:00 2001 From: Ivan Tatarinov Date: Sat, 12 Jun 2021 19:58:57 +0300 Subject: [PATCH 4/4] software/esxdos: (fix) forced removal of `build` directory when cleaning --- software/esxdos/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/software/esxdos/Makefile b/software/esxdos/Makefile index e978a44..9a9fe9c 100644 --- a/software/esxdos/Makefile +++ b/software/esxdos/Makefile @@ -199,7 +199,7 @@ uninstall: .PHONY: clean clean: - rm -rf build/* + rm -rf build .PHONY: distclean distclean: clean