diff --git a/README.md b/README.md index bcd6cf8..5198745 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -BASBINIZER v1.5 +BASBINIZER v1.8 =============== BASBINIZER is a suite of tools for native MSX-BASIC file manipulation. It is multiplatform and several builds have been provided (Windows, Linux, Mac and MSX). @@ -16,14 +16,16 @@ Using BASBINIZER on your PC/Mac/Linux computer Syntax: -basbinizer [-b [-c ]] [-a ] [-r ] [--fix] [--quiet] +basbinizer [-i ] [-b [-c ]] [-a ] [-r ] [--fix] [--quiet] Where is the path to an MSX-BASIC .BAS file in tokenized - is the resulting .CAS file. + is the .BIN file (loadable from disk) - if the name of the BLOAD name (max. 6 characters) + is the resulting .CAS file. + + is the name of the "FOUND" file (max. 6 characters) is the name of the ROM file @@ -36,7 +38,7 @@ Options: --quiet suppress messages on screen (except for critical errors) -ROM files must be under 16384 bytes and the variable area must start beyond address #C000. The program will fail if it sets the variable area to any address under #C000 (e.g. by using a CLEAR statement). +ROM files must be under 16368 bytes and the variable area must start beyond address #C000. The program will fail if it sets the variable area to any address under #C000 (e.g. by using a CLEAR statement). Example: @@ -47,6 +49,8 @@ Example: basbinizer NIBBLES.BAS -a NIBBLES.ASC -b NIBBLES.CAS -C NIBBLE --fix basbinizer NIBBLES.BAS -b NIBBLES.CAS -C NIBBLE -r NIBBLES.ROM --quiet + + basbinizer NIBBLES.BAS -i NIBBLES.BIN Using BASBINIZER on your MSX computer diff --git a/src/cli/basbinizer.c b/src/cli/basbinizer.c index 107ef9a..b233d7d 100644 --- a/src/cli/basbinizer.c +++ b/src/cli/basbinizer.c @@ -24,24 +24,25 @@ SOFTWARE. void title(void) { - fprintf(options.stdoutf, "_/_/_/_/_/_/_/_/ Basbinizer v1.5 _/_/_/_/_/_/_/_/\n"); + fprintf(options.stdoutf, "_/_/_/_/_/_/_/_/ Basbinizer v%s _/_/_/_/_/_/_/_/\n",VERSION); fprintf(options.stdoutf, "_/_/_/_/_/_/_/_/ 2023 MSXWiki.org _/_/_/_/_/_/_/_/\n\n\n"); } void usage(void) { fprintf(options.stdoutf, "Syntax:\n\n"); - fprintf(options.stdoutf, "basbinizer [-b [-c ]] [-a ] [-r ] [--fix] [--quiet]\n\n"); + fprintf(options.stdoutf, "basbinizer [-i ] [-b [-c ]] [-a ] [-r ] [--fix] [--quiet]\n\n"); fprintf(options.stdoutf, "Where\n"); fprintf(options.stdoutf, "\t is the path to an MSX-BASIC .BAS file in tokenized format\n"); - fprintf(options.stdoutf, "\t is the resulting .CAS file.\n"); - fprintf(options.stdoutf, "\t is the name of the BLOAD name (max. 6 characters)\n"); + fprintf(options.stdoutf, "\t is the .BIN file (loadable from disk)\n"); + fprintf(options.stdoutf, "\t is the resulting .CAS file.\n"); + fprintf(options.stdoutf, "\t is the name of the \"FOUND\" file (max. 6 characters)\n"); fprintf(options.stdoutf, "\t is the name of the ROM file\n"); fprintf(options.stdoutf, "\t to generate an ASCII file from the tokenized BASIC. If not specified, the ASCII text is written to the standard output.\n\n"); fprintf(options.stdoutf, "Options:\n"); fprintf(options.stdoutf, "\t--fix\t\tFixes certain data errors found in the source .BAS file\n"); fprintf(options.stdoutf, "\t--quiet\t\t suppress messages on screen (except for critical errors\n\n"); - fprintf(options.stdoutf, "ROM files must be under 16384 bytes and the variable area must start beyond address #C000. The program will fail if it sets the variable area to any address under #C000 (e.g. by using a CLEAR statement)\n\n"); + fprintf(options.stdoutf, "ROM files must be under %d bytes and the variable area must start beyond address #C000. The program will fail if it sets the variable area to any address under #C000 (e.g. by using a CLEAR statement)\n\n", MAX_ROM_SIZE); fprintf(options.stdoutf, "Example:\n\tbasbinizer STARS.BAS -b STARS.CAS -c STARS\n\n\n"); } @@ -53,7 +54,7 @@ bool process_params(int argc, char **argv, options_t *opt) */ opt->infile = NULL; opt->infile_s = 0; - opt->outfile = NULL; + opt->casfile = NULL; opt->ascfile = NULL; opt->romfile = NULL; memset(opt->casname, ' ', CAS_NAME_LEN); @@ -100,52 +101,59 @@ bool process_params(int argc, char **argv, options_t *opt) int i = 2; while (i < argc) { - if ((!strcmp(argv[i], "-b")) && (i < (argc - 1))) + if ((!strcmp(argv[i], "-i")) && (i < (argc - 1))) { - opt->outfile = argv[++i]; + opt->binfile = argv[++i]; } else { - if ((!strcmp(argv[i], "-c")) && (i < (argc - 1))) + if ((!strcmp(argv[i], "-b")) && (i < (argc - 1))) { - int name_len = strlen(argv[++i]); - memcpy(opt->casname, argv[i], name_len > CAS_NAME_LEN ? CAS_NAME_LEN : name_len); + opt->casfile = argv[++i]; } else { - if (!strcmp(argv[i], "--fix")) + if ((!strcmp(argv[i], "-c")) && (i < (argc - 1))) { - opt->fix = true; + int name_len = strlen(argv[++i]); + memcpy(opt->casname, argv[i], name_len > CAS_NAME_LEN ? CAS_NAME_LEN : name_len); } else { - if (!strcmp(argv[i], "--quiet")) + if (!strcmp(argv[i], "--fix")) { - opt->quiet = true; -#ifdef _WIN32 - opt->stdoutf = fopen("NUL", "wb"); -#else - opt->stdoutf = fopen("/dev/null", "wb"); -#endif + opt->fix = true; } else { - if ((!strcmp(argv[i], "-a")) && (i < (argc - 1))) + if (!strcmp(argv[i], "--quiet")) { - opt->ascfile = argv[++i]; + opt->quiet = true; +#ifdef _WIN32 + opt->stdoutf = fopen("NUL", "wb"); +#else + opt->stdoutf = fopen("/dev/null", "wb"); +#endif } else { - if ((!strcmp(argv[i], "-r")) && (i < (argc - 1))) + if ((!strcmp(argv[i], "-a")) && (i < (argc - 1))) { - if (opt->infile_s <= MAX_ROM_SIZE) - { - opt->romfile = argv[++i]; - } - else + opt->ascfile = argv[++i]; + } + else + { + if ((!strcmp(argv[i], "-r")) && (i < (argc - 1))) { - strcpy(opt->valerror, "BASIC program is too big to be fitted in a ROM.\n"); - return (false); + if (opt->infile_s <= MAX_ROM_SIZE) + { + opt->romfile = argv[++i]; + } + else + { + strcpy(opt->valerror, "BASIC program is too big to be fitted in a ROM.\n"); + return (false); + } } } } @@ -230,9 +238,20 @@ int main(int argc, char **argv) /* Write .BIN file if requested */ - if (options.outfile) + if (options.binfile) { - if (!write_bin(inbuf, options.infile_s, options.outfile)) + if (!write_bin(inbuf, options.infile_s, options.binfile)) + { + return (1); + } + } + + /* + Write .CAS file if requested + */ + if (options.casfile) + { + if (!write_cas(inbuf, options.infile_s, options.casfile)) { return (1); } @@ -268,21 +287,76 @@ bool write_bin(byte *buffer, off_t buf_size, char *binf) { /* - Write file size into binary loader data (loader_data is a global array) + Write file size into binary loader data (bin_loader_data is a global array) + and BSAVE data on BIN header + */ + bin_loader_data[BIN_PATCH_POS] = (byte)((0x8000 + buf_size) & 0xff); + bin_loader_data[BIN_PATCH_POS + 1] = (byte)((0x8000 + buf_size) >> 8); + + BIN_header[3] = (byte)((0x8000 + buf_size + BIN_LOADER_SIZE - 1) & 0xff); + BIN_header[4] = (byte)((0x8000 + buf_size + BIN_LOADER_SIZE - 1) >> 8); + + BIN_header[5] = (byte)((0x8000 + buf_size) & 0xff); + BIN_header[6] = (byte)((0x8000 + buf_size) >> 8); + + /* + Get memory for the buffer + */ + byte *bin_buffer = malloc(sizeof(BIN_header) + buf_size + BIN_LOADER_SIZE); + + if (!bin_buffer) + { + fprintf(stderr, "Memory error trying to find %lld bytes free while writing .BIN File... exiting.\n\n", sizeof(BIN_header) + buf_size + BIN_LOADER_SIZE); + + return (false); + } + + /* + Copy data to the .BIN buffer + */ + memcpy(bin_buffer, BIN_header, 7); + memcpy(bin_buffer + 7, buffer, buf_size); + memcpy(bin_buffer + 7 + buf_size, bin_loader_data, BIN_LOADER_SIZE); + + /* + finally, open output file and write data + */ + FILE *fo = fopen(binf, "wb"); + if (!fo) + { + fprintf(stderr, "Error opening .BIN file %s.\n", binf); + return (false); + } + + if (fwrite(bin_buffer, 1, sizeof(BIN_header) + buf_size + BIN_LOADER_SIZE, fo) != (sizeof(BIN_header) + buf_size + BIN_LOADER_SIZE)) + { + fprintf(stderr, "Error writing .BIN file %s.\n", binf); + } + + fclose(fo); + free(bin_buffer); + + return (true); +} +bool write_cas(byte *buffer, off_t buf_size, char *casf) +{ + + /* + Write file size into cas binary loader data (cas_loader_data is a global array) */ - loader_data[PATCH_POS] = (byte)(buf_size & 0xff); - loader_data[PATCH_POS + 1] = (byte)((buf_size & 0xff00) >> 8); + cas_loader_data[PATCH_POS] = (byte)(buf_size & 0xff); + cas_loader_data[PATCH_POS + 1] = (byte)((buf_size & 0xff00) >> 8); - memcpy(loader_data + PATCH_NAME_POS, options.casname, CAS_NAME_LEN); + memcpy(cas_loader_data + PATCH_NAME_POS, options.casname, CAS_NAME_LEN); /* Get memory for the buffer */ - byte *cas_buffer = malloc(LOADER_SIZE + buf_size); + byte *cas_buffer = malloc(CAS_LOADER_SIZE + buf_size); if (!cas_buffer) { - fprintf(stderr, "Memory error trying to find %lld bytes free while writing CAS file... exiting.\n\n", LOADER_SIZE + buf_size); + fprintf(stderr, "Memory error trying to find %lld bytes free while writing CAS file... exiting.\n\n", CAS_LOADER_SIZE + buf_size); return (false); } @@ -290,22 +364,22 @@ bool write_bin(byte *buffer, off_t buf_size, char *binf) /* copy data and concat .BAS file */ - memcpy(cas_buffer, loader_data, LOADER_SIZE); - memcpy(cas_buffer + LOADER_SIZE, buffer, buf_size); + memcpy(cas_buffer, cas_loader_data, CAS_LOADER_SIZE); + memcpy(cas_buffer + CAS_LOADER_SIZE, buffer, buf_size); /* finally, open output file and write data */ - FILE *fo = fopen(binf, "wb"); + FILE *fo = fopen(casf, "wb"); if (!fo) { - fprintf(stderr, "Error opening .CAS file %s.\n", binf); + fprintf(stderr, "Error opening .CAS file %s.\n", casf); return (false); } - if (fwrite(cas_buffer, 1, LOADER_SIZE + buf_size, fo) != (LOADER_SIZE + buf_size)) + if (fwrite(cas_buffer, 1, CAS_LOADER_SIZE + buf_size, fo) != (CAS_LOADER_SIZE + buf_size)) { - fprintf(stderr, "Error writing .CAS file %s.\n", binf); + fprintf(stderr, "Error writing .CAS file %s.\n", casf); } fclose(fo); @@ -322,7 +396,7 @@ bool write_rom(byte *inbuf, off_t buf_size, char *romfile) if (!rom_buffer) { - fprintf(stderr, "Memory error trying to find %lld bytes free while writing ROM file... exiting.\n\n", LOADER_SIZE + buf_size); + fprintf(stderr, "Memory error trying to find %d bytes free while writing ROM file... exiting.\n\n", ROM_SIZE); return (false); } diff --git a/src/cli/basbinizer.h b/src/cli/basbinizer.h index 0b1450a..da5c7ec 100644 --- a/src/cli/basbinizer.h +++ b/src/cli/basbinizer.h @@ -36,7 +36,10 @@ typedef long long int off_t; typedef struct _stat st_stat; #endif -#define LOADER_SIZE 174 +#define VERSION "1.8" +#define BIN_LOADER_SIZE 50 +#define CAS_LOADER_SIZE 174 +#define BIN_PATCH_POS 10 #define PATCH_POS 51 #define PATCH_NAME_POS 0x12 #define CAS_NAME_LEN 6 @@ -45,6 +48,7 @@ typedef struct _stat st_stat; #define MAX_ROM_SIZE 16384 - 0x10 #define BASE_BIN 0x8000 #define BASE_ROM 0x8010 +#define REL_PROG 0xf975 typedef uint8_t byte; @@ -52,7 +56,18 @@ byte ROM_header[16] = { 0x41, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -byte loader_data[LOADER_SIZE] = { +byte BIN_header[7] = { + 0xfe, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00 +}; +byte bin_loader_data[BIN_LOADER_SIZE] = { + 0xF3, 0x3E, 0xC9, 0x32, 0x9A, 0xFD, 0x32, 0x9F, 0xFD, 0x21, 0x00, 0x00, + 0x22, 0xC2, 0xF6, 0x21, 0x01, 0x80, 0x22, 0x76, 0xF6, 0x2B, 0x22, 0x48, + 0xFC, 0x3E, 0x0F, 0x21, 0xE9, 0xF3, 0x77, 0x3E, 0x01, 0x23, 0x77, 0x23, + 0x77, 0xCD, 0x62, 0x00, 0xCD, 0x6C, 0x00, 0xAF, 0x32, 0x00, 0x80, 0xC3, + 0xAC, 0x73 + +}; +byte cas_loader_data[CAS_LOADER_SIZE] = { 0x1F, 0xA6, 0xDE, 0xBA, 0xCC, 0x13, 0x7D, 0x74, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0x47, 0x41, 0x4D, 0x45, 0x20, 0x20, 0x1F, 0xA6, 0xDE, 0xBA, 0xCC, 0x13, 0x7D, 0x74, 0x75, 0xF9, 0xF4, 0xF9, @@ -80,7 +95,8 @@ typedef struct options bool quiet; char *infile; off_t infile_s; - char *outfile; + char *casfile; + char *binfile; char *ascfile; char *romfile; byte casname[CAS_NAME_LEN]; @@ -117,6 +133,7 @@ int get_colon(byte *buffer, int pos, FILE *output); int get_string(byte *buffer, int pos, FILE *output); bool process_bas(byte *buffer, off_t file_size, uint16_t base_addr, bool force_quiet); bool write_bin(byte *buffer, off_t buf_size, char *binf); +bool write_cas(byte *buffer, off_t buf_size, char *casf); bool write_rom(byte *inbuf, off_t buf_size, char *romfile); bool process_opt(int argc, char **argv, options_t *opt); diff --git a/src/common/loader_bin.asm b/src/common/loader_bin.asm new file mode 100644 index 0000000..61c2be0 --- /dev/null +++ b/src/common/loader_bin.asm @@ -0,0 +1,84 @@ +/****************************************************************************** +Copyright 2023 Jose Angel Morente - MSXWiki.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the �Software�), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + + include common.asm + + +BASPRG equ #8000 +buffer equ #8000 + +JMPLDR equ #F000 + +LAUNCH equ #4000 + +CRTSLT equ #f975 +PG0SLT equ CRTSLT+1 +PG1SLT equ PG0SLT+1 +PG2SLT equ PG1SLT+1 +DZX0 equ PG2SLT+1 + + +LDRSTART equ #F975 +LDREXEC equ LDRSTART + + output loader_bin.dat + + + org LDRSTART + di + ld a,#c9 + ld (H.KEYI),a + ld (H.TIMI),a + + +; ld hl,BASPRG+#10 ;#10 is the headroom to hold the LDIR routine +; ld de,BASPRG +; ld bc,0000 ;value to be overwritten externally +; ldir + ;HL contains the top address + +; di +; ld h,d +; ld l,e + ld hl,0000 ;to be modified + ld (VARTAB),hl + ld hl,BASPRG+1 + ld (TXTTAB),hl + dec hl + ld (BOTTOM),hl + + ld a,15 + ld hl,FORCLR + ld (hl),a + ld a,1 + inc hl + ld (hl),a + inc hl + ld (hl),a + call CHGCLR + + call INITXT + xor a + ld (BASPRG),a + + jp BASRUN +LDREND: diff --git a/src/common/loader_bin.dat b/src/common/loader_bin.dat new file mode 100644 index 0000000..b31b98f Binary files /dev/null and b/src/common/loader_bin.dat differ