aboutsummaryrefslogtreecommitdiff
path: root/src/specout.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/specout.c')
-rw-r--r--src/specout.c220
1 files changed, 217 insertions, 3 deletions
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 <stdlib.h>
#include <stdio.h>
+#include <stdarg.h>
#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;