From ace88543a32f2c6dfc6a3aa17bd9a35f55a0b1d8 Mon Sep 17 00:00:00 2001 From: Ian C Date: Wed, 14 Sep 2016 22:03:40 +0100 Subject: Added option for BASIC loader to Spectrum TAP file. --- doc/casm.html | 36 +++++++- src/example/spectrum.asm | 4 +- src/listing.c | 2 +- src/specout.c | 220 ++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 256 insertions(+), 6 deletions(-) diff --git a/doc/casm.html b/doc/casm.html index 014262e..28284f8 100644 --- a/doc/casm.html +++ b/doc/casm.html @@ -1030,11 +1030,45 @@ have been used, in which case each code file in the TAP file will use the output-bank setting to generate the filename for each block.

+

If the options are set the TAP file will contain a BASIC loader for the +machine code.

+

Remember that TAP files can be concatenated, so the output could be appended to -another TAP file containing a BASIC loader, for example. +another TAP file. +

+ +

Spectrum TAP Output Format options

+ +

The Spectrum TAP output driver supports the following settings that can be +set via an option command.

+ + + + + + + + + + + + +
OptionDescription
+option spectrum-loader, <on|off> + +Whether the TAP file should contain a BASIC loader to load and run the machine +code. +
+option spectrum-start, address + +The start address for the generated BASIC loader. If left undefined defaults +to the start of written memory. +
+ +

ZX81 .P Output Format

diff --git a/src/example/spectrum.asm b/src/example/spectrum.asm index 01175f9..70cb6ea 100644 --- a/src/example/spectrum.asm +++ b/src/example/spectrum.asm @@ -8,8 +8,10 @@ option output-file,spectrum.tap option output-format,spectrum + option +spectrum-loader + option spectrum-start,start - org 32768 +start: org 32768 ld a,0 loop: diff --git a/src/listing.c b/src/listing.c index 13fcc2e..5bc6568 100644 --- a/src/listing.c +++ b/src/listing.c @@ -19,7 +19,7 @@ ------------------------------------------------------------------------- - Common utilities + Listing */ #include diff --git a/src/specout.c b/src/specout.c index dbb8684..3f6719e 100644 --- a/src/specout.c +++ b/src/specout.c @@ -24,13 +24,134 @@ */ #include #include +#include #include "global.h" #include "specout.h" +#include "expr.h" + + +/* ---------------------------------------- PRIVATE TYPES +*/ +enum option_t +{ + OPT_LOADER, + OPT_START_ADDR, +}; + +static const ValueTable option_set[] = +{ + {"spectrum-loader", OPT_LOADER}, + {"spectrum-start", OPT_START_ADDR}, + {NULL} +}; + +typedef struct +{ + int loader; + int start_addr; +} Options; + + +/* ---------------------------------------- PRIVATE DATA +*/ + +/* Types for AddLine() +*/ +#define TYPE_END 0 +#define TYPE_TOKEN 1 +#define TYPE_STRING 2 + +/* Constants for some tokens +*/ +#define TOK_VAL 176 +#define TOK_QUOTE 34 +#define TOK_CODE 175 +#define TOK_USR 192 +#define TOK_LOAD 239 +#define TOK_RAND 249 +#define TOK_CLEAR 253 + + +static Options options = +{ + FALSE, + -1 +}; + +/* Buffers used for BASIC loader +*/ +static unsigned char basic[0x10000]; +static unsigned endptr = 0; +static unsigned line_no = 10; /* ---------------------------------------- PRIVATE FUNCTIONS */ +static void Poke(unsigned char b, int *len) +{ + if (len) + { + (*len)++; + } + + basic[endptr++]=b; +} + + +static void AddBASICLine(int type, ...) +{ + va_list va; + int len; + unsigned char *len_ptr; + + Poke(line_no>>8, NULL); + Poke(line_no&0xff, NULL); + line_no += 10; + + len_ptr = basic + endptr; + endptr += 2; + len = 0; + + va_start(va,type); + + while(type!=TYPE_END) + { + char *str; + + switch(type) + { + case TYPE_TOKEN: + Poke(va_arg(va,int), &len); + break; + + case TYPE_STRING: + str = va_arg(va,char *); + + Poke(TOK_QUOTE, &len); + + while(*str) + { + Poke(*str++, &len); + } + + Poke(TOK_QUOTE, &len); + + break; + + default: + break; + } + + type = va_arg(va,int); + } + + Poke(0x0d, &len); + + *len_ptr++ = len&0xff; + *len_ptr = len>>8; +} + static Byte TapByte(FILE *fp, Byte b, Byte chk) { @@ -59,18 +180,48 @@ static Byte TapString(FILE *fp, const char *p, int len, Byte chk) } +static unsigned char TapStream(FILE *fp, const unsigned char *p, + unsigned addr, unsigned len, unsigned char chk) +{ + while(len--) + { + chk = TapByte(fp, p[addr], chk); + addr = (addr + 1) & 0xffff; + } + + return chk; +} + /* ---------------------------------------- INTERFACES */ const ValueTable *SpecTAPOutputOptions(void) { - return NULL; + return option_set; } CommandStatus SpecTAPOutputSetOption(int opt, int argc, char *argv[], int quoted[], - char *error, size_t error_size) + char *err, size_t errsize) { - return CMD_NOT_KNOWN; + CommandStatus stat = CMD_OK; + + CMD_ARGC_CHECK(1); + + switch(opt) + { + case OPT_LOADER: + options.loader = ParseTrueFalse(argv[0], FALSE); + break; + + case OPT_START_ADDR: + CMD_EXPR(argv[0], options.start_addr); + break; + + default: + break; + } + + return stat; } int SpecTAPOutput(const char *filename, const char *filename_bank, @@ -85,6 +236,69 @@ int SpecTAPOutput(const char *filename, const char *filename_bank, return FALSE; } + /* First get the initial address is none defined + */ + if (options.loader && options.start_addr == -1) + { + options.start_addr = bank[0]->min_address_used; + } + + /* Output the BASIC loader if set + */ + if (options.loader) + { + char no[64]; + Byte chk = 0; + + snprintf(no, sizeof no, "%u", options.start_addr); + + /* CLEAR VAL "start_addr" + */ + AddBASICLine(TYPE_TOKEN, TOK_CLEAR, + TYPE_TOKEN, TOK_VAL, + TYPE_STRING, no, + TYPE_END); + + /* LOAD "" CODE + */ + for(f = 0; f < count; f++) + { + AddBASICLine(TYPE_TOKEN, TOK_LOAD, + TYPE_TOKEN, TOK_QUOTE, + TYPE_TOKEN, TOK_QUOTE, + TYPE_TOKEN, TOK_CODE, + TYPE_END); + } + + /* RANDOMIZE USR VAL "start_addr" + */ + AddBASICLine(TYPE_TOKEN, TOK_RAND, + TYPE_TOKEN, TOK_USR, + TYPE_TOKEN, TOK_VAL, + TYPE_STRING, no, + TYPE_END); + + TapWord(fp, 19, 0); + chk = TapByte(fp, 0, chk); + chk = TapByte(fp, 0, chk); + chk = TapString(fp, "LOADER.BAS", 10, chk); + chk = TapWord(fp, endptr, chk); + chk = TapWord(fp, 10, chk); + chk = TapWord(fp, endptr, chk); + + TapByte(fp, chk, 0); + + TapWord(fp, endptr + 2, 0); + + chk = 0; + + chk = TapByte(fp, 0xff, chk); + chk = TapStream(fp, basic, 0, endptr, chk); + TapByte(fp, chk, 0); + } + + /* Output the binary files + */ for(f = 0; f < count; f++) { Byte chk = 0; -- cgit v1.2.3