OpenCores
URL https://opencores.org/ocsvn/forth-cpu/forth-cpu/trunk

Subversion Repositories forth-cpu

[/] [forth-cpu/] [trunk/] [h2.c] - Blame information for rev 3

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 howe.r.j.8
/** @file      h2.c
2
 *  @brief     Simulate the H2 CPU and surrounding system
3
 *  @copyright Richard James Howe (2017)
4
 *  @license   MIT
5
 *
6
 * This file contains the toolchain for the H2, it is an assembler/compiler,
7
 * a simulator, a disassembler and a debugger. The H2 is written in VHDL and
8
 * is based on the J1 processor (see http://excamera.com/sphinx/fpga-j1.html).
9
 *
10
 * The processor has been tested on an FPGA and is working.
11
 * The project can be found at: https://github.com/howerj/forth-cpu
12
 *
13
 * @todo Generate VCD or GHW files directly so that GTKWave can view
14
 * the resulting trace. See
15
 * <http://www.ic.unicamp.br/~ducatte/mc542/Docs/gtkwave.pdf>
16
 * @todo The compiler section could be replace by an embedded Forth interpreter
17
 * The one available at <https://github.com/howerj/embed> would work well, the
18
 * metacompiler could be retargeted for the H2 processor instead of its own
19
 * 16-bit virtual machine. This should cut down on program size and increase
20
 * functionality.
21
 * @todo Allow state to be saved/loaded by serializing the objects within
22
 * here. This would allow the simulation state to be saved and resumed.
23
 */
24
 
25
/* ========================== Preamble: Types, Macros, Globals ============= */
26
 
27
#include "h2.h"
28
#include <assert.h>
29
#include <ctype.h>
30
#include <errno.h>
31
#include <inttypes.h>
32
#include <setjmp.h>
33
#include <stdarg.h>
34
#include <stdlib.h>
35
#include <string.h>
36
 
37
#define UNUSED(VARIABLE) ((void)(VARIABLE))
38
 
39
#ifdef _WIN32 /* Making standard input streams on Windows binary */
40
#include <windows.h>
41
#include <io.h>
42
#include <fcntl.h>
43
extern int _fileno(FILE *stream);
44
static void binary(FILE *f) { _setmode(_fileno(f), _O_BINARY); }
45
#else
46
static inline void binary(FILE *f) { UNUSED(f); }
47
#endif
48
 
49
#define DEFAULT_STEPS (0) /*default is to run forever*/
50
#define MAX(X, Y)     ((X) > (Y) ? (X) : (Y))
51
#define MIN(X, Y)     ((X) > (Y) ? (Y) : (X))
52
 
53
#define NUMBER_OF_INTERRUPTS (8u)
54
 
55
#define OP_BRANCH        (0x0000)
56
#define OP_0BRANCH       (0x2000)
57
#define OP_CALL          (0x4000)
58
#define OP_ALU_OP        (0x6000)
59
#define OP_LITERAL       (0x8000)
60
 
61
#define IS_LITERAL(INST) (((INST) & 0x8000) == 0x8000)
62
#define IS_BRANCH(INST)  (((INST) & 0xE000) == 0x0000)
63
#define IS_0BRANCH(INST) (((INST) & 0xE000) == 0x2000)
64
#define IS_CALL(INST)    (((INST) & 0xE000) == 0x4000)
65
#define IS_ALU_OP(INST)  (((INST) & 0xE000) == 0x6000)
66
 
67
#define ALU_OP_LENGTH   (5u)
68
#define ALU_OP_START    (8u)
69
#define ALU_OP(INST)    (((INST) >> ALU_OP_START) & ((1 << ALU_OP_LENGTH) - 1))
70
 
71
#define DSTACK_LENGTH   (2u)
72
#define DSTACK_START    (0u)
73
#define DSTACK(INST)    (((INST) >> DSTACK_START) & ((1 << DSTACK_LENGTH) - 1))
74
 
75
#define RSTACK_LENGTH   (2u)
76
#define RSTACK_START    (2u)
77
#define RSTACK(INST)    (((INST) >> RSTACK_START) & ((1 << RSTACK_LENGTH) - 1))
78
 
79
#define R_TO_PC_BIT_INDEX     (4u)
80
#define N_TO_ADDR_T_BIT_INDEX (5u)
81
#define T_TO_R_BIT_INDEX      (6u)
82
#define T_TO_N_BIT_INDEX      (7u)
83
 
84
#define R_TO_PC         (1u << R_TO_PC_BIT_INDEX)
85
#define N_TO_ADDR_T     (1u << N_TO_ADDR_T_BIT_INDEX)
86
#define T_TO_R          (1u << T_TO_R_BIT_INDEX)
87
#define T_TO_N          (1u << T_TO_N_BIT_INDEX)
88
 
89
typedef enum {
90
        ALU_OP_T,                  /**< Top of Stack         */
91
        ALU_OP_N,                  /**< Copy T to N          */
92
        ALU_OP_T_PLUS_N,           /**< Addition             */
93
        ALU_OP_T_AND_N,            /**< Bitwise AND          */
94
        ALU_OP_T_OR_N,             /**< Bitwise OR           */
95
        ALU_OP_T_XOR_N,            /**< Bitwise XOR          */
96
        ALU_OP_T_INVERT,           /**< Bitwise Inversion    */
97
        ALU_OP_T_EQUAL_N,          /**< Equality test        */
98
        ALU_OP_N_LESS_T,           /**< Signed comparison    */
99
        ALU_OP_N_RSHIFT_T,         /**< Logical Right Shift  */
100
        ALU_OP_T_DECREMENT,        /**< Decrement            */
101
        ALU_OP_R,                  /**< Top of return stack  */
102
        ALU_OP_T_LOAD,             /**< Load from address    */
103
        ALU_OP_N_LSHIFT_T,         /**< Logical Left Shift   */
104
        ALU_OP_DEPTH,              /**< Depth of stack       */
105
        ALU_OP_N_ULESS_T,          /**< Unsigned comparison  */
106
        ALU_OP_ENABLE_INTERRUPTS,  /**< Enable interrupts    */
107
 
108
        ALU_OP_INTERRUPTS_ENABLED, /**< Are interrupts on?   */
109
        ALU_OP_RDEPTH,             /**< R Stack Depth        */
110
        ALU_OP_T_EQUAL_0,          /**< T == 0               */
111
        ALU_OP_CPU_ID              /**< CPU Identifier       */
112
} alu_code_e;
113
 
114
#define DELTA_0  (0)
115
#define DELTA_1  (1)
116
#define DELTA_N2 (2)
117
#define DELTA_N1 (3)
118
 
119
#define MK_DSTACK(DELTA) ((DELTA) << DSTACK_START)
120
#define MK_RSTACK(DELTA) ((DELTA) << RSTACK_START)
121
#define MK_CODE(CODE)    ((CODE)  << ALU_OP_START)
122
 
123
/**
124
 * @warning This table keeps most things synchronized when it comes
125
 * to instructions, the exception is in the lexer, which accepts
126
 * a range of tokens in one clause of the grammar from the first
127
 * instruction to the last. This must be manually updated
128
 * @note In the original J1 specification both r@ and r> both have
129
 * their T_TO_R bit set in their instruction description tables, this
130
 * appears to be incorrect */
131
#define X_MACRO_INSTRUCTIONS \
132
        X(DUP,    "dup",    true,  (OP_ALU_OP | MK_CODE(ALU_OP_T)        | T_TO_N  | MK_DSTACK(DELTA_1)))\
133
        X(OVER,   "over",   true,  (OP_ALU_OP | MK_CODE(ALU_OP_N)        | T_TO_N  | MK_DSTACK(DELTA_1)))\
134
        X(INVERT, "invert", true,  (OP_ALU_OP | MK_CODE(ALU_OP_T_INVERT)))\
135
        X(ADD,    "+",      true,  (OP_ALU_OP | MK_CODE(ALU_OP_T_PLUS_N)               | MK_DSTACK(DELTA_N1)))\
136
        X(SWAP,   "swap",   true,  (OP_ALU_OP | MK_CODE(ALU_OP_N)        | T_TO_N))\
137
        X(NIP,    "nip",    true,  (OP_ALU_OP | MK_CODE(ALU_OP_T)                      | MK_DSTACK(DELTA_N1)))\
138
        X(DROP,   "drop",   true,  (OP_ALU_OP | MK_CODE(ALU_OP_N)                      | MK_DSTACK(DELTA_N1)))\
139
        X(EXIT,   "exit",   true,  (OP_ALU_OP | MK_CODE(ALU_OP_T)        | R_TO_PC | MK_RSTACK(DELTA_N1)))\
140
        X(TOR,    ">r",     true,  (OP_ALU_OP | MK_CODE(ALU_OP_N)        | T_TO_R  | MK_DSTACK(DELTA_N1) | MK_RSTACK(DELTA_1)))\
141
        X(FROMR,  "r>",     true,  (OP_ALU_OP | MK_CODE(ALU_OP_R)        | T_TO_N  | MK_DSTACK(DELTA_1)  | MK_RSTACK(DELTA_N1)))\
142
        X(RAT,    "r@",     true,  (OP_ALU_OP | MK_CODE(ALU_OP_R)        | T_TO_N  | MK_DSTACK(DELTA_1)))\
143
        X(LOAD,   "@",      true,  (OP_ALU_OP | MK_CODE(ALU_OP_T_LOAD)))\
144
        X(STORE,  "store",  false, (OP_ALU_OP | MK_CODE(ALU_OP_N)        | N_TO_ADDR_T | MK_DSTACK(DELTA_N1)))\
145
        X(RSHIFT, "rshift", true,  (OP_ALU_OP | MK_CODE(ALU_OP_N_RSHIFT_T)             | MK_DSTACK(DELTA_N1)))\
146
        X(LSHIFT, "lshift", true,  (OP_ALU_OP | MK_CODE(ALU_OP_N_LSHIFT_T)             | MK_DSTACK(DELTA_N1)))\
147
        X(EQUAL,  "=",      true,  (OP_ALU_OP | MK_CODE(ALU_OP_T_EQUAL_N)              | MK_DSTACK(DELTA_N1)))\
148
        X(ULESS,  "u<",     true,  (OP_ALU_OP | MK_CODE(ALU_OP_N_ULESS_T)              | MK_DSTACK(DELTA_N1)))\
149
        X(LESS,   "<",      true,  (OP_ALU_OP | MK_CODE(ALU_OP_N_LESS_T)               | MK_DSTACK(DELTA_N1)))\
150
        X(AND,    "and",    true,  (OP_ALU_OP | MK_CODE(ALU_OP_T_AND_N)                | MK_DSTACK(DELTA_N1)))\
151
        X(XOR,    "xor",    true,  (OP_ALU_OP | MK_CODE(ALU_OP_T_XOR_N)                | MK_DSTACK(DELTA_N1)))\
152
        X(OR,     "or",     true,  (OP_ALU_OP | MK_CODE(ALU_OP_T_OR_N)                 | MK_DSTACK(DELTA_N1)))\
153
        X(DEPTH,  "sp@",    true,  (OP_ALU_OP | MK_CODE(ALU_OP_DEPTH)   | T_TO_N       | MK_DSTACK(DELTA_1)))\
154
        X(T_N1,   "1-",     true,  (OP_ALU_OP | MK_CODE(ALU_OP_T_DECREMENT)))\
155
        X(IEN,    "ien",    true,  (OP_ALU_OP | MK_CODE(ALU_OP_ENABLE_INTERRUPTS)     /* | MK_DSTACK(DELTA_N1) */))\
156
        X(ISIEN,  "ien?",   true,  (OP_ALU_OP | MK_CODE(ALU_OP_INTERRUPTS_ENABLED) | T_TO_N  | MK_DSTACK(DELTA_1)))\
157
        X(RDEPTH, "rp@",    true,  (OP_ALU_OP | MK_CODE(ALU_OP_RDEPTH)  | T_TO_N       | MK_DSTACK(DELTA_1)))\
158
        X(TE0,    "0=",     true,  (OP_ALU_OP | MK_CODE(ALU_OP_T_EQUAL_0)))\
159
        X(NOP,    "nop",    false, (OP_ALU_OP | MK_CODE(ALU_OP_T)))\
160
        X(CPU_ID, "cpu-id", true,  (OP_ALU_OP | MK_CODE(ALU_OP_CPU_ID))                | MK_DSTACK(DELTA_1))\
161
        X(RUP,    "rup",    false, (OP_ALU_OP | MK_CODE(ALU_OP_T))                     | MK_RSTACK(DELTA_1))\
162
        X(RDROP,  "rdrop",  true,  (OP_ALU_OP | MK_CODE(ALU_OP_T) | MK_RSTACK(DELTA_N1)))
163
 
164
 
165
typedef enum {
166
#define X(NAME, STRING, DEFINE, INSTRUCTION) CODE_ ## NAME = INSTRUCTION,
167
        X_MACRO_INSTRUCTIONS
168
#undef X
169
} forth_word_codes_e;
170
 
171
static const char *log_levels[] =
172
{
173
#define X(ENUM, NAME) [ENUM] = NAME,
174
        X_MACRO_LOGGING
175
#undef X
176
};
177
 
178
log_level_e log_level = LOG_WARNING;
179
 
180
typedef struct {
181
        int error;
182
        int jmp_buf_valid;
183
        jmp_buf j;
184
} error_t;
185
 
186
/* ========================== Preamble: Types, Macros, Globals ============= */
187
 
188
/* ========================== Utilities ==================================== */
189
 
190
int logger(log_level_e level, const char *func,
191
                const unsigned line, const char *fmt, ...)
192
{
193
        int r = 0;
194
        va_list ap;
195
        assert(func);
196
        assert(fmt);
197
        assert(level <= LOG_ALL_MESSAGES);
198
        if(level <= log_level) {
199
                fprintf(stderr, "[%s %u] %s: ", func, line, log_levels[level]);
200
                va_start(ap, fmt);
201
                r = vfprintf(stderr, fmt, ap);
202
                va_end(ap);
203
                fputc('\n', stderr);
204
                fflush(stderr);
205
        }
206
        if(level == LOG_FATAL)
207
                exit(EXIT_FAILURE);
208
        return r;
209
}
210
 
211
static const char *reason(void)
212
{
213
        static const char *unknown = "unknown reason";
214
        const char *r;
215
        if(errno == 0)
216
                return unknown;
217
        r = strerror(errno);
218
        if(!r)
219
                return unknown;
220
        return r;
221
}
222
 
223
void *allocate_or_die(size_t length)
224
{
225
        void *r;
226
        errno = 0;
227
        r = calloc(1, length);
228
        if(!r)
229
                fatal("allocation of size %zu failed: %s",
230
                                length, reason());
231
        return r;
232
}
233
 
234
FILE *fopen_or_die(const char *file, const char *mode)
235
{
236
        FILE *f = NULL;
237
        assert(file);
238
        assert(mode);
239
        errno = 0;
240
        f = fopen(file, mode);
241
        if(!f)
242
                fatal("failed to open file '%s' (mode %s): %s",
243
                                file, mode, reason());
244
        return f;
245
}
246
 
247
static int indent(FILE *output, char c, unsigned i)
248
{
249
        assert(output);
250
        while(i--)
251
                if(fputc(c, output) != c)
252
                        return -1;
253
        return 0;
254
}
255
 
256
static int string_to_long(int base, long *n, const char *s)
257
{
258
        char *end = NULL;
259
        assert(base >= 0);
260
        assert(base != 1);
261
        assert(base <= 36);
262
        assert(n);
263
        assert(s);
264
        errno = 0;
265
        *n = strtol(s, &end, base);
266
        return errno || *s == '\0' || *end != '\0';
267
}
268
 
269
static int string_to_cell(int base, uint16_t *n, const char *s)
270
{
271
        long n1 = 0;
272
        int r = string_to_long(base, &n1, s);
273
        *n = n1;
274
        return r;
275
}
276
 
277
static char *duplicate(const char *str)
278
{
279
        char *r;
280
        assert(str);
281
        errno = 0;
282
        r = malloc(strlen(str) + 1);
283
        if(!r)
284
                fatal("duplicate of '%s' failed: %s", str, reason());
285
        strcpy(r, str);
286
        return r;
287
}
288
 
289
static void ethrow(error_t *e)
290
{
291
        if(e && e->jmp_buf_valid) {
292
                e->jmp_buf_valid = 0;
293
                e->error = 1;
294
                longjmp(e->j, 1);
295
        }
296
        exit(EXIT_FAILURE);
297
}
298
 
299
h2_t *h2_new(uint16_t start_address)
300
{
301
        h2_t *h = allocate_or_die(sizeof(h2_t));
302
        h->pc = start_address;
303
        for(uint16_t i = 0; i < start_address; i++)
304
                h->core[i] = OP_BRANCH | start_address;
305
        return h;
306
}
307
 
308
void h2_free(h2_t *h)
309
{
310
        if(!h)
311
                return;
312
        free(h->bp.points);
313
        memset(h, 0, sizeof(*h));
314
        free(h);
315
}
316
 
317
int binary_memory_load(FILE *input, uint16_t *p, size_t length)
318
{
319
        assert(input);
320
        assert(p);
321
        for(size_t i = 0; i < length; i++) {
322
                errno = 0;
323
                const int r1 = fgetc(input);
324
                const int r2 = fgetc(input);
325
                if(r1 < 0 || r2 < 0) {
326
                        debug("memory read failed: %s", strerror(errno));
327
                        return -1;
328
                }
329
                p[i] = (((unsigned)r1 & 0xffu)) | (((unsigned)r2 & 0xffu) << 8u);
330
        }
331
        return 0;
332
}
333
 
334
int binary_memory_save(FILE *output, uint16_t *p, size_t length)
335
{
336
        assert(output);
337
        assert(p);
338
        for(size_t i = 0; i < length; i++) {
339
                errno = 0;
340
                const int r1 = fputc((p[i])&0xff,output);
341
                const int r2 = fputc((p[i]>>8u)& 0xff, output);
342
                if(r1 < 0 || r2 < 0) {
343
                        debug("memory write failed: %s", strerror(errno));
344
                        return -1;
345
                }
346
        }
347
        return 0;
348
}
349
 
350
int nvram_load_and_transfer(h2_io_t *io, const char *name, bool transfer_to_sram)
351
{
352
        assert(io);
353
        assert(name);
354
        FILE *input = NULL;
355
        int r = 0;
356
        errno = 0;
357
        if((input = fopen(name, "rb"))) {
358
                r = binary_memory_load(input, io->soc->flash.nvram, CHIP_MEMORY_SIZE);
359
                if(transfer_to_sram)
360
                        memcpy(io->soc->vram, io->soc->flash.nvram, CHIP_MEMORY_SIZE);
361
                fclose(input);
362
        } else {
363
                error("nvram file read (from %s) failed: %s", name, strerror(errno));
364
                r = -1;
365
        }
366
        return r;
367
}
368
 
369
int nvram_save(h2_io_t *io, const char *name)
370
{
371
        FILE *output = NULL;
372
        int r = 0;
373
        assert(io);
374
        assert(name);
375
        errno = 0;
376
        if((output = fopen(name, "wb"))) {
377
                r = binary_memory_save(output, io->soc->flash.nvram, CHIP_MEMORY_SIZE);
378
                fclose(output);
379
        } else {
380
                error("nvram file write (to %s) failed: %s", name, strerror(errno));
381
                r = -1;
382
        }
383
        return r;
384
}
385
 
386
int memory_load(FILE *input, uint16_t *p, size_t length)
387
{
388
        assert(input);
389
        assert(p);
390
        char line[80] = {0}; /*more than enough!*/
391
        size_t i = 0;
392
 
393
        for(;fgets(line, sizeof(line), input); i++) {
394
                int r;
395
                if(i >= length) {
396
                        error("file contains too many lines: %zu", i);
397
                        return -1;
398
                }
399
                r = string_to_cell(16, &p[i], line);
400
                if(!r) {
401
                        error("invalid line - expected hex string: %s", line);
402
                        return -1;
403
                }
404
                debug("%zu %u", i, (unsigned)p[i]);
405
        }
406
 
407
        return 0;
408
}
409
 
410
int memory_save(FILE *output, uint16_t *p, size_t length)
411
{
412
        assert(output);
413
        assert(p);
414
        for(size_t i = 0; i < length; i++)
415
                if(fprintf(output, "%04"PRIx16"\n", p[i]) < 0) {
416
                        error("failed to write line: %"PRId16, i);
417
                        return -1;
418
                }
419
        return 0;
420
}
421
 
422
int h2_load(h2_t *h, FILE *hexfile)
423
{
424
        assert(h);
425
        assert(hexfile);
426
        return memory_load(hexfile, h->core, MAX_CORE);
427
}
428
 
429
int h2_save(h2_t *h, FILE *output, bool full)
430
{
431
        assert(h);
432
        assert(output);
433
        return memory_save(output, h->core, full ? MAX_CORE : h->pc);
434
}
435
 
436
/* From: https://stackoverflow.com/questions/215557/how-do-i-implement-a-circular-list-ring-buffer-in-c */
437
 
438
fifo_t *fifo_new(size_t size)
439
{
440
        assert(size >= 2); /* It does not make sense to have a FIFO less than this size */
441
        fifo_data_t *buffer = allocate_or_die(size * sizeof(buffer[0]));
442
        fifo_t *fifo = allocate_or_die(sizeof(fifo_t));
443
 
444
        fifo->buffer = buffer;
445
        fifo->head   = 0;
446
        fifo->tail   = 0;
447
        fifo->size   = size;
448
 
449
        return fifo;
450
}
451
 
452
void fifo_free(fifo_t *fifo)
453
{
454
        if(!fifo)
455
                return;
456
        free(fifo->buffer);
457
        free(fifo);
458
}
459
 
460
bool fifo_is_full(fifo_t * fifo)
461
{
462
        assert(fifo);
463
        return (fifo->head == (fifo->size - 1) && fifo->tail == 0)
464
            || (fifo->head == (fifo->tail - 1));
465
}
466
 
467
bool fifo_is_empty(fifo_t * fifo)
468
{
469
        assert(fifo);
470
        return fifo->head == fifo->tail;
471
}
472
 
473
size_t fifo_count(fifo_t * fifo)
474
{
475
        assert(fifo);
476
        if (fifo_is_empty(fifo))
477
                return 0;
478
        else if (fifo_is_full(fifo))
479
                return fifo->size;
480
        else if (fifo->head < fifo->tail)
481
                return fifo->head + (fifo->size - fifo->tail);
482
        else
483
                return fifo->head - fifo->tail;
484
}
485
 
486
size_t fifo_push(fifo_t * fifo, fifo_data_t data)
487
{
488
        assert(fifo);
489
 
490
        if (fifo_is_full(fifo))
491
                return 0;
492
 
493
        fifo->buffer[fifo->head] = data;
494
 
495
        fifo->head++;
496
        if (fifo->head == fifo->size)
497
                fifo->head = 0;
498
 
499
        return 1;
500
}
501
 
502
size_t fifo_pop(fifo_t * fifo, fifo_data_t * data)
503
{
504
        assert(fifo);
505
        assert(data);
506
 
507
        if (fifo_is_empty(fifo))
508
                return 0;
509
 
510
        *data = fifo->buffer[fifo->tail];
511
 
512
        fifo->tail++;
513
        if (fifo->tail == fifo->size)
514
                fifo->tail = 0;
515
 
516
        return 1;
517
}
518
 
519
#ifdef __unix__
520
#include <unistd.h>
521
#include <termios.h>
522
static int getch(void)
523
{
524
        struct termios oldattr, newattr;
525
        int ch;
526
        tcgetattr(STDIN_FILENO, &oldattr);
527
        newattr = oldattr;
528
        newattr.c_iflag &= ~(ICRNL);
529
        newattr.c_lflag &= ~(ICANON | ECHO);
530
 
531
        tcsetattr(STDIN_FILENO, TCSANOW, &newattr);
532
        ch = getchar();
533
 
534
        tcsetattr(STDIN_FILENO, TCSANOW, &oldattr);
535
 
536
        return ch;
537
}
538
 
539
static int putch(int c)
540
{
541
        int res = putchar(c);
542
        fflush(stdout);
543
        return res;
544
}
545
#else
546
#ifdef _WIN32
547
 
548
extern int getch(void);
549
extern int putch(int c);
550
 
551
#else
552
static int getch(void)
553
{
554
        return getchar();
555
}
556
 
557
static int putch(int c)
558
{
559
        return putchar(c);
560
}
561
#endif
562
#endif /** __unix__ **/
563
 
564
static int wrap_getch(bool *debug_on)
565
{
566
        int ch = getch();
567
        assert(debug_on);
568
        if(ch == EOF) {
569
                note("End Of Input - exiting", ESCAPE);
570
                exit(EXIT_SUCCESS);
571
        }
572
        if(ch == ESCAPE && debug_on)
573
                *debug_on = true;
574
 
575
        return ch == DELETE ? BACKSPACE : ch;
576
}
577
 
578
/* ========================== Utilities ==================================== */
579
 
580
/* ========================== Symbol Table ================================= */
581
 
582
static const char *symbol_names[] =
583
{
584
        [SYMBOL_TYPE_LABEL]       = "label",
585
        [SYMBOL_TYPE_CALL]        = "call",
586
        [SYMBOL_TYPE_CONSTANT]    = "constant",
587
        [SYMBOL_TYPE_VARIABLE]    = "variable",
588
        NULL
589
};
590
 
591
static symbol_t *symbol_new(symbol_type_e type, const char *id, uint16_t value)
592
{
593
        symbol_t *s = allocate_or_die(sizeof(*s));
594
        assert(id);
595
        s->id = duplicate(id);
596
        s->value = value;
597
        s->type = type;
598
        return s;
599
}
600
 
601
static void symbol_free(symbol_t *s)
602
{
603
        if(!s)
604
                return;
605
        free(s->id);
606
        memset(s, 0, sizeof(*s));
607
        free(s);
608
}
609
 
610
static symbol_table_t *symbol_table_new(void)
611
{
612
        symbol_table_t *t = allocate_or_die(sizeof(*t));
613
        return t;
614
}
615
 
616
static void symbol_table_free(symbol_table_t *t)
617
{
618
        if(!t)
619
                return;
620
        for(size_t i = 0; i < t->length; i++)
621
                symbol_free(t->symbols[i]);
622
        free(t->symbols);
623
        memset(t, 0, sizeof(*t));
624
        free(t);
625
}
626
 
627
static symbol_t *symbol_table_lookup(symbol_table_t *t, const char *id)
628
{
629
        for(size_t i = 0; i < t->length; i++)
630
                if(!strcmp(t->symbols[i]->id, id))
631
                        return t->symbols[i];
632
        return NULL;
633
}
634
 
635
/** @note There can be multiple symbols with the same value of the same type */
636
static symbol_t *symbol_table_reverse_lookup(symbol_table_t *t, symbol_type_e type, uint16_t value)
637
{
638
        for(size_t i = 0; i < t->length; i++)
639
                if(t->symbols[i]->type == type && t->symbols[i]->value == value)
640
                        return t->symbols[i];
641
        return NULL;
642
}
643
 
644
static int symbol_table_add(symbol_table_t *t, symbol_type_e type, const char *id, uint16_t value, error_t *e, bool hidden)
645
{
646
        symbol_t *s = symbol_new(type, id, value);
647
        symbol_t **xs = NULL;
648
        assert(t);
649
 
650
        if(symbol_table_lookup(t, id)) {
651
                error("redefinition of symbol: %s", id);
652
                if(e)
653
                        ethrow(e);
654
                else
655
                        return -1;
656
        }
657
        s->hidden = hidden;
658
 
659
        t->length++;
660
        errno = 0;
661
        xs = realloc(t->symbols, sizeof(*t->symbols) * t->length);
662
        if(!xs)
663
                fatal("reallocate of size %zu failed: %s", t->length, reason());
664
        t->symbols = xs;
665
        t->symbols[t->length - 1] = s;
666
        return 0;
667
}
668
 
669
static int symbol_table_print(symbol_table_t *t, FILE *output)
670
{
671
 
672
        assert(t);
673
        for(size_t i = 0; i < t->length; i++) {
674
                symbol_t *s = t->symbols[i];
675
                char *visibility = s->hidden ? "hidden" : "visible";
676
                if(fprintf(output, "%s %s %"PRId16" %s\n", symbol_names[s->type], s->id, s->value, visibility) < 0)
677
                        return -1;
678
        }
679
        return 0;
680
}
681
 
682
symbol_table_t *symbol_table_load(FILE *input)
683
{
684
        symbol_table_t *t = symbol_table_new();
685
        assert(input);
686
        char symbol[80];
687
        char id[256];
688
        char visibility[80];
689
        uint16_t value;
690
 
691
        while(!feof(input)) {
692
                int r = 0;
693
                memset(symbol,     0, sizeof(symbol));
694
                memset(id,         0, sizeof(id));
695
                memset(visibility, 0, sizeof(visibility));
696
                value = 0;
697
                r = fscanf(input, "%79s%255s%"SCNd16"%79s", symbol, id, &value, visibility);
698
                if(r != 4 && r > 0) {
699
                        error("invalid symbol table: %d", r);
700
                        goto fail;
701
                }
702
                if(r == 4) {
703
                        size_t i = 0;
704
                        bool hidden = false;
705
                        if(!strcmp(visibility, "hidden")) {
706
                                hidden = true;
707
                        }else if(!strcmp(visibility, "visible")) {
708
                                error("invalid visibility value: %s", visibility);
709
                                goto fail;
710
                        }
711
 
712
                        for(i = 0; symbol_names[i] && strcmp(symbol_names[i], symbol); i++)
713
                                /*do nothing*/;
714
                        if(symbol_names[i]) {
715
                                if(symbol_table_add(t, i, id, value, NULL, hidden) < 0)
716
                                        goto fail;
717
                        } else {
718
                                error("invalid symbol: %s", symbol);
719
                                goto fail;
720
                        }
721
                }
722
        }
723
        if(log_level >= LOG_DEBUG)
724
                symbol_table_print(t, stderr);
725
        return t;
726
fail:
727
        symbol_table_free(t);
728
        return NULL;
729
}
730
/* ========================== Symbol Table ================================= */
731
 
732
/* ========================== Disassembler ================================= */
733
 
734
static const char *instruction_to_string(uint16_t i)
735
{
736
        switch(i) {
737
#define X(NAME, STRING, DEFINE, INSTRUCTION) case CODE_ ## NAME : return STRING ;
738
        X_MACRO_INSTRUCTIONS
739
#undef X
740
        default:          break;
741
        }
742
        return NULL;
743
}
744
 
745
static const char *alu_op_to_string(uint16_t instruction)
746
{
747
        switch(ALU_OP(instruction)) {
748
        case ALU_OP_T:                  return "T";
749
        case ALU_OP_N:                  return "N";
750
        case ALU_OP_T_PLUS_N:           return "T+N";
751
        case ALU_OP_T_AND_N:            return "T&N";
752
        case ALU_OP_T_OR_N:             return "T|N";
753
        case ALU_OP_T_XOR_N:            return "T^N";
754
        case ALU_OP_T_INVERT:           return "~T";
755
        case ALU_OP_T_EQUAL_N:          return "N=T";
756
        case ALU_OP_N_LESS_T:           return "T>N";
757
        case ALU_OP_N_RSHIFT_T:         return "N>>T";
758
        case ALU_OP_T_DECREMENT:        return "T-1";
759
        case ALU_OP_R:                  return "R";
760
        case ALU_OP_T_LOAD:             return "[T]";
761
        case ALU_OP_N_LSHIFT_T:         return "N<<T";
762
        case ALU_OP_DEPTH:              return "depth";
763
        case ALU_OP_N_ULESS_T:          return "Tu>N";
764
        case ALU_OP_ENABLE_INTERRUPTS:  return "ien";
765
        case ALU_OP_INTERRUPTS_ENABLED: return "ien?";
766
        case ALU_OP_RDEPTH:             return "rdepth";
767
        case ALU_OP_T_EQUAL_0:          return "0=";
768
        case ALU_OP_CPU_ID:             return "cpu-id";
769
        default:                        return "unknown";
770
        }
771
}
772
 
773
static char *disassembler_alu(uint16_t instruction)
774
{
775
        char buf[256] = {0};
776
        const char *r = instruction_to_string(OP_ALU_OP | instruction);
777
        if(r)
778
                return duplicate(r);
779
        sprintf(buf, "%04x:%s:%s:%s:%s:%s:%u:%u",
780
                        (unsigned)instruction,
781
                        alu_op_to_string(instruction),
782
                        instruction & T_TO_N ? "T->N" : "",
783
                        instruction & T_TO_R ? "T->R" : "",
784
                        instruction & N_TO_ADDR_T ? "N->[T]" : "",
785
                        instruction & R_TO_PC ? "R->PC" : "",
786
                        (unsigned)(instruction & 0x000C),
787
                        (unsigned)(instruction & 0x0003));
788
        return duplicate(buf);
789
}
790
 
791
static const char *disassemble_jump(symbol_table_t *symbols, symbol_type_e type, uint16_t address)
792
{
793
        static const char *r = "";
794
        symbol_t *found = NULL;
795
        if(!symbols)
796
                return r;
797
        if((found = symbol_table_reverse_lookup(symbols, type, address)))
798
                return found->id;
799
        return r;
800
}
801
 
802
 
803
#define CSI "\033["
804
#define ANSI_RESET   (CSI "0m")
805
#define ANSI_BLACK   (CSI "30m")
806
#define ANSI_RED     (CSI "31m")
807
#define ANSI_GREEN   (CSI "32m")
808
#define ANSI_YELLOW  (CSI "33m")
809
#define ANSI_BLUE    (CSI "34m")
810
#define ANSI_MAGENTA (CSI "35m")
811
#define ANSI_CYAN    (CSI "36m")
812
#define ANSI_WHITE   (CSI "37m")
813
 
814
typedef enum {
815
        DCM_NONE,
816
        DCM_X11,
817
        DCM_ANSI,
818
        DCM_MAX_DCM
819
} disassemble_color_method_e;
820
 
821
typedef enum {
822
        DC_LITERAL,
823
        DC_ALU,
824
        DC_CALL,
825
        DC_0BRANCH,
826
        DC_BRANCH,
827
        DC_ERROR,  /* Invalid instruction */
828
        DC_RESET,  /* Reset color */
829
} decompilation_color_e;
830
 
831
static int disassemble_instruction(uint16_t instruction, FILE *output, symbol_table_t *symbols, disassemble_color_method_e dcm)
832
{
833
        int r = 0;
834
        unsigned short literal, address;
835
        char *s = NULL;
836
        assert(output);
837
        assert(dcm < DCM_MAX_DCM);
838
 
839
        static const char *colors[3][7] = { /* for colorizing decompilation stream with in-band signalling */
840
                /* LITERAL     ALU            CALL        0BRANCH      BRANCH    ERROR      RESET */
841
                [DCM_NONE] = { "",           "",           "",         "",          "",        "",       "" },         /* No-Color */
842
                [DCM_X11]  = { "?HotPink?",  "?SkyBlue?",  "?GreenYellow?",  "?Khaki?",  "?MediumTurquoise?",  "?FireBrick?",  "" },         /* X11/GTKWave */
843
                [DCM_ANSI] = { ANSI_MAGENTA, ANSI_BLUE,    ANSI_GREEN, ANSI_YELLOW, ANSI_CYAN, ANSI_RED, ANSI_RESET }, /* ANSI Escape Sequences */
844
        };
845
 
846
        const char **color = colors[dcm];
847
 
848
        literal = instruction & 0x7FFF;
849
        address = instruction & 0x1FFF;
850
 
851
        if (IS_LITERAL(instruction))
852
                r = fprintf(output, "%s%hx%s", color[DC_LITERAL], literal, color[DC_RESET]);
853
        else if (IS_ALU_OP(instruction))
854
                r = fprintf(output, "%s%s%s", color[DC_ALU], s = disassembler_alu(instruction), color[DC_RESET]);
855
        else if (IS_CALL(instruction))
856
                r = fprintf(output, "%scall%s %hx %s",  color[DC_CALL], color[DC_RESET], address, disassemble_jump(symbols, SYMBOL_TYPE_CALL, address));
857
        else if (IS_0BRANCH(instruction))
858
                r = fprintf(output, "%s0branch%s %hx %s", color[DC_0BRANCH], color[DC_RESET], address, disassemble_jump(symbols, SYMBOL_TYPE_LABEL, address));
859
        else if (IS_BRANCH(instruction))
860
                r = fprintf(output, "%sbranch%s %hx %s",  color[DC_BRANCH], color[DC_RESET], address, disassemble_jump(symbols, SYMBOL_TYPE_LABEL, address));
861
        else
862
                r = fprintf(output, "%s?(%hx)%s", color[DC_ERROR], instruction, color[DC_RESET]);
863
        free(s);
864
        return r < 0 ? -1 : 0;
865
}
866
 
867
int h2_disassemble(disassemble_color_method_e dcm, FILE *input, FILE *output, symbol_table_t *symbols)
868
{
869
        assert(input);
870
        assert(output);
871
        assert(dcm < DCM_MAX_DCM);
872
        char line[80] = {0};
873
        while(!feof(input)) {
874
                memset(line, 0, sizeof(line));
875
                fscanf(input, "%79s", line);
876
                if(line[0]) {
877
                        uint16_t instruction;
878
                        if(string_to_cell(16, &instruction, line)) {
879
                                error("invalid input to disassembler: %s", line);
880
                                return -1;
881
                        }
882
                        if(disassemble_instruction(instruction, output, symbols, dcm) < 0) {
883
                                error("disassembly failed");
884
                                return -1;
885
                        }
886
                        if(fputc('\n', output) != '\n') {
887
                                error("disassembly failed");
888
                                return -1;
889
                        }
890
                        fflush(output);
891
                }
892
        }
893
        return 0;
894
}
895
 
896
/* ========================== Disassembler ================================= */
897
 
898
/* ========================== Simulation And Debugger ====================== */
899
 
900
/* @note At the moment I/O is not timing accurate, the UART behaves as if reads
901
 * and writes happened instantly, along with the PS/2 keyboard. Also the UART
902
 * has a FIFO which is not simulated. It should be easy enough to delay for
903
 * the roughly the right number of cycles, but not to get exact cycle
904
 * accurate timing */
905
 
906
static char to_char(uint8_t c)
907
{
908
        return isprint(c) ? c : '.';
909
}
910
 
911
static void memory_print(FILE *out, uint16_t start, uint16_t *p, uint16_t length, bool chars)
912
{
913
        const uint16_t line_length = 16;
914
        assert(out);
915
        assert(p);
916
        for(uint16_t i = 0; i < length; i += line_length) {
917
                fprintf(out, "%04"PRIx16 ": ", i + start);
918
                for(uint16_t j = 0; j < line_length && j + i < length; j++)
919
                        fprintf(out, "%04"PRIx16 " ", p[j + i]);
920
                fputc('\t', out);
921
                if(chars) /* correct endianess? */
922
                        for(uint16_t j = 0; j < line_length && j + i < length; j++)
923
                                fprintf(out, "%c%c", to_char(p[j + i] >> 8), to_char(p[j + i]));
924
 
925
                putc('\n', out);
926
        }
927
        putc('\n', out);
928
}
929
 
930
static bool break_point_find(break_point_t *bp, uint16_t find_me)
931
{
932
        assert(bp);
933
        for(size_t i = 0; i < bp->length; i++)
934
                if(bp->points[i] == find_me)
935
                        return true;
936
        return false;
937
}
938
 
939
static void break_point_add(break_point_t *bp, uint16_t point)
940
{
941
        assert(bp);
942
        size_t a;
943
        uint16_t *r;
944
        if(break_point_find(bp, point))
945
                return;
946
 
947
        a = (bp->length + 1) * sizeof(bp->points[0]);
948
        r = realloc(bp->points, a);
949
        if(!r || a < bp->length)
950
                fatal("realloc of size %zu failed", a);
951
        r[bp->length] = point;
952
        bp->length++;
953
        bp->points = r;
954
}
955
 
956
static int break_point_print(FILE *out, break_point_t *bp)
957
{
958
        for(size_t i = 0; i < bp->length; i++)
959
                if(fprintf(out, "\t0x%04"PRIx16 "\n", bp->points[i]) < 0)
960
                        return -1;
961
        return 0;
962
}
963
 
964
#define LED_7_SEGMENT_DISPLAY_CHARSET_HEX  "0123456789AbCdEF"
965
#define LED_7_SEGMENT_DISPLAY_CHARSET_BCD  "0123456789 .-   "
966
 
967
static char l7seg(uint8_t c)
968
{
969
        static const char *v = LED_7_SEGMENT_DISPLAY_CHARSET_HEX;
970
        return v[c & 0xf];
971
}
972
 
973
void soc_print(FILE *out, h2_soc_state_t *soc)
974
{
975
        assert(out);
976
        assert(soc);
977
        unsigned char led0 = l7seg(soc->led_7_segments >> 12);
978
        unsigned char led1 = l7seg(soc->led_7_segments >>  8);
979
        unsigned char led2 = l7seg(soc->led_7_segments >>  4);
980
        unsigned char led3 = l7seg(soc->led_7_segments);
981
 
982
        fprintf(out, "LEDS:             %02"PRIx8"\n",  soc->leds);
983
        /*fprintf(out, "VGA Cursor:       %04"PRIx16"\n", soc->vga_cursor);
984
        fprintf(out, "VGA Control:      %04"PRIx16"\n", soc->vga_control);*/
985
        fprintf(out, "Timer Control:    %04"PRIx16"\n", soc->timer_control);
986
        fprintf(out, "Timer:            %04"PRIx16"\n", soc->timer);
987
        fprintf(out, "IRC Mask:         %04"PRIx16"\n", soc->irc_mask);
988
        fprintf(out, "UART Input:       %02"PRIx8"\n",  soc->uart_getchar_register);
989
        fprintf(out, "LED 7 segment:    %c%c%c%c\n",    led0, led1, led2, led3);
990
        fprintf(out, "Switches:         %04"PRIx16"\n", soc->switches);
991
        fprintf(out, "Waiting:          %s\n",          soc->wait ? "true" : "false");
992
        fprintf(out, "Flash Control:    %04"PRIx16"\n", soc->mem_control);
993
        fprintf(out, "Flash Address Lo: %04"PRIx16"\n", soc->mem_addr_low);
994
        fprintf(out, "Flash Data Out:   %04"PRIx16"\n", soc->mem_dout);
995
}
996
 
997
static void terminal_default_command_sequence(vt100_t *t)
998
{
999
        assert(t);
1000
        t->n1 = 1;
1001
        t->n2 = 1;
1002
        t->command_index = 0;
1003
}
1004
 
1005
static void terminal_at_xy(vt100_t *t, unsigned x, unsigned y, bool limit_not_wrap)
1006
{
1007
        assert(t);
1008
        if(limit_not_wrap) {
1009
                x = MAX(x, 0);
1010
                y = MAX(y, 0);
1011
                x = MIN(x, t->width - 1);
1012
                y = MIN(y, t->height - 1);
1013
        } else {
1014
                x %= t->width;
1015
                y %= t->height;
1016
        }
1017
        t->cursor = (y * t->width) + x;
1018
}
1019
 
1020
static int terminal_x_current(vt100_t *t)
1021
{
1022
        assert(t);
1023
        return t->cursor % t->width;
1024
}
1025
 
1026
static int terminal_y_current(vt100_t *t)
1027
{
1028
        assert(t);
1029
        return t->cursor / t->width;
1030
}
1031
 
1032
static void terminal_at_xy_relative(vt100_t *t, int x, int y, bool limit_not_wrap)
1033
{
1034
        assert(t);
1035
        int x_current = terminal_x_current(t);
1036
        int y_current = terminal_y_current(t);
1037
        terminal_at_xy(t, x_current + x, y_current + y, limit_not_wrap);
1038
}
1039
 
1040
static void terminal_parse_attribute(vt100_attribute_t *a, unsigned v)
1041
{
1042
        switch(v) {
1043
        case 0:
1044
                memset(a, 0, sizeof(*a));
1045
                a->foreground_color = WHITE;
1046
                a->background_color = BLACK;
1047
                return;
1048
        case 1: a->bold          = true; return;
1049
        case 4: a->under_score   = true; return;
1050
        case 5: a->blink         = true; return;
1051
        case 7: a->reverse_video = true; return;
1052
        case 8: a->conceal       = true; return;
1053
        default:
1054
                if(v >= 30 && v <= 37)
1055
                        a->foreground_color = v - 30;
1056
                if(v >= 40 && v <= 47)
1057
                        a->background_color = v - 40;
1058
        }
1059
}
1060
 
1061
static const vt100_attribute_t vt100_default_attribute = {
1062
        .foreground_color = WHITE,
1063
        .background_color = BLACK,
1064
};
1065
 
1066
static void terminal_attribute_block_set(vt100_t *t, size_t size, const vt100_attribute_t const *a)
1067
{
1068
        assert(t);
1069
        assert(a);
1070
        for(size_t i = 0; i < size; i++)
1071
                memcpy(&t->attributes[i], a, sizeof(*a));
1072
}
1073
 
1074
static int terminal_escape_sequences(vt100_t *t, uint8_t c)
1075
{
1076
        assert(t);
1077
        assert(t->state != TERMINAL_NORMAL_MODE);
1078
        switch(t->state) {
1079
        case TERMINAL_CSI:
1080
                if(c == '[')
1081
                        t->state = TERMINAL_COMMAND;
1082
                else
1083
                        goto fail;
1084
                break;
1085
        case TERMINAL_COMMAND:
1086
                switch(c) {
1087
                case 's':
1088
                        t->cursor_saved = t->cursor;
1089
                        goto success;
1090
                case 'n':
1091
                        t->cursor = t->cursor_saved;
1092
                        goto success;
1093
                case '?':
1094
                        terminal_default_command_sequence(t);
1095
                        t->state = TERMINAL_DECTCEM;
1096
                        break;
1097
                case ';':
1098
                        terminal_default_command_sequence(t);
1099
                        t->state = TERMINAL_NUMBER_2;
1100
                        break;
1101
                default:
1102
                        if(isdigit(c)) {
1103
                                terminal_default_command_sequence(t);
1104
                                t->command_index++;
1105
                                t->n1 = c - '0';
1106
                                t->state = TERMINAL_NUMBER_1;
1107
                        } else {
1108
                                goto fail;
1109
                        }
1110
                }
1111
                break;
1112
        case TERMINAL_NUMBER_1:
1113
                if(isdigit(c)) {
1114
                        if(t->command_index > 3)
1115
                                goto fail;
1116
                        t->n1 = (t->n1 * (t->command_index ? 10 : 0)) + (c - '0');
1117
                        t->command_index++;
1118
                        break;
1119
                }
1120
 
1121
                switch(c) {
1122
                case 'A': terminal_at_xy_relative(t,  0,     -t->n1, true); goto success;/* relative cursor up */
1123
                case 'B': terminal_at_xy_relative(t,  0,      t->n1, true); goto success;/* relative cursor down */
1124
                case 'C': terminal_at_xy_relative(t,  t->n1,  0,     true); goto success;/* relative cursor forward */
1125
                case 'D': terminal_at_xy_relative(t, -t->n1,  0,     true); goto success;/* relative cursor back */
1126
                case 'E': terminal_at_xy(t, 0,  t->n1, false); goto success; /* relative cursor down, beginning of line */
1127
                case 'F': terminal_at_xy(t, 0, -t->n1, false); goto success; /* relative cursor up, beginning of line */
1128
                case 'G': terminal_at_xy(t, t->n1, terminal_y_current(t), true); goto success; /* move the cursor to column n */
1129
                case 'm': /* set attribute, CSI number m */
1130
                        terminal_parse_attribute(&t->attribute, t->n1);
1131
                        t->attributes[t->cursor] = t->attribute;
1132
                        goto success;
1133
                case 'i': /* AUX Port On == 5, AUX Port Off == 4 */
1134
                        if(t->n1 == 5 || t->n1 == 4)
1135
                                goto success;
1136
                        goto fail;
1137
                case 'n': /* Device Status Report */
1138
                        /** @note This should transmit to the H2 system the
1139
                         * following "ESC[n;mR", where n is the row and m is the column,
1140
                         * we're not going to do this, although fifo_push() on
1141
                         * uart_rx_fifo could be called to do this */
1142
                        if(t->n1 == 6)
1143
                                goto success;
1144
                        goto fail;
1145
                case 'J': /* reset */
1146
                        switch(t->n1) {
1147
                        case 3:
1148
                        case 2: t->cursor = 0; /* with cursor */
1149
                        case 1:
1150
                                if(t->command_index) {
1151
                                        memset(t->m, ' ', t->size);
1152
                                        terminal_attribute_block_set(t, t->size, &vt100_default_attribute);
1153
                                        goto success;
1154
                                } /* fall through if number not supplied */
1155
                        case 0:
1156
                                memset(t->m, ' ', t->cursor);
1157
                                terminal_attribute_block_set(t, t->cursor, &vt100_default_attribute);
1158
                                goto success;
1159
                        }
1160
                        goto fail;
1161
                case ';':
1162
                        t->command_index = 0;
1163
                        t->state = TERMINAL_NUMBER_2;
1164
                        break;
1165
                default:
1166
                        goto fail;
1167
                }
1168
                break;
1169
        case TERMINAL_NUMBER_2:
1170
                if(isdigit(c)) {
1171
                        if(t->command_index > 3)
1172
                                goto fail;
1173
                        t->n2 = (t->n2 * (t->command_index ? 10 : 0)) + (c - '0');
1174
                        t->command_index++;
1175
                } else {
1176
                        switch(c) {
1177
                        case 'm':
1178
                                terminal_parse_attribute(&t->attribute, t->n1);
1179
                                terminal_parse_attribute(&t->attribute, t->n2);
1180
                                t->attributes[t->cursor] = t->attribute;
1181
                                goto success;
1182
                        case 'H':
1183
                        case 'f':
1184
                                terminal_at_xy(t, MIN(t->n2-1,t->n2), MIN(t->n1-1,t->n1), true);
1185
                                goto success;
1186
                        }
1187
                        goto fail;
1188
                }
1189
                break;
1190
        case TERMINAL_DECTCEM:
1191
                if(isdigit(c)) {
1192
                        if(t->command_index > 1)
1193
                                goto fail;
1194
                        t->n1 = (t->n1 * (t->command_index ? 10 : 0)) + (c - '0');
1195
                        t->command_index++;
1196
                        break;
1197
                }
1198
 
1199
                if(t->n1 != 25)
1200
                        goto fail;
1201
                switch(c) {
1202
                case 'l': t->cursor_on = false; goto success;
1203
                case 'h': t->cursor_on = true;  goto success;
1204
                default:
1205
                        goto fail;
1206
                }
1207
        case TERMINAL_STATE_END:
1208
                t->state = TERMINAL_NORMAL_MODE;
1209
                break;
1210
        default:
1211
                fatal("invalid terminal state: %u", (unsigned)t->state);
1212
        }
1213
 
1214
        return 0;
1215
success:
1216
        t->state = TERMINAL_NORMAL_MODE;
1217
        return 0;
1218
fail:
1219
        t->state = TERMINAL_NORMAL_MODE;
1220
        return -1;
1221
}
1222
 
1223
void vt100_update(vt100_t *t, uint8_t c)
1224
{
1225
        assert(t);
1226
        assert(t->size <= VT100_MAX_SIZE);
1227
        assert((t->width * t->height) <= VT100_MAX_SIZE);
1228
 
1229
        if(t->state != TERMINAL_NORMAL_MODE) {
1230
                if(terminal_escape_sequences(t, c)) {
1231
                        t->state = TERMINAL_NORMAL_MODE;
1232
                        /*warning("invalid ANSI command sequence");*/
1233
                }
1234
        } else {
1235
                switch(c) {
1236
                case ESCAPE:
1237
                        t->state = TERMINAL_CSI;
1238
                        break;
1239
                case '\t':
1240
                        t->cursor += 8;
1241
                        t->cursor &= ~0x7;
1242
                        break;
1243
                case '\n':
1244
                        t->cursor += t->width;
1245
                        t->cursor = (t->cursor / t->width) * t->width;
1246
                        break;
1247
                case '\r':
1248
                        break;
1249
                case BACKSPACE:
1250
                        terminal_at_xy_relative(t, -1, 0, true);
1251
                        break;
1252
                default:
1253
                        assert(t->cursor < t->size);
1254
                        t->m[t->cursor] = c;
1255
                        memcpy(&t->attributes[t->cursor], &t->attribute, sizeof(t->attribute));
1256
                        t->cursor++;
1257
                }
1258
                if(t->cursor >= t->size) {
1259
                        terminal_attribute_block_set(t, t->size, &vt100_default_attribute);
1260
                        memset(t->m, ' ', t->size);
1261
                }
1262
                t->cursor %= t->size;
1263
        }
1264
}
1265
 
1266
#define FLASH_WRITE_CYCLES (20)  /* x10ns */
1267
#define FLASH_ERASE_CYCLES (200) /* x10ns */
1268
 
1269
typedef enum {
1270
        FLASH_STATUS_RESERVED         = 1u << 0,
1271
        FLASH_STATUS_BLOCK_LOCKED     = 1u << 1,
1272
        FLASH_STATUS_PROGRAM_SUSPEND  = 1u << 2,
1273
        FLASH_STATUS_VPP              = 1u << 3,
1274
        FLASH_STATUS_PROGRAM          = 1u << 4,
1275
        FLASH_STATUS_ERASE_BLANK      = 1u << 5,
1276
        FLASH_STATUS_ERASE_SUSPEND    = 1u << 6,
1277
        FLASH_STATUS_DEVICE_READY     = 1u << 7,
1278
} flash_status_register_t;
1279
 
1280
typedef enum {
1281
        FLASH_READ_ARRAY,
1282
        FLASH_QUERY,
1283
        FLASH_READ_DEVICE_IDENTIFIER,
1284
        FLASH_READ_STATUS_REGISTER,
1285
        FLASH_WORD_PROGRAM,
1286
        FLASH_WORD_PROGRAMMING,
1287
        FLASH_LOCK_OPERATION,
1288
        FLASH_LOCK_OPERATING,
1289
        FLASH_BLOCK_ERASE,
1290
        FLASH_BLOCK_ERASING,
1291
        FLASH_BUFFERED_PROGRAM,
1292
        FLASH_BUFFERED_PROGRAMMING,
1293
} flash_state_t;
1294
 
1295
/** @note read the PC28F128P33BF60 datasheet to decode this
1296
 * information, this table was actually acquired from reading
1297
 * the data from the actual device. */
1298
static const uint16_t PC28F128P33BF60_CFI_Query_Table[0x200] = {
1299
0x0089, 0x881E, 0x0000, 0xFFFF, 0x0089, 0xBFCF, 0x0000, 0xFFFF,
1300
0x0089, 0x881E, 0x0000, 0x0000, 0x0089, 0xBFCF, 0x0000, 0xFFFF,
1301
0x0051, 0x0052, 0x0059, 0x0001, 0x0000, 0x000A, 0x0001, 0x0000,
1302
0x0000, 0x0000, 0x0000, 0x0023, 0x0036, 0x0085, 0x0095, 0x0006,
1303
0x0009, 0x0009, 0x0000, 0x0002, 0x0002, 0x0003, 0x0000, 0x0018,
1304
0x0001, 0x0000, 0x0009, 0x0000, 0x0002, 0x007E, 0x0000, 0x0000,
1305
0x0002, 0x0003, 0x0000, 0x0080, 0x0000, 0x0000, 0x0000, 0x0000,
1306
0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1307
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1308
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1309
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1310
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1311
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1312
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1313
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1314
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1315
0xFFBE, 0x0396, 0x66A2, 0xA600, 0x395A, 0xFFFF, 0xFFFF, 0xFFFF,
1316
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1317
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1318
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1319
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1320
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1321
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1322
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1323
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1324
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1325
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1326
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1327
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1328
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1329
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1330
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1331
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1332
0xFFFF, 0xFFFF, 0x0050, 0x0052, 0x0049, 0x0031, 0x0035, 0x00E6,
1333
0x0001, 0x0000, 0x0000, 0x0001, 0x0003, 0x0000, 0x0030, 0x0090,
1334
0x0002, 0x0080, 0x0000, 0x0003, 0x0003, 0x0089, 0x0000, 0x0000,
1335
0x0000, 0x0000, 0x0000, 0x0000, 0x0010, 0x0000, 0x0004, 0x0004,
1336
0x0004, 0x0001, 0x0002, 0x0003, 0x0007, 0x0001, 0x0024, 0x0000,
1337
0x0001, 0x0000, 0x0011, 0x0000, 0x0000, 0x0002, 0x007E, 0x0000,
1338
0x0000, 0x0002, 0x0064, 0x0000, 0x0002, 0x0003, 0x0000, 0x0080,
1339
0x0000, 0x0000, 0x0000, 0x0080, 0x0003, 0x0000, 0x0080, 0x0000,
1340
0x0064, 0x0000, 0x0002, 0x0003, 0x0000, 0x0080, 0x0000, 0x0000,
1341
0x0000, 0x0080, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1342
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1343
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1344
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1345
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1346
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1347
0xF020, 0x4DBF, 0x838C, 0xFC08, 0x638F, 0x20E3, 0xFF03, 0xD8D7,
1348
0xC838, 0xFFFF, 0xFFFF, 0xAFFF, 0x3352, 0xB333, 0x3004, 0x1353,
1349
0x0003, 0xA000, 0x80D5, 0x8A03, 0xFF4A, 0xFFFF, 0xFFFF, 0x0FFF,
1350
0x2000, 0x0000, 0x0004, 0x0080, 0x1000, 0x0000, 0x0002, 0x0040,
1351
0x0000, 0x0008, 0x0000, 0x0001, 0x2000, 0x0000, 0x0400, 0x0000,
1352
0x0080, 0x0000, 0x0010, 0x0000, 0x0002, 0x4000, 0x0000, 0x0800,
1353
0x0000, 0x0100, 0x0000, 0x0020, 0x0000, 0x0004, 0x8000, 0x0000,
1354
0x1000, 0x0000, 0x0200, 0x0000, 0x0040, 0x0000, 0x0008, 0x0000,
1355
0x0001, 0x2000, 0x0000, 0x0800, 0x0000, 0x0200, 0x0000, 0x0040,
1356
0x0000, 0x0008, 0x0000, 0x0001, 0x2000, 0x0000, 0x0400, 0x0000,
1357
0x0080, 0x0000, 0x0010, 0x0000, 0x0002, 0x4000, 0x0000, 0x0800,
1358
0x0000, 0x0100, 0x0000, 0x0020, 0x0000, 0x0004, 0x8000, 0x0000,
1359
0x1000, 0x0000, 0x0200, 0x0000, 0x0040, 0x0000, 0x0008, 0x0000,
1360
0x0001, 0x4000, 0x0000, 0x1000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1361
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1362
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1363
};
1364
 
1365
uint16_t PC28F128P33BF60_CFI_Query_Read(uint32_t addr)
1366
{
1367
        addr &= 0x3ff;
1368
        if(addr > 0x1ff) {
1369
                addr &= 0x7;
1370
                static const uint16_t r[] = {
1371
                        0x0089, 0x881E, 0x0000, 0x0000,
1372
                        0x0089, 0xBFCF, 0x0000, 0xFFFF
1373
                };
1374
                return r[addr];
1375
        }
1376
        return PC28F128P33BF60_CFI_Query_Table[addr];
1377
}
1378
 
1379
static uint16_t h2_io_flash_read(flash_t *f, uint32_t addr, bool oe, bool we, bool rst)
1380
{
1381
        if(rst)
1382
                return 0;
1383
 
1384
        if(oe && we) {
1385
                warning("OE and WE set at the same time");
1386
                return 0;
1387
        }
1388
 
1389
        if(!oe) {
1390
                warning("flash read with OE not selected");
1391
                return 0;
1392
        }
1393
 
1394
        switch(f->mode) {
1395
        case FLASH_READ_ARRAY:             return f->nvram[0x7ffffff & addr];
1396
        case FLASH_READ_DEVICE_IDENTIFIER:
1397
        case FLASH_QUERY:                  return PC28F128P33BF60_CFI_Query_Read(addr);
1398
        case FLASH_READ_STATUS_REGISTER:   return f->status;
1399
        case FLASH_WORD_PROGRAMMING:
1400
        case FLASH_WORD_PROGRAM:           return f->status;
1401
        case FLASH_BLOCK_ERASING:
1402
        case FLASH_BLOCK_ERASE:            return f->status;
1403
        case FLASH_LOCK_OPERATING:
1404
        case FLASH_LOCK_OPERATION:         return f->status; /* return what? */
1405
        default:
1406
                fatal("invalid flash state: %u", f->mode);
1407
        }
1408
 
1409
        return 0;
1410
}
1411
 
1412
static unsigned addr_to_block(uint32_t addr)
1413
{
1414
        uint32_t lower_64k_blocks_highest_address = 127u * 64u * 1024u; /* 0x7F000 */
1415
        /*assert(addr < 0x7ffffff);*/
1416
        if(addr < lower_64k_blocks_highest_address)
1417
                return addr / (64u * 1024u);
1418
        addr -= lower_64k_blocks_highest_address;
1419
        addr /= (16u * 1024u);
1420
        return addr + 127u;
1421
}
1422
 
1423
static unsigned block_size(unsigned block)
1424
{
1425
        if(block >= 127u)
1426
                return 16u * 1024u;
1427
        return 64u * 1024u;
1428
}
1429
 
1430
static bool block_locked(flash_t *f, unsigned block)
1431
{
1432
        assert(f);
1433
        assert(block < FLASH_BLOCK_MAX);
1434
        return !!(f->locks[block]);
1435
}
1436
 
1437
static bool address_protected(flash_t *f, uint32_t addr)
1438
{
1439
        assert(f);
1440
        return block_locked(f, addr_to_block(addr));
1441
}
1442
 
1443
/**@todo implement the full standard for the Common Flash Memory Interface, and
1444
 * make the timing based on a simulated calculated time instead multiples of
1445
 * 10us see:
1446
 * <https://en.wikipedia.org/wiki/Common_Flash_Memory_Interface> with the
1447
 * devices PC28F128P33BF60 and NP8P128A13T1760E. The lock status of a register
1448
 * should be read as well as checking f->arg1_address == f->arg2_address for
1449
 * commands which require this.*/
1450
static void h2_io_flash_update(flash_t *f, uint32_t addr, uint16_t data, bool oe, bool we, bool rst, bool cs)
1451
{
1452
        assert(f);
1453
        if(oe && we)
1454
                warning("OE and WE set at the same time");
1455
 
1456
        if(rst) {
1457
                f->mode = FLASH_READ_ARRAY;
1458
                return;
1459
        }
1460
 
1461
        switch(f->mode) {
1462
        case FLASH_READ_ARRAY:
1463
        case FLASH_READ_STATUS_REGISTER:
1464
        case FLASH_QUERY:
1465
        case FLASH_READ_DEVICE_IDENTIFIER:
1466
                f->arg1_address = addr;
1467
                f->cycle = 0;
1468
                f->status |= FLASH_STATUS_DEVICE_READY;
1469
 
1470
                if(!we && f->we && cs) {
1471
                        switch(f->data) {
1472
                        case 0x00: break;
1473
                        case 0xff: f->mode = FLASH_READ_ARRAY;             break;
1474
                        case 0x90: f->mode = FLASH_READ_DEVICE_IDENTIFIER; break;
1475
                        case 0x98: f->mode = FLASH_QUERY;                  break;
1476
                        case 0x70: f->mode = FLASH_READ_STATUS_REGISTER;   break;
1477
                        case 0x50: f->status = FLASH_STATUS_DEVICE_READY;  break; /* changes state? */
1478
                        case 0x10:
1479
                        case 0x40: f->mode = FLASH_WORD_PROGRAM;           break;
1480
                        case 0xE8: f->mode = FLASH_BUFFERED_PROGRAM;       break;
1481
                        case 0x20: f->mode = FLASH_BLOCK_ERASE;            break;
1482
                        /*case 0xB0: SUSPEND NOT IMPLEMENTED;              break; */
1483
                        /*case 0xD0: RESUME NOT IMPLEMENTED;               break; */
1484
                        case 0x60: f->mode = FLASH_LOCK_OPERATION;         break;
1485
                        /*case 0xC0: PROTECTION PROGRAM NOT IMPLEMENTED;     break; */
1486
                        default:
1487
                                warning("Common Flash Interface command not implemented: %x", (unsigned)(f->data));
1488
                                f->mode = FLASH_READ_ARRAY;
1489
                        }
1490
                }
1491
                break;
1492
        case FLASH_WORD_PROGRAM:
1493
                if(!we && f->we && cs) {
1494
                        f->cycle   = 0;
1495
                        if(address_protected(f, f->arg1_address)) {
1496
                                warning("address locked: %u", (unsigned)f->arg1_address);
1497
                                f->status |= FLASH_STATUS_BLOCK_LOCKED;
1498
                                f->status |= FLASH_STATUS_PROGRAM;
1499
                                f->mode    = FLASH_READ_STATUS_REGISTER;
1500
                        } else {
1501
                                f->status &= ~FLASH_STATUS_DEVICE_READY;
1502
                                f->mode    = FLASH_WORD_PROGRAMMING;
1503
                        }
1504
                } else if(we && cs) {
1505
                        f->arg2_address = addr;
1506
                }
1507
                break;
1508
        case FLASH_WORD_PROGRAMMING:
1509
                if(f->cycle++ > FLASH_WRITE_CYCLES) {
1510
                        f->nvram[f->arg1_address] &= f->data;
1511
                        f->mode         = FLASH_READ_STATUS_REGISTER;
1512
                        f->cycle        = 0;
1513
                        f->status |= FLASH_STATUS_DEVICE_READY;
1514
                }
1515
                break;
1516
        case FLASH_LOCK_OPERATION:
1517
                if(!we && f->we && cs) {
1518
                        f->mode = FLASH_LOCK_OPERATING;
1519
                } else if(we && cs) {
1520
                        f->arg2_address = addr;
1521
                }
1522
                break;
1523
        case FLASH_LOCK_OPERATING:
1524
                if(f->arg1_address > FLASH_BLOCK_MAX) {
1525
                        warning("block address invalid: %u", (unsigned)f->arg1_address);
1526
                        f->mode = FLASH_READ_STATUS_REGISTER;
1527
                        break;
1528
                }
1529
 
1530
                switch(f->data) {
1531
                case 0xD0:
1532
                        if(f->locks[f->arg1_address] != FLASH_LOCKED_DOWN)
1533
                                f->locks[f->arg1_address] = FLASH_UNLOCKED;
1534
                        else
1535
                                warning("block locked down: %u", (unsigned)f->arg1_address);
1536
                        break;
1537
                case 0x01:
1538
                        if(f->locks[f->arg1_address] != FLASH_LOCKED_DOWN)
1539
                                f->locks[f->arg1_address] = FLASH_LOCKED;
1540
                        else
1541
                                warning("block locked down: %u", (unsigned)f->arg1_address);
1542
                        break;
1543
                case 0x2F:
1544
                        f->locks[f->arg1_address] = FLASH_LOCKED_DOWN;
1545
                        break;
1546
                default:
1547
                        warning("Unknown/Unimplemented Common Flash Interface Lock Operation: %x", (unsigned)(f->data));
1548
                }
1549
                f->mode = FLASH_READ_STATUS_REGISTER;
1550
                break;
1551
        case FLASH_BLOCK_ERASE:
1552
                /*f->status &= ~FLASH_STATUS_DEVICE_READY;*/
1553
                if(!we && f->we && cs) {
1554
                        if(addr != f->arg1_address)
1555
                                warning("block addresses differ: 1(%u) 2(%u)", f->arg1_address, addr);
1556
                        if(f->data != 0xD0) /* erase confirm */
1557
                                f->mode = FLASH_READ_STATUS_REGISTER;
1558
                        else
1559
                                f->mode = FLASH_BLOCK_ERASING;
1560
 
1561
                        if(f->mode == FLASH_BLOCK_ERASING && address_protected(f, f->arg1_address)) {
1562
                                warning("address locked: %u", (unsigned)f->arg1_address);
1563
                                f->status |= FLASH_STATUS_BLOCK_LOCKED;
1564
                                f->status |= FLASH_STATUS_ERASE_BLANK;
1565
                                f->mode    = FLASH_READ_STATUS_REGISTER;
1566
                        }
1567
                } else if(we && cs) {
1568
                        f->arg2_address = addr;
1569
                }
1570
                f->cycle = 0;
1571
                break;
1572
        case FLASH_BLOCK_ERASING:
1573
                f->status &= ~FLASH_STATUS_DEVICE_READY;
1574
                if(f->cycle++ > FLASH_ERASE_CYCLES) {
1575
                        unsigned block = f->arg1_address;
1576
                        unsigned size  = block_size(block);
1577
                        if(block >= FLASH_BLOCK_MAX) {
1578
                                warning("block operation out of range: %u", block);
1579
                                f->status |= FLASH_STATUS_ERASE_BLANK;
1580
                        } else {
1581
                                memset(f->nvram+block*size, 0xff, sizeof(f->nvram[0])*size);
1582
                        }
1583
                        f->cycle = 0;
1584
                        f->mode = FLASH_READ_STATUS_REGISTER;
1585
                        f->status |= FLASH_STATUS_DEVICE_READY;
1586
                }
1587
                break;
1588
        case FLASH_BUFFERED_PROGRAM:
1589
        case FLASH_BUFFERED_PROGRAMMING:
1590
                warning("block programming not implemented");
1591
                f->status |= FLASH_STATUS_PROGRAM;
1592
                f->mode = FLASH_READ_STATUS_REGISTER;
1593
                break;
1594
        default:
1595
                fatal("invalid flash state: %u", f->mode);
1596
                return;
1597
        }
1598
        if(we && !oe)
1599
                f->data = data;
1600
        f->we = we;
1601
        f->cs = cs;
1602
}
1603
 
1604
uint16_t h2_io_memory_read_operation(h2_soc_state_t *soc)
1605
{
1606
        assert(soc);
1607
        uint32_t flash_addr = ((uint32_t)(soc->mem_control & FLASH_MASK_ADDR_UPPER_MASK) << 16) | soc->mem_addr_low;
1608
        bool flash_rst = soc->mem_control & FLASH_MEMORY_RESET;
1609
        bool flash_cs  = soc->mem_control & FLASH_CHIP_SELECT;
1610
        bool sram_cs   = soc->mem_control & SRAM_CHIP_SELECT;
1611
        bool oe        = soc->mem_control & FLASH_MEMORY_OE;
1612
        bool we        = soc->mem_control & FLASH_MEMORY_WE;
1613
 
1614
        if(oe && we)
1615
                return 0;
1616
 
1617
        if(flash_cs && sram_cs)
1618
                warning("SRAM and Flash Chip selects both high");
1619
 
1620
        if(flash_cs)
1621
                return h2_io_flash_read(&soc->flash, flash_addr >> 1, oe, we, flash_rst);
1622
 
1623
        if(sram_cs && oe && !we)
1624
                return soc->vram[flash_addr >> 1];
1625
        return 0;
1626
}
1627
 
1628
static uint16_t h2_io_get_default(h2_soc_state_t *soc, uint16_t addr, bool *debug_on)
1629
{
1630
        assert(soc);
1631
        debug("IO read addr: %"PRIx16, addr);
1632
        (void)debug_on;
1633
        switch(addr) {
1634
        case iUart:         return UART_TX_FIFO_EMPTY | soc->uart_getchar_register;
1635
        case iVT100:        return UART_TX_FIFO_EMPTY | soc->ps2_getchar_register;
1636
        case iSwitches:     return soc->switches;
1637
        case iTimerDin:     return soc->timer;
1638
        case iMemDin:       return h2_io_memory_read_operation(soc);
1639
        default:
1640
                warning("invalid read from %04"PRIx16, addr);
1641
        }
1642
        return 0;
1643
}
1644
 
1645
static void h2_io_set_default(h2_soc_state_t *soc, uint16_t addr, uint16_t value, bool *debug_on)
1646
{
1647
        assert(soc);
1648
        debug("IO write addr/value: %"PRIx16"/%"PRIx16, addr, value);
1649
 
1650
        switch(addr) {
1651
        case oUart:
1652
                        if(value & UART_TX_WE)
1653
                                putch(0xFF & value);
1654
                        if(value & UART_RX_RE)
1655
                                soc->uart_getchar_register = wrap_getch(debug_on);
1656
                        break;
1657
        case oLeds:       soc->leds           = value; break;
1658
        case oTimerCtrl:  soc->timer_control  = value; break;
1659
        case oVT100:
1660
                if(value & UART_TX_WE)
1661
                        vt100_update(&soc->vt100, value);
1662
                if(value & UART_RX_RE)
1663
                        soc->ps2_getchar_register = wrap_getch(debug_on);
1664
                break;
1665
        case o7SegLED:    soc->led_7_segments = value; break;
1666
        case oIrcMask:    soc->irc_mask       = value; break;
1667
        case oMemControl:
1668
        {
1669
                soc->mem_control    = value;
1670
 
1671
                bool sram_cs   = soc->mem_control & SRAM_CHIP_SELECT;
1672
                bool oe        = soc->mem_control & FLASH_MEMORY_OE;
1673
                bool we        = soc->mem_control & FLASH_MEMORY_WE;
1674
 
1675
                if(sram_cs && !oe && we)
1676
                        soc->vram[(((uint32_t)(soc->mem_control & FLASH_MASK_ADDR_UPPER_MASK) << 16) | soc->mem_addr_low) >> 1] = soc->mem_dout;
1677
                break;
1678
        }
1679
        case oMemAddrLow: soc->mem_addr_low   = value; break;
1680
        case oMemDout:    soc->mem_dout       = value; break;
1681
        default:
1682
                warning("invalid write to %04"PRIx16 ":%04"PRIx16, addr, value);
1683
        }
1684
}
1685
 
1686
static void h2_io_update_default(h2_soc_state_t *soc)
1687
{
1688
        assert(soc);
1689
 
1690
        if(soc->timer_control & TIMER_ENABLE) {
1691
                if(soc->timer_control & TIMER_RESET) {
1692
                        soc->timer = 0;
1693
                        soc->timer_control &= ~TIMER_RESET;
1694
                } else {
1695
                        soc->timer++;
1696
                        if((soc->timer > (soc->timer_control & 0x1FFF))) {
1697
                                if(soc->timer_control & TIMER_INTERRUPT_ENABLE) {
1698
                                        soc->interrupt           = soc->irc_mask & (1 << isrTimer);
1699
                                        soc->interrupt_selector |= soc->irc_mask & (1 << isrTimer);
1700
                                }
1701
                                soc->timer = 0;
1702
                        }
1703
                }
1704
        }
1705
 
1706
        { /* DPAD interrupt on change state */
1707
                uint16_t prev = soc->switches_previous;
1708
                uint16_t cur  = soc->switches;
1709
                if((prev & 0xff00) != (cur & 0xff00)) {
1710
                        soc->interrupt           = soc->irc_mask & (1 << isrDPadButton);
1711
                        soc->interrupt_selector |= soc->irc_mask & (1 << isrDPadButton);
1712
                }
1713
                soc->switches_previous = soc->switches;
1714
        }
1715
 
1716
        {
1717
                uint32_t flash_addr = ((uint32_t)(soc->mem_control & FLASH_MASK_ADDR_UPPER_MASK) << 16) | soc->mem_addr_low;
1718
                bool flash_rst = soc->mem_control & FLASH_MEMORY_RESET;
1719
                bool flash_cs  = soc->mem_control & FLASH_CHIP_SELECT;
1720
                bool oe        = soc->mem_control & FLASH_MEMORY_OE;
1721
                bool we        = soc->mem_control & FLASH_MEMORY_WE;
1722
                h2_io_flash_update(&soc->flash, flash_addr >> 1, soc->mem_dout, oe, we, flash_rst, flash_cs);
1723
        }
1724
}
1725
 
1726
h2_soc_state_t *h2_soc_state_new(void)
1727
{
1728
        h2_soc_state_t *r = allocate_or_die(sizeof(h2_soc_state_t));
1729
        vt100_t *v = &r->vt100;
1730
        memset(r->flash.nvram, 0xff, sizeof(r->flash.nvram[0])*FLASH_BLOCK_MAX);
1731
        memset(r->flash.locks, FLASH_LOCKED, FLASH_BLOCK_MAX);
1732
 
1733
        v->width        = VGA_WIDTH;
1734
        v->height       = VGA_HEIGHT;
1735
        v->size         = VGA_WIDTH * VGA_HEIGHT;
1736
        v->state        = TERMINAL_NORMAL_MODE;
1737
        v->cursor_on    = true;
1738
        v->blinks       = false;
1739
        v->n1           = 1;
1740
        v->n2           = 1;
1741
        v->attribute.foreground_color = WHITE;
1742
        v->attribute.background_color = BLACK;
1743
        for(size_t i = 0; i < v->size; i++)
1744
                v->attributes[i] = v->attribute;
1745
        return r;
1746
}
1747
 
1748
void h2_soc_state_free(h2_soc_state_t *soc)
1749
{
1750
        if(!soc)
1751
                return;
1752
        memset(soc, 0, sizeof(*soc));
1753
        free(soc);
1754
}
1755
 
1756
h2_io_t *h2_io_new(void)
1757
{
1758
        h2_io_t *io =  allocate_or_die(sizeof(*io));
1759
        io->in      = h2_io_get_default;
1760
        io->out     = h2_io_set_default;
1761
        io->update  = h2_io_update_default;
1762
        io->soc     = h2_soc_state_new();
1763
        return io;
1764
}
1765
 
1766
void h2_io_free(h2_io_t *io)
1767
{
1768
        if(!io)
1769
                return;
1770
        h2_soc_state_free(io->soc);
1771
        memset(io, 0, sizeof(*io));
1772
        free(io);
1773
}
1774
 
1775
static void dpush(h2_t *h, uint16_t v)
1776
{
1777
        assert(h);
1778
        h->sp++;
1779
        h->dstk[h->sp % STK_SIZE] = h->tos;
1780
        h->tos = v;
1781
        if(h->sp >= STK_SIZE)
1782
                warning("data stack overflow");
1783
        h->sp %= STK_SIZE;
1784
}
1785
 
1786
static uint16_t dpop(h2_t *h)
1787
{
1788
        uint16_t r;
1789
        assert(h);
1790
        r = h->tos;
1791
        h->tos = h->dstk[h->sp % STK_SIZE];
1792
        h->sp--;
1793
        if(h->sp >= STK_SIZE)
1794
                warning("data stack underflow");
1795
        h->sp %= STK_SIZE;
1796
        return r;
1797
}
1798
 
1799
static void rpush(h2_t *h, uint16_t r)
1800
{
1801
        assert(h);
1802
        h->rp++;
1803
        h->rstk[(h->rp) % STK_SIZE] = r;
1804
        if(h->rp >= STK_SIZE)
1805
                warning("return stack overflow");
1806
        h->rp %= STK_SIZE;
1807
}
1808
 
1809
static uint16_t stack_delta(uint16_t d)
1810
{
1811
        static const uint16_t i[4] = { 0x0000, 0x0001, 0xFFFE, 0xFFFF };
1812
        assert((d & 0xFFFC) == 0);
1813
        return i[d];
1814
}
1815
 
1816
static int trace(FILE *output, uint16_t instruction, symbol_table_t *symbols, const char *fmt, ...)
1817
{
1818
        int r = 0;
1819
        va_list ap;
1820
        assert(output);
1821
        if(!output)
1822
                return r;
1823
        assert(fmt);
1824
        va_start(ap, fmt);
1825
        r = vfprintf(output, fmt, ap);
1826
        va_end(ap);
1827
        if(r < 0)
1828
                return r;
1829
        if(fputc('\t', output) != '\t')
1830
                return -1;
1831
        r = disassemble_instruction(instruction, output, symbols, DCM_NONE);
1832
        if(r < 0)
1833
                return r;
1834
        if(fputc('\n', output) != '\n')
1835
                return -1;
1836
        if(fflush(output) == EOF)
1837
                return -1;
1838
        return r;
1839
}
1840
 
1841
typedef struct {
1842
        FILE *input;
1843
        FILE *output;
1844
        bool step;
1845
        bool trace_on;
1846
} debug_state_t;
1847
 
1848
static const char *debug_prompt = "debug> ";
1849
 
1850
static int number(char *s, uint16_t *o, size_t length);
1851
 
1852
static void h2_print(FILE *out, h2_t *h)
1853
{
1854
        fputs("Return Stack:\n", out);
1855
        memory_print(out, 0, h->rstk, STK_SIZE, false);
1856
        fputs("Variable Stack:\n", out);
1857
        fprintf(out, "tos:  %04"PRIx16"\n", h->tos);
1858
        memory_print(out, 1, h->dstk, STK_SIZE, false);
1859
 
1860
        fprintf(out, "pc:   %04"PRIx16"\n", h->pc);
1861
        fprintf(out, "rp:   %04"PRIx16" (max %04"PRIx16")\n", h->rp, h->rpm);
1862
        fprintf(out, "dp:   %04"PRIx16" (max %04"PRIx16")\n", h->sp, h->spm);
1863
        fprintf(out, "ie:   %s\n", h->ie ? "true" : "false");
1864
}
1865
 
1866
typedef enum {
1867
        DBG_CMD_NO_ARG,
1868
        DBG_CMD_NUMBER,
1869
        DBG_CMD_STRING,
1870
        DBG_CMD_EITHER,
1871
} debug_command_type_e;
1872
 
1873
typedef struct
1874
{
1875
        int cmd;
1876
        int argc;
1877
        debug_command_type_e arg1;
1878
        debug_command_type_e arg2;
1879
        char *description;
1880
} debug_command_t;
1881
 
1882
static const debug_command_t debug_commands[] = {
1883
        { .cmd = 'a', .argc = 1, .arg1 = DBG_CMD_NUMBER, .arg2 = DBG_CMD_NO_ARG, .description = "assemble               " },
1884
        { .cmd = 'b', .argc = 1, .arg1 = DBG_CMD_EITHER, .arg2 = DBG_CMD_NO_ARG, .description = "set break point        " },
1885
        { .cmd = 'c', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "continue               " },
1886
        { .cmd = 'd', .argc = 2, .arg1 = DBG_CMD_NUMBER, .arg2 = DBG_CMD_NUMBER, .description = "dump                   " },
1887
        { .cmd = 'f', .argc = 1, .arg1 = DBG_CMD_EITHER, .arg2 = DBG_CMD_NO_ARG, .description = "save to file           " },
1888
        { .cmd = 'g', .argc = 1, .arg1 = DBG_CMD_EITHER, .arg2 = DBG_CMD_NO_ARG, .description = "goto address           " },
1889
        { .cmd = 'h', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "help                   " },
1890
        { .cmd = 'i', .argc = 1, .arg1 = DBG_CMD_NUMBER, .arg2 = DBG_CMD_NO_ARG, .description = "input (port)           " },
1891
        { .cmd = 'k', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "list all breakpoints   " },
1892
        { .cmd = 'l', .argc = 1, .arg1 = DBG_CMD_NUMBER, .arg2 = DBG_CMD_NO_ARG, .description = "set debug level        " },
1893
        { .cmd = 'o', .argc = 2, .arg1 = DBG_CMD_NUMBER, .arg2 = DBG_CMD_NUMBER, .description = "output (port value)    " },
1894
        { .cmd = 'p', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "print IO state         " },
1895
        { .cmd = 'q', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "quit                   " },
1896
        { .cmd = 'r', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "remove all break points" },
1897
        { .cmd = 's', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "step                   " },
1898
        { .cmd = 't', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "toggle tracing         " },
1899
        { .cmd = 'u', .argc = 2, .arg1 = DBG_CMD_NUMBER, .arg2 = DBG_CMD_NUMBER, .description = "unassemble             " },
1900
        { .cmd = 'y', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "list symbols           " },
1901
        { .cmd = 'v', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "print VGA display      " },
1902
        { .cmd = 'P', .argc = 1, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "push value             " },
1903
        { .cmd = 'D', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "pop value              " },
1904
        { .cmd = 'G', .argc = 1, .arg1 = DBG_CMD_EITHER, .arg2 = DBG_CMD_NO_ARG, .description = "call function/location " },
1905
        { .cmd = '!', .argc = 2, .arg1 = DBG_CMD_NUMBER, .arg2 = DBG_CMD_NUMBER, .description = "set value              " },
1906
        { .cmd = '.', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "print H2 CPU state     " },
1907
        { .cmd = -1,  .argc = 0, .arg1 = DBG_CMD_EITHER, .arg2 = DBG_CMD_NO_ARG, .description = NULL },
1908
};
1909
 
1910
static void debug_command_print_help(FILE *out, const debug_command_t *dc)
1911
{
1912
        assert(out);
1913
        assert(dc);
1914
 
1915
        static const char *debug_help = "\
1916
Debugger Help: \n\n\
1917
Hit 'Escape' when the simulation is and is reading from input to exit \n\
1918
into the back debugger.\n\n\
1919
Command list:\n\n";
1920
 
1921
        static const char *arg_type[] = {
1922
                [DBG_CMD_NO_ARG] = "             ",
1923
                [DBG_CMD_NUMBER] = "number       ",
1924
                [DBG_CMD_STRING] = "string       ",
1925
                [DBG_CMD_EITHER] = "number/string"
1926
        };
1927
        fputs(debug_help, out);
1928
        for(unsigned i = 0; dc[i].cmd != -1; i++)
1929
                fprintf(out, " %c %s\t%d\t%s %s\n", dc[i].cmd, dc[i].description, dc[i].argc, arg_type[dc[i].arg1], arg_type[dc[i].arg2]);
1930
}
1931
 
1932
static int debug_command_check(FILE *out, const debug_command_t *dc, int cmd, int argc, bool is_numeric1, bool is_numeric2)
1933
{
1934
        assert(out);
1935
        assert(dc);
1936
        for(unsigned i = 0; dc[i].cmd != -1 ; i++) {
1937
                if(dc[i].cmd == cmd) {
1938
                        if(dc[i].argc != argc) {
1939
                                fprintf(out, "command '%c' expects %d arguments, got %d\n", cmd, dc[i].argc, argc);
1940
                                return -1;
1941
                        }
1942
 
1943
                        if(dc[i].argc == 0)
1944
                                return 0;
1945
 
1946
                        if(dc[i].arg1 == DBG_CMD_NUMBER && !is_numeric1) {
1947
                                fprintf(out, "command '%c' expects arguments one to be numeric\n", cmd);
1948
                                return -1;
1949
                        }
1950
 
1951
                        if(dc[i].argc == 1)
1952
                                return 0;
1953
 
1954
                        if(dc[i].arg2 == DBG_CMD_NUMBER && !is_numeric2) {
1955
                                fprintf(out, "command '%c' expects arguments two to be numeric\n", cmd);
1956
                                return -1;
1957
                        }
1958
 
1959
                        return 0;
1960
                }
1961
        }
1962
        fprintf(out, "unrecognized command '%c'\n", cmd);
1963
        return -1;
1964
}
1965
 
1966
static int debug_resolve_symbol(FILE *out, char *symbol, symbol_table_t *symbols, uint16_t *value)
1967
{
1968
        assert(out);
1969
        assert(symbol);
1970
        assert(symbols);
1971
        assert(value);
1972
        symbol_t *sym;
1973
        *value = 0;
1974
        if(!(sym = symbol_table_lookup(symbols, symbol))) {
1975
                fprintf(out, "symbol '%s' not found\n", symbol);
1976
                return -1;
1977
        }
1978
        if(sym->type != SYMBOL_TYPE_LABEL && sym->type != SYMBOL_TYPE_CALL) {
1979
                fprintf(out, "symbol is not call or label\n");
1980
                return -1;
1981
        }
1982
        *value = sym->value;
1983
        return 0;
1984
}
1985
 
1986
static int h2_debugger(debug_state_t *ds, h2_t *h, h2_io_t *io, symbol_table_t *symbols, uint16_t point)
1987
{
1988
        bool breaks = false;
1989
        assert(h);
1990
        assert(ds);
1991
 
1992
        breaks = break_point_find(&h->bp, point);
1993
        if(breaks)
1994
                fprintf(ds->output, "\n === BREAK(0x%04"PRIx16") ===\n", h->pc);
1995
 
1996
        if(ds->step || breaks) {
1997
                char line[256];
1998
                char op[256], arg1[256], arg2[256];
1999
                int argc;
2000
                bool is_numeric1, is_numeric2;
2001
                uint16_t num1, num2;
2002
 
2003
                ds->step = true;
2004
 
2005
again:
2006
                memset(line, 0, sizeof(line));
2007
                memset(op,   0, sizeof(op));
2008
                memset(arg1, 0, sizeof(arg1));
2009
                memset(arg2, 0, sizeof(arg2));
2010
 
2011
                fputs(debug_prompt, ds->output);
2012
                if(!fgets(line, sizeof(line), ds->input)) {
2013
                        fputs("End Of Input - exiting\n", ds->output);
2014
                        return -1;
2015
                }
2016
 
2017
                argc = sscanf(line, "%256s %256s %256s", op, arg1, arg2);
2018
                if(argc < 1)
2019
                        goto again;
2020
 
2021
                is_numeric1 = number(arg1, &num1, strlen(arg1));
2022
                is_numeric2 = number(arg2, &num2, strlen(arg2));
2023
 
2024
                if(!(strlen(op) == 1)) {
2025
                        fprintf(ds->output, "invalid command '%s'\n", op);
2026
                        goto again;
2027
                }
2028
 
2029
                if(debug_command_check(ds->output, debug_commands, op[0], argc-1, is_numeric1, is_numeric2) < 0)
2030
                        goto again;
2031
 
2032
                switch(op[0]) {
2033
                case ' ':
2034
                case '\t':
2035
                case '\r':
2036
                case '\n':
2037
                        break;
2038
                case 'a':
2039
                        fprintf(ds->output, "command '%c' not implemented yet!\n", op[0]);
2040
                        break;
2041
                case 'f':
2042
                {
2043
                        FILE *o = fopen(arg1, "wb");
2044
                        if(!o) {
2045
                                fprintf(ds->output, "could not open file '%s 'for writing: %s", arg1, strerror(errno));
2046
                                break;
2047
                        }
2048
                        h2_save(h, o, true);
2049
                        fclose(o);
2050
                        break;
2051
                }
2052
                case 'd':
2053
                        if(((long)num1 + (long)num2) > MAX_CORE)
2054
                                fprintf(ds->output, "overflow in RAM dump\n");
2055
                        else
2056
                                memory_print(ds->output, num1, h->core + num1, num2, true);
2057
                        break;
2058
                case 'l':
2059
                        if(!is_numeric1) {
2060
                                fprintf(ds->output, "set log level expects one numeric argument\n");
2061
                                break;
2062
                        }
2063
                        log_level = num1;
2064
                        break;
2065
                case 'b':
2066
                        if(!is_numeric1) {
2067
                                if(debug_resolve_symbol(ds->output, arg1, symbols, &num1))
2068
                                        break;
2069
                        }
2070
                        break_point_add(&h->bp, num1);
2071
                        break;
2072
 
2073
                case 'g':
2074
                        if(!is_numeric1) {
2075
                                if(debug_resolve_symbol(ds->output, arg1, symbols, &num1))
2076
                                        break;
2077
                        }
2078
                        h->pc = num1;
2079
                        break;
2080
                case 'G':
2081
                        if(!is_numeric1) {
2082
                                if(debug_resolve_symbol(ds->output, arg1, symbols, &num1))
2083
                                        break;
2084
                        }
2085
                        rpush(h, h->pc);
2086
                        h->pc = num1;
2087
                        break;
2088
                case '.':
2089
                        h2_print(ds->output, h);
2090
                        break;
2091
 
2092
                case '!':
2093
                        if(num1 >= MAX_CORE) {
2094
                                fprintf(ds->output, "invalid write\n");
2095
                                break;
2096
                        }
2097
                        h->core[num1] = num2;
2098
                        break;
2099
                case 'P':
2100
                        dpush(h, num1);
2101
                        break;
2102
                case 'D':
2103
                        fprintf(ds->output, "popped: %04u\n", (unsigned)dpop(h));
2104
                        break;
2105
 
2106
                case 'r':
2107
                        free(h->bp.points);
2108
                        h->bp.points = NULL;
2109
                        h->bp.length = 0;
2110
                        break;
2111
                case 'u':
2112
                        if(num2 >= MAX_CORE || num1 > num2) {
2113
                                fprintf(ds->output, "invalid range\n");
2114
                                break;
2115
                        }
2116
                        for(uint16_t i = num1; i < num2; i++) {
2117
                                fprintf(ds->output, "%04"PRIx16 ":\t", i);
2118
                                disassemble_instruction(h->core[i], ds->output, symbols, DCM_NONE);
2119
                                fputc('\n', ds->output);
2120
                        }
2121
                        break;
2122
 
2123
                case 'o':
2124
                        if(!io) {
2125
                                fprintf(ds->output, "I/O unavailable\n");
2126
                                break;
2127
                        }
2128
                        io->out(io->soc, num1, num2, NULL);
2129
 
2130
                        break;
2131
 
2132
                case 'i':
2133
                        if(!io) {
2134
                                fprintf(ds->output, "I/O unavailable\n");
2135
                                break;
2136
                        }
2137
                        fprintf(ds->output, "read: %"PRIx16"\n", io->in(io->soc, num1, NULL));
2138
                        break;
2139
 
2140
                case 'k':
2141
                        break_point_print(ds->output, &h->bp);
2142
                        break;
2143
                case 'h':
2144
                        debug_command_print_help(ds->output, debug_commands);
2145
                        break;
2146
                case 's':
2147
                        return 0;
2148
                case 'c':
2149
                        ds->step = false;
2150
                        return 0;
2151
                case 't':
2152
                        ds->trace_on = !ds->trace_on;
2153
                        fprintf(ds->output, "trace %s\n", ds->trace_on ? "on" : "off");
2154
                        break;
2155
                case 'y':
2156
                        if(symbols)
2157
                                symbol_table_print(symbols, ds->output);
2158
                        else
2159
                                fprintf(ds->output, "symbol table unavailable\n");
2160
                        break;
2161
                case 'v':
2162
                        if(!io) {
2163
                                fprintf(ds->output, "I/O unavailable\n");
2164
                                break;
2165
                        }
2166
                        for(size_t i = 0; i < VGA_HEIGHT; i++) {
2167
                                for(size_t j = 0; j < VGA_WIDTH; j++) {
2168
                                        unsigned char c = io->soc->vt100.m[i*VGA_WIDTH + j];
2169
                                        fputc(c < 32 || c > 127 ? '?' : c, ds->output);
2170
                                }
2171
                                fputc('\n', ds->output);
2172
                        }
2173
 
2174
                        break;
2175
                case 'p':
2176
                        if(io)
2177
                                soc_print(ds->output, io->soc);
2178
                        else
2179
                                fprintf(ds->output, "I/O unavailable\n");
2180
                        break;
2181
                case 'q':
2182
                        fprintf(ds->output, "Quiting simulator\n");
2183
                        return -1;
2184
                default:
2185
                        fprintf(ds->output, "unknown command '%c'\n", op[0]);
2186
                }
2187
                goto again;
2188
        }
2189
        return 0;
2190
}
2191
 
2192
static uint16_t interrupt_decode(uint8_t *vector)
2193
{
2194
        for(unsigned i = 0; i < NUMBER_OF_INTERRUPTS; i++)
2195
                if(*vector & (1 << i)) {
2196
                        *vector ^= 1 << i;
2197
                        return i;
2198
                }
2199
        return 0;
2200
}
2201
 
2202
int h2_run(h2_t *h, h2_io_t *io, FILE *output, unsigned steps, symbol_table_t *symbols, bool run_debugger)
2203
{
2204
        bool turn_debug_on = false;
2205
        assert(h);
2206
        debug_state_t ds = { .input = stdin, .output = stderr, .step = run_debugger, .trace_on = false /*run_debugger*/ };
2207
 
2208
        if(run_debugger)
2209
                fputs("Debugger running, type 'h' for a list of command\n", ds.output);
2210
 
2211
        for(unsigned i = 0; i < steps || steps == 0 || run_debugger; i++) {
2212
                uint16_t instruction,
2213
                         literal,
2214
                         address,
2215
                         pc_plus_one;
2216
 
2217
                if(run_debugger)
2218
                        if(h2_debugger(&ds, h, io, symbols, h->pc))
2219
                                return 0;
2220
 
2221
                if(io)
2222
                        io->update(io->soc);
2223
 
2224
                if(io && io->soc->wait) /* wait only applies to the H2 core not the rest of the SoC */
2225
                        continue;
2226
 
2227
                if(h->pc >= MAX_CORE) {
2228
                        error("invalid program counter: %04x > %04x", (unsigned)h->pc, MAX_CORE);
2229
                        return -1;
2230
                }
2231
                instruction = h->core[h->pc];
2232
 
2233
                literal = instruction & 0x7FFF;
2234
                address = instruction & 0x1FFF; /* NB. also used for ALU OP */
2235
 
2236
                if(h->ie && io && io->soc->interrupt) {
2237
                        rpush(h, h->pc << 1);
2238
                        io->soc->interrupt = false;
2239
                        h->pc = interrupt_decode(&io->soc->interrupt_selector);
2240
                        continue;
2241
                }
2242
 
2243
                pc_plus_one = (h->pc + 1) % MAX_CORE;
2244
 
2245
                if(log_level >= LOG_DEBUG || ds.trace_on)
2246
                        trace(output, instruction, symbols,
2247
                                "%04u: pc(%04x) inst(%04x) sp(%x) rp(%x) tos(%04x) r(%04x)",
2248
                                i,
2249
                                (unsigned)h->pc,
2250
                                (unsigned)instruction,
2251
                                (unsigned)h->sp,
2252
                                (unsigned)h->rp,
2253
                                (unsigned)h->tos,
2254
                                (unsigned)h->rstk[h->rp % STK_SIZE]);
2255
 
2256
                /* decode / execute */
2257
                if(IS_LITERAL(instruction)) {
2258
                        dpush(h, literal);
2259
                        h->pc = pc_plus_one;
2260
                } else if (IS_ALU_OP(instruction)) {
2261
                        uint16_t rd  = stack_delta(RSTACK(instruction));
2262
                        uint16_t dd  = stack_delta(DSTACK(instruction));
2263
                        uint16_t nos = h->dstk[h->sp % STK_SIZE];
2264
                        uint16_t tos = h->tos;
2265
                        uint16_t npc = pc_plus_one;
2266
 
2267
                        if(instruction & R_TO_PC)
2268
                                npc = h->rstk[h->rp % STK_SIZE] >> 1;
2269
 
2270
                        switch(ALU_OP(instruction)) {
2271
                        case ALU_OP_T:        /* tos = tos; */ break;
2272
                        case ALU_OP_N:           tos = nos;    break;
2273
                        case ALU_OP_T_PLUS_N:    tos += nos;   break;
2274
                        case ALU_OP_T_AND_N:     tos &= nos;   break;
2275
                        case ALU_OP_T_OR_N:      tos |= nos;   break;
2276
                        case ALU_OP_T_XOR_N:     tos ^= nos;   break;
2277
                        case ALU_OP_T_INVERT:    tos = ~tos;   break;
2278
                        case ALU_OP_T_EQUAL_N:   tos = -(tos == nos); break;
2279
                        case ALU_OP_N_LESS_T:    tos = -((int16_t)nos < (int16_t)tos); break;
2280
                        case ALU_OP_N_RSHIFT_T:  tos = nos >> tos; break;
2281
                        case ALU_OP_T_DECREMENT: tos--; break;
2282
                        case ALU_OP_R:           tos = h->rstk[h->rp % STK_SIZE]; break;
2283
                        case ALU_OP_T_LOAD:
2284
                                if(h->tos & 0x4000) {
2285
                                        if(io) {
2286
                                                if(h->tos & 0x1)
2287
                                                        warning("unaligned register read: %04x", (unsigned)h->tos);
2288
                                                tos = io->in(io->soc, h->tos & ~0x1, &turn_debug_on);
2289
                                                if(turn_debug_on) {
2290
                                                        ds.step = true;
2291
                                                        run_debugger = true;
2292
                                                        turn_debug_on = false;
2293
                                                }
2294
                                        } else {
2295
                                                warning("I/O read attempted on addr: %"PRIx16, h->tos);
2296
                                        }
2297
                                } else {
2298
                                        tos = h->core[(h->tos >> 1) % MAX_CORE];
2299
                                }
2300
                                break;
2301
                        case ALU_OP_N_LSHIFT_T: tos = nos << tos;           break;
2302
                        case ALU_OP_DEPTH:      tos = h->sp;                break;
2303
                        case ALU_OP_N_ULESS_T:  tos = -(nos < tos);         break;
2304
                        case ALU_OP_ENABLE_INTERRUPTS: h->ie = tos & 1; /*tos = nos;*/ break;
2305
                        case ALU_OP_INTERRUPTS_ENABLED: tos = -h->ie;       break;
2306
                        case ALU_OP_RDEPTH:     tos = h->rp;                break;
2307
                        case ALU_OP_T_EQUAL_0:  tos = -(tos == 0);          break;
2308
                        case ALU_OP_CPU_ID:     tos = H2_CPU_ID_SIMULATION; break;
2309
                        default:
2310
                                warning("unknown ALU operation: %u", (unsigned)ALU_OP(instruction));
2311
                        }
2312
 
2313
                        h->sp += dd;
2314
                        if(h->sp >= STK_SIZE)
2315
                                warning("data stack overflow");
2316
                        h->sp %= STK_SIZE;
2317
 
2318
                        h->rp += rd;
2319
                        if(h->rp >= STK_SIZE)
2320
                                warning("return stack overflow");
2321
                        h->rp %= STK_SIZE;
2322
 
2323
                        if(instruction & T_TO_R)
2324
                                h->rstk[h->rp % STK_SIZE] = h->tos;
2325
 
2326
                        if(instruction & T_TO_N)
2327
                                h->dstk[h->sp % STK_SIZE] = h->tos;
2328
 
2329
                        if(instruction & N_TO_ADDR_T) {
2330
                                if((h->tos & 0x4000) && ALU_OP(instruction) != ALU_OP_T_LOAD) {
2331
                                        if(io) {
2332
                                                if(h->tos & 0x1)
2333
                                                        warning("unaligned register write: %04x <- %04x", (unsigned)h->tos, (unsigned)nos);
2334
                                                io->out(io->soc, h->tos & ~0x1, nos, &turn_debug_on);
2335
                                                if(turn_debug_on) {
2336
                                                        ds.step = true;
2337
                                                        run_debugger = true;
2338
                                                        turn_debug_on = false;
2339
                                                }
2340
                                        } else {
2341
                                                warning("I/O write attempted with addr/value: %"PRIx16 "/%"PRIx16, tos, nos);
2342
                                        }
2343
                                } else {
2344
                                        h->core[(h->tos >> 1) % MAX_CORE] = nos;
2345
                                }
2346
                        }
2347
 
2348
                        h->tos = tos;
2349
                        h->pc = npc;
2350
                } else if (IS_CALL(instruction)) {
2351
                        rpush(h, pc_plus_one << 1);
2352
                        h->pc = address;
2353
                } else if (IS_0BRANCH(instruction)) {
2354
                        if(!dpop(h))
2355
                                h->pc = address % MAX_CORE;
2356
                        else
2357
                                h->pc = pc_plus_one;
2358
                } else if (IS_BRANCH(instruction)) {
2359
                        h->pc = address;
2360
                } else {
2361
                        error("invalid instruction: %"PRId16, instruction);
2362
                }
2363
 
2364
                h->rpm = MAX(h->rpm, h->rp);
2365
                h->spm = MAX(h->spm, h->sp);
2366
        }
2367
        return 0;
2368
}
2369
 
2370
/* ========================== Simulation And Debugger ====================== */
2371
 
2372
/* ========================== Assembler ==================================== */
2373
/* This section is the most complex, it implements a lexer, parser and code
2374
 * compiler for a simple pseudo Forth like language, whilst it looks like
2375
 * Forth it is not Forth. */
2376
 
2377
#define MAX_ID_LENGTH (256u)
2378
 
2379
/**@warning The ordering of the following enumerations matters a lot */
2380
typedef enum {
2381
        LEX_LITERAL,
2382
        LEX_IDENTIFIER,
2383
        LEX_LABEL,
2384
        LEX_STRING,
2385
 
2386
        LEX_CONSTANT, /* start of named tokens */
2387
        LEX_CALL,
2388
        LEX_BRANCH,
2389
        LEX_0BRANCH,
2390
        LEX_BEGIN,
2391
        LEX_WHILE,
2392
        LEX_REPEAT,
2393
        LEX_AGAIN,
2394
        LEX_UNTIL,
2395
        LEX_FOR,
2396
        LEX_AFT,
2397
        LEX_NEXT,
2398
        LEX_IF,
2399
        LEX_ELSE,
2400
        LEX_THEN,
2401
        LEX_DEFINE,
2402
        LEX_ENDDEFINE,
2403
        LEX_CHAR,
2404
        LEX_VARIABLE,
2405
        LEX_LOCATION,
2406
        LEX_IMMEDIATE,
2407
        LEX_HIDDEN,
2408
        LEX_INLINE,
2409
        LEX_QUOTE,
2410
 
2411
        LEX_PWD,
2412
        LEX_SET,
2413
        LEX_PC,
2414
        LEX_BREAK,
2415
        LEX_MODE,
2416
        LEX_ALLOCATE,
2417
        LEX_BUILT_IN,
2418
 
2419
        /* start of instructions */
2420
#define X(NAME, STRING, DEFINE, INSTRUCTION) LEX_ ## NAME,
2421
        X_MACRO_INSTRUCTIONS
2422
#undef X
2423
        /* end of named tokens and instructions */
2424
 
2425
        LEX_ERROR, /* error token: this needs to be after the named tokens */
2426
 
2427
        LEX_EOI = EOF
2428
} token_e;
2429
 
2430
static const char *keywords[] =
2431
{
2432
        [LEX_LITERAL]    = "literal",
2433
        [LEX_IDENTIFIER] = "identifier",
2434
        [LEX_LABEL]      = "label",
2435
        [LEX_STRING]     = "string",
2436
        [LEX_CONSTANT]   =  "constant",
2437
        [LEX_CALL]       =  "call",
2438
        [LEX_BRANCH]     =  "branch",
2439
        [LEX_0BRANCH]    =  "0branch",
2440
        [LEX_BEGIN]      =  "begin",
2441
        [LEX_WHILE]      =  "while",
2442
        [LEX_REPEAT]     =  "repeat",
2443
        [LEX_AGAIN]      =  "again",
2444
        [LEX_UNTIL]      =  "until",
2445
        [LEX_FOR]        =  "for",
2446
        [LEX_AFT]        =  "aft",
2447
        [LEX_NEXT]       =  "next",
2448
        [LEX_IF]         =  "if",
2449
        [LEX_ELSE]       =  "else",
2450
        [LEX_THEN]       =  "then",
2451
        [LEX_DEFINE]     =  ":",
2452
        [LEX_ENDDEFINE]  =  ";",
2453
        [LEX_CHAR]       =  "[char]",
2454
        [LEX_VARIABLE]   =  "variable",
2455
        [LEX_LOCATION]   =  "location",
2456
        [LEX_IMMEDIATE]  =  "immediate",
2457
        [LEX_HIDDEN]     =  "hidden",
2458
        [LEX_INLINE]     =  "inline",
2459
        [LEX_QUOTE]      =  "'",
2460
        [LEX_PWD]        =  ".pwd",
2461
        [LEX_SET]        =  ".set",
2462
        [LEX_PC]         =  ".pc",
2463
        [LEX_BREAK]      =  ".break",
2464
        [LEX_MODE]       =  ".mode",
2465
        [LEX_ALLOCATE]   =  ".allocate",
2466
        [LEX_BUILT_IN]   =  ".built-in",
2467
 
2468
        /* start of instructions */
2469
#define X(NAME, STRING, DEFINE, INSTRUCTION) [ LEX_ ## NAME ] = STRING,
2470
        X_MACRO_INSTRUCTIONS
2471
#undef X
2472
        /* end of named tokens and instructions */
2473
 
2474
        [LEX_ERROR]      =  NULL,
2475
        NULL
2476
};
2477
 
2478
typedef struct {
2479
        union {
2480
                char *id;
2481
                uint16_t number;
2482
        } p;
2483
        unsigned location;
2484
        unsigned line;
2485
        token_e type;
2486
} token_t;
2487
 
2488
typedef struct {
2489
        error_t error;
2490
        FILE *input;
2491
        unsigned line;
2492
        int c;
2493
        char id[MAX_ID_LENGTH];
2494
        token_t *token;
2495
        token_t *accepted;
2496
        bool in_definition;
2497
} lexer_t;
2498
 
2499
/********* LEXER *********/
2500
 
2501
/**@note it would be possible to add a very small amount of state to the
2502
 * lexer, so when keywords like 'hex' and 'decimal' are encountered, the
2503
 * base is changed. */
2504
 
2505
static token_t *token_new(token_e type, unsigned line)
2506
{
2507
        token_t *r = allocate_or_die(sizeof(*r));
2508
        r->type = type;
2509
        r->line = line;
2510
        return r;
2511
}
2512
 
2513
void token_free(token_t *t)
2514
{
2515
        if(!t)
2516
                return;
2517
        if(t->type == LEX_IDENTIFIER || t->type == LEX_STRING || t->type == LEX_LABEL)
2518
                free(t->p.id);
2519
        memset(t, 0, sizeof(*t));
2520
        free(t);
2521
}
2522
 
2523
static int next_char(lexer_t *l)
2524
{
2525
        assert(l);
2526
        return fgetc(l->input);
2527
}
2528
 
2529
static int unget_char(lexer_t *l, int c)
2530
{
2531
        assert(l);
2532
        return ungetc(c, l->input);
2533
}
2534
 
2535
static lexer_t* lexer_new(FILE *input)
2536
{
2537
        lexer_t *l = allocate_or_die(sizeof(lexer_t));
2538
        l->input = input;
2539
        return l;
2540
}
2541
 
2542
static void lexer_free(lexer_t *l)
2543
{
2544
        assert(l);
2545
        token_free(l->token);
2546
        memset(l, 0, sizeof(*l));
2547
        free(l);
2548
}
2549
 
2550
static int token_print(token_t *t, FILE *output, unsigned depth)
2551
{
2552
        token_e type;
2553
        int r = 0;
2554
        if(!t)
2555
                return 0;
2556
        indent(output, ' ', depth);
2557
        type = t->type;
2558
        if(type == LEX_LITERAL) {
2559
                r = fprintf(output, "number: %"PRId16, t->p.number);
2560
        } else if(type == LEX_LABEL) {
2561
                r = fprintf(output, "label: %s", t->p.id);
2562
        } else if(type == LEX_IDENTIFIER) {
2563
                r = fprintf(output, "id: %s", t->p.id);
2564
        } else if(type == LEX_ERROR) {
2565
                r = fputs("error", output);
2566
        } else if(type == LEX_EOI) {
2567
                r = fputs("EOI", output);
2568
        } else {
2569
                r = fprintf(output, "keyword: %s", keywords[type]);
2570
        }
2571
        return r < 0 ? -1 : 0;
2572
}
2573
 
2574
static int _syntax_error(lexer_t *l,
2575
                const char *func, unsigned line, const char *fmt, ...)
2576
{
2577
        va_list ap;
2578
        assert(l);
2579
        assert(func);
2580
        assert(fmt);
2581
        fprintf(stderr, "%s:%u\n", func, line);
2582
        fprintf(stderr, "  syntax error on line %u of input\n", l->line);
2583
        va_start(ap, fmt);
2584
        vfprintf(stderr, fmt, ap);
2585
        va_end(ap);
2586
        fputc('\n', stderr);
2587
        token_print(l->token, stderr, 2);
2588
        fputc('\n', stderr);
2589
        ethrow(&l->error);
2590
        return 0;
2591
}
2592
 
2593
#define syntax_error(LEXER, ...) _syntax_error(LEXER, __func__, __LINE__, ## __VA_ARGS__)
2594
 
2595
static uint16_t map_char_to_number(int c)
2596
{
2597
        if(c >= '0' && c <= '9')
2598
                return c - '0';
2599
        c = tolower(c);
2600
        if(c >= 'a' && c <= 'z')
2601
                return c + 10 - 'a';
2602
        fatal("invalid numeric character: %c", c);
2603
        return 0;
2604
}
2605
 
2606
static bool numeric(int c, int base)
2607
{
2608
        assert(base == 10 || base == 16);
2609
        if(base == 10)
2610
                return isdigit(c);
2611
        return isxdigit(c);
2612
}
2613
 
2614
static int number(char *s, uint16_t *o, size_t length)
2615
{
2616
        size_t i = 0, start = 0;
2617
        uint32_t out = 0;
2618
        int base = 10;
2619
        bool negate = false;
2620
        assert(o);
2621
        if(s[i] == '\0')
2622
                return 0;
2623
 
2624
        if(s[i] == '-') {
2625
                if(s[i+1] == '\0')
2626
                        return 0;
2627
                negate = true;
2628
                start = ++i;
2629
        }
2630
 
2631
        if(s[i] == '$') {
2632
                base = 16;
2633
                if(s[i+1] == '\0')
2634
                        return 0;
2635
                start = i + 1;
2636
        }
2637
 
2638
        for(i = start; i < length; i++)
2639
                if(!numeric(s[i], base))
2640
                        return 0;
2641
 
2642
        for(i = start; i < length; i++)
2643
                out = out * base + map_char_to_number(s[i]);
2644
 
2645
        *o = negate ? out * -1 : out;
2646
        return 1;
2647
}
2648
 
2649
static void lexer(lexer_t *l)
2650
{
2651
        size_t i;
2652
        int ch;
2653
        token_e sym;
2654
        uint16_t lit = 0;
2655
        assert(l);
2656
        ch = next_char(l);
2657
        l->token = token_new(LEX_ERROR, l->line);
2658
 
2659
again:
2660
        switch(ch) {
2661
        case '\n':
2662
                l->line++;
2663
        case ' ':
2664
        case '\t':
2665
        case '\r':
2666
        case '\v':
2667
                ch = next_char(l);
2668
                goto again;
2669
        case EOF:
2670
                l->token->type = LEX_EOI;
2671
                return;
2672
        case '\\':
2673
                for(; '\n' != (ch = next_char(l));)
2674
                        if(ch == EOF)
2675
                                syntax_error(l, "'\\' commented terminated by EOF");
2676
                ch = next_char(l);
2677
                l->line++;
2678
                goto again;
2679
        case '(':
2680
                ch = next_char(l);
2681
                if(!isspace(ch)) {
2682
                        unget_char(l, ch);
2683
                        ch = '(';
2684
                        goto graph;
2685
                }
2686
                for(; ')' != (ch = next_char(l));)
2687
                        if(ch == EOF)
2688
                                syntax_error(l, "'(' comment terminated by EOF");
2689
                        else if(ch == '\n')
2690
                                l->line++;
2691
                ch = next_char(l);
2692
                goto again;
2693
        case '"':
2694
                for(i = 0; '"' != (ch = next_char(l));) {
2695
                        if(ch == EOF)
2696
                                syntax_error(l, "string terminated by EOF");
2697
                        if(i >= MAX_ID_LENGTH - 1)
2698
                                syntax_error(l, "identifier too large: %s", l->id);
2699
                        l->id[i++] = ch;
2700
                }
2701
                l->id[i] = '\0';
2702
                l->token->type = LEX_STRING;
2703
                l->token->p.id = duplicate(l->id);
2704
                ch = next_char(l);
2705
                break;
2706
        default:
2707
                i = 0;
2708
        graph:
2709
                if(isgraph(ch)) {
2710
                        while(isgraph(ch)) {
2711
                                if(i >= MAX_ID_LENGTH - 1)
2712
                                        syntax_error(l, "identifier too large: %s", l->id);
2713
                                l->id[i++] = ch;
2714
                                ch = next_char(l);
2715
                        }
2716
                        l->id[i] = '\0';
2717
                } else {
2718
                        syntax_error(l, "invalid character: %c", ch);
2719
                }
2720
 
2721
                if(number(l->id, &lit, i)) {
2722
                        l->token->type = LEX_LITERAL;
2723
                        l->token->p.number = lit;
2724
                        break;
2725
                }
2726
 
2727
                for(sym = LEX_CONSTANT; sym != LEX_ERROR && keywords[sym] && strcmp(keywords[sym], l->id); sym++)
2728
                        /*do nothing*/;
2729
                if(!keywords[sym]) {
2730
                        if(i > 1 && l->id[i - 1] == ':') {
2731
                                l->id[strlen(l->id) - 1] = '\0';
2732
                                l->token->type = LEX_LABEL;
2733
                        } else { /* IDENTIFIER */
2734
                                l->token->type = LEX_IDENTIFIER;
2735
                        }
2736
                        l->token->p.id = duplicate(l->id);
2737
                } else {
2738
                        l->token->type = sym;
2739
 
2740
                        if(sym == LEX_DEFINE) {
2741
                                if(l->in_definition)
2742
                                        syntax_error(l, "Nested definitions are not allowed");
2743
                                l->in_definition = true;
2744
                        }
2745
                        if(sym == LEX_ENDDEFINE) {
2746
                                if(!(l->in_definition))
2747
                                        syntax_error(l, "Use of ';' not terminating word definition");
2748
                                l->in_definition = false;
2749
                        }
2750
                }
2751
                break;
2752
        }
2753
        unget_char(l, ch);
2754
}
2755
 
2756
/********* PARSER *********/
2757
 
2758
#define X_MACRO_PARSE\
2759
        X(SYM_PROGRAM,             "program")\
2760
        X(SYM_STATEMENTS,          "statements")\
2761
        X(SYM_LABEL,               "label")\
2762
        X(SYM_BRANCH,              "branch")\
2763
        X(SYM_0BRANCH,             "0branch")\
2764
        X(SYM_CALL,                "call")\
2765
        X(SYM_CONSTANT,            "constant")\
2766
        X(SYM_VARIABLE,            "variable")\
2767
        X(SYM_LOCATION,            "location")\
2768
        X(SYM_LITERAL,             "literal")\
2769
        X(SYM_STRING,              "string")\
2770
        X(SYM_INSTRUCTION,         "instruction")\
2771
        X(SYM_BEGIN_UNTIL,         "begin...until")\
2772
        X(SYM_BEGIN_AGAIN,         "begin...again")\
2773
        X(SYM_BEGIN_WHILE_REPEAT,  "begin...while...repeat")\
2774
        X(SYM_FOR_NEXT,            "for...next")\
2775
        X(SYM_FOR_AFT_THEN_NEXT,   "for...aft...then...next")\
2776
        X(SYM_IF1,                 "if1")\
2777
        X(SYM_DEFINITION,          "definition")\
2778
        X(SYM_CHAR,                "[char]")\
2779
        X(SYM_QUOTE,               "'")\
2780
        X(SYM_PWD,                 "pwd")\
2781
        X(SYM_SET,                 "set")\
2782
        X(SYM_PC,                  "pc")\
2783
        X(SYM_BREAK,               "break")\
2784
        X(SYM_BUILT_IN,            "built-in")\
2785
        X(SYM_MODE,                "mode")\
2786
        X(SYM_ALLOCATE,            "allocate")\
2787
        X(SYM_CALL_DEFINITION,     "call-definition")
2788
 
2789
typedef enum {
2790
#define X(ENUM, NAME) ENUM,
2791
        X_MACRO_PARSE
2792
#undef X
2793
} parse_e;
2794
 
2795
static const char *names[] = {
2796
#define X(ENUM, NAME) [ENUM] = NAME,
2797
        X_MACRO_PARSE
2798
#undef X
2799
        NULL
2800
};
2801
 
2802
typedef struct node_t  {
2803
        parse_e type;
2804
        size_t length;
2805
        uint16_t bits; /*general use bits*/
2806
        token_t *token, *value;
2807
        struct node_t *o[];
2808
} node_t;
2809
 
2810
static node_t *node_new(parse_e type, size_t size)
2811
{
2812
        node_t *r = allocate_or_die(sizeof(*r) + sizeof(r->o[0]) * size);
2813
        if(log_level >= LOG_DEBUG)
2814
                fprintf(stderr, "node> %s\n", names[type]);
2815
        r->length = size;
2816
        r->type = type;
2817
        return r;
2818
}
2819
 
2820
static node_t *node_grow(node_t *n)
2821
{
2822
        node_t *r = NULL;
2823
        assert(n);
2824
        errno = 0;
2825
        r = realloc(n, sizeof(*n) + (sizeof(n->o[0]) * (n->length + 1)));
2826
        if(!r)
2827
                fatal("reallocate of size %zu failed: %s", n->length + 1, reason());
2828
        r->o[r->length++] = 0;
2829
        return r;
2830
}
2831
 
2832
static void node_free(node_t *n)
2833
{
2834
        if(!n)
2835
                return;
2836
        for(unsigned i = 0; i < n->length; i++)
2837
                node_free(n->o[i]);
2838
        token_free(n->token);
2839
        token_free(n->value);
2840
        free(n);
2841
}
2842
 
2843
static int accept_token(lexer_t *l, token_e sym)
2844
{
2845
        assert(l);
2846
        if(sym == l->token->type) {
2847
                token_free(l->accepted); /* free token owned by lexer */
2848
                l->accepted = l->token;
2849
                if(sym != LEX_EOI)
2850
                        lexer(l);
2851
                return 1;
2852
        }
2853
        return 0;
2854
}
2855
 
2856
static int accept_range(lexer_t *l, token_e low, token_e high)
2857
{
2858
        assert(l);
2859
        assert(low <= high);
2860
        for(token_e i = low; i <= high; i++)
2861
                if(accept_token(l, i))
2862
                        return 1;
2863
        return 0;
2864
}
2865
 
2866
static void use(lexer_t *l, node_t *n)
2867
{ /* move ownership of token from lexer to parse tree */
2868
        assert(l);
2869
        assert(n);
2870
        if(n->token)
2871
                n->value = l->accepted;
2872
        else
2873
                n->token = l->accepted;
2874
        l->accepted = NULL;
2875
}
2876
 
2877
static int token_enum_print(token_e sym, FILE *output)
2878
{
2879
        assert(output);
2880
        assert(sym < LEX_ERROR);
2881
        const char *s = keywords[sym];
2882
        return fprintf(output, "%s(%u)", s ? s : "???", sym);
2883
}
2884
 
2885
static void node_print(FILE *output, node_t *n, bool shallow, unsigned depth)
2886
{
2887
        if(!n)
2888
                return;
2889
        assert(output);
2890
        indent(output, ' ', depth);
2891
        fprintf(output, "node(%d): %s\n", n->type, names[n->type]);
2892
        token_print(n->token, output, depth);
2893
        if(n->token)
2894
                fputc('\n', output);
2895
        if(shallow)
2896
                return;
2897
        for(size_t i = 0; i < n->length; i++)
2898
                node_print(output, n->o[i], shallow, depth+1);
2899
}
2900
 
2901
static int _expect(lexer_t *l, token_e token, const char *file, const char *func, unsigned line)
2902
{
2903
        assert(l);
2904
        assert(file);
2905
        assert(func);
2906
        if(accept_token(l, token))
2907
                return 1;
2908
        fprintf(stderr, "%s:%s:%u\n", file, func, line);
2909
        fprintf(stderr, "  Syntax error: unexpected token\n  Got:          ");
2910
        token_print(l->token, stderr, 0);
2911
        fputs("  Expected:     ", stderr);
2912
        token_enum_print(token, stderr);
2913
        fprintf(stderr, "\n  On line: %u\n", l->line);
2914
        ethrow(&l->error);
2915
        return 0;
2916
}
2917
 
2918
#define expect(L, TOKEN) _expect((L), (TOKEN), __FILE__, __func__, __LINE__)
2919
 
2920
/* for rules in the BNF tree defined entirely by their token */
2921
static node_t *defined_by_token(lexer_t *l, parse_e type)
2922
{
2923
        node_t *r;
2924
        assert(l);
2925
        r = node_new(type, 0);
2926
        use(l, r);
2927
        return r;
2928
}
2929
 
2930
typedef enum {
2931
        DEFINE_HIDDEN    = 1 << 0,
2932
        DEFINE_IMMEDIATE = 1 << 1,
2933
        DEFINE_INLINE    = 1 << 2,
2934
} define_type_e;
2935
 
2936
/** @note LEX_LOCATION handled by modifying return node in statement() */
2937
static node_t *variable_or_constant(lexer_t *l, bool variable)
2938
{
2939
        node_t *r;
2940
        assert(l);
2941
        r = node_new(variable ? SYM_VARIABLE : SYM_CONSTANT, 1);
2942
        expect(l, LEX_IDENTIFIER);
2943
        use(l, r);
2944
        if(accept_token(l, LEX_LITERAL)) {
2945
                r->o[0] = defined_by_token(l, SYM_LITERAL);
2946
        } else {
2947
                expect(l, LEX_STRING);
2948
                r->o[0] = defined_by_token(l, SYM_STRING);
2949
        }
2950
        if(accept_token(l, LEX_HIDDEN)) {
2951
                if(r->bits & DEFINE_HIDDEN)
2952
                        syntax_error(l, "hidden bit already set on latest word definition");
2953
                r->bits |= DEFINE_HIDDEN;
2954
        }
2955
        return r;
2956
}
2957
 
2958
static node_t *jump(lexer_t *l, parse_e type)
2959
{
2960
        node_t *r;
2961
        assert(l);
2962
        r = node_new(type, 0);
2963
        (void)(accept_token(l, LEX_LITERAL) || accept_token(l, LEX_STRING) || expect(l, LEX_IDENTIFIER));
2964
        use(l, r);
2965
        return r;
2966
}
2967
 
2968
static node_t *statements(lexer_t *l);
2969
 
2970
static node_t *for_next(lexer_t *l)
2971
{
2972
        node_t *r;
2973
        assert(l);
2974
        r = node_new(SYM_FOR_NEXT, 1);
2975
        r->o[0] = statements(l);
2976
        if(accept_token(l, LEX_AFT)) {
2977
                r->type = SYM_FOR_AFT_THEN_NEXT;
2978
                r = node_grow(r);
2979
                r->o[1] = statements(l);
2980
                r = node_grow(r);
2981
                expect(l, LEX_THEN);
2982
                r->o[2] = statements(l);
2983
        }
2984
        expect(l, LEX_NEXT);
2985
        return r;
2986
}
2987
 
2988
static node_t *begin(lexer_t *l)
2989
{
2990
        node_t *r;
2991
        assert(l);
2992
        r = node_new(SYM_BEGIN_UNTIL, 1);
2993
        r->o[0] = statements(l);
2994
        if(accept_token(l, LEX_AGAIN)) {
2995
                r->type = SYM_BEGIN_AGAIN;
2996
        } else if(accept_token(l, LEX_WHILE)) {
2997
                r->type = SYM_BEGIN_WHILE_REPEAT;
2998
                r = node_grow(r);
2999
                r->o[1] = statements(l);
3000
                expect(l, LEX_REPEAT);
3001
        } else {
3002
                expect(l, LEX_UNTIL);
3003
        }
3004
        return r;
3005
}
3006
 
3007
static node_t *if1(lexer_t *l)
3008
{
3009
        node_t *r;
3010
        assert(l);
3011
        r = node_new(SYM_IF1, 2);
3012
        r->o[0] = statements(l);
3013
        if(accept_token(l, LEX_ELSE))
3014
                r->o[1] = statements(l);
3015
        expect(l, LEX_THEN);
3016
        return r;
3017
}
3018
 
3019
static node_t *define(lexer_t *l)
3020
{
3021
        node_t *r;
3022
        assert(l);
3023
        r = node_new(SYM_DEFINITION, 1);
3024
        if(accept_token(l, LEX_IDENTIFIER))
3025
                ;
3026
        else
3027
                expect(l, LEX_STRING);
3028
        use(l, r);
3029
        r->o[0] = statements(l);
3030
        expect(l, LEX_ENDDEFINE);
3031
again:
3032
        if(accept_token(l, LEX_IMMEDIATE)) {
3033
                if(r->bits & DEFINE_IMMEDIATE)
3034
                        syntax_error(l, "immediate bit already set on latest word definition");
3035
                r->bits |= DEFINE_IMMEDIATE;
3036
                goto again;
3037
        }
3038
        if(accept_token(l, LEX_HIDDEN)) {
3039
                if(r->bits & DEFINE_HIDDEN)
3040
                        syntax_error(l, "hidden bit already set on latest word definition");
3041
                r->bits |= DEFINE_HIDDEN;
3042
                goto again;
3043
        }
3044
        if(accept_token(l, LEX_INLINE)) {
3045
                if(r->bits & DEFINE_INLINE)
3046
                        syntax_error(l, "inline bit already set on latest word definition");
3047
                r->bits |= DEFINE_INLINE;
3048
                goto again;
3049
        }
3050
        return r;
3051
}
3052
 
3053
static node_t *char_compile(lexer_t *l)
3054
{
3055
        node_t *r;
3056
        assert(l);
3057
        r = node_new(SYM_CHAR, 0);
3058
        expect(l, LEX_IDENTIFIER);
3059
        use(l, r);
3060
        if(strlen(r->token->p.id) > 1)
3061
                syntax_error(l, "expected single character, got identifier: %s", r->token->p.id);
3062
        return r;
3063
}
3064
 
3065
static node_t *mode(lexer_t *l)
3066
{
3067
        node_t *r;
3068
        assert(l);
3069
        r = node_new(SYM_MODE, 0);
3070
        expect(l, LEX_LITERAL);
3071
        use(l, r);
3072
        return r;
3073
}
3074
 
3075
static node_t *pc(lexer_t *l)
3076
{
3077
        node_t *r;
3078
        assert(l);
3079
        r = node_new(SYM_PC, 0);
3080
        if(!accept_token(l, LEX_LITERAL))
3081
                expect(l, LEX_IDENTIFIER);
3082
        use(l, r);
3083
        return r;
3084
}
3085
 
3086
static node_t *pwd(lexer_t *l)
3087
{
3088
        node_t *r;
3089
        assert(l);
3090
        r = node_new(SYM_PWD, 0);
3091
        if(!accept_token(l, LEX_LITERAL))
3092
                expect(l, LEX_IDENTIFIER);
3093
        use(l, r);
3094
        return r;
3095
}
3096
 
3097
static node_t *set(lexer_t *l)
3098
{
3099
        node_t *r;
3100
        assert(l);
3101
        r = node_new(SYM_SET, 0);
3102
        if(!accept_token(l, LEX_IDENTIFIER) && !accept_token(l, LEX_STRING))
3103
                expect(l, LEX_LITERAL);
3104
        use(l, r);
3105
        if(!accept_token(l, LEX_IDENTIFIER) && !accept_token(l, LEX_STRING))
3106
                expect(l, LEX_LITERAL);
3107
        use(l, r);
3108
        return r;
3109
}
3110
 
3111
static node_t *allocate(lexer_t *l)
3112
{
3113
        node_t *r;
3114
        assert(l);
3115
        r = node_new(SYM_ALLOCATE, 0);
3116
        if(!accept_token(l, LEX_IDENTIFIER))
3117
                expect(l, LEX_LITERAL);
3118
        use(l, r);
3119
        return r;
3120
}
3121
 
3122
static node_t *quote(lexer_t *l)
3123
{
3124
        node_t *r;
3125
        assert(l);
3126
        r = node_new(SYM_QUOTE, 0);
3127
        if(!accept_token(l, LEX_IDENTIFIER))
3128
                expect(l, LEX_STRING);
3129
        use(l, r);
3130
        return r;
3131
}
3132
 
3133
static node_t *statements(lexer_t *l)
3134
{
3135
        node_t *r;
3136
        size_t i = 0;
3137
        assert(l);
3138
        r = node_new(SYM_STATEMENTS, 2);
3139
again:
3140
        r = node_grow(r);
3141
        if(accept_token(l, LEX_CALL)) {
3142
                r->o[i++] = jump(l, SYM_CALL);
3143
                goto again;
3144
        } else if(accept_token(l, LEX_BRANCH)) {
3145
                r->o[i++] = jump(l, SYM_BRANCH);
3146
                goto again;
3147
        } else if(accept_token(l, LEX_0BRANCH)) {
3148
                r->o[i++] = jump(l, SYM_0BRANCH);
3149
                goto again;
3150
        } else if(accept_token(l, LEX_LITERAL)) {
3151
                r->o[i++] = defined_by_token(l, SYM_LITERAL);
3152
                goto again;
3153
        } else if(accept_token(l, LEX_LABEL)) {
3154
                r->o[i++] = defined_by_token(l, SYM_LABEL);
3155
                goto again;
3156
        } else if(accept_token(l, LEX_CONSTANT)) {
3157
                r->o[i++] = variable_or_constant(l, false);
3158
                goto again;
3159
        } else if(accept_token(l, LEX_VARIABLE)) {
3160
                r->o[i++] = variable_or_constant(l, true);
3161
                goto again;
3162
        } else if(accept_token(l, LEX_LOCATION)) {
3163
                r->o[i]   = variable_or_constant(l, true);
3164
                r->o[i++]->type = SYM_LOCATION;
3165
                goto again;
3166
        } else if(accept_token(l, LEX_IF)) {
3167
                r->o[i++] = if1(l);
3168
                goto again;
3169
        } else if(accept_token(l, LEX_DEFINE)) {
3170
                r->o[i++] = define(l);
3171
                goto again;
3172
        } else if(accept_token(l, LEX_CHAR)) {
3173
                r->o[i++] = char_compile(l);
3174
                goto again;
3175
        } else if(accept_token(l, LEX_BEGIN)) {
3176
                r->o[i++] = begin(l);
3177
                goto again;
3178
        } else if(accept_token(l, LEX_FOR)) {
3179
                r->o[i++] = for_next(l);
3180
                goto again;
3181
        } else if(accept_token(l, LEX_QUOTE)) {
3182
                r->o[i++] = quote(l);
3183
                goto again;
3184
        } else if(accept_token(l, LEX_IDENTIFIER)) {
3185
                r->o[i++] = defined_by_token(l, SYM_CALL_DEFINITION);
3186
                goto again;
3187
        } else if(accept_token(l, LEX_PWD)) {
3188
                r->o[i++] = pwd(l);
3189
                goto again;
3190
        } else if(accept_token(l, LEX_SET)) {
3191
                r->o[i++] = set(l);
3192
                goto again;
3193
        } else if(accept_token(l, LEX_PC)) {
3194
                r->o[i++] = pc(l);
3195
                goto again;
3196
        } else if(accept_token(l, LEX_BREAK)) {
3197
                r->o[i++] = defined_by_token(l, SYM_BREAK);
3198
                goto again;
3199
        } else if(accept_token(l, LEX_MODE)) {
3200
                r->o[i++] = mode(l);
3201
                goto again;
3202
        } else if(accept_token(l, LEX_ALLOCATE)) {
3203
                r->o[i++] = allocate(l);
3204
                goto again;
3205
        } else if(accept_token(l, LEX_BUILT_IN)) {
3206
                r->o[i++] = defined_by_token(l, SYM_BUILT_IN);
3207
                goto again;
3208
        /**@warning This is a token range from the first instruction to the
3209
         * last instruction */
3210
        } else if(accept_range(l, LEX_DUP, LEX_RDROP)) {
3211
                r->o[i++] = defined_by_token(l, SYM_INSTRUCTION);
3212
                goto again;
3213
        }
3214
        return r;
3215
}
3216
 
3217
static node_t *program(lexer_t *l) /* block ( "." | EOF ) */
3218
{
3219
        node_t *r;
3220
        assert(l);
3221
        r = node_new(SYM_PROGRAM, 1);
3222
        lexer(l);
3223
        r->o[0] = statements(l);
3224
        expect(l, LEX_EOI);
3225
        return r;
3226
}
3227
 
3228
static node_t *parse(FILE *input)
3229
{
3230
        lexer_t *l;
3231
        assert(input);
3232
        l = lexer_new(input);
3233
        l->error.jmp_buf_valid = 1;
3234
        if(setjmp(l->error.j)) {
3235
                lexer_free(l);
3236
                return NULL;
3237
        }
3238
        node_t *n = program(l);
3239
        lexer_free(l);
3240
        return n;
3241
}
3242
 
3243
/********* CODE ***********/
3244
 
3245
typedef enum {
3246
        MODE_NORMAL              = 0 << 0,
3247
        MODE_COMPILE_WORD_HEADER = 1 << 0,
3248
        MODE_OPTIMIZATION_ON     = 1 << 1,
3249
} assembler_mode_e;
3250
 
3251
typedef struct {
3252
        bool in_definition;
3253
        bool start_defined;
3254
        bool built_in_words_defined;
3255
        uint16_t start;
3256
        uint16_t mode;
3257
        uint16_t pwd; /* previous word register */
3258
        uint16_t fence; /* mark a boundary before which optimization cannot take place */
3259
        symbol_t *do_r_minus_one;
3260
        symbol_t *do_next;
3261
        symbol_t *do_var;
3262
        symbol_t *do_const;
3263
} assembler_t;
3264
 
3265
static void update_fence(assembler_t *a, uint16_t pc)
3266
{
3267
        assert(a);
3268
        a->fence = MAX(a->fence, pc);
3269
}
3270
 
3271
static void generate(h2_t *h, assembler_t *a, uint16_t instruction)
3272
{
3273
        assert(h);
3274
        assert(a);
3275
        debug("%"PRIx16":\t%"PRIx16, h->pc, instruction);
3276
 
3277
        if(IS_CALL(instruction) || IS_LITERAL(instruction) || IS_0BRANCH(instruction) || IS_BRANCH(instruction))
3278
                update_fence(a, h->pc);
3279
 
3280
        /** @note This implements two ad-hoc optimizations, both related to
3281
         * CODE_EXIT, they should be replaced by a generic peep hole optimizer */
3282
        if(a->mode & MODE_OPTIMIZATION_ON && h->pc) {
3283
                uint16_t previous = h->core[h->pc - 1];
3284
                if(((h->pc - 1) > a->fence) && IS_ALU_OP(previous) && (instruction == CODE_EXIT)) {
3285
                        /* merge the CODE_EXIT instruction with the previous instruction if it is possible to do so */
3286
                        if(!(previous & R_TO_PC) && !(previous & MK_RSTACK(DELTA_N1))) {
3287
                                debug("optimization EXIT MERGE pc(%04"PRIx16 ") [%04"PRIx16 " -> %04"PRIx16"]", h->pc, previous, previous|instruction);
3288
                                previous |= instruction;
3289
                                h->core[h->pc - 1] = previous;
3290
                                update_fence(a, h->pc - 1);
3291
                                return;
3292
                        }
3293
                } else if(h->pc > a->fence && IS_CALL(previous) && (instruction == CODE_EXIT)) {
3294
                        /* do not emit CODE_EXIT if last instruction in a word
3295
                         * definition is a call, instead replace that call with
3296
                         * a jump */
3297
                        debug("optimization TAIL CALL pc(%04"PRIx16 ") [%04"PRIx16 " -> %04"PRIx16"]", h->pc, previous, OP_BRANCH | (previous & 0x1FFF));
3298
                        h->core[h->pc - 1] = (OP_BRANCH | (previous & 0x1FFF));
3299
                        update_fence(a, h->pc - 1);
3300
                        return;
3301
                }
3302
        }
3303
 
3304
        h->core[h->pc++] = instruction;
3305
}
3306
 
3307
static uint16_t here(h2_t *h, assembler_t *a)
3308
{
3309
        assert(h);
3310
        assert(h->pc < MAX_CORE);
3311
        update_fence(a, h->pc);
3312
        return h->pc;
3313
}
3314
 
3315
static uint16_t hole(h2_t *h, assembler_t *a)
3316
{
3317
        assert(h);
3318
        assert(h->pc < MAX_CORE);
3319
        here(h, a);
3320
        return h->pc++;
3321
}
3322
 
3323
static void fix(h2_t *h, uint16_t hole, uint16_t patch)
3324
{
3325
        assert(h);
3326
        assert(hole < MAX_CORE);
3327
        h->core[hole] = patch;
3328
}
3329
 
3330
#define assembly_error(ERROR, FMT, ...) do{ error(FMT, ##__VA_ARGS__); ethrow(e); }while(0)
3331
 
3332
static void generate_jump(h2_t *h, assembler_t *a, symbol_table_t *t, token_t *tok, parse_e type, error_t *e)
3333
{
3334
        uint16_t or = 0;
3335
        uint16_t addr = 0;
3336
        symbol_t *s;
3337
        assert(h);
3338
        assert(t);
3339
        assert(a);
3340
 
3341
        if(tok->type == LEX_IDENTIFIER || tok->type == LEX_STRING) {
3342
                s = symbol_table_lookup(t, tok->p.id);
3343
                if(!s)
3344
                        assembly_error(e, "undefined symbol: %s", tok->p.id);
3345
                addr = s->value;
3346
 
3347
                if(s->type == SYMBOL_TYPE_CALL && type != SYM_CALL)
3348
                        assembly_error(e, "cannot branch/0branch to call: %s", tok->p.id);
3349
 
3350
        } else if (tok->type == LEX_LITERAL) {
3351
                addr = tok->p.number;
3352
        } else {
3353
                fatal("invalid jump target token type");
3354
        }
3355
 
3356
        if(addr > MAX_CORE)
3357
                assembly_error(e, "invalid jump address: %"PRId16, addr);
3358
 
3359
        switch(type) {
3360
        case SYM_BRANCH:  or = OP_BRANCH ; break;
3361
        case SYM_0BRANCH: or = OP_0BRANCH; break;
3362
        case SYM_CALL:    or = OP_CALL;    break;
3363
        default:
3364
                fatal("invalid call type: %u", type);
3365
        }
3366
        generate(h, a, or | addr);
3367
}
3368
 
3369
static void generate_literal(h2_t *h, assembler_t *a, uint16_t number)
3370
{
3371
        if(number & OP_LITERAL) {
3372
                number = ~number;
3373
                generate(h, a, OP_LITERAL | number);
3374
                generate(h, a, CODE_INVERT);
3375
        } else {
3376
                generate(h, a, OP_LITERAL | number);
3377
        }
3378
}
3379
 
3380
static uint16_t lexer_to_alu_op(token_e t)
3381
{
3382
        assert(t >= LEX_DUP && t <= LEX_RDROP);
3383
        switch(t) {
3384
#define X(NAME, STRING, DEFINE, INSTRUCTION) case LEX_ ## NAME : return CODE_ ## NAME ;
3385
        X_MACRO_INSTRUCTIONS
3386
#undef X
3387
        default: fatal("invalid ALU operation: %u", t);
3388
        }
3389
        return 0;
3390
}
3391
 
3392
static uint16_t literal_or_symbol_lookup(token_t *token, symbol_table_t *t, error_t *e)
3393
{
3394
        symbol_t *s = NULL;
3395
        assert(token);
3396
        assert(t);
3397
        if(token->type == LEX_LITERAL)
3398
                return token->p.number;
3399
 
3400
        assert(token->type == LEX_IDENTIFIER);
3401
 
3402
        if(!(s = symbol_table_lookup(t, token->p.id)))
3403
                assembly_error(e, "symbol not found: %s", token->p.id);
3404
        return s->value;
3405
}
3406
 
3407
static uint16_t pack_16(const char lb, const char hb)
3408
{
3409
        return (((uint16_t)hb) << 8) | (uint16_t)lb;
3410
}
3411
 
3412
static uint16_t pack_string(h2_t *h, assembler_t *a, const char *s, error_t *e)
3413
{
3414
        assert(h);
3415
        assert(s);
3416
        size_t l = strlen(s);
3417
        size_t i = 0;
3418
        uint16_t r = h->pc;
3419
        if(l > 255)
3420
                assembly_error(e, "string \"%s\" is too large (%zu > 255)", s, l);
3421
        h->core[hole(h, a)] = pack_16(l, s[0]);
3422
        for(i = 1; i < l; i += 2)
3423
                h->core[hole(h, a)] = pack_16(s[i], s[i+1]);
3424
        if(i < l)
3425
                h->core[hole(h, a)] = pack_16(s[i], 0);
3426
        here(h, a);
3427
        return r;
3428
}
3429
 
3430
static uint16_t symbol_special(h2_t *h, assembler_t *a, const char *id, error_t *e)
3431
{
3432
        static const char *special[] = {
3433
                "$pc",
3434
                "$pwd",
3435
                NULL
3436
        };
3437
 
3438
        enum special_e {
3439
                SPECIAL_VARIABLE_PC,
3440
                SPECIAL_VARIABLE_PWD
3441
        };
3442
 
3443
        size_t i;
3444
        assert(h);
3445
        assert(id);
3446
        assert(a);
3447
 
3448
        for(i = 0; special[i]; i++)
3449
                if(!strcmp(id, special[i]))
3450
                        break;
3451
        if(!special[i])
3452
                assembly_error(e, "'%s' is not a symbol", id);
3453
 
3454
        switch(i) {
3455
        case SPECIAL_VARIABLE_PC:   return h->pc << 1;
3456
        case SPECIAL_VARIABLE_PWD:  return a->pwd; /**@note already as a character address */
3457
        default: fatal("reached the unreachable: %zu", i);
3458
        }
3459
 
3460
        return 0;
3461
}
3462
 
3463
typedef struct {
3464
        char *name;
3465
        size_t len;
3466
        bool inline_bit;
3467
        bool hidden;
3468
        bool compile;
3469
        uint16_t code[32];
3470
} built_in_words_t;
3471
 
3472
static built_in_words_t built_in_words[] = {
3473
#define X(NAME, STRING, DEFINE, INSTRUCTION) \
3474
        {\
3475
                .name = STRING,\
3476
                .compile = DEFINE,\
3477
                .len = 1,\
3478
                .inline_bit = true,\
3479
                .hidden = false,\
3480
                .code = { INSTRUCTION }\
3481
        },
3482
        X_MACRO_INSTRUCTIONS
3483
#undef X
3484
        /**@note We might want to compile these words, even if we are not
3485
         * compiling the other in-line-able, so the compiler can use them for
3486
         * variable declaration and for...next loops */
3487
        { .name = "doVar",   .compile = true, .inline_bit = false, .hidden = true, .len = 1, .code = {CODE_FROMR} },
3488
        { .name = "doConst", .compile = true, .inline_bit = false, .hidden = true, .len = 2, .code = {CODE_FROMR, CODE_LOAD} },
3489
        { .name = "r1-",     .compile = true, .inline_bit = false, .hidden = true, .len = 5, .code = {CODE_FROMR, CODE_FROMR, CODE_T_N1, CODE_TOR, CODE_TOR} },
3490
        { .name = NULL,      .compile = true, .inline_bit = false, .hidden = true, .len = 0, .code = {0} }
3491
};
3492
 
3493
static void generate_loop_decrement(h2_t *h, assembler_t *a, symbol_table_t *t)
3494
{
3495
        a->do_r_minus_one = a->do_r_minus_one ? a->do_r_minus_one : symbol_table_lookup(t, "r1-");
3496
        if(a->do_r_minus_one && a->mode & MODE_OPTIMIZATION_ON) {
3497
                generate(h, a, OP_CALL | a->do_r_minus_one->value);
3498
        } else {
3499
                generate(h, a, CODE_FROMR);
3500
                generate(h, a, CODE_T_N1);
3501
                generate(h, a, CODE_TOR);
3502
        }
3503
}
3504
 
3505
static void assemble(h2_t *h, assembler_t *a, node_t *n, symbol_table_t *t, error_t *e)
3506
{
3507
        uint16_t hole1, hole2;
3508
        assert(h);
3509
        assert(t);
3510
        assert(e);
3511
 
3512
        if(!n)
3513
                return;
3514
 
3515
        if(h->pc > MAX_CORE)
3516
                assembly_error(e, "PC/Dictionary overflow: %"PRId16, h->pc);
3517
 
3518
        switch(n->type) {
3519
        case SYM_PROGRAM:
3520
                assemble(h, a, n->o[0], t, e);
3521
                break;
3522
        case SYM_STATEMENTS:
3523
                for(size_t i = 0; i < n->length; i++)
3524
                        assemble(h, a, n->o[i], t, e);
3525
                break;
3526
        case SYM_LABEL:
3527
                symbol_table_add(t, SYMBOL_TYPE_LABEL, n->token->p.id, here(h, a), e, false);
3528
                break;
3529
        case SYM_BRANCH:
3530
        case SYM_0BRANCH:
3531
        case SYM_CALL:
3532
                generate_jump(h, a, t, n->token, n->type, e);
3533
                break;
3534
        case SYM_CONSTANT:
3535
                if(a->mode & MODE_COMPILE_WORD_HEADER && a->built_in_words_defined && (!(n->bits & DEFINE_HIDDEN))) {
3536
                        a->do_const = a->do_const ? a->do_const : symbol_table_lookup(t, "doConst");
3537
                        assert(a->do_const);
3538
                        hole1 = hole(h, a);
3539
                        fix(h, hole1, a->pwd);
3540
                        a->pwd = hole1 << 1;
3541
                        pack_string(h, a, n->token->p.id, e);
3542
                        generate(h, a, OP_CALL | a->do_const->value);
3543
                        hole1 = hole(h, a);
3544
                        fix(h, hole1, n->o[0]->token->p.number);
3545
                }
3546
                symbol_table_add(t, SYMBOL_TYPE_CONSTANT, n->token->p.id, n->o[0]->token->p.number, e, false);
3547
                break;
3548
        case SYM_VARIABLE:
3549
                if(a->mode & MODE_COMPILE_WORD_HEADER && a->built_in_words_defined && (!(n->bits & DEFINE_HIDDEN))) {
3550
                        a->do_var = a->do_var ? a->do_var : symbol_table_lookup(t, "doVar");
3551
                        assert(a->do_var);
3552
                        hole1 = hole(h, a);
3553
                        fix(h, hole1, a->pwd);
3554
                        a->pwd = hole1 << 1;
3555
                        pack_string(h, a, n->token->p.id, e);
3556
                        generate(h, a, OP_CALL | a->do_var->value);
3557
                } else if (!(n->bits & DEFINE_HIDDEN)) {
3558
                        assembly_error(e, "variable used but doVar not defined, use location");
3559
                }
3560
                /* fall through */
3561
        case SYM_LOCATION:
3562
                here(h, a);
3563
 
3564
                if(n->o[0]->token->type == LEX_LITERAL) {
3565
                        hole1 = hole(h, a);
3566
                        fix(h, hole1, n->o[0]->token->p.number);
3567
                } else {
3568
                        assert(n->o[0]->token->type == LEX_STRING);
3569
                        hole1 = pack_string(h, a, n->o[0]->token->p.id, e);
3570
                }
3571
 
3572
                /**@note The lowest bit of the address for memory loads is
3573
                 * discarded. */
3574
                symbol_table_add(t, SYMBOL_TYPE_VARIABLE, n->token->p.id, hole1 << 1, e, n->type == SYM_LOCATION ? true : false);
3575
                break;
3576
        case SYM_QUOTE:
3577
        {
3578
                symbol_t *s = symbol_table_lookup(t, n->token->p.id);
3579
                if(!s || (s->type != SYMBOL_TYPE_CALL && s->type != SYMBOL_TYPE_LABEL))
3580
                        assembly_error(e, "not a defined procedure: %s", n->token->p.id);
3581
                generate_literal(h, a, s->value << 1);
3582
                break;
3583
        }
3584
        case SYM_LITERAL:
3585
                generate_literal(h, a, n->token->p.number);
3586
                break;
3587
        case SYM_INSTRUCTION:
3588
                generate(h, a, lexer_to_alu_op(n->token->type));
3589
                break;
3590
        case SYM_BEGIN_AGAIN: /* fall through */
3591
        case SYM_BEGIN_UNTIL:
3592
                hole1 = here(h, a);
3593
                assemble(h, a, n->o[0], t, e);
3594
                generate(h, a, (n->type == SYM_BEGIN_AGAIN ? OP_BRANCH : OP_0BRANCH) | hole1);
3595
                break;
3596
 
3597
        case SYM_FOR_NEXT:
3598
        {
3599
                symbol_t *s = a->do_next ? a->do_next : symbol_table_lookup(t, "doNext");
3600
                if(s && a->mode & MODE_OPTIMIZATION_ON) {
3601
                        generate(h, a, CODE_TOR);
3602
                        hole1 = here(h, a);
3603
                        assemble(h, a, n->o[0], t, e);
3604
                        generate(h, a, OP_CALL | s->value);
3605
                        generate(h, a, hole1 << 1);
3606
                } else {
3607
                        generate(h, a, CODE_TOR);
3608
                        hole1 = here(h, a);
3609
                        assemble(h, a, n->o[0], t, e);
3610
                        generate(h, a, CODE_RAT);
3611
                        hole2 = hole(h, a);
3612
                        generate_loop_decrement(h, a, t);
3613
                        generate(h, a, OP_BRANCH | hole1);
3614
                        fix(h, hole2, OP_0BRANCH | here(h, a));
3615
                        generate(h, a, CODE_RDROP);
3616
                }
3617
                break;
3618
        }
3619
        case SYM_FOR_AFT_THEN_NEXT:
3620
        {
3621
                symbol_t *s = a->do_next ? a->do_next : symbol_table_lookup(t, "doNext");
3622
                if(s && a->mode & MODE_OPTIMIZATION_ON) {
3623
                        generate(h, a, CODE_TOR);
3624
                        assemble(h, a, n->o[0], t, e);
3625
                        hole1 = hole(h, a);
3626
                        hole2 = here(h, a);
3627
                        assemble(h, a, n->o[1], t, e);
3628
                        fix(h, hole1, OP_BRANCH | here(h, a));
3629
                        assemble(h, a, n->o[2], t, e);
3630
                        generate(h, a, OP_CALL | s->value);
3631
                        generate(h, a, hole2 << 1);
3632
                } else {
3633
                        generate(h, a, CODE_TOR);
3634
                        assemble(h, a, n->o[0], t, e);
3635
                        hole1 = hole(h, a);
3636
                        generate(h, a, CODE_RAT);
3637
                        generate_loop_decrement(h, a, t);
3638
                        hole2 = hole(h, a);
3639
                        assemble(h, a, n->o[1], t, e);
3640
                        fix(h, hole1, OP_BRANCH | (here(h, a)));
3641
                        assemble(h, a, n->o[2], t, e);
3642
                        generate(h, a, OP_BRANCH | (hole1 + 1));
3643
                        fix(h, hole2, OP_0BRANCH | (here(h, a)));
3644
                        generate(h, a, CODE_RDROP);
3645
                }
3646
                break;
3647
        }
3648
        case SYM_BEGIN_WHILE_REPEAT:
3649
                hole1 = here(h, a);
3650
                assemble(h, a, n->o[0], t, e);
3651
                hole2 = hole(h, a);
3652
                assemble(h, a, n->o[1], t, e);
3653
                generate(h, a, OP_BRANCH  | hole1);
3654
                fix(h, hole2, OP_0BRANCH | here(h, a));
3655
                break;
3656
        case SYM_IF1:
3657
                hole1 = hole(h, a);
3658
                assemble(h, a, n->o[0], t, e);
3659
                if(n->o[1]) { /* if ... else .. then */
3660
                        hole2 = hole(h, a);
3661
                        fix(h, hole1, OP_0BRANCH | (hole2 + 1));
3662
                        assemble(h, a, n->o[1], t, e);
3663
                        fix(h, hole2, OP_BRANCH  | here(h, a));
3664
                } else { /* if ... then */
3665
                        fix(h, hole1, OP_0BRANCH | here(h, a));
3666
                }
3667
                break;
3668
        case SYM_CALL_DEFINITION:
3669
        {
3670
                symbol_t *s = symbol_table_lookup(t, n->token->p.id);
3671
                if(!s)
3672
                        assembly_error(e, "not a constant or a defined procedure: %s", n->token->p.id);
3673
                if(s->type == SYMBOL_TYPE_CALL) {
3674
                        generate(h, a, OP_CALL | s->value);
3675
                } else if(s->type == SYMBOL_TYPE_CONSTANT || s->type == SYMBOL_TYPE_VARIABLE) {
3676
                        generate_literal(h, a, s->value);
3677
                } else {
3678
                        error("can only call or push literal: %s", s->id);
3679
                        ethrow(e);
3680
                }
3681
                break;
3682
        }
3683
        case SYM_DEFINITION:
3684
                if(n->bits && !(a->mode & MODE_COMPILE_WORD_HEADER))
3685
                        assembly_error(e, "cannot modify word bits (immediate/hidden/inline) if not in compile mode");
3686
                if(a->mode & MODE_COMPILE_WORD_HEADER && !(n->bits & DEFINE_HIDDEN)) {
3687
                        hole1 = hole(h, a);
3688
                        n->bits &= (DEFINE_IMMEDIATE | DEFINE_INLINE);
3689
                        fix(h, hole1, a->pwd | (n->bits << 13)); /* shift in word bits into PWD field */
3690
                        a->pwd = hole1 << 1;
3691
                        pack_string(h, a, n->token->p.id, e);
3692
                }
3693
                symbol_table_add(t, SYMBOL_TYPE_CALL, n->token->p.id, here(h, a), e, n->bits & DEFINE_HIDDEN);
3694
                if(a->in_definition)
3695
                        assembly_error(e, "nested word definition is not allowed");
3696
                a->in_definition = true;
3697
                assemble(h, a, n->o[0], t, e);
3698
                generate(h, a, CODE_EXIT);
3699
                a->in_definition = false;
3700
                break;
3701
        case SYM_CHAR: /* [char] A  */
3702
                generate(h, a, OP_LITERAL | n->token->p.id[0]);
3703
                break;
3704
        case SYM_SET:
3705
        {
3706
                uint16_t location, value;
3707
                symbol_t *l = NULL;
3708
                location = literal_or_symbol_lookup(n->token, t, e);
3709
 
3710
                if(n->value->type == LEX_LITERAL) {
3711
                        value = n->value->p.number;
3712
                } else {
3713
                        l = symbol_table_lookup(t, n->value->p.id);
3714
                        if(l) {
3715
                                value = l->value;
3716
                                if(l->type == SYMBOL_TYPE_CALL) // || l->type == SYMBOL_TYPE_LABEL)
3717
                                        value <<= 1;
3718
                        } else {
3719
                                value = symbol_special(h, a, n->value->p.id, e);
3720
                        }
3721
                }
3722
                fix(h, location >> 1, value);
3723
                break;
3724
        }
3725
        case SYM_PWD:
3726
                a->pwd = literal_or_symbol_lookup(n->token, t, e);
3727
                break;
3728
        case SYM_PC:
3729
                h->pc = literal_or_symbol_lookup(n->token, t, e);
3730
                update_fence(a, h->pc);
3731
                break;
3732
        case SYM_MODE:
3733
                a->mode = n->token->p.number;
3734
                break;
3735
        case SYM_ALLOCATE:
3736
                h->pc += literal_or_symbol_lookup(n->token, t, e) >> 1;
3737
                update_fence(a, h->pc);
3738
                break;
3739
        case SYM_BREAK:
3740
                break_point_add(&h->bp, h->pc);
3741
                update_fence(a, h->pc);
3742
                break;
3743
        case SYM_BUILT_IN:
3744
                if(!(a->mode & MODE_COMPILE_WORD_HEADER))
3745
                        break;
3746
 
3747
                if(a->built_in_words_defined)
3748
                        assembly_error(e, "built in words already defined");
3749
                a->built_in_words_defined = true;
3750
 
3751
                for(unsigned i = 0; built_in_words[i].name; i++) {
3752
                        if(!(built_in_words[i].compile))
3753
                                continue;
3754
 
3755
                        if(!built_in_words[i].hidden) {
3756
                                uint16_t pwd = a->pwd;
3757
                                hole1 = hole(h, a);
3758
                                if(built_in_words[i].inline_bit)
3759
                                        pwd |= (DEFINE_INLINE << 13);
3760
                                fix(h, hole1, pwd);
3761
                                a->pwd = hole1 << 1;
3762
                                pack_string(h, a, built_in_words[i].name, e);
3763
                        }
3764
                        symbol_table_add(t, SYMBOL_TYPE_CALL, built_in_words[i].name, here(h, a), e, built_in_words[i].hidden);
3765
                        for(size_t j = 0; j < built_in_words[i].len; j++)
3766
                                generate(h, a, built_in_words[i].code[j]);
3767
                        generate(h, a, CODE_EXIT);
3768
                }
3769
                break;
3770
        default:
3771
                fatal("Invalid or unknown type: %u", n->type);
3772
        }
3773
}
3774
 
3775
static bool assembler(h2_t *h, assembler_t *a, node_t *n, symbol_table_t *t, error_t *e)
3776
{
3777
        assert(h && a && n && t && e);
3778
        if(setjmp(e->j))
3779
                return false;
3780
        assemble(h, a, n, t, e);
3781
        return true;
3782
}
3783
 
3784
static h2_t *code(node_t *n, symbol_table_t *symbols)
3785
{
3786
        error_t e;
3787
        h2_t *h;
3788
        symbol_table_t *t = NULL;
3789
        assembler_t a;
3790
        assert(n);
3791
        memset(&a, 0, sizeof a);
3792
 
3793
        t = symbols ? symbols : symbol_table_new();
3794
        h = h2_new(START_ADDR);
3795
        a.fence = h->pc;
3796
 
3797
        e.jmp_buf_valid = 1;
3798
        if(!assembler(h, &a, n, t, &e)) {
3799
                h2_free(h);
3800
                if(!symbols)
3801
                        symbol_table_free(t);
3802
                return NULL;
3803
        }
3804
 
3805
        if(log_level >= LOG_DEBUG)
3806
                symbol_table_print(t, stderr);
3807
        if(!symbols)
3808
                symbol_table_free(t);
3809
        return h;
3810
}
3811
 
3812
int h2_assemble_file(FILE *input, FILE *output, symbol_table_t *symbols)
3813
{
3814
        int r = 0;
3815
        node_t *n;
3816
        assert(input);
3817
        assert(output);
3818
 
3819
        n = parse(input);
3820
 
3821
        if(log_level >= LOG_DEBUG)
3822
                node_print(stderr, n, false, 0);
3823
        if(n) {
3824
                h2_t *h = code(n, symbols);
3825
                if(h)
3826
                        r = h2_save(h, output, false);
3827
                else
3828
                        r = -1;
3829
                h2_free(h);
3830
        } else {
3831
                r = -1;
3832
        }
3833
        node_free(n);
3834
        return r;
3835
}
3836
 
3837
h2_t *h2_assemble_core(FILE *input, symbol_table_t *symbols)
3838
{
3839
        assert(input);
3840
        h2_t *h = NULL;
3841
        node_t *n = parse(input);
3842
        if(log_level >= LOG_DEBUG)
3843
                node_print(stderr, n, false, 0);
3844
        if(n)
3845
                h = code(n, symbols);
3846
        node_free(n);
3847
        return h;
3848
}
3849
 
3850
/* ========================== Assembler ==================================== */
3851
 
3852
/* ========================== Assembler ==================================== */
3853
 
3854
/* ========================== Embed Forth Virtual Machine ================== */
3855
/* This Forth virtual machine is based on the H2 processor, but it is meant
3856
 * to run on a hosted system. It is a small, limited virtual machine, but
3857
 * capable of running a cross-compiler (metacompiler) and saving the resulting
3858
 * binary. This will eventually replace the assembler/compiler. This requires
3859
 * another file which contains the metacompiler, and an image for the virtual
3860
 * machine.
3861
 *
3862
 * The 'embed' project can be found at <https://github.com/howerj/embed> */
3863
 
3864
#define CORE (65536u)  /* core size in bytes */
3865
#define SP0  (8704u)   /* Variable Stack Start: 8192 (end of program area) + 512 (block size) */
3866
#define RP0  (32767u)  /* Return Stack Start: end of CORE in words */
3867
 
3868
#ifdef TRON
3869
#define TRACE(PC,I,SP,RP) \
3870
        fprintf(stderr, "%04x %04x %04x %04x\n", (unsigned)(PC), (unsigned)(I), (unsigned)(SP), (unsigned)(RP));
3871
#else
3872
#define TRACE(PC, I, SP, RP)
3873
#endif
3874
 
3875
typedef uint16_t uw_t;
3876
typedef int16_t  sw_t;
3877
typedef uint32_t ud_t;
3878
 
3879
typedef struct { uw_t pc, t, rp, sp, core[CORE/sizeof(uw_t)]; } forth_t;
3880
 
3881
static const uw_t embed_image[] = { /* MAGIC! */
3882
0x094d, 0x034d, 0x4689, 0x4854, 0x0a0d, 0x0a1a, 0x1570, 0x00fe, 0x0001, 0x1984, 0x0001, 0x628d, 0x601c, 0x628d, 0x631c, 0x1570,
3883
0x10d2, 0x1566, 0x149e, 0x0024, 0x0000, 0x6403, 0x7075, 0x609d, 0x0028, 0x6f04, 0x6576, 0x0072, 0x619d, 0x0030, 0x6906, 0x766e,
3884
0x7265, 0x0074, 0x6a1c, 0x003a, 0x7503, 0x2b6d, 0x651c, 0x0046, 0x2b01, 0x653f, 0x004e, 0x7503, 0x2a6d, 0x661c, 0x0054, 0x2a01,
3885
0x663f, 0x005c, 0x7304, 0x6177, 0x0070, 0x619c, 0x0062, 0x6e03, 0x7069, 0x601f, 0x006c, 0x6404, 0x6f72, 0x0070, 0x611f, 0x0074,
3886
0x4001, 0x631c, 0x007e, 0x2101, 0x641f, 0x0084, 0x7206, 0x6873, 0x6669, 0x0074, 0x701f, 0x008a, 0x6c06, 0x6873, 0x6669, 0x0074,
3887
0x711f, 0x0096, 0x3d01, 0x6d1f, 0x00a2, 0x7502, 0x003c, 0x6e1f, 0x00a8, 0x3c01, 0x6f1f, 0x00b0, 0x6103, 0x646e, 0x671f, 0x00b6,
3888
0x7803, 0x726f, 0x691f, 0x00be, 0x6f02, 0x0072, 0x681f, 0x00c6, 0x3102, 0x002d, 0x6b1c, 0x00ce, 0x3002, 0x003d, 0x6c1c, 0x00d6,
3889
0x2805, 0x7962, 0x2965, 0x7b1c, 0x00de, 0x7203, 0x3f78, 0x789d, 0x00e8, 0x7403, 0x2178, 0x773f, 0x00f0, 0x2806, 0x6173, 0x6576,
3890
0x0029, 0x761f, 0x00f8, 0x7505, 0x6d2f, 0x646f, 0x799c, 0x0104, 0x2f04, 0x6f6d, 0x0064, 0x7a9c, 0x010e, 0x2f01, 0x7a1f, 0x0118,
3891
0x6d03, 0x646f, 0x7a3f, 0x811e, 0x6504, 0x6978, 0x0074, 0x601c, 0x8126, 0x3e02, 0x0072, 0x6147, 0x8130, 0x7202, 0x003e, 0x628d,
3892
0x8138, 0x7202, 0x0040, 0x6281, 0x8140, 0x7205, 0x7264, 0x706f, 0x600c, 0x0148, 0x6304, 0x6c65, 0x006c, 0x400d, 0x0002, 0x0152,
3893
0x3e03, 0x6e69, 0x400b, 0x0000, 0x015e, 0x7305, 0x6174, 0x6574, 0x400b, 0x0000, 0x0168, 0x6803, 0x646c, 0x400b, 0x0000, 0x0174,
3894
0x6204, 0x7361, 0x0065, 0x400b, 0x0010, 0x017e, 0x7304, 0x6170, 0x006e, 0x400b, 0x0000, 0x018a, 0x2305, 0x6f76, 0x7363, 0x400d,
3895
0x0008, 0x0196, 0x6205, 0x622f, 0x6675, 0x400d, 0x0400, 0x01a2, 0x6203, 0x6b6c, 0x400b, 0x0000, 0x01ae, 0x7003, 0x6461, 0x400d,
3896
0x4280, 0x01b8, 0x3c09, 0x696c, 0x6574, 0x6172, 0x3e6c, 0x400b, 0x0c2a, 0x01c2, 0x3c06, 0x6f62, 0x746f, 0x003e, 0x400b, 0x12e2,
3897
0x01d2, 0x3c04, 0x6b6f, 0x003e, 0x400b, 0x0000, 0x8000, 0x6a1c, 0xffff, 0x6a1c, 0x6103, 0x6103, 0x8000, 0x601c, 0x8172, 0x631c,
3898
0x8001, 0x671f, 0x8166, 0x641f, 0x8166, 0x631c, 0x01e0, 0x3205, 0x7264, 0x706f, 0x6103, 0x611f, 0x020c, 0x3102, 0x002b, 0x8001,
3899
0x653f, 0x0218, 0x6e06, 0x6765, 0x7461, 0x0065, 0x6a00, 0x010f, 0x0222, 0x2d01, 0x4116, 0x653f, 0x6181, 0x011a, 0x6181, 0x653f,
3900
0x0230, 0x6107, 0x696c, 0x6e67, 0x6465, 0x6081, 0x4100, 0x653f, 0x0240, 0x6203, 0x6579, 0x8000, 0x7b1c, 0x8002, 0x011a, 0x0250,
3901
0x6305, 0x6c65, 0x2b6c, 0x8002, 0x653f, 0x025e, 0x6305, 0x6c65, 0x736c, 0x8001, 0x711f, 0x026a, 0x6305, 0x6168, 0x7372, 0x8001,
3902
0x701f, 0x0276, 0x3f04, 0x7564, 0x0070, 0x6081, 0x2148, 0x609d, 0x601c, 0x0282, 0x3e01, 0x6180, 0x6f1f, 0x0292, 0x7502, 0x003e,
3903
0x6180, 0x6e1f, 0x6e03, 0x6a1c, 0x029a, 0x3c02, 0x003e, 0x6d03, 0x6a1c, 0x02a8, 0x3003, 0x3e3c, 0x6c00, 0x6a1c, 0x02b2, 0x3002,
3904
0x003e, 0x8000, 0x014b, 0x02bc, 0x3002, 0x003c, 0x8000, 0x6f1f, 0x02c6, 0x3204, 0x7564, 0x0070, 0x6181, 0x619d, 0x02d0, 0x7404,
3905
0x6375, 0x006b, 0x6180, 0x619d, 0x02dc, 0x2b02, 0x0021, 0x4172, 0x6300, 0x6523, 0x6180, 0x641f, 0x02e8, 0x3103, 0x212b, 0x8001,
3906
0x6180, 0x0177, 0x02f8, 0x3103, 0x212d, 0x40f6, 0x6180, 0x0177, 0x0304, 0x3202, 0x0021, 0x4172, 0x6403, 0x4133, 0x641f, 0x0310,
3907
0x3202, 0x0040, 0x6081, 0x4133, 0x6300, 0x6180, 0x631c, 0x031e, 0x670b, 0x7465, 0x632d, 0x7275, 0x6572, 0x746e, 0x8026, 0x631c,
3908
0x032e, 0x730b, 0x7465, 0x632d, 0x7275, 0x6572, 0x746e, 0x8026, 0x641f, 0x0340, 0x6202, 0x006c, 0x8020, 0x601c, 0x0352, 0x7706,
3909
0x7469, 0x6968, 0x006e, 0x411c, 0x6147, 0x411a, 0x628d, 0x6e1f, 0x035c, 0x6103, 0x7362, 0x6081, 0x4166, 0x21bf, 0x0116, 0x601c,
3910
0x0370, 0x7403, 0x6269, 0xc122, 0x4133, 0x631c, 0x0380, 0x7306, 0x756f, 0x6372, 0x0065, 0xc122, 0x0192, 0x038c, 0x7309, 0x756f,
3911
0x6372, 0x2d65, 0x6469, 0xc006, 0x631c, 0x039a, 0x6403, 0x3d30, 0x6c00, 0x6180, 0x6c00, 0x671f, 0x03aa, 0x6407, 0x656e, 0x6167,
3912
0x6574, 0x6a00, 0x6147, 0x6a00, 0x8001, 0x6500, 0x628d, 0x653f, 0x03b8, 0x6507, 0x6578, 0x7563, 0x6574, 0x6147, 0x601c, 0x6300,
3913
0x4145, 0x21f3, 0x6147, 0x601c, 0x03d0, 0x6302, 0x0040, 0x6381, 0x6180, 0x4100, 0x21fd, 0x8008, 0x701f, 0x80ff, 0x671f, 0x03e8,
3914
0x6302, 0x0021, 0x6180, 0x80ff, 0x6703, 0x6081, 0x8008, 0x7103, 0x6803, 0x6180, 0x6180, 0x6181, 0x6081, 0x6300, 0x6180, 0x4100,
3915
0x6c00, 0x80ff, 0x6903, 0x6147, 0x6181, 0x6903, 0x628d, 0x6703, 0x6903, 0x6180, 0x641f, 0x40fe, 0x6c1c, 0x03fe, 0x6804, 0x7265,
3916
0x0065, 0x801e, 0x631c, 0x043a, 0x6105, 0x696c, 0x6e67, 0x4221, 0x4125, 0x801e, 0x641f, 0x0446, 0x6105, 0x6c6c, 0x746f, 0x801e,
3917
0x0177, 0x0456, 0x7203, 0x746f, 0x6147, 0x6180, 0x628d, 0x619c, 0x0462, 0x2d04, 0x6f72, 0x0074, 0x6180, 0x6147, 0x6180, 0x628d,
3918
0x601c, 0x6240, 0x6180, 0x6147, 0x6147, 0x601c, 0x628d, 0x628d, 0x6180, 0x6240, 0x601c, 0x4246, 0x4145, 0x2253, 0x6b00, 0x6147,
3919
0x6300, 0x6147, 0x601c, 0x4133, 0x6147, 0x601c, 0x0470, 0x6d03, 0x6e69, 0x416c, 0x6f03, 0x225d, 0x611f, 0x601f, 0x04ac, 0x6d03,
3920
0x7861, 0x416c, 0x414b, 0x025b, 0x04bc, 0x6b03, 0x7965, 0xc010, 0x41ef, 0x6081, 0x40f6, 0x6d03, 0x226f, 0x412b, 0x00fc, 0x601c,
3921
0x04c8, 0x2f07, 0x7473, 0x6972, 0x676e, 0x6181, 0x4259, 0x4234, 0x411e, 0x423c, 0x011a, 0x8001, 0x0275, 0x04e0, 0x6305, 0x756f,
3922
0x746e, 0x6081, 0x410f, 0x6180, 0x01f7, 0x6181, 0x01f7, 0x6181, 0x8008, 0x7003, 0x6903, 0x6081, 0x8004, 0x7003, 0x6903, 0x6081,
3923
0x8005, 0x7103, 0x6903, 0x6081, 0x800c, 0x7103, 0x6903, 0x6180, 0x8008, 0x7103, 0x691f, 0x04fa, 0x6303, 0x6372, 0x8000, 0x6a00,
3924
0x6147, 0x6081, 0x22ab, 0x4285, 0x628d, 0x6180, 0x4287, 0x6147, 0x8001, 0x4275, 0x02a1, 0x410a, 0x628d, 0x601c, 0x6300, 0xbfff,
3925
0x671f, 0x419e, 0x02ae, 0x0536, 0x6504, 0x696d, 0x0074, 0xc012, 0x01ef, 0x0566, 0x6302, 0x0072, 0x800d, 0x42b7, 0x800a, 0x02b7,
3926
0x803a, 0x02b7, 0x0572, 0x7305, 0x6170, 0x6563, 0x8020, 0x02b7, 0x8020, 0x6180, 0x8000, 0x4261, 0x6147, 0x02d0, 0x6081, 0x42b7,
3927
0x424b, 0x059c, 0x611f, 0x0584, 0x6405, 0x7065, 0x6874, 0x7281, 0xc400, 0x411a, 0x013f, 0x05a6, 0x7004, 0x6369, 0x006b, 0x4139,
3928
0x7281, 0x6180, 0x411a, 0x631c, 0x807f, 0x6703, 0x6081, 0x807f, 0x8020, 0x41b3, 0x22ed, 0x6103, 0x805f, 0x601c, 0x05b6, 0x7404,
3929
0x7079, 0x0065, 0x8000, 0x6147, 0x6081, 0x22ff, 0x6180, 0x4281, 0x6281, 0x22fb, 0x42e4, 0x42b7, 0x6180, 0x6b00, 0x02f4, 0x600c,
3930
0x010a, 0x4281, 0x02f2, 0x40f6, 0x02f3, 0x05dc, 0x6305, 0x6f6d, 0x6576, 0x6147, 0x0313, 0x6147, 0x6081, 0x41f7, 0x6281, 0x4202,
3931
0x410f, 0x628d, 0x410f, 0x424b, 0x0616, 0x010a, 0x060a, 0x6604, 0x6c69, 0x006c, 0x6180, 0x6147, 0x6180, 0x0321, 0x416c, 0x4202,
3932
0x410f, 0x424b, 0x063c, 0x010a, 0x6147, 0x0327, 0x6103, 0x424b, 0x064c, 0x601c, 0x062c, 0x6305, 0x7461, 0x6863, 0x7281, 0x6147,
3933
0xc00a, 0x6300, 0x6147, 0x7381, 0xc00a, 0x6403, 0x41ed, 0x628d, 0xc00a, 0x6403, 0x628d, 0x00fb, 0x0654, 0x7405, 0x7268, 0x776f,
3934
0x4145, 0x234c, 0xc00a, 0x6300, 0x7503, 0x628d, 0xc00a, 0x6403, 0x6240, 0x7400, 0x6103, 0x628d, 0x601c, 0x4116, 0x0340, 0x8001,
3935
0x42d7, 0x6b00, 0x4150, 0x2356, 0x8004, 0x034d, 0x601c, 0x8002, 0x0350, 0x0678, 0x7506, 0x2f6d, 0x6f6d, 0x0064, 0x4145, 0x6c00,
3936
0x2363, 0x800a, 0x034d, 0x416c, 0x6e03, 0x2386, 0x4116, 0x800f, 0x6147, 0x6147, 0x6081, 0x6500, 0x6147, 0x6147, 0x6081, 0x6500,
3937
0x628d, 0x6523, 0x6081, 0x628d, 0x6281, 0x6180, 0x6147, 0x6500, 0x628d, 0x6803, 0x2380, 0x6147, 0x6103, 0x410f, 0x628d, 0x0381,
3938
0x6103, 0x628d, 0x424b, 0x06d2, 0x6103, 0x619c, 0x6103, 0x410a, 0x40f6, 0x609d, 0x06b2, 0x6407, 0x6365, 0x6d69, 0x6c61, 0x800a,
3939
0x8188, 0x641f, 0x0714, 0x6803, 0x7865, 0x8010, 0x8188, 0x641f, 0x8188, 0x6300, 0x6081, 0x8002, 0x411a, 0x8022, 0x4150, 0x23a3,
3940
0x4395, 0x8028, 0x034d, 0x601c, 0x0724, 0x6804, 0x6c6f, 0x0064, 0x817c, 0x6300, 0x6b00, 0x6081, 0x817c, 0x6403, 0x4202, 0x817c,
3941
0x6300, 0xc280, 0x8100, 0x6523, 0x4150, 0x23b8, 0x8011, 0x034d, 0x601c, 0x6081, 0x6147, 0x435e, 0x628d, 0x6180, 0x6147, 0x435e,
3942
0x628d, 0x0234, 0x8009, 0x6181, 0x6f03, 0x8007, 0x6703, 0x6523, 0x8030, 0x653f, 0x0748, 0x2302, 0x003e, 0x410a, 0x817c, 0x6300,
3943
0xc280, 0x6181, 0x011a, 0x0794, 0x2301, 0x4357, 0x8000, 0x8188, 0x6300, 0x43b9, 0x43c2, 0x03a8, 0x07a6, 0x2302, 0x0073, 0x43d5,
3944
0x416c, 0x41d8, 0x23df, 0x601c, 0x07b8, 0x3c02, 0x0023, 0xc280, 0x817c, 0x641f, 0x07c8, 0x7304, 0x6769, 0x006e, 0x4166, 0x23f2,
3945
0x802d, 0x03a8, 0x601c, 0x6044, 0x41bb, 0x8000, 0x43e7, 0x43df, 0x628d, 0x43ee, 0x03cd, 0x8000, 0x43e7, 0x43df, 0x03cd, 0x07d4,
3946
0x7503, 0x722e, 0x6147, 0x43fb, 0x628d, 0x411c, 0x42c8, 0x02f2, 0x8005, 0x0402, 0x07fe, 0x7502, 0x002e, 0x43fb, 0x42c6, 0x02f2,
3947
0x0814, 0x2e01, 0x4398, 0x800a, 0x6903, 0x2417, 0x040d, 0x43f3, 0x42c6, 0x02f2, 0xc000, 0x4221, 0x011a, 0x441a, 0x040d, 0x0820,
3948
0x7005, 0x6361, 0x246b, 0x4125, 0x6044, 0x6181, 0x6081, 0x8002, 0x4116, 0x6703, 0x411a, 0x411e, 0x8000, 0x417a, 0x416c, 0x4202,
3949
0x410f, 0x6180, 0x4309, 0x628d, 0x601c, 0x083e, 0x3d07, 0x7473, 0x6972, 0x676e, 0x6147, 0x6180, 0x628d, 0x6181, 0x6903, 0x2442,
3950
0x6103, 0x00fa, 0x6147, 0x044d, 0x4281, 0x6147, 0x6180, 0x4281, 0x628d, 0x6903, 0x244d, 0x600c, 0x00fa, 0x424b, 0x0888, 0x410a,
3951
0x00f6, 0x6181, 0x4202, 0x010f, 0x086a, 0x6106, 0x6363, 0x7065, 0x0074, 0x411e, 0x6181, 0x6981, 0x2468, 0x4267, 0x6081, 0x800a,
3952
0x6903, 0x2464, 0x4451, 0x0467, 0x6103, 0x6003, 0x6081, 0x045b, 0x6103, 0x011c, 0x08a8, 0x6506, 0x7078, 0x6365, 0x0074, 0xc014,
3953
0x41ef, 0x8194, 0x6403, 0x611f, 0x08d4, 0x7105, 0x6575, 0x7972, 0x41c3, 0x8050, 0xc014, 0x41ef, 0xc122, 0x6403, 0x40fb, 0x0102,
3954
0x08e8, 0x6e03, 0x6166, 0x42af, 0x0133, 0x0900, 0x6303, 0x6166, 0x4483, 0x6081, 0x41f7, 0x6523, 0x4133, 0x8001, 0x6a00, 0x671f,
3955
0x4483, 0x0301, 0x6300, 0xc000, 0x6703, 0x6c00, 0x6c1c, 0x6300, 0x40f8, 0x6703, 0x0495, 0x8126, 0x8152, 0x01b3, 0x6180, 0x6147,
3956
0x6081, 0x6081, 0x24b6, 0x6081, 0x4483, 0x4281, 0x6281, 0x4281, 0x443a, 0x24b2, 0x6081, 0x4492, 0x24af, 0x8001, 0x04b0, 0x40f6,
3957
0x600c, 0x601c, 0x6003, 0x6081, 0x42ae, 0x04a1, 0x600c, 0x00fa, 0x6147, 0xc110, 0x6381, 0x24cb, 0x6381, 0x6300, 0x6281, 0x6180,
3958
0x449e, 0x4145, 0x24c9, 0x6147, 0x4234, 0x6103, 0x628d, 0x600c, 0x601c, 0x4133, 0x04ba, 0x40fb, 0x628d, 0x00fc, 0x090a, 0x730f,
3959
0x6165, 0x6372, 0x2d68, 0x6f77, 0x6472, 0x696c, 0x7473, 0x449e, 0x4234, 0x611f, 0x099c, 0x6604, 0x6e69, 0x0064, 0x44b8, 0x4234,
3960
0x611f, 0x8030, 0x803a, 0x01b3, 0x8061, 0x807b, 0x01b3, 0x8041, 0x805b, 0x01b3, 0x6081, 0x44e7, 0x24ef, 0x8020, 0x691f, 0x601c,
3961
0x44ea, 0x6081, 0x44e4, 0x24f6, 0x8057, 0x011a, 0x6081, 0x44e1, 0x24fb, 0x8030, 0x011a, 0x6103, 0x00f6, 0x44ea, 0x44f0, 0x8188,
3962
0x6300, 0x6e1f, 0x416c, 0x4241, 0x6103, 0x41f7, 0x6081, 0x44fd, 0x2511, 0x6180, 0x8188, 0x6300, 0x6623, 0x6180, 0x44f0, 0x6523,
3963
0x0514, 0x6103, 0x4246, 0x601c, 0x4246, 0x427b, 0x6081, 0x6c00, 0x2502, 0x601c, 0x4285, 0x802d, 0x6d03, 0x2520, 0x427b, 0x00f6,
3964
0x00fc, 0x4285, 0x8024, 0x6d03, 0x2527, 0x427b, 0x0395, 0x4285, 0x8023, 0x6d03, 0x252d, 0x427b, 0x038f, 0x601c, 0x09b4, 0x3e07,
3965
0x756e, 0x626d, 0x7265, 0x4398, 0x6147, 0x451a, 0x6147, 0x4521, 0x4502, 0x628d, 0x253e, 0x4234, 0x4116, 0x423c, 0x628d, 0x8188,
3966
0x641f, 0x8000, 0x423c, 0x4533, 0x6003, 0x6c1c, 0x6147, 0x0551, 0x8020, 0x6181, 0x6281, 0x6523, 0x41f7, 0x6f03, 0x2551, 0x628d,
3967
0x010f, 0x424b, 0x0a90, 0x00fc, 0x6147, 0x6081, 0x2564, 0x4285, 0x6281, 0x411a, 0x6281, 0x8020, 0x6d03, 0xc000, 0x41ef, 0x2562,
3968
0x600c, 0x601c, 0x427b, 0x0555, 0x600c, 0x601c, 0x2568, 0x0161, 0x015c, 0x4566, 0x6a1c, 0x8acc, 0xc000, 0x6403, 0x0554, 0x8ad2,
3969
0xc000, 0x6403, 0x0554, 0x6147, 0x6181, 0x628d, 0x6180, 0x4241, 0x6281, 0x456b, 0x416c, 0x628d, 0x456f, 0x6180, 0x628d, 0x411a,
3970
0x6147, 0x411a, 0x628d, 0x010f, 0x0a5c, 0x7005, 0x7261, 0x6573, 0x6147, 0x41c3, 0x4104, 0x6523, 0xc122, 0x6300, 0x4104, 0x411a,
3971
0x628d, 0x4573, 0x8166, 0x4177, 0x4546, 0x8000, 0x0261, 0x4b08, 0x2901, 0x601c, 0x4b2e, 0x2801, 0x8029, 0x4588, 0x010a, 0x0b34,
3972
0x2e02, 0x0028, 0x8029, 0x4588, 0x02f2, 0x4b3e, 0x5c01, 0xc122, 0x6300, 0x0102, 0x6081, 0x801f, 0x4150, 0x25b0, 0x8013, 0x034d,
3973
0x601c, 0x0b4a, 0x7704, 0x726f, 0x0064, 0x434f, 0x4588, 0x45aa, 0x4221, 0x0423, 0x0b62, 0x7405, 0x6b6f, 0x6e65, 0x8020, 0x05b5,
3974
0x0b74, 0x6304, 0x6168, 0x0072, 0x45be, 0x4281, 0x6103, 0x01f7, 0x6081, 0xbf00, 0x4150, 0x25ce, 0x8008, 0x034d, 0x601c, 0x0b80,
3975
0x2c01, 0x4221, 0x6081, 0x4133, 0x45c8, 0x4228, 0x641f, 0x0b9e, 0x6302, 0x002c, 0x4221, 0x45c8, 0x4202, 0x801e, 0x017f, 0x40f8,
3976
0x6803, 0x05d1, 0xcbae, 0x6c07, 0x7469, 0x7265, 0x6c61, 0x6081, 0x40f8, 0x6703, 0x25ef, 0x6a00, 0x45df, 0xea00, 0x05d1, 0x05df,
3977
0x413f, 0xc000, 0x681f, 0x0bc4, 0x6308, 0x6d6f, 0x6970, 0x656c, 0x002c, 0x45f0, 0x05d1, 0x6081, 0x449b, 0x2601, 0x4488, 0x6300,
3978
0x05d1, 0x4488, 0x05f9, 0x41cb, 0x42f2, 0x800d, 0x034d, 0x6081, 0x4497, 0x260e, 0x41cb, 0x42f2, 0x800e, 0x034d, 0x601c, 0x0be6,
3979
0x2809, 0x696c, 0x6574, 0x6172, 0x296c, 0x40fe, 0x2618, 0x05e7, 0x601c, 0x0c1e, 0x6909, 0x746e, 0x7265, 0x7270, 0x7465, 0x44de,
3980
0x4145, 0x262d, 0x40fe, 0x2629, 0x4161, 0x2628, 0x4488, 0x01ed, 0x05fb, 0x6103, 0x4607, 0x4488, 0x01ed, 0x6081, 0x4281, 0x4541,
3981
0x2634, 0x6003, 0x81d0, 0x01ef, 0x0603, 0x8c32, 0x6307, 0x6d6f, 0x6970, 0x656c, 0x628d, 0x6381, 0x45d1, 0x4133, 0x6147, 0x601c,
3982
0x0c6a, 0x6909, 0x6d6d, 0x6465, 0x6169, 0x6574, 0xc000, 0x42b1, 0x4172, 0x6300, 0x6903, 0x017a, 0x0c80, 0x7306, 0x756d, 0x6764,
3983
0x0065, 0x42b1, 0x4483, 0x8080, 0x6180, 0x0648, 0x628d, 0x6281, 0x628d, 0x4281, 0x6523, 0x4125, 0x6147, 0x6180, 0x6147, 0x601c,
3984
0x4656, 0x601c, 0x4656, 0x0301, 0x8022, 0x45b5, 0x4281, 0x6523, 0x0228, 0xcc98, 0x2402, 0x0022, 0x463a, 0x4660, 0x0664, 0xccd2,
3985
0x2e02, 0x0022, 0x463a, 0x4662, 0x0664, 0x0cde, 0x6105, 0x6f62, 0x7472, 0x40f6, 0x7b1c, 0x6180, 0x2681, 0x4301, 0x42bc, 0x4679,
3986
0x0682, 0x6103, 0x601c, 0x4656, 0x067b, 0xccea, 0x6106, 0x6f62, 0x7472, 0x0022, 0x463a, 0x4683, 0x0664, 0xc126, 0xc122, 0x4133,
3987
0x6403, 0x8000, 0x4102, 0x8000, 0xc006, 0x641f, 0x0d0a, 0x5d01, 0x40f6, 0x8172, 0x641f, 0x4d2c, 0x5b01, 0x8000, 0x8172, 0x641f,
3988
0x4145, 0x26aa, 0x4412, 0x803f, 0x42b7, 0x42bc, 0xc400, 0x7400, 0x468d, 0x069d, 0x601c, 0x421b, 0x26b1, 0x4662, 0x2003, 0x6b6f,
3989
0x02bc, 0x601c, 0x7281, 0xc400, 0x6e03, 0x26b8, 0x8004, 0x034d, 0x601c, 0x45be, 0x6081, 0x41f7, 0x26c0, 0x461f, 0x46b2, 0x06b9,
3990
0x6103, 0x81ea, 0x01ef, 0x0d36, 0x7104, 0x6975, 0x0074, 0x468d, 0x469d, 0x4478, 0x8d72, 0x432e, 0x46a0, 0x06c9, 0x601c, 0x41cb,
3991
0x4104, 0xc006, 0x6300, 0x81ea, 0x631c, 0x81ea, 0x6403, 0xc006, 0x6403, 0x4102, 0xc122, 0x018b, 0x0d86, 0x6508, 0x6176, 0x756c,
3992
0x7461, 0x0065, 0x46cf, 0x4241, 0x4241, 0x6147, 0x8000, 0x40f6, 0x8000, 0x46d5, 0x8d72, 0x432e, 0x628d, 0x4246, 0x4246, 0x46d5,
3993
0x0340, 0x468d, 0x80ee, 0xc010, 0x6403, 0x80f6, 0xc012, 0x6403, 0x8d56, 0x88b2, 0xc014, 0x6403, 0x81ea, 0x641f, 0xabad, 0x4157,
3994
0x2703, 0x8016, 0x034d, 0x601c, 0x6081, 0x42b1, 0x6300, 0x449e, 0x2717, 0x42c6, 0x410a, 0xc002, 0x6300, 0x4483, 0x4301, 0x4662,
3995
0x200a, 0x6572, 0x6564, 0x6966, 0x656e, 0x0064, 0x02bc, 0x601c, 0x4281, 0x6c00, 0x271d, 0x800a, 0x034d, 0x6b1c, 0x45be, 0x44de,
3996
0x6c00, 0x2723, 0x0603, 0x601c, 0x471e, 0x0488, 0x4db8, 0x2701, 0x4724, 0x40fe, 0x272c, 0x05e7, 0x601c, 0xce4c, 0x5b09, 0x6f63,
3997
0x706d, 0x6c69, 0x5d65, 0x4724, 0x05f9, 0xce5a, 0x5b06, 0x6863, 0x7261, 0x005d, 0x45c4, 0x05e7, 0xce6a, 0x3b01, 0x46fe, 0xe01c,
3998
0x45d1, 0x469d, 0x4145, 0x2746, 0x419e, 0x641f, 0x601c, 0x0e78, 0x3a01, 0x4227, 0x4221, 0x6081, 0xc002, 0x6403, 0x42b1, 0x45d1,
3999
0x45be, 0x4718, 0x4704, 0x4281, 0x6523, 0x4228, 0xabad, 0x0698, 0xce8e, 0x6205, 0x6765, 0x6e69, 0x0221, 0xceb0, 0x7505, 0x746e,
4000
0x6c69, 0x413f, 0xa000, 0x6803, 0x05d1, 0xceba, 0x6105, 0x6167, 0x6e69, 0x413f, 0x05d1, 0x4221, 0x00fc, 0x476b, 0x0769, 0xceca,
4001
0x6902, 0x0066, 0x476b, 0x0761, 0xcede, 0x7404, 0x6568, 0x006e, 0x4221, 0x413f, 0x6181, 0x6300, 0x6803, 0x017a, 0xcee8, 0x6504,
4002
0x736c, 0x0065, 0x476d, 0x6180, 0x0778, 0xcefc, 0x7705, 0x6968, 0x656c, 0x0772, 0xcf0a, 0x7206, 0x7065, 0x6165, 0x0074, 0x6180,
4003
0x4769, 0x0778, 0xc002, 0x6300, 0x0488, 0xcf14, 0x7207, 0x6365, 0x7275, 0x6573, 0x4792, 0x05f9, 0xcf2a, 0x7404, 0x6961, 0x006c,
4004
0x4792, 0x0769, 0x0f38, 0x6306, 0x6572, 0x7461, 0x0065, 0x4749, 0x6103, 0x463a, 0x400b, 0x419e, 0x6403, 0x069d, 0x0f44, 0x3e05,
4005
0x6f62, 0x7964, 0x0133, 0x628d, 0x413f, 0x4221, 0x413f, 0x4792, 0x6081, 0x4133, 0x45df, 0x6403, 0x05d1, 0xcf5c, 0x6405, 0x656f,
4006
0x3e73, 0x463a, 0x47b3, 0x601c, 0x0f7a, 0x7608, 0x7261, 0x6169, 0x6c62, 0x0065, 0x47a7, 0x8000, 0x05d1, 0x0f88, 0x6308, 0x6e6f,
4007
0x7473, 0x6e61, 0x0074, 0x47a7, 0x801a, 0x45f0, 0x4221, 0x412d, 0x6403, 0x05d1, 0x0f9a, 0x3a07, 0x6f6e, 0x616e, 0x656d, 0x476b,
4008
0xabad, 0x0698, 0xcfb4, 0x6603, 0x726f, 0xe147, 0x45d1, 0x0221, 0xcfc4, 0x6e04, 0x7865, 0x0074, 0x463a, 0x424b, 0x05d1, 0xcfd0,
4009
0x6103, 0x7466, 0x6103, 0x476d, 0x475c, 0x619c, 0x0fde, 0x6804, 0x6469, 0x0065, 0x471e, 0x0652, 0x8000, 0x6147, 0x6381, 0x6281,
4010
0x4157, 0x2804, 0x4133, 0x07fe, 0x600c, 0x601c, 0x0fec, 0x6709, 0x7465, 0x6f2d, 0x6472, 0x7265, 0xc110, 0x47fc, 0x6081, 0x412d,
4011
0x6180, 0xc110, 0x411a, 0x413f, 0x6044, 0x6b00, 0x6081, 0x4166, 0x281b, 0x8032, 0x034d, 0x6147, 0x0820, 0x6381, 0x6180, 0x412d,
4012
0x424b, 0x103a, 0x6300, 0x628d, 0x601c, 0x0000, 0x660e, 0x726f, 0x6874, 0x772d, 0x726f, 0x6c64, 0x7369, 0x0074, 0x8024, 0x601c,
4013
0x104a, 0x7309, 0x7465, 0x6f2d, 0x6472, 0x7265, 0x6081, 0x40f6, 0x6d03, 0x283e, 0x6103, 0x8020, 0x8001, 0x0836, 0x6081, 0x8008,
4014
0x414b, 0x2844, 0x8031, 0x034d, 0xc110, 0x6180, 0x6147, 0x084b, 0x4172, 0x6403, 0x4133, 0x424b, 0x1090, 0x8000, 0x017a, 0x1060,
4015
0x6605, 0x726f, 0x6874, 0x8020, 0x482e, 0x8002, 0x0836, 0x4483, 0x41f7, 0x8080, 0x6703, 0x6c1c, 0x42c6, 0x6081, 0x2867, 0x6081,
4016
0x4857, 0x2865, 0x6081, 0x4490, 0x42c6, 0x42ae, 0x085d, 0x6103, 0x02bc, 0x109e, 0x7705, 0x726f, 0x7364, 0x480c, 0x4145, 0x2879,
4017
0x6180, 0x6081, 0x42bc, 0x440d, 0x42c0, 0x6300, 0x485c, 0x6b00, 0x086e, 0x601c, 0x100c, 0x6f04, 0x6c6e, 0x0079, 0x40f6, 0x0836,
4018
0x10f4, 0x640b, 0x6665, 0x6e69, 0x7469, 0x6f69, 0x736e, 0xc110, 0x6300, 0x01a7, 0x6081, 0x2898, 0x6b00, 0x6180, 0x6147, 0x488a,
4019
0x6181, 0x6281, 0x6903, 0x2897, 0x410f, 0x628d, 0x023c, 0x600c, 0x601c, 0x1100, 0x2d06, 0x726f, 0x6564, 0x0072, 0x480c, 0x488a,
4020
0x6003, 0x0836, 0x1132, 0x2b06, 0x726f, 0x6564, 0x0072, 0x6044, 0x489e, 0x480c, 0x628d, 0x6180, 0x410f, 0x0836, 0x1144, 0x6506,
4021
0x6964, 0x6f74, 0x0072, 0x438f, 0x8022, 0x08a7, 0x115c, 0x7506, 0x6470, 0x7461, 0x0065, 0x40f6, 0xc00c, 0x641f, 0x81b6, 0x631c,
4022
0x48be, 0x653f, 0x116c, 0x7304, 0x7661, 0x0065, 0x8000, 0x4221, 0x7603, 0x0340, 0x1184, 0x6605, 0x756c, 0x6873, 0xc00c, 0x6300,
4023
0x28d5, 0x8000, 0x40f6, 0x7603, 0x0340, 0x601c, 0x1194, 0x6205, 0x6f6c, 0x6b63, 0x434f, 0x6081, 0x803f, 0x4150, 0x28e1, 0x8023,
4024
0x034d, 0x6081, 0x81b6, 0x6403, 0x800a, 0x711f, 0x8006, 0x711f, 0x8006, 0x701f, 0x6180, 0x48da, 0x6180, 0x48e6, 0x6523, 0x8040,
4025
0x601c, 0x48ea, 0x06e2, 0x11ac, 0x6c04, 0x616f, 0x0064, 0x8000, 0x8010, 0x6b00, 0x6147, 0x416c, 0x4241, 0x48f1, 0x4246, 0x410f,
4026
0x424b, 0x11f6, 0x010a, 0x807c, 0x02b7, 0x8003, 0x42c8, 0x8040, 0x802d, 0x42c9, 0x02bc, 0x6081, 0x8002, 0x0402, 0x8020, 0x031a,
4027
0x48da, 0x611f, 0x11e6, 0x6c04, 0x7369, 0x0074, 0x6081, 0x4910, 0x42bc, 0x4905, 0x8000, 0x6081, 0x8010, 0x6f03, 0x2928, 0x416c,
4028
0x490b, 0x4903, 0x48ea, 0x4303, 0x4903, 0x42bc, 0x410f, 0x091b, 0x4905, 0x010a, 0x8014, 0x6300, 0x4100, 0x6c1c, 0x8001, 0x8014,
4029
0x0648, 0x492a, 0x2934, 0x00fc, 0x800c, 0x6300, 0x4221, 0x6903, 0x293b, 0x8002, 0x601c, 0x800e, 0x6300, 0x8000, 0x800e, 0x6403,
4030
0x8000, 0x4221, 0x429e, 0x6903, 0x2947, 0x8003, 0x601c, 0x492e, 0x00fc, 0x1224, 0x6304, 0x6c6f, 0x0064, 0x4931, 0x4145, 0x2952,
4031
0x4116, 0x7b1c, 0x8010, 0x48da, 0x8400, 0x8000, 0x431a, 0x8012, 0x4910, 0x46f1, 0x4853, 0xc400, 0x7400, 0x81de, 0x41ef, 0x012b,
4032
0x4395, 0x42bc, 0x4662, 0x6508, 0x4f46, 0x5452, 0x2048, 0x0056, 0x9984, 0x8000, 0x4402, 0x42bc, 0x4221, 0x4412, 0x441d, 0x42bc,
4033
0x069d, 0x4960, 0x06c7, 0x4172, 0x4488, 0x4157, 0x2978, 0x00fb, 0x0483, 0x42af, 0x4139, 0x6147, 0x6081, 0x298e, 0x42af, 0x6081,
4034
0x6281, 0x6180, 0x6381, 0x42af, 0x6180, 0x41b3, 0x298b, 0x42ae, 0x628d, 0x6180, 0x0973, 0x42af, 0x6300, 0x097c, 0x600c, 0x601c,
4035
0x6147, 0x480c, 0x6081, 0x29a1, 0x6180, 0x6281, 0x4979, 0x4145, 0x299f, 0x6147, 0x6b00, 0x4324, 0x628d, 0x600c, 0x601c, 0x6b00,
4036
0x0992, 0x600c, 0x601c, 0x4990, 0x4145, 0x6c00, 0x29aa, 0x4660, 0x3f03, 0x3f3f, 0x0301, 0x6147, 0x6181, 0x6703, 0x628d, 0x4172,
4037
0x6d03, 0x29b4, 0x6003, 0x00f6, 0x00fb, 0x40f8, 0x40f8, 0x49ab, 0x29bd, 0x4662, 0x4c03, 0x5449, 0x601c, 0xe000, 0xe000, 0x49ab,
4038
0x29c5, 0x4662, 0x4103, 0x554c, 0x601c, 0xe000, 0xc000, 0x49ab, 0x29cd, 0x4662, 0x4303, 0x4c41, 0x601c, 0xe000, 0xa000, 0x49ab,
4039
0x29d5, 0x4662, 0x4203, 0x5a52, 0x601c, 0x40fb, 0x4662, 0x4203, 0x4e52, 0x601c, 0x1292, 0x6409, 0x6365, 0x6d6f, 0x6970, 0x656c,
4040
0x6081, 0x49b5, 0xc000, 0x6d03, 0x29e7, 0x42c6, 0x09a3, 0x611f, 0x6147, 0x6081, 0x6281, 0x6e03, 0x29f9, 0x6081, 0x4408, 0x42c0,
4041
0x42c6, 0x6381, 0x6081, 0x4408, 0x42c6, 0x49e0, 0x42bc, 0x4133, 0x09e9, 0x600c, 0x611f, 0x13b4, 0x7303, 0x6565, 0x45be, 0x44b8,
4042
0x6c00, 0x2a03, 0x0603, 0x6180, 0x6d81, 0x2a08, 0x6103, 0x4221, 0x6147, 0x42bc, 0x42c0, 0x42c6, 0x6081, 0x4490, 0x42c6, 0x6081,
4043
0x42bc, 0x4488, 0x628d, 0x49e8, 0x42c6, 0x803b, 0x42b7, 0x6081, 0x4497, 0x2a22, 0x4662, 0x200d, 0x6f63, 0x706d, 0x6c69, 0x2d65,
4044
0x6e6f, 0x796c, 0x6081, 0x449b, 0x2a2a, 0x4662, 0x2007, 0x6e69, 0x696c, 0x656e, 0x4492, 0x2a33, 0x4662, 0x200a, 0x6d69, 0x656d,
4045
0x6964, 0x7461, 0x0065, 0x02bc, 0x13f6, 0x2e02, 0x0073, 0x42bc, 0x42d7, 0x6147, 0x0a3e, 0x6281, 0x42df, 0x4412, 0x424b, 0x1476,
4046
0x4662, 0x2004, 0x733c, 0x0070, 0x601c, 0x413f, 0x6147, 0x0a4c, 0x6381, 0x42c6, 0x4408, 0x4133, 0x424b, 0x1490, 0x601c, 0x1468,
4047
0x6404, 0x6d75, 0x0070, 0x8010, 0x6523, 0x8004, 0x7003, 0x6147, 0x0a65, 0x42bc, 0x8010, 0x416c, 0x6181, 0x4408, 0x42c0, 0x42c6,
4048
0x4a45, 0x423c, 0x8002, 0x42c8, 0x4303, 0x424b, 0x14b2, 0x611f, 0x48be, 0x08da, 0x6081, 0x8400, 0x48e8, 0x4152, 0x2a71, 0x8018,
4049
0x034d, 0x601c, 0x4a6a, 0x48e6, 0x4a68, 0x653f, 0x0000, 0x6201, 0x0910, 0x14ec, 0x6c01, 0x48be, 0x0916, 0x14f2, 0x6e01, 0x8001,
4050
0x48c0, 0x4a78, 0x0a7b, 0x14fa, 0x7001, 0x40f6, 0x48c0, 0x4a78, 0x0a7b, 0x1506, 0x6401, 0x4a72, 0x8040, 0x090e, 0x1512, 0x7801,
4051
0x4a68, 0x8400, 0x090e, 0x151c, 0x7301, 0x48bb, 0x08ce, 0x1526, 0x7101, 0x8022, 0x089e, 0x152e, 0x6501, 0x4a99, 0x48be, 0x48f7,
4052
0x08b3, 0x1536, 0x6902, 0x0061, 0x48e6, 0x6523, 0x4a68, 0x6523, 0x41cb, 0x6103, 0x4104, 0x6523, 0x6180, 0x41cb, 0x6003, 0x4104,
4053
0x411a, 0x4309, 0x05a7, 0x1542, 0x6901, 0x8000, 0x6180, 0x0aa4,
4054
};
4055
 
4056
forth_t *embed_new(void)
4057
{
4058
        forth_t *h = allocate_or_die(sizeof(*h));
4059
        memcpy(h->core, embed_image, sizeof(embed_image));
4060
        h->pc = 0;
4061
        h->t  = 0;
4062
        h->rp = RP0;
4063
        h->sp = SP0;
4064
        return h;
4065
}
4066
 
4067
void embed_free(forth_t *h)
4068
{
4069
        assert(h);
4070
        free(h);
4071
}
4072
 
4073
static int embed_save(forth_t *h, const char *name, size_t start, size_t length)
4074
{
4075
        assert(h);
4076
        if(!name)
4077
                return -1;
4078
        FILE *output = fopen_or_die(name, "wb");
4079
        const int r  = binary_memory_save(output, h->core+start, length);
4080
        fclose(output);
4081
        return r;
4082
}
4083
 
4084
int embed_forth(forth_t *h, FILE *in, FILE *out, const char *block)
4085
{
4086
        static const uw_t delta[] = { 0, 1, -2, -1};
4087
        assert(h && in && out);
4088
        uw_t pc = h->pc, t = h->t, rp = h->rp, sp = h->sp, *m = h->core;
4089
        ud_t d;
4090
        for(;;) {
4091
                const uw_t instruction = m[pc];
4092
                TRACE(pc, instruction, sp, rp);
4093
                assert(!(sp & 0x8000) && !(rp & 0x8000));
4094
 
4095
                if(0x8000 & instruction) { /* literal */
4096
                        m[++sp] = t;
4097
                        t       = instruction & 0x7FFF;
4098
                        pc++;
4099
                } else if ((0xE000 & instruction) == 0x6000) { /* ALU */
4100
                        uw_t n = m[sp], T = t;
4101
                        pc = instruction & 0x10 ? m[rp] >> 1 : pc + 1;
4102
 
4103
                        switch((instruction >> 8u) & 0x1f) {
4104
                        case  0: /*T = t;*/                break;
4105
                        case  1: T = n;                    break;
4106
                        case  2: T = m[rp];                break;
4107
                        case  3: T = m[t>>1];              break;
4108
                        case  4: m[t>>1] = n; T = m[--sp]; break;
4109
                        case  5: d = (ud_t)t + (ud_t)n; T = d >> 16; m[sp] = d; n = d; break;
4110
                        case  6: d = (ud_t)t * (ud_t)n; T = d >> 16; m[sp] = d; n = d; break;
4111
                        case  7: T &= n;                   break;
4112
                        case  8: T |= n;                   break;
4113
                        case  9: T ^= n;                   break;
4114
                        case 10: T = ~t;                   break;
4115
                        case 11: T--;                      break;
4116
                        case 12: T = -(t == 0);            break;
4117
                        case 13: T = -(t == n);            break;
4118
                        case 14: T = -(n < t);             break;
4119
                        case 15: T = -((sw_t)n < (sw_t)t); break;
4120
                        case 16: T = n >> t;               break;
4121
                        case 17: T = n << t;               break;
4122
                        case 18: T = sp << 1;              break;
4123
                        case 19: T = rp << 1;              break;
4124
                        case 20: sp = t >> 1;              break;
4125
                        case 21: rp = t >> 1; T = n;       break;
4126
                        case 22: T = embed_save(h, block, n>>1, ((ud_t)T+1)>>1); break;
4127
                        case 23: T = fputc(t, out);        break;
4128
                        case 24: T = fgetc(in);            break;
4129
                        case 25: if(t) { T=n/t; t=n%t; n=t; } else { pc=1; T=10; } break;
4130
                        case 26: if(t) { T=(sw_t)n/(sw_t)t; t=(sw_t)n%(sw_t)t; n=t; } else { pc=1; T=10; } break;
4131
                        case 27: goto finished;
4132
                        }
4133
                        sp += delta[ instruction       & 0x3];
4134
                        rp -= delta[(instruction >> 2) & 0x3];
4135
                        if(instruction & 0x20)
4136
                                T = n;
4137
                        if(instruction & 0x40)
4138
                                m[rp] = t;
4139
                        if(instruction & 0x80)
4140
                                m[sp] = t;
4141
                        t = T;
4142
                } else if (0x4000 & instruction) { /* call */
4143
                        m[--rp] = (pc + 1) << 1;
4144
                        pc      = instruction & 0x1FFF;
4145
                } else if (0x2000 & instruction) { /* 0branch */
4146
                        pc = !t ? instruction & 0x1FFF : pc + 1;
4147
                        t  = m[sp--];
4148
                } else { /* branch */
4149
                        pc = instruction & 0x1FFF;
4150
                }
4151
        }
4152
finished: h->pc = pc; h->sp = sp; h->rp = rp; h->t = t;
4153
        return (int16_t)t;
4154
}
4155
 
4156
/* ========================== Embed Forth Virtual Machine ================== */
4157
 
4158
/* ========================== Assembler ==================================== */
4159
 
4160
 
4161
/* ========================== Main ========================================= */
4162
 
4163
#ifndef NO_MAIN
4164
typedef enum {
4165
        DEFAULT_COMMAND,
4166
        DISASSEMBLE_COMMAND,
4167
        ASSEMBLE_COMMAND,
4168
        RUN_COMMAND,
4169
        ASSEMBLE_RUN_COMMAND
4170
} command_e;
4171
 
4172
typedef struct {
4173
        command_e cmd;
4174
        long steps;
4175
        bool full_disassembly;
4176
        bool debug_mode;
4177
        bool hacks;
4178
        disassemble_color_method_e dcm;
4179
        const char *nvram;
4180
} command_args_t;
4181
 
4182
static const char *help = "\
4183
usage ./h2 [-hvdDarRTH] [-sc number] [-L symbol.file] [-S symbol.file] (file.hex|file.fth)\n\n\
4184
Brief:     A H2 CPU Assembler, disassembler and Simulator.\n\
4185
Author:    Richard James Howe\n\
4186
Site:      https://github.com/howerj/forth-cpu\n\
4187
License:   MIT\n\
4188
Copyright: Richard James Howe (2017)\n\
4189
Options:\n\n\
4190
\t-\tstop processing options, following arguments are files\n\
4191
\t-h\tprint this help message and exit\n\
4192
\t-v\tincrease logging level\n\
4193
\t-d\tdisassemble input files (default)\n\
4194
\t-D\tfull disassembly of input files\n\
4195
\t-T\tEnter debug mode when running simulation\n\
4196
\t-a\tassemble file\n\
4197
\t-H\tenable hacks to make the simulation easier to use\n\
4198
\t-r\trun hex file\n\
4199
\t-R\tassemble file then run it\n\
4200
\t-e #\tRun Embed Forth Virtual Machine\n\
4201
\t-L #\tload symbol file\n\
4202
\t-S #\tsave symbols to file\n\
4203
\t-s #\tnumber of steps to run simulation (0 = forever)\n\
4204
\t-n #\tspecify nvram file\n\
4205
\t-H #\tenable certain hacks for simulation purposes\n\
4206
\t-c #\tset colorization method for disassembly\n\
4207
\tfile\thex or forth file to process\n\n\
4208
Options must precede any files given, if a file has not been\n\
4209
given as arguments input is taken from stdin. Output is to\n\
4210
stdout. Program returns zero on success, non zero on failure.\n\n\
4211
";
4212
 
4213
static void debug_note(command_args_t *cmd)
4214
{
4215
        if(cmd->debug_mode)
4216
                note("entering debug mode");
4217
        else
4218
                note("running for %u cycles (0 = forever)", (unsigned)cmd->steps);
4219
}
4220
 
4221
static int assemble_run_command(command_args_t *cmd, FILE *input, FILE *output, symbol_table_t *symbols, bool assemble, uint16_t *vga_initial_contents)
4222
{
4223
        assert(input);
4224
        assert(output);
4225
        assert(cmd);
4226
        assert(cmd->nvram);
4227
        h2_t *h = NULL;
4228
        h2_io_t *io = NULL;
4229
        int r = 0;
4230
 
4231
        if(assemble) {
4232
                h = h2_assemble_core(input, symbols);
4233
        } else {
4234
                h = h2_new(START_ADDR);
4235
                if(h2_load(h, input) < 0)
4236
                        return -1;
4237
        }
4238
 
4239
        if(!h)
4240
                return -1;
4241
 
4242
        io = h2_io_new();
4243
        assert(VGA_BUFFER_LENGTH <= VT100_MAX_SIZE);
4244
        for(size_t i = 0; i < VGA_BUFFER_LENGTH; i++) {
4245
                vt100_attribute_t attr;
4246
                memset(&attr, 0, sizeof(attr));
4247
                io->soc->vt100.m[i]   =  vga_initial_contents[i] & 0xff;
4248
                attr.background_color = (vga_initial_contents[i] >> 8)  & 0x7;
4249
                attr.foreground_color = (vga_initial_contents[i] >> 11) & 0x7;
4250
                memcpy(&io->soc->vt100.attributes[i], &attr, sizeof(attr));
4251
        }
4252
 
4253
        nvram_load_and_transfer(io, cmd->nvram, cmd->hacks);
4254
        h->pc = START_ADDR;
4255
        debug_note(cmd);
4256
        r = h2_run(h, io, output, cmd->steps, symbols, cmd->debug_mode);
4257
        nvram_save(io, cmd->nvram);
4258
 
4259
        h2_free(h);
4260
        h2_io_free(io);
4261
        return r;
4262
}
4263
 
4264
int command(command_args_t *cmd, FILE *input, FILE *output, symbol_table_t *symbols, uint16_t *vga_initial_contents)
4265
{
4266
        assert(input);
4267
        assert(output);
4268
        assert(cmd);
4269
        switch(cmd->cmd) {
4270
        case DEFAULT_COMMAND:      /* fall through */
4271
        case DISASSEMBLE_COMMAND:  return h2_disassemble(cmd->dcm, input, output, symbols);
4272
        case ASSEMBLE_COMMAND:     return h2_assemble_file(input, output, symbols);
4273
        case RUN_COMMAND:          return assemble_run_command(cmd, input, output, symbols, false, vga_initial_contents);
4274
        case ASSEMBLE_RUN_COMMAND: return assemble_run_command(cmd, input, output, symbols, true,  vga_initial_contents);
4275
        default:                   fatal("invalid command: %d", cmd->cmd);
4276
        }
4277
        return -1;
4278
}
4279
 
4280
static const char *nvram_file = FLASH_INIT_FILE;
4281
 
4282
int h2_main(int argc, char **argv)
4283
{
4284
        int i;
4285
        const char *optarg = NULL;
4286
        command_args_t cmd;
4287
        symbol_table_t *symbols = NULL;
4288
        FILE *symfile = NULL;
4289
        FILE *newsymfile = NULL;
4290
        FILE *input = NULL;
4291
        memset(&cmd, 0, sizeof(cmd));
4292
        cmd.steps = DEFAULT_STEPS;
4293
        cmd.nvram = nvram_file;
4294
        cmd.dcm   = DCM_X11;
4295
 
4296
        static uint16_t vga_initial_contents[VGA_BUFFER_LENGTH] = { 0 };
4297
 
4298
        binary(stdin);
4299
        binary(stdout);
4300
        binary(stderr);
4301
 
4302
        { /* attempt to load initial contents of VGA memory */
4303
                errno = 0;
4304
                FILE *vga_init = fopen(VGA_INIT_FILE, "rb");
4305
                if(vga_init) {
4306
                        memory_load(vga_init, vga_initial_contents, VGA_BUFFER_LENGTH);
4307
                        fclose(vga_init);
4308
                } else {
4309
                        warning("could not load initial VGA memory file %s: %s", VGA_INIT_FILE, strerror(errno));
4310
                }
4311
        }
4312
 
4313
        for(i = 1; i < argc && argv[i][0] == '-'; i++) {
4314
 
4315
                if(strlen(argv[i]) > 2) {
4316
                        error("Only one option allowed at a time (got %s)", argv[i]);
4317
                        goto fail;
4318
                }
4319
 
4320
                switch(argv[i][1]) {
4321
                case '\0':
4322
                        goto done; /* stop processing options */
4323
                case 'h':
4324
                        fprintf(stderr, "%s\n", help);
4325
                        return -1;
4326
                case 'v':  /* increase verbosity */
4327
                        log_level += log_level < LOG_ALL_MESSAGES ? 1 : 0;
4328
                        break;
4329
                case 'D':
4330
                        cmd.full_disassembly = true;
4331
                        /* fall through */
4332
                case 'd':
4333
                        if(cmd.cmd)
4334
                                goto fail;
4335
                        cmd.cmd = DISASSEMBLE_COMMAND;
4336
                        break;
4337
                case 'e':
4338
                {
4339
                        forth_t *f = embed_new();
4340
                        if(i >= (argc - 1)) {
4341
                                embed_free(f);
4342
                                goto fail;
4343
                        }
4344
                        optarg = argv[++i];
4345
                        int r = embed_forth(f, stdin, stdout, optarg);
4346
                        embed_free(f);
4347
                        if(r < 0)
4348
                                fatal("embed run failed: %u\n", r);
4349
                        break;
4350
                }
4351
                case 'a':
4352
                        if(cmd.cmd)
4353
                                goto fail;
4354
                        cmd.cmd = ASSEMBLE_COMMAND;
4355
                        break;
4356
                case 'r':
4357
                        if(cmd.cmd)
4358
                                goto fail;
4359
                        cmd.cmd = RUN_COMMAND;
4360
                        break;
4361
                case 'T':
4362
                        cmd.debug_mode = true;
4363
                        break;
4364
                case 'R':
4365
                        if(cmd.cmd)
4366
                                goto fail;
4367
                        cmd.cmd = ASSEMBLE_RUN_COMMAND;
4368
                        break;
4369
                case 'L':
4370
                        if(i >= (argc - 1) || symfile)
4371
                                goto fail;
4372
                        optarg = argv[++i];
4373
                        /* NB. Cannot merge symbol tables */
4374
                        symfile = fopen_or_die(optarg, "rb");
4375
                        symbols = symbol_table_load(symfile);
4376
                        break;
4377
                case 'S':
4378
                        if(i >= (argc - 1) || newsymfile)
4379
                                goto fail;
4380
                        optarg = argv[++i];
4381
                        newsymfile = fopen_or_die(optarg, "wb");
4382
                        break;
4383
                case 'c':
4384
                {
4385
                        long dcm = DCM_NONE;
4386
                        if(i >= (argc - 1))
4387
                                goto fail;
4388
                        optarg = argv[++i];
4389
                        if(string_to_long(0, &dcm, optarg))
4390
                                goto fail;
4391
                        cmd.dcm = dcm;
4392
                        if(cmd.dcm >= DCM_MAX_DCM) {
4393
                                fprintf(stderr, "Invalid Colorization Method: %u\n", cmd.dcm);
4394
                                goto fail;
4395
                        }
4396
                        break;
4397
                }
4398
                case 's':
4399
                        if(i >= (argc - 1))
4400
                                goto fail;
4401
                        optarg = argv[++i];
4402
                        if(string_to_long(0, &cmd.steps, optarg))
4403
                                goto fail;
4404
                        break;
4405
                case 'n':
4406
                        if(i >= (argc - 1))
4407
                                goto fail;
4408
                        cmd.nvram = argv[++i];
4409
                        note("nvram file %s", cmd.nvram);
4410
                        break;
4411
                case 'H':
4412
                        cmd.hacks = true;
4413
                        break;
4414
                default:
4415
                fail:
4416
                        fatal("invalid argument '%s'\n%s\n", argv[i], help);
4417
                }
4418
        }
4419
        if(!symbols)
4420
                symbols = symbol_table_new();
4421
 
4422
done:
4423
        if(i == argc) {
4424
                if(command(&cmd, stdin, stdout, symbols, vga_initial_contents) < 0)
4425
                        fatal("failed to process standard input");
4426
                return 0;
4427
        }
4428
 
4429
        if(i < (argc - 1))
4430
                fatal("more than one file argument given");
4431
 
4432
        input = fopen_or_die(argv[i], "rb");
4433
        if(command(&cmd, input, stdout, symbols, vga_initial_contents) < 0)
4434
                fatal("failed to process file: %s", argv[i]);
4435
        /**@note keeping "input" open until the command exits locks the
4436
         * file for longer than is necessary under Windows */
4437
        fclose(input);
4438
 
4439
        if(newsymfile) {
4440
                symbol_table_print(symbols, newsymfile);
4441
                fclose(newsymfile);
4442
        }
4443
        symbol_table_free(symbols);
4444
        if(symfile)
4445
                fclose(symfile);
4446
        return 0;
4447
}
4448
 
4449
int main(int argc, char **argv)
4450
{
4451
        return h2_main(argc, argv);
4452
}
4453
#endif
4454
 
4455
/* ========================== Main ========================================= */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.