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.
+
+
+Option |
+Description |
+
+
+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