aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/casm.html41
-rw-r--r--src/Makefile6
-rw-r--r--src/codepage.c25
-rw-r--r--src/codepage.h16
-rw-r--r--src/example/Makefile5
-rw-r--r--src/example/c64.asm19
-rw-r--r--src/output.c147
-rw-r--r--src/t64out.c158
-rw-r--r--src/t64out.h56
9 files changed, 322 insertions, 151 deletions
diff --git a/doc/casm.html b/doc/casm.html
index 35d6683..4724729 100644
--- a/doc/casm.html
+++ b/doc/casm.html
@@ -800,6 +800,20 @@ A raw binary image.
A Spectrum emulator TAP file.
</td></tr>
+<tr><td class="cmd">
+<a href="#zx81out">p-file</a>
+</td>
+<td class="def">
+A ZX-81 emulator P file.
+</td></tr>
+
+<tr><td class="cmd">
+<a href="#t64out">t64</a>
+</td>
+<td class="def">
+A Commodore 64 T64 tape file.
+</td></tr>
+
</table>
</td></tr>
@@ -823,14 +837,33 @@ file holding the bytes that the real Spectrum would have written to a tape.
</p>
<p>The TAP file will be given the same name as the output filename, and the
-internal code block will also be given the same name, unless if memory banks
-have been used then each code file in the TAP file will use the
-<b>output-bank</b> setting is used to generate the filename for each block.
+internal code block will also be given the same name, unless memory banks
+have been used, in which case each code file in the TAP file will use the
+<b>output-bank</b> setting to generate the filename for each block.
</p>
<p>
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 containing a BASIC loader, for example.
+</p>
+
+
+<h3 id="zx81out">ZX81 .P Output Format</h3>
+
+
+<h3 id="t64out">C64 T64 Tape Output Format</h3>
+<p>
+Generates a T64 tape file for an emulator.
+</p>
+
+<p>The tape file will be given the same name as the output filename, and the
+internal code block will also be given the same name, unless memory banks
+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>
diff --git a/src/Makefile b/src/Makefile
index 1980209..3931901 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -40,7 +40,8 @@ SOURCE = casm.c \
6502.c \
z80.c \
rawout.c \
- specout.c
+ specout.c \
+ t64out.c
OBJECTS = casm.o \
expr.o \
@@ -58,7 +59,8 @@ OBJECTS = casm.o \
6502.o \
z80.o \
rawout.o \
- specout.o
+ specout.o \
+ t64out.o
$(TARGET): $(OBJECTS)
$(CC) $(CLAGS) -o $(TARGET) $(OBJECTS)
diff --git a/src/codepage.c b/src/codepage.c
index 0083947..4cbc1bc 100644
--- a/src/codepage.c
+++ b/src/codepage.c
@@ -33,15 +33,6 @@
/* ---------------------------------------- TYPES
*/
-typedef enum
-{
- CP_ASCII,
- CP_ZX81,
- CP_SPECTRUM,
- CP_CBM
-} Codepage;
-
-
typedef struct
{
int code;
@@ -254,6 +245,22 @@ int CodepageConvert(int code)
}
+int CodeFromNative(Codepage page, int code)
+{
+ int f;
+
+ for(f = 0; cp_table[page][f].code; f++)
+ {
+ if (cp_table[page][f].code == code)
+ {
+ return cp_table[page][f].result;
+ }
+ }
+
+ return 0;
+}
+
+
/*
vim: ai sw=4 ts=8 expandtab
*/
diff --git a/src/codepage.h b/src/codepage.h
index 64f5868..5da55cb 100644
--- a/src/codepage.h
+++ b/src/codepage.h
@@ -31,6 +31,14 @@
/* ---------------------------------------- INTERFACES
*/
+typedef enum
+{
+ CP_ASCII,
+ CP_ZX81,
+ CP_SPECTRUM,
+ CP_CBM
+} Codepage;
+
/* Codepage options
*/
@@ -45,7 +53,13 @@ CommandStatus CodepageSetOption(int opt, int argc, char *argv[],
/* Converts the passed character into the appropriate codepage value.
Returns zero for unknown/unconvertable characters.
*/
-int CodepageConvert(int code);
+int CodepageConvert(int code);
+
+
+/* Converts from the execution character set into a code from the specified
+ codepage.
+*/
+int CodeFromNative(Codepage page, int code);
#endif
diff --git a/src/example/Makefile b/src/example/Makefile
index 282cd6d..13d24bb 100644
--- a/src/example/Makefile
+++ b/src/example/Makefile
@@ -20,7 +20,7 @@
# Makefile for examples
#
-ALL = spectrum.tap # c64.t64 zx81.p
+ALL = spectrum.tap c64.t64 # zx81.p
CASM = ../casm
all: $(ALL)
@@ -28,5 +28,8 @@ all: $(ALL)
spectrum.tap: spectrum.asm
$(CASM) spectrum.asm
+c64.t64: c64.asm
+ $(CASM) c64.asm
+
clean:
rm -f $(ALL)
diff --git a/src/example/c64.asm b/src/example/c64.asm
new file mode 100644
index 0000000..5e80223
--- /dev/null
+++ b/src/example/c64.asm
@@ -0,0 +1,19 @@
+ ; Simple example C64 code
+ ;
+
+ cpu 6502
+
+ option codepage,cbm
+
+ option output-file,c64.t64
+ option output-format,t64
+
+ org $6000
+
+ lda #0
+ clc
+loop:
+ sta 53280
+ adc #1
+ and #$0f
+ jmp loop
diff --git a/src/output.c b/src/output.c
index 789531f..5d4aef6 100644
--- a/src/output.c
+++ b/src/output.c
@@ -53,150 +53,25 @@ static const ValueTable option_set[] =
typedef enum
{
- Raw,
- SpectrumTap
+ RAW,
+ TAP,
+ T64
} Format;
static char output[4096] = "output";
static char output_bank[4096] = "output.%u";
static char error[1024];
-static Format format = Raw;
+static Format format = RAW;
static ValueTable format_table[] =
{
- {"raw", Raw},
- {"spectrum", SpectrumTap},
+ {"raw", RAW},
+ {"spectrum", TAP},
+ {"t64", T64},
{NULL}
};
-/* ---------------------------------------- PRIVATE FUNCTIONS
-*/
-static int OutputRawBinary(MemoryBank **bank, int count)
-{
- char buff[4096];
- int f;
-
- for(f = 0; f < count; f++)
- {
- FILE *fp;
- const char *name;
- const Byte *mem;
- int min, max;
-
- if (count == 1)
- {
- name = output;
- }
- else
- {
- snprintf(buff, sizeof buff, "%s.%u", output, bank[f]->number);
- name = buff;
- }
-
- if (!(fp = fopen(name, "wb")))
- {
- snprintf(error, sizeof error,"Failed to open %s\n", name);
- return FALSE;
- }
-
- mem = bank[f]->memory;
- min = bank[f]->min_address_used;
- max = bank[f]->max_address_used;
-
- fwrite(mem + min, 1, max - min + 1, fp);
-
- fclose(fp);
- }
-
- return TRUE;
-}
-
-
-static Byte TapByte(FILE *fp, Byte b, Byte chk)
-{
- chk ^= b;
- putc(b, fp);
- return chk;
-}
-
-
-static Byte TapWord(FILE *fp, int w, Byte chk)
-{
- chk = TapByte(fp, w & 0xff, chk);
- chk = TapByte(fp, (w & 0xff00) >> 8, chk);
- return chk;
-}
-
-
-static Byte TapString(FILE *fp, const char *p, int len, Byte chk)
-{
- while(len--)
- {
- chk = TapByte(fp, *p ? *p++ : ' ', chk);
- }
-
- return chk;
-}
-
-
-static int OutputSpectrumTap(MemoryBank **bank, int count)
-{
- FILE *fp = fopen(output, "wb");
- int f;
-
- if (!fp)
- {
- snprintf(error, sizeof error,"Failed to open %s\n", output);
- return FALSE;
- }
-
- /* Output header
- */
- for(f = 0; f < count; f++)
- {
- Byte chk = 0;
- const Byte *mem;
- int min, max, len;
-
- mem = bank[f]->memory;
- min = bank[f]->min_address_used;
- max = bank[f]->max_address_used;
- len = max - min + 1;
-
- TapWord(fp, 19, 0);
-
- chk = TapByte(fp, 0, chk);
- chk = TapByte(fp, 3, chk);
- chk = TapString(fp, output, 10, chk);
- chk = TapWord(fp, len, chk);
- chk = TapWord(fp, min, chk);
- chk = TapWord(fp, 32768, chk);
-
- TapByte(fp, chk, 0);
-
- /* Output file data
- */
- TapWord(fp, len + 2, 0);
-
- chk = 0;
-
- chk = TapByte(fp, 0xff, chk);
-
- while(min <= max)
- {
- chk = TapByte(fp, mem[min], chk);
- min++;
- }
-
- TapByte(fp, chk, 0);
- }
-
- fclose(fp);
-
- return TRUE;
-}
-
/* ---------------------------------------- INTERFACES
*/
@@ -254,14 +129,18 @@ int OutputCode(void)
switch(format)
{
- case Raw:
+ case RAW:
return RawOutput(output, output_bank, bank, count,
error, sizeof error);
- case SpectrumTap:
+ case TAP:
return SpecTAPOutput(output, output_bank, bank, count,
error, sizeof error);
+ case T64:
+ return T64Output(output, output_bank, bank, count,
+ error, sizeof error);
+
default:
break;
}
diff --git a/src/t64out.c b/src/t64out.c
new file mode 100644
index 0000000..6509323
--- /dev/null
+++ b/src/t64out.c
@@ -0,0 +1,158 @@
+/*
+
+ casm - Simple, portable assembler
+
+ Copyright (C) 2003-2015 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ -------------------------------------------------------------------------
+
+ Commodore T64 tape output handler.
+
+*/
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "global.h"
+#include "codepage.h"
+#include "t64out.h"
+
+
+/* ---------------------------------------- MACROS & TYPES
+*/
+
+#define NOT_USED 0
+
+/* ---------------------------------------- PRIVATE FUNCTIONS
+*/
+
+static void WriteByte(FILE *fp, Byte b)
+{
+ putc(b, fp);
+}
+
+
+static void WriteWord(FILE *fp, int w)
+{
+ WriteByte(fp, w & 0xff);
+ WriteByte(fp, (w & 0xff00) >> 8);
+}
+
+
+static void WriteLong(FILE *fp, unsigned long l)
+{
+ int f;
+
+ for(f = 0; f < 4; f++)
+ {
+ WriteByte(fp, l & 0xff);
+ l >>= 8u;
+ }
+}
+
+
+static void WriteString(FILE *fp, const char *p, int len,
+ Byte fill, Codepage cp)
+{
+ while(len--)
+ {
+ WriteByte(fp, *p ? CodeFromNative(cp, *p++) : CodeFromNative(cp, fill));
+ }
+}
+
+
+/* ---------------------------------------- INTERFACES
+*/
+const ValueTable *T64OutputOptions(void)
+{
+ return NULL;
+}
+
+CommandStatus T64OutputSetOption(int opt, int argc, char *argv[],
+ int quoted[],
+ char *error, size_t error_size)
+{
+ return CMD_NOT_KNOWN;
+}
+
+int T64Output(const char *filename, const char *filename_bank,
+ MemoryBank **bank, int count, char *error, size_t error_size)
+{
+ FILE *fp = fopen(filename, "wb");
+ int f;
+ int offset;
+
+ if (!fp)
+ {
+ snprintf(error, error_size, "Failed to create %s\n", filename);
+ return FALSE;
+ }
+
+ /* Write signature
+ */
+ WriteString(fp, "C64 tape image file", 32, 0, CP_ASCII);
+
+ /* Write directory header
+ */
+ WriteWord(fp, 0x1010);
+ WriteWord(fp, count);
+ WriteWord(fp, count);
+ WriteWord(fp, NOT_USED);
+ WriteString(fp, filename, 24, ' ', CP_CBM);
+
+ /* Offset to tape data
+ */
+ offset = 64 + 32 * count;
+
+ /* Write directory entries
+ */
+ for(f = 0; f < count; f++)
+ {
+ WriteByte(fp, 1);
+ WriteByte(fp, 0x82);
+ WriteWord(fp, bank[f]->min_address_used);
+ WriteWord(fp, bank[f]->max_address_used);
+ 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;
+ }
+
+ /* Write actual contents
+ */
+ for(f = 0; f < count; f++)
+ {
+ Byte *mem;
+ int min, max, len;
+
+ mem = bank[f]->memory;
+ min = bank[f]->min_address_used;
+ max = bank[f]->max_address_used;
+ len = max - min + 1;
+
+ fwrite(mem, len, 1, fp);
+ }
+
+ fclose(fp);
+
+ return TRUE;
+}
+
+
+/*
+vim: ai sw=4 ts=8 expandtab
+*/
diff --git a/src/t64out.h b/src/t64out.h
new file mode 100644
index 0000000..2743d0e
--- /dev/null
+++ b/src/t64out.h
@@ -0,0 +1,56 @@
+/*
+
+ casm - Simple, portable assembler
+
+ Copyright (C) 2003-2015 Ian Cowburn (ianc@noddybox.demon.co.uk)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ -------------------------------------------------------------------------
+
+ Commodore T64 tape output
+
+*/
+
+#ifndef CASM_T64OUT_H
+#define CASM_T64OUT_H
+
+#include "parse.h"
+#include "state.h"
+#include "cmd.h"
+
+/* ---------------------------------------- INTERFACES
+*/
+
+
+/* RAW Output options
+*/
+const ValueTable *T64OutputOptions(void);
+
+CommandStatus T64OutputSetOption(int opt, int argc, char *argv[],
+ int quoted[], char *error,
+ size_t error_size);
+
+
+/* Spectrum TAP output of assembly. Returns TRUE if OK, FALSE for failure.
+*/
+int T64Output(const char *filename, const char *filename_bank,
+ MemoryBank **bank, int count,
+ char *error, size_t error_size);
+
+#endif
+
+/*
+vim: ai sw=4 ts=8 expandtab
+*/