aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/casm.html13
-rw-r--r--src/Makefile4
-rw-r--r--src/example/Makefile2
-rw-r--r--src/example/c64.asm2
-rw-r--r--src/output.c1
-rw-r--r--src/t64out.c102
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);