diff options
-rw-r--r-- | doc/casm.html | 13 | ||||
-rw-r--r-- | src/Makefile | 4 | ||||
-rw-r--r-- | src/example/Makefile | 2 | ||||
-rw-r--r-- | src/example/c64.asm | 2 | ||||
-rw-r--r-- | src/output.c | 1 | ||||
-rw-r--r-- | src/t64out.c | 102 |
6 files changed, 114 insertions, 10 deletions
diff --git a/doc/casm.html b/doc/casm.html index 4724729..9553a15 100644 --- a/doc/casm.html +++ b/doc/casm.html @@ -862,10 +862,19 @@ have been used, in which case then each entry in the tape file will use the <b>output-bank</b> setting to generate the filename for each entry. </p> -<p>Each entry in the tape file will be marked as a PRG with the start address -the same as the first assembled byte. +<p>The first (or only) bank will have a small BASIC program inserted as part of +the generated file. For this reason the first bank should start near the BASIC +area (0x820 should be a safe place to start) unless you have a great +desire for a tape full of zero bytes. This BASIC will simply hold a SYS command +to start the machine code, e.g. </p> +<pre class="codeblock"> +10 SYS 2080 +</pre> + +<p>Any remaining blocks will be stored as-is without any basic loader.</p> + <h3>Listing</h3> diff --git a/src/Makefile b/src/Makefile index 3931901..0812105 100644 --- a/src/Makefile +++ b/src/Makefile @@ -84,7 +84,7 @@ listing.o: listing.c global.h basetype.h util.h state.h label.h macro.h \ macro.o: macro.c global.h basetype.h util.h state.h codepage.h parse.h \ cmd.h varchar.h macro.h output.o: output.c global.h basetype.h util.h state.h output.h parse.h \ - cmd.h rawout.h specout.h + cmd.h rawout.h specout.h t64out.h parse.o: parse.c global.h basetype.h util.h state.h codepage.h parse.h \ cmd.h rawout.o: rawout.c global.h basetype.h util.h state.h rawout.h parse.h \ @@ -93,6 +93,8 @@ specout.o: specout.c global.h basetype.h util.h state.h specout.h parse.h \ cmd.h stack.o: stack.c global.h basetype.h util.h state.h stack.h state.o: state.c global.h basetype.h util.h state.h expr.h +t64out.o: t64out.c global.h basetype.h util.h state.h codepage.h parse.h \ + cmd.h t64out.h util.o: util.c global.h basetype.h util.h state.h varchar.o: varchar.c global.h basetype.h util.h state.h codepage.h \ parse.h cmd.h varchar.h diff --git a/src/example/Makefile b/src/example/Makefile index 13d24bb..e9ddfce 100644 --- a/src/example/Makefile +++ b/src/example/Makefile @@ -25,6 +25,8 @@ CASM = ../casm all: $(ALL) +remake: clean all + spectrum.tap: spectrum.asm $(CASM) spectrum.asm diff --git a/src/example/c64.asm b/src/example/c64.asm index 5e80223..e627e32 100644 --- a/src/example/c64.asm +++ b/src/example/c64.asm @@ -8,7 +8,7 @@ option output-file,c64.t64 option output-format,t64 - org $6000 + org $820 lda #0 clc diff --git a/src/output.c b/src/output.c index 5d4aef6..4c03e4e 100644 --- a/src/output.c +++ b/src/output.c @@ -30,6 +30,7 @@ #include "rawout.h" #include "specout.h" +#include "t64out.h" /* TODO #include "zx81out.h" */ diff --git a/src/t64out.c b/src/t64out.c index 6509323..0fd308f 100644 --- a/src/t64out.c +++ b/src/t64out.c @@ -24,6 +24,7 @@ */ #include <stdlib.h> #include <stdio.h> +#include <string.h> #include "global.h" #include "codepage.h" @@ -38,6 +39,31 @@ /* ---------------------------------------- PRIVATE FUNCTIONS */ +static int PokeB(Byte *mem, int addr, Byte b) +{ + mem[addr++] = b; + return (addr % 0x10000); +} + + +static int PokeW(Byte *mem, int addr, int w) +{ + addr = PokeB(mem, addr, w & 0xff); + return PokeB(mem, addr, (w & 0xff00) >> 8); +} + + +static int PokeS(Byte *mem, int addr, const char *str) +{ + while(*str) + { + addr = PokeB(mem, addr, CodeFromNative(CP_CBM, *str++)); + } + + return addr; +} + + static void WriteByte(FILE *fp, Byte b) { putc(b, fp); @@ -106,11 +132,11 @@ int T64Output(const char *filename, const char *filename_bank, /* Write directory header */ - WriteWord(fp, 0x1010); + WriteWord(fp, 0x200); WriteWord(fp, count); WriteWord(fp, count); WriteWord(fp, NOT_USED); - WriteString(fp, filename, 24, ' ', CP_CBM); + WriteString(fp, filename, 24, ' ', CP_ASCII); /* Offset to tape data */ @@ -120,16 +146,53 @@ int T64Output(const char *filename, const char *filename_bank, */ for(f = 0; f < count; f++) { + int min, max, len; + + min = bank[f]->min_address_used; + max = bank[f]->max_address_used; + + /* If this is the first bank, we're going to prepend some BASIC + */ + if (f == 0) + { + if (min < 0x810) + { + snprintf(error, error_size, "First bank starts below a safe " + "area to add BASIC loader"); + + return FALSE; + } + + min = 0x801; /* Start of BASIC */ + } + + len = max - min + 1; + WriteByte(fp, 1); WriteByte(fp, 0x82); - WriteWord(fp, bank[f]->min_address_used); - WriteWord(fp, bank[f]->max_address_used); + WriteWord(fp, min); + WriteWord(fp, max + 1); WriteWord(fp, NOT_USED); WriteLong(fp, offset); WriteWord(fp, NOT_USED); WriteWord(fp, NOT_USED); - offset += bank[f]->max_address_used - bank[f]->min_address_used + 1; + if (count == 1) + { + WriteString(fp, filename, 16, ' ', CP_CBM); + } + else + { + char fn[16]; + + snprintf(fn, sizeof fn, filename_bank, bank[f]->number); + WriteString(fp, fn, 16, ' ', CP_CBM); + } + + /* +2 is to include the 2-byte PRG header + offset += len + 2; + */ + offset += len; } /* Write actual contents @@ -140,11 +203,38 @@ int T64Output(const char *filename, const char *filename_bank, int min, max, len; mem = bank[f]->memory; + min = bank[f]->min_address_used; max = bank[f]->max_address_used; + + /* If this is the first bank, we're going to prepend some BASIC. + Note that output drivers are allowed to manipulate memory directly. + */ + if (f == 0) + { + char sys[16]; + int a = 0x803; + int next; + + snprintf(sys, sizeof sys, "%u", min); + + a = PokeW(mem, a, 10); + a = PokeB(mem, a, 0x9e); + a = PokeS(mem, a, sys); + a = PokeB(mem, a, 0x00); + + next = a; + + a = PokeW(mem, a, 0x00); + + PokeW(mem, 0x801, next); + + min = 0x801; + } + len = max - min + 1; - fwrite(mem, len, 1, fp); + fwrite(mem + min, len, 1, fp); } fclose(fp); |