zxuno-git/software/loadpzx/loadpzx.c

726 lines
15 KiB
C
Raw Blame History

/*
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<75>a pausa de 20ms para evitar errores de carga
// a causa de la conmutaci<63>n brusca de la se<73>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;
}