#include #include #include #include #include void read_image(char * s); void write_image(char * s); void read_jpp(char * s); void write_jpp(char * s); void read_vgaspec_header(char * s); void read_vgaspec(char * s); void write_vgaspec(char * s); void read_old_vgaspec(char * s); void write_old_vgaspec(char * s); void read_raw(char * s); void read_z80(char * s); void write_z80(char * s); void jpp_to_vgaspec(); void vgaspec_to_jpp(); void raw_to_jpp(); void jpp_to_z80(); void z80_to_jpp(); void z80_uncompress(); int z80_compress(); union header_u { char in[9]; struct { char type; unsigned int length; unsigned int start; char var; char res1; int line; } header; } h; char expect[]={ 0x03, /* type CODE */ 0x00,0xc0, /* image size */ 0x00,0x40, /* image start */ 0xff, /* var */ 0xff, /* res1 */ 0xff,0xff /* line */ }; struct jpp_s { unsigned char i; unsigned char lax; unsigned char hax; unsigned char eax; unsigned char dax; unsigned char cax; unsigned char bax; unsigned char fax; unsigned char aax; unsigned char l; unsigned char h; unsigned char e; unsigned char d; unsigned char c; unsigned char b; unsigned char iyl; unsigned char iyh; unsigned char ixl; unsigned char ixh; unsigned char iff2; unsigned char r; unsigned char f; unsigned char a; unsigned char spl; unsigned char sph; unsigned char im; unsigned char border; } jpp; struct vga_s { /*00*/ unsigned char S; /*01*/ unsigned char P; /*02*/ unsigned int len; /*04*/ unsigned int start; /*06*/ unsigned char c; /*07*/ unsigned char b; /*08*/ unsigned char e; /*09*/ unsigned char d; /*0A*/ unsigned char l; /*0B*/ unsigned char h; /*0C*/ unsigned char f; /*0D*/ unsigned char a; /*0E*/ unsigned char ixl; /*0F*/ unsigned char ixh; /*10*/ unsigned char iyl; /*11*/ unsigned char iyh; /*12*/ unsigned char cax; /*13*/ unsigned char bax; /*14*/ unsigned char eax; /*15*/ unsigned char dax; /*16*/ unsigned char lax; /*17*/ unsigned char hax; /*18*/ unsigned char fax; /*19*/ unsigned char aax; /*1A*/ unsigned char r; /*1B*/ unsigned char i; /*1C*/ unsigned char spl; /*1D*/ unsigned char sph; /*1E*/ unsigned char pcl; /*1F*/ unsigned char pch; /*20*/ unsigned char res2; /*21*/ unsigned char res3; /*22*/ unsigned char border; /*23*/ unsigned char res4; /*24*/ unsigned char im; /*25*/ unsigned char res5; } vga; struct z80_s { /*00*/ unsigned char a; /*01*/ unsigned char f; /*02*/ unsigned char c; /*03*/ unsigned char b; /*04*/ unsigned char l; /*05*/ unsigned char h; /*06*/ unsigned char pcl; /*07*/ unsigned char pch; /*08*/ unsigned char spl; /*09*/ unsigned char sph; /*0A*/ unsigned char i; /*0B*/ unsigned char r; /*0C*/ unsigned char data; /*0D*/ unsigned char e; /*0E*/ unsigned char d; /*0F*/ unsigned char cax; /*10*/ unsigned char bax; /*11*/ unsigned char eax; /*12*/ unsigned char dax; /*13*/ unsigned char lax; /*14*/ unsigned char hax; /*15*/ unsigned char aax; /*16*/ unsigned char fax; /*17*/ unsigned char iyl; /*18*/ unsigned char iyh; /*19*/ unsigned char ixl; /*1A*/ unsigned char ixh; /*1B*/ unsigned char iff1; /*1C*/ unsigned char iff2; /*1D*/ unsigned char im; } z80; #define IMSIZE 49152 unsigned char image[IMSIZE]; unsigned int z80_size; int intype; int outtype; #define RAW 1 #define JPP 2 #define SPECTRUM 3 #define Z80 4 #define UNKNOWN 5 unsigned int addr; unsigned int sp; unsigned int pc; int fd; main(argc,argv) int argc; char *argv[]; { int i; char *p; struct stat status; char * fromstring; char * tostring; if(argc != 3) { fprintf(stderr,"SPCONV version 1.01 - %s\n\n",__DATE__); fprintf(stderr,"Usage: spconv \n\n"); fprintf(stderr,"Source must be a valid .SNA, .SP, .Z80 or RAW file.\n"); fprintf(stderr,"Target must be a .SNA, .SP or .Z80 file.\n"); fprintf(stderr,"Output .SP files are in the new format, .Z80 files are compressed.\n"); fprintf(stderr,"If and are .SP files, convertion from old\n"); fprintf(stderr,"to new format or from new to old format will be performed.\n"); fprintf(stderr,"If and are of the same type an error message\n"); fprintf(stderr,"will be generated (unless they are both .SP files)\n"); fprintf(stderr,"\n\nPublic Domain, H. de Groot 1992\n\n"); exit(1); } if(stat(argv[1],&status)<0) { perror(argv[1]); exit(1); } /* * recognize input type on filename: * * .SNA -> JPP file * .SP -> SPECTRUM file (was VGASPEC) * .Z80 -> Z80 file * other -> if exact 48+header -> raw file * otherwise unknown */ intype=UNKNOWN; p=strrchr(argv[1],'.'); if((strcmp(p,".SNA")==0) || (strcmp(p,".sna")==0)) { fromstring="Converting from .SNA "; intype=JPP; } if((strcmp(p,".Z80")==0) || (strcmp(p,".z80")==0)) { fromstring="Converting from .Z80 "; intype=Z80; } if((strcmp(p,".SP")==0) || (strcmp(p,".sp")==0)) { fromstring="Converting from .SP "; intype=SPECTRUM; } if(intype==UNKNOWN) if (status.st_size == (sizeof(h)+IMSIZE)) { fromstring="Converting from RAW "; intype=RAW; } /* * recognize output type on filename: * * .SNA -> JPP file * .SP -> SPECTRUM file (was VGASPEC) * .Z80 -> Z80 file * otherwise unknown */ outtype=UNKNOWN; p=strrchr(argv[2],'.'); if((strcmp(p,".SNA")==0) || (strcmp(p,".sna")==0)) { tostring="to .SNA"; outtype=JPP; } if((strcmp(p,".Z80")==0) || (strcmp(p,".z80")==0)) { tostring="to .Z80"; outtype=Z80; } if((strcmp(p,".SP")==0) || (strcmp(p,".sp")==0)) { tostring="to .SP"; outtype=SPECTRUM; } if(intype==UNKNOWN) { fprintf(stderr,"Unknown input file format. Must be a valid .SNA, .SP, .Z80 file, "); fprintf(stderr,"or a Raw file\n"); return 3; } if(outtype==UNKNOWN) { fprintf(stderr,"Unknown output file format. Must be a .SNA, .SP or .Z80 file\n"); return 4; } if(intype==outtype) { if(intype!=SPECTRUM) { fprintf(stderr,"Input and output file format are the same. "); fprintf(stderr,"What you try to do\n"); fprintf(stderr,"is handled much better by the MSDOS \"COPY\" "); fprintf(stderr,"command!\n"); return 3; } else { if((status.st_size == (sizeof(vga)+IMSIZE))) { printf("Converting new .SP format to old .SP format.\n"); read_vgaspec(argv[1]); write_old_vgaspec(argv[2]); return 0; } else if((status.st_size == (sizeof(vga)+IMSIZE-6))) { read_vgaspec_header(argv[1]); if((vga.S=='S')&&(vga.P=='P')) { fprintf(stderr,"Invalid input file format. This could be a new syle .SP file whith\n"); fprintf(stderr,"an image of another length than 48Kb. This kind of .SP files cannot\n"); fprintf(stderr,"be converted. All other file formats (including the old .SP format\n"); fprintf(stderr,"contain images of 48Kb length.\n"); } printf("Converting old .SP format to new .SP format.\n"); read_old_vgaspec(argv[1]); vga.S='S'; vga.P='P'; vga.len=0xC000; vga.start=0x4000; write_vgaspec(argv[2]); return 0; } else { read_vgaspec_header(argv[1]); if((vga.S=='S')&&(vga.P=='P')) { fprintf(stderr,"Invalid input file format. This could be a new syle .SP file whith\n"); fprintf(stderr,"an image of another length than 48Kb. This kind of .SP files cannot\n"); fprintf(stderr,"be converted. All other file formats (including the old .SP format\n"); fprintf(stderr,"contain images of 48Kb length.\n"); return 3; } else { fprintf(stderr,"Unknown input file format. Must be a valid .SNA, .SP or .Z80 file\n"); return 3; } } } } printf("%s%s\n",fromstring,tostring); /* * convert input_file to JPP */ if((intype==JPP) && (status.st_size == (sizeof(jpp)+IMSIZE))) { read_jpp(argv[1]); } else if ((intype==SPECTRUM)&&((status.st_size == (sizeof(vga)+IMSIZE)))) { read_vgaspec(argv[1]); vgaspec_to_jpp(); } else if ((intype==SPECTRUM)&&((status.st_size == (sizeof(vga)+IMSIZE-6)))) { read_old_vgaspec(argv[1]); vgaspec_to_jpp(); } else if (intype==RAW) { read_raw(argv[1]); raw_to_jpp(); } else if (intype==Z80) { read_z80(argv[1]); z80_to_jpp(); } else { printf("Unrecognized input file type, can't convert\n"); return 3; } /* * convert internal JPP format to output file */ if(outtype==JPP) { write_jpp(argv[2]); } else if (outtype==SPECTRUM) { jpp_to_vgaspec(); write_vgaspec(argv[2]); } else if (outtype==Z80) { jpp_to_z80(); write_z80(argv[2]); } else { printf("Unrecognized output file type, can't convert\n"); return 4; } return 0; } void read_image(char * s) { if(read(fd,image,IMSIZE)==-1) { perror(s); exit(1); } } void write_image(char * s) { if(write(fd,image,IMSIZE)==-1) { perror(s); exit(2); } } void read_jpp(char * s) { fd=open(s,O_RDONLY|O_BINARY); if(fd < 0) { perror(s); exit(1); } if(read(fd,&jpp,sizeof(jpp))==-1) { perror(s); exit(1); } read_image(s); close(fd); } void write_jpp(char * s) { unlink(s); fd=open(s,O_WRONLY|O_CREAT|O_BINARY,0666); if(fd<0) { perror(s); exit(2); } if(write(fd,&jpp,sizeof(jpp))==-1) { perror(s); exit(2); } write_image(s); close(fd); } void read_vgaspec_header(char * s) { fd=open(s,O_RDONLY|O_BINARY); if(fd < 0) { perror(s); exit(1); } if(read(fd,&vga,sizeof(vga))==-1) { perror(s); exit(1); } close(fd); } void read_vgaspec(char * s) { fd=open(s,O_RDONLY|O_BINARY); if(fd < 0) { perror(s); exit(1); } if(read(fd,&vga,sizeof(vga))==-1) { perror(s); exit(1); } read_image(s); close(fd); } void write_vgaspec(char * s) { unlink(s); fd=open(s,O_WRONLY|O_CREAT|O_BINARY,0666); if(fd<0) { perror(s); exit(2); } if(write(fd,&vga,sizeof(vga))==-1) { perror(s); exit(2); } write_image(s); close(fd); } void read_old_vgaspec(char * s) { fd=open(s,O_RDONLY|O_BINARY); if(fd < 0) { perror(s); exit(1); } if(read(fd,((char *)&vga)+6,sizeof(vga)-6)==-1) { perror(s); exit(1); } read_image(s); close(fd); } void write_old_vgaspec(char * s) { unlink(s); fd=open(s,O_WRONLY|O_CREAT|O_BINARY,0666); if(fd<0) { perror(s); exit(2); } if(write(fd,((char *)&vga)+6,sizeof(vga)-6)==-1) { perror(s); exit(2); } write_image(s); close(fd); } void read_raw(char * s) { int i; fd=open(s,O_RDONLY|O_BINARY); if(fd < 0) { perror(s); exit(1); } if(read(fd,&h,sizeof(h))==-1) { perror(s); exit(1); } for(i=0;i<9;i++) { if(h.in[i]!=expect[i]) { fprintf(stderr,"Header of spectum image not ok, "); fprintf(stderr,"Spectrum image should be saved with:\n"); fprintf(stderr,"SAVE *\"b\"CODE 16384,49152"); exit(1); } } read_image(s); close(fd); } void read_z80(char * s) { fd=open(s,O_RDONLY|O_BINARY); if(fd < 0) { perror(s); exit(1); } if(read(fd,&z80,sizeof(z80))==-1) { perror(s); exit(1); } read_image(s); close(fd); } void write_z80(char * s) { unlink(s); fd=open(s,O_WRONLY|O_CREAT|O_BINARY,0666); if(fd<0) { perror(s); exit(2); } if(write(fd,&z80,sizeof(z80))==-1) { perror(s); exit(2); } if(write(fd,image,z80_size)==-1) { perror(s); exit(2); } close(fd); } void jpp_to_vgaspec() { sp=256*jpp.sph+jpp.spl; addr=sp-0x4000; pc=image[addr]+256*image[addr+1]; sp=sp+2; vga.S='S'; vga.P='P'; vga.len=0xC000; vga.start=0x4000; vga.f=jpp.f; vga.a=jpp.a; vga.b=jpp.b; vga.c=jpp.c; vga.d=jpp.d; vga.e=jpp.e; vga.h=jpp.h; vga.l=jpp.l; vga.fax=jpp.fax; vga.aax=jpp.aax; vga.bax=jpp.bax; vga.cax=jpp.cax; vga.dax=jpp.dax; vga.eax=jpp.eax; vga.hax=jpp.hax; vga.lax=jpp.lax; vga.ixh=jpp.ixh; vga.ixl=jpp.ixl; vga.iyh=jpp.iyh; vga.iyl=jpp.iyl; vga.i=jpp.i; vga.r=jpp.r; vga.im=jpp.im & 0x03; /* works? how does it know it was IM1 ? */ if((jpp.iff2 & 0x04) != 0) vga.im=vga.im | 0x20; vga.sph=sp/256; vga.spl=sp%256; vga.pch=pc/256; vga.pcl=pc%256; vga.border=jpp.border; vga.res2=0; vga.res3=0; vga.res4=0; vga.res5=0; } void vgaspec_to_jpp() { pc=256*vga.pch+vga.pcl; jpp.f=vga.f; jpp.a=vga.a; jpp.b=vga.b; jpp.c=vga.c; jpp.d=vga.d; jpp.e=vga.e; jpp.h=vga.h; jpp.l=vga.l; jpp.fax=vga.fax; jpp.aax=vga.aax; jpp.bax=vga.bax; jpp.cax=vga.cax; jpp.dax=vga.dax; jpp.eax=vga.eax; jpp.hax=vga.hax; jpp.lax=vga.lax; jpp.ixh=vga.ixh; jpp.ixl=vga.ixl; jpp.iyh=vga.iyh; jpp.iyl=vga.iyl; jpp.border=vga.border; jpp.i=vga.i; jpp.r=vga.r; jpp.im=vga.im & 0x0f; /* IM0 not used, must be IM1 */ if (jpp.im==0) jpp.im=0x01; if((vga.im & 0xf0) == 0) jpp.iff2=0xff; else jpp.iff2=0x00; sp=256*vga.sph+vga.spl; sp=sp-2; addr=sp-0x4000; image[addr]=vga.pcl; image[addr+1]=vga.pch; jpp.sph=sp/256; jpp.spl=sp%256; } void raw_to_jpp() { pc=0x1bf4; /* entry of "next statement" */ jpp.f=0x99; jpp.a=0x5f; jpp.b=0x1f; jpp.c=0xf0; jpp.d=0x5d; jpp.e=0x0c; jpp.h=0x5d; jpp.l=0x0e; jpp.fax=0x44; jpp.aax=0x00; jpp.bax=0x18; jpp.cax=0x20; jpp.dax=0x00; jpp.eax=0x07; jpp.hax=0x5c; jpp.lax=0xf1; jpp.ixh=0x03; jpp.ixl=0xd4; jpp.iyh=0x5c; jpp.iyl=0x3a; jpp.i=0x3f; jpp.r=0x00; jpp.im=0x01; jpp.iff2=0xFF; /* set sp by means of RAMTOP in the image */ addr=0x5cb2-0x4000; sp=256*image[addr+1]+image[addr]-1; /* Reset ERR NR to no error */ image[0x5c3a-0x4000]=0xff; /* Set border by means of BORDCR */ jpp.border=(image[0x5c48-0x4000] & 0x38)>>3; /* put return address to MAIN-4 (0x1303) on stack */ sp=sp-2; addr=sp-0x4000; image[addr]=0x03; image[addr+1]=0x13; sp=sp-2; addr=sp-0x4000; image[addr]=pc%256; image[addr+1]=pc/256; jpp.sph=sp/256; jpp.spl=sp%256; } void jpp_to_z80() { sp=256*jpp.sph+jpp.spl; addr=sp-0x4000; pc=image[addr]+256*image[addr+1]; sp=sp+2; z80.f=jpp.f; z80.a=jpp.a; z80.b=jpp.b; z80.c=jpp.c; z80.d=jpp.d; z80.e=jpp.e; z80.h=jpp.h; z80.l=jpp.l; z80.fax=jpp.fax; z80.aax=jpp.aax; z80.bax=jpp.bax; z80.cax=jpp.cax; z80.dax=jpp.dax; z80.eax=jpp.eax; z80.hax=jpp.hax; z80.lax=jpp.lax; z80.ixh=jpp.ixh; z80.ixl=jpp.ixl; z80.iyh=jpp.iyh; z80.iyl=jpp.iyl; z80.i=jpp.i; z80.r=jpp.r | 0x080; /* bit 7 is stored somewhere else, always set */ z80.im=jpp.im & 0x03; z80.im=z80.im + 0x60; /* fixed normal video/kempston joystick */ z80.sph=sp/256; z80.spl=sp%256; z80.pch=pc/256; z80.pcl=pc%256; /* all kinds of stuff put in "data" */ z80.data=(jpp.border & 0x07)*2; if((jpp.r & 0x80)!=0) z80.data=z80.data+1; /* here is bit 7 of r */ z80.data=z80.data | z80_compress(); if((jpp.iff2 & 0x04) != 0) { z80.iff1=0xff; z80.iff2=0xff; } else { z80.iff1=0; z80.iff2=0; } } void z80_to_jpp() { pc=256*z80.pch+z80.pcl; jpp.f=z80.f; jpp.a=z80.a; jpp.b=z80.b; jpp.c=z80.c; jpp.d=z80.d; jpp.e=z80.e; jpp.h=z80.h; jpp.l=z80.l; jpp.fax=z80.fax; jpp.aax=z80.aax; jpp.bax=z80.bax; jpp.cax=z80.cax; jpp.dax=z80.dax; jpp.eax=z80.eax; jpp.hax=z80.hax; jpp.lax=z80.lax; jpp.ixh=z80.ixh; jpp.ixl=z80.ixl; jpp.iyh=z80.iyh; jpp.iyl=z80.iyl; jpp.border=(z80.data/2) & 0x07; jpp.i=z80.i; if(z80.data==0xff) z80.data=0; if((z80.data & 0x01)==1) jpp.r=(z80.r & 0x7f)+0x80; else jpp.r=z80.r & 0x7f; jpp.im=z80.im & 0x03; if(z80.iff2 != 0) jpp.iff2=0xff; else jpp.iff2=0x00; sp=256*z80.sph+z80.spl; sp=sp-2; addr=sp-0x4000; jpp.sph=sp/256; jpp.spl=sp%256; if((z80.data & 0x20)!=0) z80_uncompress(); /* PC can only be stored in the image after decompression!! */ image[addr]=z80.pcl; image[addr+1]=z80.pch; } void z80_uncompress() { unsigned char far * uc; unsigned int i,j,k; unsigned char l; uc=farmalloc(IMSIZE+0x0100); if(uc==NULL) { fprintf(stderr,"Not enough memory to uncompress z80 image\n"); exit(7); } j=0; i=0; while(i= (IMSIZE-4)) { /* compressed image bigger or same than original */ farfree(comp); return NOTCOMPRESSED; } } /* append "end of compressed area" mark */ comp[j]=0; j++; comp[j]=0xed; j++; comp[j]=0xed; j++; comp[j]=0; j++; z80_size = j; /* copy back */ i=0; j=0; while(i