From 16e3e35846578e2df90a0c0d75bc2ff41e403946 Mon Sep 17 00:00:00 2001 From: Ian Cowburn Date: Tue, 21 Sep 2021 21:07:39 +0100 Subject: Imported V1.7 --- README.md | 10 +- doc/casm.html | 43 ++++++++ src/casm.c | 2 +- src/cpcout.c | 288 ++++++++++++++++++++++++++++++++++++++++------------ src/example/cpc.asm | 11 +- 5 files changed, 278 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index 519aa51..7983730 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,6 @@ # casm -Portable cross assembler. Source control for this is now located in Subversion -at -https://noddybox.co.uk/svn/casm/trunk. The homepage is at - -https://noddybox.co.uk/casm.php. -Sorry, I tried to like GIT but -found it's workflow not as comfortable as SVN for me. +Portable cross assembler. ## Usage @@ -15,7 +9,7 @@ Simply pass it the file to assemble, i.e. `casm source.txt` Full documentation can be found in -HTML format. +HTML format. ## Processors diff --git a/doc/casm.html b/doc/casm.html index 31e1d92..c7e17ab 100644 --- a/doc/casm.html +++ b/doc/casm.html @@ -1005,6 +1005,13 @@ labels. A NES ROM file. + +cpc + + +An Amstrad CPC CDT file. + + @@ -1459,6 +1466,42 @@ Defines whether there is battery backed RAM in the cartridge. Defaults to +

Amstrad CPC CDT Output Format

+

+Generates an Amstrad CPC TAP file for an emulator. +The file can also be run into a real CPC using TZX to wav file converters. +

+ +

The CDT file will be given the same name as the output filename, +unless memory banks have been used, in which case each code file in the CDT +file will use the output-bank setting to generate the filename for +each block. +

+ +

Amstrad CPC CDT Output Format options

+ +

The Amstrad CPC CDT output driver supports the following settings that can be +set via an option command. +

+ + + + + + + + + + +
OptionDescription
+option cpc-start, address + +The start address for the tape file. If left undefined defaults to the start +of written memory. +
+ + +

Listing

diff --git a/src/casm.c b/src/casm.c index 852fa24..c747ad9 100644 --- a/src/casm.c +++ b/src/casm.c @@ -59,7 +59,7 @@ */ static const char *casm_usage = -"Version 1.7 development\n" +"Version 1.7\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" diff --git a/src/cpcout.c b/src/cpcout.c index e3e871d..6e37a1c 100644 --- a/src/cpcout.c +++ b/src/cpcout.c @@ -36,6 +36,8 @@ */ #define BLOCK_SIZE 2048 +#define LO_BYTE(w) ((w) & 0xff) +#define HI_BYTE(w) (((w) & 0xff00)>>8) enum option_t { @@ -55,43 +57,162 @@ typedef struct static Options options = {-1}; +typedef struct +{ + Byte *stream; + size_t length; +} Stream; + /* ---------------------------------------- PRIVATE FUNCTIONS */ -static Byte WriteByte(FILE *fp, Byte b, Byte chk) +static void InitStream(Stream *s) +{ + s->stream = NULL; + s->length = 0; +} + +static void AddStreamByte(Stream *s, Byte b) +{ + s->length++; + s->stream = Realloc(s->stream, s->length); + s->stream[s->length - 1] = b; +} + +static void AddStreamMem(Stream *s, Byte *mem, size_t len) +{ + while(len--) + { + AddStreamByte(s, *mem++); + } +} + + +static void FreeStream(Stream *s) +{ + if (s->stream) + { + free(s->stream); + } + + InitStream(s); +} + + +static Word CRC(const Byte *b, int size) +{ + Word crc = 0xffff; + int f; + + for(f = 0; f < 256; f++) + { + Word w; + int n; + + if (f < size) + { + w = b[f]; + } + else + { + w = 0; + } + + crc ^= w << 8; + + for(n = 0; n < 8; n++) + { + if (crc & 0x8000) + { + crc = ((crc << 1) ^ 0x1021) & 0xffff; + } + else + { + crc = (crc << 1) & 0xffff; + } + } + } + + crc ^= 0xffff; + + return crc; +} + + +static void WriteByte(FILE *fp, Byte b) { - chk ^= b; putc(b, fp); - return chk; } -static Byte WriteWord(FILE *fp, int w, Byte chk) +static void WriteWord(FILE *fp, int w) +{ + WriteByte(fp, LO_BYTE(w)); + WriteByte(fp, HI_BYTE(w)); +} + + +static void WriteDWord(FILE *fp, unsigned long w) +{ + WriteWord(fp, w & 0xffff); + WriteWord(fp, (w & 0xffff0000) >> 16); +} + + +static void WriteMem(FILE *fp, const Byte *mem, int len) +{ + fwrite(mem, 1, len, fp); +} + + +static void WriteWordMem(Byte *mem, int offset, int w) +{ + mem[offset] = LO_BYTE(w); + mem[offset+1] = HI_BYTE(w); +} + + +static void Write3Word(FILE *fp, int w) { - chk = WriteByte(fp, w & 0xff, chk); - chk = WriteByte(fp, (w & 0xff00) >> 8, chk); - return chk; + WriteByte(fp, LO_BYTE(w)); + WriteByte(fp, HI_BYTE(w)); + WriteByte(fp, (w & 0xff0000) >> 16); } -static Byte Write3Word(FILE *fp, int w, Byte chk) +static void WriteString(FILE *fp, const char *p, int len, + Byte fill, Codepage cp) { - chk = WriteByte(fp, w & 0xff, chk); - chk = WriteByte(fp, (w & 0xff00) >> 8, chk); - chk = WriteByte(fp, (w & 0xff0000) >> 16, chk); - return chk; + while(len--) + { + WriteByte(fp, *p ? CodeFromNative(cp, *p++) : CodeFromNative(cp, fill)); + } } -static Byte WriteString(FILE *fp, const char *p, int len, - Byte fill, Codepage cp, Byte chk) +static void WriteStringMem(Byte *mem, int offset, const char *p, int len, + Byte fill, Codepage cp) { while(len--) { - chk = WriteByte(fp, *p ? CodeFromNative(cp, *p++) : - CodeFromNative(cp, fill), chk); + mem[offset++] = + *p ? CodeFromNative(cp, *p++) : CodeFromNative(cp, fill); } +} + - return chk; +static void OutputTZXTurboBlock(FILE *fp, Stream *s) +{ + WriteByte(fp, 0x11); /* Block type - Turbo block */ + WriteWord(fp, 0x0b21); /* PILOT pulse len */ + WriteWord(fp, 0x05ad); /* SYNC 1 len */ + WriteWord(fp, 0x05ad); /* SYNC 2 len */ + WriteWord(fp, 0x05ac); /* Zero len */ + WriteWord(fp, 0x0af4); /* One len */ + WriteWord(fp, 0x1002); /* PILOT tone */ + WriteByte(fp, 8); /* Last byte used bits */ + WriteWord(fp, 0x0011); /* Pause after block */ + Write3Word(fp, s->length); + WriteMem(fp, s->stream, s->length); } @@ -143,16 +264,17 @@ int CPCOutput(const char *filename, const char *filename_bank, /* Output the binary files */ - WriteString(fp, "ZXTape!", 7, 0, CP_ASCII, 0); - WriteByte(fp, 0x1a, 0); - WriteByte(fp, 1, 0); - WriteByte(fp, 13, 0); + WriteString(fp, "ZXTape!", 7, 0, CP_ASCII); + WriteByte(fp, 0x1a); + WriteByte(fp, 1); + WriteByte(fp, 0x14); for(f = 0; f < count; f++) { const Byte *mem; int min, max, len, blocks, addr; int block, blocklen; + Stream stream; mem = bank[f]->memory; min = bank[f]->min_address_used; @@ -168,39 +290,31 @@ int CPCOutput(const char *filename, const char *filename_bank, for(block = 0; block <= blocks; block++) { - Byte chk; + Byte header[256] = {0}; + Word crc; int first, last; + int seg, segs; + + InitStream(&stream); first = 0; last = 0; - WriteByte(fp, 0x11, 0); /* Block type */ - - WriteWord(fp, 0x626, 0); /* PILOT */ - WriteWord(fp, 0x34f, 0); /* SYNC1 */ - WriteWord(fp, 0x302, 0); /* SYNC2 */ - WriteWord(fp, 0x33a, 0); /* ZERO */ - WriteWord(fp, 0x673, 0); /* ONE */ - WriteWord(fp, 0xffe, 0); /* PILOT LEN */ - WriteByte(fp, 8, 0); /* USED BITS */ - WriteWord(fp, 0x10, 0); /* PAUSE */ - Write3Word(fp, 0x0041, 0); /* LEN */ - - chk = 0; - + /* Create the header + */ if (f == 0) { - chk = WriteString(fp, filename, 16, 0, CP_ASCII, chk); + WriteStringMem(header, 0, filename, 16, 0, CP_ASCII); } else { char fn[16]; snprintf(fn, sizeof fn, filename_bank, bank[f]->number); - chk = WriteString(fp, fn, 16, 0, CP_ASCII, chk); + WriteStringMem(header, 0, fn, 16, 0, CP_ASCII); } - chk = WriteByte(fp, block+1, chk); + header[16] = block + 1; if (block == 0) { @@ -222,42 +336,86 @@ int CPCOutput(const char *filename, const char *filename_bank, blocklen = len % BLOCK_SIZE; } - chk = WriteByte(fp, last, chk); - chk = WriteByte(fp, 2, chk); - chk = WriteWord(fp, blocklen, chk); - chk = WriteWord(fp, addr, chk); - chk = WriteByte(fp, first, chk); - chk = WriteWord(fp, len, chk); - chk = WriteWord(fp, options.start_addr, chk); - chk = WriteString(fp, "", 64 - 28, 0, CP_ASCII, chk); + if (blocklen == BLOCK_SIZE) + { + segs = 7; + } + else + { + segs = blocklen / 256; + } - WriteByte(fp, chk, 0); + header[17] = last; + header[18] = 2; + WriteWordMem(header, 19, blocklen); + WriteWordMem(header, 21, addr); + header[23] = first; + WriteWordMem(header, 24, len); + WriteWordMem(header, 26, options.start_addr); - addr += blocklen; + crc = CRC(header, 256); - /* Output file data + /* Write CSW data */ - WriteByte(fp, 0x11, 0); /* Block type */ + AddStreamByte(&stream, 0x2c); + AddStreamMem(&stream, header, 256); + AddStreamByte(&stream, HIBYTE(crc)); + AddStreamByte(&stream, LOBYTE(crc)); + AddStreamByte(&stream, 0xff); + AddStreamByte(&stream, 0xff); + AddStreamByte(&stream, 0xff); + AddStreamByte(&stream, 0xff); + + OutputTZXTurboBlock(fp, &stream); - WriteWord(fp, 0x626, 0); /* PILOT */ - WriteWord(fp, 0x34f, 0); /* SYNC1 */ - WriteWord(fp, 0x302, 0); /* SYNC2 */ - WriteWord(fp, 0x33a, 0); /* ZERO */ - WriteWord(fp, 0x673, 0); /* ONE */ - WriteWord(fp, 0xffe, 0); /* PILOT LEN */ - WriteByte(fp, 8, 0); /* USED BITS */ - WriteWord(fp, 0x10, 0); /* PAUSE */ - Write3Word(fp, blocklen + 1, 0); /* LEN */ + FreeStream(&stream); - chk = 0; + /* Loop round for the segments (up to 8) + */ + InitStream(&stream); + AddStreamByte(&stream, 0x16); - while(min < addr) + for(seg = 0; seg <= segs; seg++) { - chk = WriteByte(fp, mem[min], chk); - min++; + Byte segment[256] = {0}; + int segi = 0; + int last_seg = 0; + + last_seg = (seg == segs); + + if (!last_seg || blocklen == BLOCK_SIZE) + { + addr += 256; + } + else + { + addr += blocklen % 256; + } + + while(min < addr) + { + segment[segi++] = mem[min++]; + } + + /* Add segment data to stream + */ + AddStreamMem(&stream, segment, 256); + crc = CRC(segment, 256); + AddStreamByte(&stream, HIBYTE(crc)); + AddStreamByte(&stream, LOBYTE(crc)); + + if (last_seg) + { + AddStreamByte(&stream, 0xff); + AddStreamByte(&stream, 0xff); + AddStreamByte(&stream, 0xff); + AddStreamByte(&stream, 0xff); + } } - WriteByte(fp, chk, 0); + OutputTZXTurboBlock(fp, &stream); + + FreeStream(&stream); } } diff --git a/src/example/cpc.asm b/src/example/cpc.asm index 0c9ff5e..5a37702 100644 --- a/src/example/cpc.asm +++ b/src/example/cpc.asm @@ -11,12 +11,19 @@ start: org $8000 ld hl,msg -loop: + call print + jp $ + + org $8400 +print: ld a,(hl) + cp 0 ret z + push hl call $bb5a + pop hl inc hl - jr loop + jr print org $8800 msg: defb "Hello World",0 -- cgit v1.2.3