This is the manual for 64tass, the multi pass optimizing macro assembler for the 65xx series of processors. Key features:
@@ -112,7 +112,7 @@rightfirst time. -
Project page: http://sourceforge.net/projects/tass64/
+Project page: https://sourceforge.net/projects/tass64/
The page hosts the latest and older versions with sources and a bug and a feature request tracker.
@@ -279,7 +279,7 @@There are also some useful parameters which are described later.
-For comfortable compiling I use such Makefile
s (for make):
For comfortable compiling I use such Makefile
s (for make):
demo.prg: source.asm macros.asm pic.drp music.bin diff --git a/arguments.c b/arguments.c index cb6d1b6..f6bebdb 100644 --- a/arguments.c +++ b/arguments.c @@ -1,5 +1,5 @@ /* - $Id: arguments.c 2125 2019-12-23 19:50:58Z soci $ + $Id: arguments.c 2172 2020-03-22 19:46:59Z soci $ 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 @@ -458,6 +458,7 @@ static MUST_CHECK char *read_one(FILE *f) { static address_t get_all_mem2(void) { size_t i; + bool tostdout = false; address_t min = 0xffffffff; for (i = 0; i < arguments.output_len; i++) { const struct output_s *output = &arguments.output[i]; @@ -471,7 +472,11 @@ static address_t get_all_mem2(void) { case OUTPUT_APPLE: case OUTPUT_XEX: min &= 0xffff; break; } - if (dash_name(output->name)) arguments.quiet = false; + if (dash_name(output->name)) tostdout = true; + } + if (tostdout) { + arguments.quiet = false; + setvbuf(stdout, NULL, _IOFBF, BUFSIZ); } return min; } diff --git a/encoding.c b/encoding.c index 213edca..c027190 100644 --- a/encoding.c +++ b/encoding.c @@ -1,5 +1,5 @@ /* - $Id: encoding.c 2108 2019-12-10 19:16:03Z soci $ + $Id: encoding.c 2175 2020-03-23 19:18:35Z soci $ 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 @@ -31,7 +31,7 @@ struct encoding_s *actual_encoding; -#define identmap (const uint8_t *)petscii_esc +#define identmap (const uint8_t *)petscii_trans struct encoding_s { str_t name; @@ -840,7 +840,7 @@ int encode_string(void) { t = cavltree_container_of(c, struct trans_s, node); if (tmp.start >= t->start && tmp.end <= t->end) { encode_state.i += ln; - if ((ch & 0x80) == 0) { + if (ch < 0x80) { actual_encoding->table_use[ch / 32] |= 1 << (ch % 32); actual_encoding->table[ch] = (uint8_t)(ch - t->start + t->offset); } diff --git a/error.c b/error.c index 9bfdc77..1878b0e 100644 --- a/error.c +++ b/error.c @@ -1,5 +1,5 @@ /* - $Id: error.c 2155 2020-03-08 09:33:08Z soci $ + $Id: error.c 2175 2020-03-23 19:18:35Z soci $ 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 @@ -1350,11 +1350,15 @@ static void print_error(FILE *f, const struct errorentry_s *err, bool caret) { #ifdef COLOR_OUTPUT static void color_detect(FILE *f) { - char const *term = getenv ("TERM"); - print_use_color = term != NULL && strcmp(term, "dumb") != 0 && isatty(fileno(f)) == 1; + static int terminal; + if (terminal == 0) { + char const *term = getenv("TERM"); + terminal = (term != NULL && strcmp(term, "dumb") != 0) ? 1 : 2; + } + print_use_color = terminal == 1 && isatty(fileno(f)) == 1; } #else -#define color_detect(f) {} +#define color_detect(f) do {} while (false) #endif static inline bool caret_needed(const struct errorentry_s *err) { @@ -1404,7 +1408,7 @@ bool error_print(void) { } } else ferr = stderr; - color_detect(ferr); + if (ferr != stderr) color_detect(ferr); else if (arguments.quiet) fflush(stdout); warnings = errors = 0; close_error(); @@ -1466,7 +1470,7 @@ bool error_print(void) { } if (err3 != NULL) print_error(ferr, err3, different_line(err2, err3)); if (err2 != NULL) print_error(ferr, err2, caret_needed(err2)); - color_detect(stderr); + if (ferr != stderr) color_detect(stderr); if (ferr != stderr && ferr != stdout) fclose(ferr); else fflush(ferr); return errors != 0; } @@ -1546,9 +1550,6 @@ void err_msg_file(Error_types no, const char *prm, linepos_t epoint) { int err = errno; bool more; -#ifdef _WIN32 - setlocale(LC_ALL, ""); -#endif s = strerror(err); n = strlen(s); @@ -1574,17 +1575,17 @@ void err_msg_file(Error_types no, const char *prm, linepos_t epoint) { adderror((char *)s2); i += (size_t)l; } -#ifdef _WIN32 - setlocale(LC_ALL, "C"); -#endif if (more) new_error_msg_more(); } +static void error_status_val(const char *head, unsigned int val) { + fputs(head, stdout); + if (val != 0) printf("%u\n", val); else puts("None"); +} + void error_status(void) { - printf("Error messages: "); - if (errors != 0) printf("%u\n", errors); else puts("None"); - printf("Warning messages: "); - if (warnings != 0) printf("%u\n", warnings); else puts("None"); + error_status_val("Error messages: ", errors); + error_status_val("Warning messages: ", warnings); } linecpos_t interstring_position(linepos_t epoint, const uint8_t *data, size_t i) { diff --git a/file.c b/file.c index 8cbf931..f101750 100644 --- a/file.c +++ b/file.c @@ -1,5 +1,5 @@ /* - $Id: file.c 2125 2019-12-23 19:50:58Z soci $ + $Id: file.c 2163 2020-03-22 12:45:33Z soci $ 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 @@ -24,6 +24,9 @@ #include#include #endif +#if defined _POSIX_C_SOURCE || defined __MINGW32__ +#include +#endif #include "64tass.h" #include "unicode.h" #include "error.h" @@ -355,6 +358,26 @@ static inline uchar_t fromiso(uchar_t c) { return conv[c]; } +static size_t fsize(FILE *f) { +#if defined _POSIX_C_SOURCE || defined __MINGW32__ + struct stat st; + if (fstat(fileno(f), &st) == 0) { + if (S_ISREG(st.st_mode) && st.st_size > 0) { + return (size_t)st.st_size; + } + } +#else + if (fseek(f, 0, SEEK_END) == 0) { + long len = ftell(f); + rewind(f); + if (len > 0) { + return (size_t)len; + } + } +#endif + return 0; +} + static struct file_s *command_line = NULL; static struct file_s *lastfi = NULL; static struct ubuff_s last_ubuff; @@ -419,23 +442,23 @@ struct file_s *openfile(const char *name, const char *base, int ftype, const str if (path == NULL) path = s; tmp->realname = path; if (arguments.quiet) { - printf((ftype == 1) ? "Reading file: " : "Assembling file: "); + fputs((ftype == 1) ? "Reading file: " : "Assembling file: ", stdout); argv_print(path, stdout); putchar('\n'); } if (f == NULL) goto openerr; +#ifndef __DJGPP__ + setvbuf(f, NULL, _IONBF, 0); +#endif tmp->read_error = true; if (ftype == 1) { - bool check = true; - if (fseek(f, 0, SEEK_END) == 0) { - long len = ftell(f); - if (len > 0) { - size_t len2 = (size_t)len; - tmp->data = (uint8_t *)malloc(len2); - if (tmp->data != NULL) tmp->len = len2; - } - rewind(f); + bool check; + size_t fs = fsize(f); + if (fs > 0) { + tmp->data = (uint8_t *)malloc(fs); + if (tmp->data != NULL) tmp->len = fs; } + check = (tmp->data != NULL); clearerr(f); errno = 0; if (tmp->len != 0 || !extendfile(tmp)) { for (;;) { @@ -464,19 +487,16 @@ struct file_s *openfile(const char *name, const char *base, int ftype, const str line_t lines = 0; uint8_t buffer[BUFSIZ * 2]; size_t bp = 0, bl, qr = 1; - if (fseek(f, 0, SEEK_END) == 0) { - long len = ftell(f); - if (len > 0) { - size_t len2 = (size_t)len + 4096; - if (len2 < 4096) len2 = SIZE_MAX; /* overflow */ - tmp->data = (uint8_t *)malloc(len2); - if (tmp->data != NULL) tmp->len = len2; - max_lines = (len2 / 20 + 1024) & ~(size_t)1023; - if (max_lines > SIZE_MAX / sizeof *tmp->line) max_lines = SIZE_MAX / sizeof *tmp->line; /* overflow */ - tmp->line = (size_t *)malloc(max_lines * sizeof *tmp->line); - if (tmp->line == NULL) max_lines = 0; - } - rewind(f); + size_t fs = fsize(f); + if (fs > 0) { + size_t len2 = fs + 4096; + if (len2 < 4096) len2 = SIZE_MAX; /* overflow */ + tmp->data = (uint8_t *)malloc(len2); + if (tmp->data != NULL) tmp->len = len2; + max_lines = (len2 / 20 + 1024) & ~(size_t)1023; + if (max_lines > SIZE_MAX / sizeof *tmp->line) max_lines = SIZE_MAX / sizeof *tmp->line; /* overflow */ + tmp->line = (size_t *)malloc(max_lines * sizeof *tmp->line); + if (tmp->line == NULL) max_lines = 0; } clearerr(f); errno = 0; bl = fread(buffer, 1, BUFSIZ, f); diff --git a/functionobj.c b/functionobj.c index b05a936..cb0cb3e 100644 --- a/functionobj.c +++ b/functionobj.c @@ -1,5 +1,5 @@ /* - $Id: functionobj.c 2123 2019-12-21 06:42:26Z soci $ + $Id: functionobj.c 2173 2020-03-22 23:37:40Z soci $ 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 @@ -104,10 +104,11 @@ static MUST_CHECK Obj *gen_broadcast(Funcargs *vals, linepos_t epoint, func_t f) struct values_s *v = vals->val; size_t args = vals->len; size_t j; - struct { + struct elements_s { Obj *oval; struct iter_s iters; - } elements3[3], *elements; + }; + struct elements_s elements3[3], *elements; for (j = 0; j < args; j++) { const Type *objt2, *objt = v[j].val->obj; if (objt->iterable) { @@ -117,7 +118,7 @@ static MUST_CHECK Obj *gen_broadcast(Funcargs *vals, linepos_t epoint, func_t f) elements = elements3; } else { if (args > SIZE_MAX / sizeof *elements) goto failed; /* overflow */ - elements = malloc(args * sizeof *elements); + elements = (struct elements_s *)malloc(args * sizeof *elements); if (elements == NULL) goto failed; } elements[j].oval = v[j].val; diff --git a/main.c b/main.c index 88aa33c..c4b533d 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,6 @@ /* Turbo Assembler 6502/65C02/65816/DTV - $Id: main.c 2088 2019-11-17 06:44:48Z soci $ + $Id: main.c 2167 2020-03-22 14:25:29Z soci $ 6502/65C02 Turbo Assembler Version 1.3 (c) 1996 Taboo Productions, Marek Matula @@ -134,8 +134,7 @@ int main(int argc, char *argv[]) { int i, r; char **uargv; - setlocale(LC_ALL, ""); - setlocale(LC_NUMERIC, "C"); + setlocale(LC_CTYPE, ""); uargv = (char **)malloc((argc < 1 ? 1 : (unsigned int)argc) * sizeof *uargv); if (uargv == NULL) err_msg_out_of_memory2(); diff --git a/mem.c b/mem.c index c06b20d..f3c85c6 100644 --- a/mem.c +++ b/mem.c @@ -1,5 +1,5 @@ /* - $Id: mem.c 2124 2019-12-23 16:00:22Z soci $ + $Id: mem.c 2170 2020-03-22 15:18:53Z soci $ 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 @@ -169,12 +169,8 @@ void memprint(Memblocks *memblocks) { } } -static void putlw(unsigned int w, FILE *f) { - putc(w, f); - putc(w >> 8, f); -} - static void padding(size_t size, FILE *f) { + unsigned char nuls[256]; while (size >= 0x80000000) { if (fseek(f, 0x40000000, SEEK_CUR) != 0) goto err; size -= 0x40000000; @@ -182,25 +178,55 @@ static void padding(size_t size, FILE *f) { if ((long)size > 256 && fseek(f, (long)size, SEEK_CUR) == 0) { return; } -err:while ((size--) != 0) if (putc(0, f) == EOF) break; +err: + nuls[0] = 1; + while (size != 0) { + size_t db = size < sizeof nuls ? size : sizeof nuls; + size -= db; + if (nuls[0] != 0) memset(nuls, 0, db); + if (fwrite(nuls, db, 1, f) == 0) return; + } +} + +#ifdef __DJGPP__ +#define set_unbuffered(f) do {} while (false) +#else +static void set_unbuffered(FILE *fout) { + setvbuf(fout, NULL, _IONBF, 0); } +#endif static void output_mem_c64(FILE *fout, const Memblocks *memblocks, const struct output_s *output) { address_t pos, end; unsigned int i; + unsigned char header[4]; if (memblocks->p == 0) return; pos = memblocks->data[0].addr; - if (output->mode == OUTPUT_CBM || output->mode == OUTPUT_APPLE) { - putlw(pos, fout); - } - if (output->mode == OUTPUT_APPLE) { + switch (output->mode) { + case OUTPUT_CBM: + header[0] = pos; + header[1] = pos >> 8; + if (output->longaddr) { + header[2] = pos >> 16; + i = 3; + } else i = 2; + break; + case OUTPUT_APPLE: + header[0] = pos; + header[1] = pos >> 8; end = memblocks->data[memblocks->p - 1].addr + memblocks->data[memblocks->p - 1].len; end -= pos; - putlw(end, fout); - } else if (output->mode == OUTPUT_CBM) { - if (output->longaddr) putc(pos >> 16, fout); + header[2] = end; + header[3] = end >> 8; + i = 4; + break; + default: + i = 0; + break; } + if (memblocks->p == 1) set_unbuffered(fout); + if (i != 0 && fwrite(header, i, 1, fout) == 0) return; for (i = 0; i < memblocks->p; i++) { const struct memblock_s *block = &memblocks->data[i]; padding(block->addr - pos, fout); @@ -211,6 +237,7 @@ static void output_mem_c64(FILE *fout, const Memblocks *memblocks, const struct static void output_mem_nonlinear(FILE *fout, const Memblocks *memblocks, bool longaddr) { size_t i, j; + unsigned char header[6]; for (i = 0; i < memblocks->p;) { const struct memblock_s *block = &memblocks->data[i]; address_t start = block->addr; @@ -221,23 +248,32 @@ static void output_mem_nonlinear(FILE *fout, const Memblocks *memblocks, bool lo if (b->addr != addr || addr < start) break; size += b->len; } - putlw(size, fout); - if (longaddr) putc(size >> 16, fout); - putlw(start, fout); - if (longaddr) putc(start >> 16, fout); + header[0] = size; + header[1] = size >> 8; + if (longaddr) { + header[2] = size >> 16; + header[3] = start; + header[4] = start >> 8; + header[5] = start >> 16; + } else { + header[2] = start; + header[3] = start >> 8; + } + if (fwrite(header, longaddr ? 6 : 4, 1, fout) == 0) return; for (;i < j; i++) { const struct memblock_s *b = &memblocks->data[i]; if (fwrite(memblocks->mem.data + b->p, b->len, 1, fout) == 0) return; } } - putlw(0, fout); - if (longaddr) putc(0, fout); + memset(header, 0, 4); + fwrite(header, longaddr ? 3 : 2, 1, fout); } static void output_mem_flat(FILE *fout, const Memblocks *memblocks) { address_t pos; size_t i; + if (memblocks->p == 1 && memblocks->data[0].addr == 0) set_unbuffered(fout); for (pos = i = 0; i < memblocks->p; i++) { const struct memblock_s *block = &memblocks->data[i]; padding(block->addr - pos, fout); @@ -248,9 +284,14 @@ static void output_mem_flat(FILE *fout, const Memblocks *memblocks) { static void output_mem_atari_xex(FILE *fout, const Memblocks *memblocks) { size_t i, j; + unsigned char header[6]; + header[0] = 0xff; + header[1] = 0xff; + if (memblocks->p == 1) set_unbuffered(fout); for (i = 0; i < memblocks->p;) { const struct memblock_s *block = &memblocks->data[i]; - address_t start = block->addr; + bool special; + address_t end, start = block->addr; address_t size = block->len; for (j = i + 1; j < memblocks->p; j++) { const struct memblock_s *b = &memblocks->data[j]; @@ -258,9 +299,13 @@ static void output_mem_atari_xex(FILE *fout, const Memblocks *memblocks) { if (b->addr != addr || addr < start) break; size += b->len; } - if (i == 0 || start == 0xffff) putlw(0xffff, fout); - putlw(start, fout); - putlw(start + size - 1, fout); + special = (i == 0 || start == 0xffff); + header[2] = start; + header[3] = start >> 8; + end = start + size - 1; + header[4] = end; + header[5] = end >> 8; + if (fwrite(special ? header : &header[2], special ? 6 : 4, 1, fout) == 0) return; for (;i < j; i++) { const struct memblock_s *b = &memblocks->data[i]; if (fwrite(memblocks->mem.data + b->p, b->len, 1, fout) == 0) return; @@ -268,11 +313,16 @@ static void output_mem_atari_xex(FILE *fout, const Memblocks *memblocks) { } } -static unsigned int hexput(FILE *fout, unsigned int b) { +struct hexput_s { + char *line; + unsigned int sum; +}; + +static void hexput(struct hexput_s *h, unsigned int b) { const char *hex = "0123456789ABCDEF"; - putc(hex[(b >> 4) & 0xf], fout); - putc(hex[b & 0xf], fout); - return b; + *h->line++ = hex[b >> 4]; + *h->line++ = hex[b & 0xf]; + h->sum += b; } struct ihex_s { @@ -282,22 +332,25 @@ struct ihex_s { unsigned int length; }; -static void output_mem_ihex_line(FILE *fout, unsigned int length, address_t address, unsigned int type, const uint8_t *data) { - unsigned int i, sum; - putc(':', fout); - sum = hexput(fout, length); - sum += hexput(fout, address >> 8); - sum += hexput(fout, address); - sum += hexput(fout, type); +static void output_mem_ihex_line(struct ihex_s *ihex, unsigned int length, address_t address, unsigned int type, const uint8_t *data) { + unsigned int i; + char line[1+(1+2+1+32+1)*2+1]; + struct hexput_s h = { line + 1, 0 }; + line[0] = ':'; + hexput(&h, length); + hexput(&h, (address >> 8) & 0xff); + hexput(&h, address & 0xff); + hexput(&h, type); for (i = 0; i < length; i++) { - sum += hexput(fout, data[i]); + hexput(&h, data[i]); } - hexput(fout, -sum); - putc('\n', fout); + hexput(&h, (-h.sum) & 0xff); + *h.line++ = '\n'; + fwrite(line, h.line - line, 1, ihex->file); } static void output_mem_ihex_data(struct ihex_s *ihex) { - uint8_t *data = ihex->data; + const uint8_t *data = ihex->data; if ((ihex->address & 0xffff) + ihex->length > 0x10000) { uint16_t length = (uint16_t)-ihex->address; unsigned int remains = ihex->length - length; @@ -310,10 +363,10 @@ static void output_mem_ihex_data(struct ihex_s *ihex) { uint8_t ez[2]; ez[0] = (uint8_t)(ihex->address >> 24); ez[1] = (uint8_t)(ihex->address >> 16); - output_mem_ihex_line(ihex->file, sizeof ez, 0, 4, ez); + output_mem_ihex_line(ihex, sizeof ez, 0, 4, ez); ihex->segment = ihex->address; } - output_mem_ihex_line(ihex->file, ihex->length, ihex->address, 0, data); + output_mem_ihex_line(ihex, ihex->length, ihex->address, 0, data); ihex->address += ihex->length; ihex->length = 0; } @@ -348,7 +401,7 @@ static void output_mem_ihex(FILE *fout, const Memblocks *memblocks) { } } if (ihex.length != 0) output_mem_ihex_data(&ihex); - output_mem_ihex_line(fout, 0, 0, 1, NULL); + output_mem_ihex_line(&ihex, 0, 0, 1, NULL); } struct srecord_s { @@ -360,21 +413,24 @@ struct srecord_s { }; static void output_mem_srec_line(struct srecord_s *srec) { - unsigned int i, sum; - putc('S', srec->file); - putc(srec->length ? ('1' + srec->type) : ('9' - srec->type), srec->file); - sum = hexput(srec->file, srec->length + srec->type + 3); - if (srec->type > 1) sum += hexput(srec->file, srec->address >> 24); - if (srec->type > 0) sum += hexput(srec->file, srec->address >> 16); - sum += hexput(srec->file, srec->address >> 8); - sum += hexput(srec->file, srec->address); + unsigned int i; + char line[1+1+(1+4+32+1)*2+1]; + struct hexput_s h = { line + 2, 0 }; + line[0] = 'S'; + line[1] = srec->length != 0 ? ('1' + srec->type) : ('9' - srec->type); + hexput(&h, srec->length + srec->type + 3); + if (srec->type > 1) hexput(&h, (srec->address >> 24) & 0xff); + if (srec->type > 0) hexput(&h, (srec->address >> 16) & 0xff); + hexput(&h, (srec->address >> 8) & 0xff); + hexput(&h, srec->address & 0xff); for (i = 0; i < srec->length; i++) { - sum += hexput(srec->file, srec->data[i]); + hexput(&h, srec->data[i]); } - hexput(srec->file, ~sum); - putc('\n', srec->file); + hexput(&h, (~h.sum) & 0xff); + *h.line++ = '\n'; srec->address += srec->length; srec->length = 0; + fwrite(line, h.line - line, 1, srec->file); } static void output_mem_srec(FILE *fout, const Memblocks *memblocks) {