forth-cpu

Форк
0
/
h2.c 
2616 строк · 78.5 Кб
1
/** @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 simulator and debugger for the H2, 
7
 * 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
/* ========================== Preamble: Types, Macros, Globals ============= */
14

15
#include "h2.h"
16
#include <assert.h>
17
#include <ctype.h>
18
#include <errno.h>
19
#include <inttypes.h>
20
#include <setjmp.h>
21
#include <stdarg.h>
22
#include <stdlib.h>
23
#include <string.h>
24

25
#define UNUSED(VARIABLE) ((void)(VARIABLE))
26

27
#ifdef _WIN32 /* Making standard input streams on Windows binary */
28
#include <windows.h>
29
#include <io.h>
30
#include <fcntl.h>
31
extern int _fileno(FILE *stream);
32
static void binary(FILE *f) { _setmode(_fileno(f), _O_BINARY); }
33
#else
34
static inline void binary(FILE *f) { UNUSED(f); }
35
#endif
36

37
#define DEFAULT_STEPS (0) /*default is to run forever*/
38
#define MAX(X, Y)     ((X) > (Y) ? (X) : (Y))
39
#define MIN(X, Y)     ((X) > (Y) ? (Y) : (X))
40

41
#define NUMBER_OF_INTERRUPTS (8u)
42

43
#define OP_BRANCH        (0x0000)
44
#define OP_0BRANCH       (0x2000)
45
#define OP_CALL          (0x4000)
46
#define OP_ALU_OP        (0x6000)
47
#define OP_LITERAL       (0x8000)
48

49
#define IS_LITERAL(INST) (((INST) & 0x8000) == 0x8000)
50
#define IS_BRANCH(INST)  (((INST) & 0xE000) == 0x0000)
51
#define IS_0BRANCH(INST) (((INST) & 0xE000) == 0x2000)
52
#define IS_CALL(INST)    (((INST) & 0xE000) == 0x4000)
53
#define IS_ALU_OP(INST)  (((INST) & 0xE000) == 0x6000)
54

55
#define ALU_OP_LENGTH   (5u)
56
#define ALU_OP_START    (8u)
57
#define ALU_OP(INST)    (((INST) >> ALU_OP_START) & ((1 << ALU_OP_LENGTH) - 1))
58

59
#define DSTACK_LENGTH   (2u)
60
#define DSTACK_START    (0u)
61
#define DSTACK(INST)    (((INST) >> DSTACK_START) & ((1 << DSTACK_LENGTH) - 1))
62

63
#define RSTACK_LENGTH   (2u)
64
#define RSTACK_START    (2u)
65
#define RSTACK(INST)    (((INST) >> RSTACK_START) & ((1 << RSTACK_LENGTH) - 1))
66

67
#define R_TO_PC_BIT_INDEX     (4u)
68
#define N_TO_ADDR_T_BIT_INDEX (5u)
69
#define T_TO_R_BIT_INDEX      (6u)
70
#define T_TO_N_BIT_INDEX      (7u)
71

72
#define R_TO_PC         (1u << R_TO_PC_BIT_INDEX)
73
#define N_TO_ADDR_T     (1u << N_TO_ADDR_T_BIT_INDEX)
74
#define T_TO_R          (1u << T_TO_R_BIT_INDEX)
75
#define T_TO_N          (1u << T_TO_N_BIT_INDEX)
76

77
typedef enum {
78
	ALU_OP_T,                  /**< Top of Stack         */
79
	ALU_OP_N,                  /**< Copy T to N          */
80
	ALU_OP_T_PLUS_N,           /**< Addition             */
81
	ALU_OP_T_AND_N,            /**< Bitwise AND          */
82
	ALU_OP_T_OR_N,             /**< Bitwise OR           */
83
	ALU_OP_T_XOR_N,            /**< Bitwise XOR          */
84
	ALU_OP_T_INVERT,           /**< Bitwise Inversion    */
85
	ALU_OP_T_EQUAL_N,          /**< Equality test        */
86
	ALU_OP_N_LESS_T,           /**< Signed comparison    */
87
	ALU_OP_N_RSHIFT_T,         /**< Logical Right Shift  */
88
	ALU_OP_T_DECREMENT,        /**< Decrement            */
89
	ALU_OP_R,                  /**< Top of return stack  */
90
	ALU_OP_T_LOAD,             /**< Load from address    */
91
	ALU_OP_N_LSHIFT_T,         /**< Logical Left Shift   */
92
	ALU_OP_DEPTH,              /**< Depth of stack       */
93
	ALU_OP_N_ULESS_T,          /**< Unsigned comparison  */
94
	ALU_OP_ENABLE_INTERRUPTS,  /**< Enable interrupts    */
95

96
	ALU_OP_INTERRUPTS_ENABLED, /**< Are interrupts on?   */
97
	ALU_OP_RDEPTH,             /**< R Stack Depth        */
98
	ALU_OP_T_EQUAL_0,          /**< T == 0               */
99
	ALU_OP_CPU_ID,             /**< CPU Identifier       */
100

101
	ALU_OP_LITERAL,            /**< undocumented; set T to instruction & $7fff */
102
} alu_code_e;
103

104
#define DELTA_0  (0)
105
#define DELTA_1  (1)
106
#define DELTA_N2 (2)
107
#define DELTA_N1 (3)
108

109
#define MK_DSTACK(DELTA) ((DELTA) << DSTACK_START)
110
#define MK_RSTACK(DELTA) ((DELTA) << RSTACK_START)
111
#define MK_CODE(CODE)    ((CODE)  << ALU_OP_START)
112

113
/**
114
 * @warning This table keeps most things synchronized when it comes
115
 * to instructions, the exception is in the lexer, which accepts
116
 * a range of tokens in one clause of the grammar from the first
117
 * instruction to the last. This must be manually updated
118
 * @note In the original J1 specification both r@ and r> both have
119
 * their T_TO_R bit set in their instruction description tables, this
120
 * appears to be incorrect */
121
#define X_MACRO_INSTRUCTIONS \
122
	X(DUP,    "dup",    true,  (OP_ALU_OP | MK_CODE(ALU_OP_T)        | T_TO_N  | MK_DSTACK(DELTA_1)))\
123
	X(OVER,   "over",   true,  (OP_ALU_OP | MK_CODE(ALU_OP_N)        | T_TO_N  | MK_DSTACK(DELTA_1)))\
124
	X(OVERADD,"over+",  false, (OP_ALU_OP | MK_CODE(ALU_OP_T_PLUS_N)))\
125
	X(OVERAND,"over-and",  false, (OP_ALU_OP | MK_CODE(ALU_OP_T_AND_N)))\
126
	X(INVERT, "invert", true,  (OP_ALU_OP | MK_CODE(ALU_OP_T_INVERT)))\
127
	X(ADD,    "+",      true,  (OP_ALU_OP | MK_CODE(ALU_OP_T_PLUS_N)               | MK_DSTACK(DELTA_N1)))\
128
	X(SWAP,   "swap",   true,  (OP_ALU_OP | MK_CODE(ALU_OP_N)        | T_TO_N))\
129
	X(NIP,    "nip",    true,  (OP_ALU_OP | MK_CODE(ALU_OP_T)                      | MK_DSTACK(DELTA_N1)))\
130
	X(DROP,   "drop",   true,  (OP_ALU_OP | MK_CODE(ALU_OP_N)                      | MK_DSTACK(DELTA_N1)))\
131
	X(EXIT,   "exit",   true,  (OP_ALU_OP | MK_CODE(ALU_OP_T)        | R_TO_PC | MK_RSTACK(DELTA_N1)))\
132
	X(TOR,    ">r",     true,  (OP_ALU_OP | MK_CODE(ALU_OP_N)        | T_TO_R  | MK_DSTACK(DELTA_N1) | MK_RSTACK(DELTA_1)))\
133
	X(FROMR,  "r>",     true,  (OP_ALU_OP | MK_CODE(ALU_OP_R)        | T_TO_N  | MK_DSTACK(DELTA_1)  | MK_RSTACK(DELTA_N1)))\
134
	X(RAT,    "r@",     true,  (OP_ALU_OP | MK_CODE(ALU_OP_R)        | T_TO_N  | MK_DSTACK(DELTA_1)))\
135
	X(LOAD,   "@",      true,  (OP_ALU_OP | MK_CODE(ALU_OP_T_LOAD)))\
136
	X(STORE,  "store",  false, (OP_ALU_OP | MK_CODE(ALU_OP_N)        | N_TO_ADDR_T | MK_DSTACK(DELTA_N1)))\
137
	X(RSHIFT, "rshift", true,  (OP_ALU_OP | MK_CODE(ALU_OP_N_RSHIFT_T)             | MK_DSTACK(DELTA_N1)))\
138
	X(LSHIFT, "lshift", true,  (OP_ALU_OP | MK_CODE(ALU_OP_N_LSHIFT_T)             | MK_DSTACK(DELTA_N1)))\
139
	X(EQUAL,  "=",      true,  (OP_ALU_OP | MK_CODE(ALU_OP_T_EQUAL_N)              | MK_DSTACK(DELTA_N1)))\
140
	X(ULESS,  "u<",     true,  (OP_ALU_OP | MK_CODE(ALU_OP_N_ULESS_T)              | MK_DSTACK(DELTA_N1)))\
141
	X(LESS,   "<",      true,  (OP_ALU_OP | MK_CODE(ALU_OP_N_LESS_T)               | MK_DSTACK(DELTA_N1)))\
142
	X(AND,    "and",    true,  (OP_ALU_OP | MK_CODE(ALU_OP_T_AND_N)                | MK_DSTACK(DELTA_N1)))\
143
	X(XOR,    "xor",    true,  (OP_ALU_OP | MK_CODE(ALU_OP_T_XOR_N)                | MK_DSTACK(DELTA_N1)))\
144
	X(OR,     "or",     true,  (OP_ALU_OP | MK_CODE(ALU_OP_T_OR_N)                 | MK_DSTACK(DELTA_N1)))\
145
	X(DEPTH,  "sp@",    true,  (OP_ALU_OP | MK_CODE(ALU_OP_DEPTH)   | T_TO_N       | MK_DSTACK(DELTA_1)))\
146
	X(T_N1,   "1-",     true,  (OP_ALU_OP | MK_CODE(ALU_OP_T_DECREMENT)))\
147
	X(IEN,    "ien!",   true,  (OP_ALU_OP | MK_CODE(ALU_OP_ENABLE_INTERRUPTS)      | MK_DSTACK(DELTA_N1)))\
148
	X(ISIEN,  "ien?",   true,  (OP_ALU_OP | MK_CODE(ALU_OP_INTERRUPTS_ENABLED) | T_TO_N  | MK_DSTACK(DELTA_1)))\
149
	X(RDEPTH, "rp@",    true,  (OP_ALU_OP | MK_CODE(ALU_OP_RDEPTH)  | T_TO_N       | MK_DSTACK(DELTA_1)))\
150
	X(TE0,    "0=",     true,  (OP_ALU_OP | MK_CODE(ALU_OP_T_EQUAL_0)))\
151
	X(NOP,    "nop",    false, (OP_ALU_OP | MK_CODE(ALU_OP_T)))\
152
	X(CPU_ID, "cpu-id", true,  (OP_ALU_OP | MK_CODE(ALU_OP_CPU_ID))                | MK_DSTACK(DELTA_1))\
153
	X(RUP,    "rup",    false, (OP_ALU_OP | MK_CODE(ALU_OP_T))                     | MK_RSTACK(DELTA_1))\
154
	X(DUPTOR, "dup>r",  false, (OP_ALU_OP | MK_CODE(ALU_OP_T)) | T_TO_R            | MK_RSTACK(DELTA_1))\
155
	X(RDROP,  "rdrop",  true,  (OP_ALU_OP | MK_CODE(ALU_OP_T) | MK_RSTACK(DELTA_N1)))
156

157

158
typedef enum {
159
#define X(NAME, STRING, DEFINE, INSTRUCTION) CODE_ ## NAME = INSTRUCTION,
160
	X_MACRO_INSTRUCTIONS
161
#undef X
162
} forth_word_codes_e;
163

164
static const char *log_levels[] = {
165
#define X(ENUM, NAME) [ENUM] = NAME,
166
	X_MACRO_LOGGING
167
#undef X
168
};
169

170
log_level_e log_level = LOG_WARNING;
171

172
typedef struct {
173
	int error;
174
	int jmp_buf_valid;
175
	jmp_buf j;
176
} error_t;
177

178
/* ========================== Preamble: Types, Macros, Globals ============= */
179

180
/* ========================== Utilities ==================================== */
181

182
int logger(log_level_e level, const char *func, const unsigned line, const char *fmt, ...) {
183
	int r = 0;
184
       	assert(func);
185
       	assert(fmt);
186
	assert(level <= LOG_ALL_MESSAGES);
187
	if (level <= log_level) {
188
		va_list ap;
189
		fprintf(stderr, "[%s %u] %s: ", func, line, log_levels[level]);
190
		va_start(ap, fmt);
191
		r = vfprintf(stderr, fmt, ap);
192
		va_end(ap);
193
		fputc('\n', stderr);
194
		fflush(stderr);
195
	}
196
	if (level == LOG_FATAL)
197
		exit(EXIT_FAILURE);
198
	return r;
199
}
200

201
static const char *reason(void) {
202
	static const char *unknown = "unknown reason";
203
	if (errno == 0)
204
		return unknown;
205
	const char *r = strerror(errno);
206
	if (!r)
207
		return unknown;
208
	return r;
209
}
210

211
void *allocate_or_die(const size_t length) {
212
	errno = 0;
213
	void *r = calloc(1, length);
214
	if (!r)
215
		fatal("allocation of size %u failed: %s", (unsigned)length, reason());
216
	return r;
217
}
218

219
FILE *fopen_or_die(const char *file, const char *mode) {
220
	assert(file);
221
	assert(mode);
222
	errno = 0;
223
	FILE *f = fopen(file, mode);
224
	if (!f)
225
		fatal("failed to open file '%s' (mode %s): %s", file, mode, reason());
226
	return f;
227
}
228

229
static int string_to_long(const int base, long *n, const char *s) {
230
	char *end = NULL;
231
	assert(base >= 0);
232
	assert(base != 1);
233
	assert(base <= 36);
234
	assert(n);
235
	assert(s);
236
	errno = 0;
237
	*n = strtol(s, &end, base);
238
	return errno || *s == '\0' || *end != '\0';
239
}
240

241
static int string_to_cell(int base, uint16_t *n, const char *s) {
242
	long n1 = 0;
243
	const int r = string_to_long(base, &n1, s);
244
	*n = n1;
245
	return r;
246
}
247

248
static char *duplicate(const char *str) {
249
	assert(str);
250
	const size_t length = strlen(str);
251
	assert((length + 1) > length);
252
	errno = 0;
253
	char *r = malloc(length + 1);
254
	if (!r)
255
		fatal("duplicate of '%s' failed: %s", str, reason());
256
	strcpy(r, str);
257
	return r;
258
}
259

260
static void ethrow(error_t *e) {
261
	if (e && e->jmp_buf_valid) {
262
		e->jmp_buf_valid = 0;
263
		e->error = 1;
264
		longjmp(e->j, 1);
265
	}
266
	exit(EXIT_FAILURE);
267
}
268

269
h2_t *h2_new(const uint16_t start_address) {
270
	h2_t *h = allocate_or_die(sizeof(h2_t));
271
	h->pc = start_address;
272
	for (uint16_t i = 0; i < start_address; i++)
273
		h->core[i] = OP_BRANCH | start_address;
274
	return h;
275
}
276

277
void h2_free(h2_t * const h) {
278
	if (!h)
279
		return;
280
	free(h->bp.points);
281
	memset(h, 0, sizeof(*h));
282
	free(h);
283
}
284

285
int binary_memory_load(FILE *input, uint16_t *p, const size_t length) {
286
	assert(input);
287
	assert(p);
288
	for (size_t i = 0; i < length; i++) {
289
		errno = 0;
290
		const int r1 = fgetc(input);
291
		const int r2 = fgetc(input);
292
		if (r1 < 0 || r2 < 0) {
293
			debug("memory read failed: %s", strerror(errno));
294
			return -1;
295
		}
296
		p[i] = (((unsigned)r1 & 0xffu)) | (((unsigned)r2 & 0xffu) << 8u);
297
	}
298
	return 0;
299
}
300

301
int binary_memory_save(FILE *output, const uint16_t * const p, const size_t length) {
302
	assert(output);
303
	assert(p);
304
	for (size_t i = 0; i < length; i++) {
305
		errno = 0;
306
		const int r1 = fputc((p[i])       & 0xff,output);
307
		const int r2 = fputc((p[i] >> 8u) & 0xff, output);
308
		if (r1 < 0 || r2 < 0) {
309
			debug("memory write failed: %s", strerror(errno));
310
			return -1;
311
		}
312
	}
313
	return 0;
314
}
315

316
int nvram_load_and_transfer(h2_io_t *io, const char *name, const bool transfer_to_sram) {
317
	assert(io);
318
	assert(name);
319
	FILE *input = NULL;
320
	int r = 0;
321
	errno = 0;
322
	if ((input = fopen(name, "rb"))) {
323
		r = binary_memory_load(input, io->soc->flash.nvram, CHIP_MEMORY_SIZE);
324
		if (transfer_to_sram)
325
			memcpy(io->soc->vram, io->soc->flash.nvram, CHIP_MEMORY_SIZE);
326
		fclose(input);
327
	} else {
328
		error("nvram file read (from %s) failed: %s", name, strerror(errno));
329
		r = -1;
330
	}
331
	return r;
332
}
333

334
int nvram_save(h2_io_t *io, const char *name) {
335
	FILE *output = NULL;
336
	int r = 0;
337
	assert(io);
338
	assert(name);
339
	errno = 0;
340
	if ((output = fopen(name, "wb"))) {
341
		r = binary_memory_save(output, io->soc->flash.nvram, CHIP_MEMORY_SIZE);
342
		fclose(output);
343
	} else {
344
		error("nvram file write (to %s) failed: %s", name, strerror(errno));
345
		r = -1;
346
	}
347
	return r;
348
}
349

350
int memory_load(FILE *input, uint16_t *p, const size_t length) {
351
	assert(input);
352
	assert(p);
353
	char line[80] = {0}; /*more than enough!*/
354
	size_t i = 0;
355

356
	for (;fgets(line, sizeof(line), input); i++) {
357
		int r;
358
		if (i >= length) {
359
			error("file contains too many lines: %u", (unsigned)i);
360
			return -1;
361
		}
362
		r = string_to_cell(16, &p[i], line);
363
		if (!r) {
364
			error("invalid line - expected hex string: %s", line);
365
			return -1;
366
		}
367
		debug("%u %u", (unsigned)i, (unsigned)p[i]);
368
	}
369

370
	return 0;
371
}
372

373
int memory_save(FILE *output, const uint16_t * const p, const size_t length) {
374
	assert(output);
375
	assert(p);
376
	for (size_t i = 0; i < length; i++)
377
		if (fprintf(output, "%04"PRIx16"\n", p[i]) < 0) {
378
			error("failed to write line: %lu", (unsigned long)i);
379
			return -1;
380
		}
381
	return 0;
382
}
383

384
int h2_load(h2_t *h, FILE *hexfile) {
385
	assert(h);
386
	assert(hexfile);
387
	return memory_load(hexfile, h->core, MAX_CORE);
388
}
389

390
int h2_save(const h2_t * const h, FILE *output, const bool full) {
391
	assert(h);
392
	assert(output);
393
	return memory_save(output, h->core, full ? MAX_CORE : h->pc);
394
}
395

396
/* From: https://stackoverflow.com/questions/215557/how-do-i-implement-a-circular-list-ring-buffer-in-c */
397

398
fifo_t *fifo_new(const size_t size) {
399
	assert(size >= 2); /* It does not make sense to have a FIFO less than this size */
400
	fifo_data_t *buffer = allocate_or_die(size * sizeof(buffer[0]));
401
	fifo_t *fifo = allocate_or_die(sizeof(fifo_t));
402

403
	fifo->buffer = buffer;
404
	fifo->head   = 0;
405
	fifo->tail   = 0;
406
	fifo->size   = size;
407

408
	return fifo;
409
}
410

411
void fifo_free(fifo_t *fifo) {
412
	if (!fifo)
413
		return;
414
	free(fifo->buffer);
415
	free(fifo);
416
}
417

418
bool fifo_is_full(const fifo_t * const fifo) {
419
	assert(fifo);
420
	return (fifo->head == (fifo->size - 1) && fifo->tail == 0)
421
	    || (fifo->head == (fifo->tail - 1));
422
}
423

424
bool fifo_is_empty(const fifo_t * const fifo) {
425
	assert(fifo);
426
	return fifo->head == fifo->tail;
427
}
428

429
size_t fifo_count(const fifo_t * const fifo) {
430
	assert(fifo);
431
	if (fifo_is_empty(fifo))
432
		return 0;
433
	else if (fifo_is_full(fifo))
434
		return fifo->size;
435
	else if (fifo->head < fifo->tail)
436
		return fifo->head + (fifo->size - fifo->tail);
437
	else
438
		return fifo->head - fifo->tail;
439
}
440

441
size_t fifo_push(fifo_t * fifo, fifo_data_t data) {
442
	assert(fifo);
443
	if (fifo_is_full(fifo))
444
		return 0;
445

446
	fifo->buffer[fifo->head] = data;
447

448
	fifo->head++;
449
	if (fifo->head == fifo->size)
450
		fifo->head = 0;
451

452
	return 1;
453
}
454

455
size_t fifo_pop(fifo_t * fifo, fifo_data_t * data) {
456
	assert(fifo);
457
	assert(data);
458

459
	if (fifo_is_empty(fifo))
460
		return 0;
461

462
	*data = fifo->buffer[fifo->tail];
463

464
	fifo->tail++;
465
	if (fifo->tail == fifo->size)
466
		fifo->tail = 0;
467

468
	return 1;
469
}
470

471
#ifdef __unix__
472
#include <unistd.h>
473
#include <termios.h>
474
static int getch(void) {
475
	struct termios oldattr, newattr;
476
	tcgetattr(STDIN_FILENO, &oldattr);
477
	newattr = oldattr;
478
	newattr.c_iflag &= ~(ICRNL);
479
	newattr.c_lflag &= ~(ICANON | ECHO);
480

481
	tcsetattr(STDIN_FILENO, TCSANOW, &newattr);
482
	const int ch = getchar();
483

484
	tcsetattr(STDIN_FILENO, TCSANOW, &oldattr);
485

486
	return ch;
487
}
488

489
static int putch(int c) {
490
	int res = putchar(c);
491
	fflush(stdout);
492
	return res;
493
}
494
#else
495
#ifdef _WIN32
496

497
extern int getch(void);
498
extern int putch(int c);
499

500
#else
501
static int getch(void) {
502
	return getchar();
503
}
504

505
static int putch(const int c) {
506
	return putchar(c);
507
}
508
#endif
509
#endif /** __unix__ **/
510

511
static int wrap_getch(bool *debug_on) {
512
	const int ch = getch();
513
	assert(debug_on);
514
	if (ch == EOF) {
515
		note("End Of Input - exiting");
516
		exit(EXIT_SUCCESS);
517
	}
518
	if (ch == ESCAPE && debug_on)
519
		*debug_on = true;
520

521
	return ch == DELETE ? BACKSPACE : ch;
522
}
523

524
/* ========================== Utilities ==================================== */
525

526
/* ========================== Symbol Table ================================= */
527

528
static const char *symbol_names[] = {
529
	[SYMBOL_TYPE_LABEL]       = "label",
530
	[SYMBOL_TYPE_CALL]        = "call",
531
	[SYMBOL_TYPE_CONSTANT]    = "constant",
532
	[SYMBOL_TYPE_VARIABLE]    = "variable",
533
	NULL
534
};
535

536
static symbol_t *symbol_new(const symbol_type_e type, const char *id, const uint16_t value) {
537
	symbol_t *s = allocate_or_die(sizeof(*s));
538
	assert(id);
539
	s->id = duplicate(id);
540
	s->value = value;
541
	s->type = type;
542
	return s;
543
}
544

545
static void symbol_free(symbol_t *s) {
546
	if (!s)
547
		return;
548
	free(s->id);
549
	memset(s, 0, sizeof(*s));
550
	free(s);
551
}
552

553
static symbol_table_t *symbol_table_new(void) {
554
	symbol_table_t *t = allocate_or_die(sizeof(*t));
555
	return t;
556
}
557

558
static void symbol_table_free(symbol_table_t *t) {
559
	if (!t)
560
		return;
561
	for (size_t i = 0; i < t->length; i++)
562
		symbol_free(t->symbols[i]);
563
	free(t->symbols);
564
	memset(t, 0, sizeof(*t));
565
	free(t);
566
}
567

568
static symbol_t *symbol_table_lookup(const symbol_table_t * const t, const char *id) {
569
	for (size_t i = 0; i < t->length; i++)
570
		if (!strcmp(t->symbols[i]->id, id))
571
			return t->symbols[i];
572
	return NULL;
573
}
574

575
/** @note There can be multiple symbols with the same value of the same type */
576
static const symbol_t *symbol_table_reverse_lookup(const symbol_table_t * const t, const symbol_type_e type, const uint16_t value) {
577
	for (size_t i = 0; i < t->length; i++)
578
		if (t->symbols[i]->type == type && t->symbols[i]->value == value)
579
			return t->symbols[i];
580
	return NULL;
581
}
582

583
static int symbol_table_add(symbol_table_t *t, symbol_type_e type, const char *id, uint16_t value, error_t *e, bool hidden, bool used) {
584
	symbol_t *s = symbol_new(type, id, value);
585
	symbol_t **xs = NULL;
586
	assert(t);
587

588
	if (symbol_table_lookup(t, id)) {
589
		symbol_free(s);
590
		error("redefinition of symbol: %s", id);
591
		if (e)
592
			ethrow(e);
593
		else
594
			return -1;
595
	}
596
	s->hidden = hidden;
597
	s->used   = used;
598
	t->length++;
599
	errno = 0;
600
	xs = realloc(t->symbols, sizeof(*t->symbols) * t->length);
601
	if (!xs)
602
		fatal("reallocate of size %u failed: %s", (unsigned)t->length, reason());
603
	t->symbols = xs;
604
	t->symbols[t->length - 1] = s;
605
	return 0;
606
}
607

608
static int symbol_table_print(symbol_table_t *t, FILE *output) {
609
	assert(t);
610
	assert(output);
611
	for (size_t i = 0; i < t->length; i++) {
612
		symbol_t *s = t->symbols[i];
613
		char *visibility = s->hidden ? "hidden" : "visible";
614
		char *used = s->used ? "used" : "unused";
615
		if (fprintf(output, "%s %s %"PRId16" %s %s\n", symbol_names[s->type], s->id, s->value, visibility, used) < 0)
616
			return -1;
617
	}
618
	return 0;
619
}
620

621
symbol_table_t *symbol_table_load(FILE *input) {
622
	assert(input);
623
	symbol_table_t *t = symbol_table_new();
624
	char symbol[80] = { 0 };
625
	char id[256] = { 0 };
626
	char visibility[80] = { 0 };
627
	uint16_t value = false;
628

629
	while (!feof(input)) {
630
		int r = 0;
631
		memset(symbol,     0, sizeof(symbol));
632
		memset(id,         0, sizeof(id));
633
		memset(visibility, 0, sizeof(visibility));
634
		value = 0;
635
		r = fscanf(input, "%79s%255s%"SCNu16"%79s", symbol, id, &value, visibility);
636
		if (r != 4 && r > 0) {
637
			error("invalid symbol table: %d", r);
638
			goto fail;
639
		}
640
		if (r == 4) {
641
			size_t i = 0;
642
			bool hidden = false;
643
			if (!strcmp(visibility, "hidden")) {
644
				hidden = true;
645
			}else if (!strcmp(visibility, "visible")) {
646
				error("invalid visibility value: %s", visibility);
647
				goto fail;
648
			}
649

650
			for (i = 0; symbol_names[i] && strcmp(symbol_names[i], symbol); i++)
651
				/*do nothing*/;
652
			if (symbol_names[i]) {
653
				if (symbol_table_add(t, i, id, value, NULL, hidden, false) < 0)
654
					goto fail;
655
			} else {
656
				error("invalid symbol: %s", symbol);
657
				goto fail;
658
			}
659
		}
660
	}
661
	if (log_level >= LOG_DEBUG)
662
		symbol_table_print(t, stderr);
663
	return t;
664
fail:
665
	symbol_table_free(t);
666
	return NULL;
667
}
668
/* ========================== Symbol Table ================================= */
669

670
/* ========================== Disassembler ================================= */
671

672
static const char *instruction_to_string(const uint16_t i) {
673
	switch (i) {
674
#define X(NAME, STRING, DEFINE, INSTRUCTION) case CODE_ ## NAME : return STRING ;
675
	X_MACRO_INSTRUCTIONS
676
#undef X
677
	default:          break;
678
	}
679
	return NULL;
680
}
681

682
static const char *alu_op_to_string(const uint16_t instruction) {
683
	switch (ALU_OP(instruction)) {
684
	case ALU_OP_T:                  return "T";
685
	case ALU_OP_N:                  return "N";
686
	case ALU_OP_T_PLUS_N:           return "T+N";
687
	case ALU_OP_T_AND_N:            return "T&N";
688
	case ALU_OP_T_OR_N:             return "T|N";
689
	case ALU_OP_T_XOR_N:            return "T^N";
690
	case ALU_OP_T_INVERT:           return "~T";
691
	case ALU_OP_T_EQUAL_N:          return "N=T";
692
	case ALU_OP_N_LESS_T:           return "T>N";
693
	case ALU_OP_N_RSHIFT_T:         return "N>>T";
694
	case ALU_OP_T_DECREMENT:        return "T-1";
695
	case ALU_OP_R:                  return "R";
696
	case ALU_OP_T_LOAD:             return "[T]";
697
	case ALU_OP_N_LSHIFT_T:         return "N<<T";
698
	case ALU_OP_DEPTH:              return "depth";
699
	case ALU_OP_N_ULESS_T:          return "Tu>N";
700
	case ALU_OP_ENABLE_INTERRUPTS:  return "ien";
701
	case ALU_OP_INTERRUPTS_ENABLED: return "ien?";
702
	case ALU_OP_RDEPTH:             return "rdepth";
703
	case ALU_OP_T_EQUAL_0:          return "0=";
704
	case ALU_OP_CPU_ID:             return "cpu-id";
705
	case ALU_OP_LITERAL:            return "literal";
706
	default:                        return "unknown";
707
	}
708
}
709

710
static char *disassembler_alu(const uint16_t instruction) {
711
	char buf[256] = {0};
712
	const char *r = instruction_to_string(OP_ALU_OP | instruction);
713
	if (r)
714
		return duplicate(r);
715
	sprintf(buf, "%04x:%s:%s:%s:%s:%s:%u:%u",
716
			(unsigned)instruction,
717
			alu_op_to_string(instruction),
718
			(instruction & T_TO_N) ? "T->N" : "",
719
			(instruction & T_TO_R) ? "T->R" : "",
720
			(instruction & N_TO_ADDR_T) ? "N->[T]" : "",
721
			(instruction & R_TO_PC) ? "R->PC" : "",
722
			(unsigned)(instruction & 0x000C),
723
			(unsigned)(instruction & 0x0003));
724
	return duplicate(buf);
725
}
726

727
static const char *disassemble_jump(const symbol_table_t * const symbols, const symbol_type_e type, const uint16_t address) {
728
	if (!symbols)
729
		return "";
730
	const symbol_t * const found = symbol_table_reverse_lookup(symbols, type, address);
731
	return found ? found->id : "";
732
}
733

734
#define CSI "\033["
735
#define ANSI_RESET   (CSI "0m")
736
#define ANSI_BLACK   (CSI "30m")
737
#define ANSI_RED     (CSI "31m")
738
#define ANSI_GREEN   (CSI "32m")
739
#define ANSI_YELLOW  (CSI "33m")
740
#define ANSI_BLUE    (CSI "34m")
741
#define ANSI_MAGENTA (CSI "35m")
742
#define ANSI_CYAN    (CSI "36m")
743
#define ANSI_WHITE   (CSI "37m")
744

745
typedef enum {
746
	DCM_NONE,
747
	DCM_X11,
748
	DCM_ANSI,
749
	DCM_MAX_DCM
750
} disassemble_color_method_e;
751

752
typedef enum {
753
	DC_LITERAL,
754
	DC_ALU,
755
	DC_CALL,
756
	DC_0BRANCH,
757
	DC_BRANCH,
758
	DC_ERROR,  /* Invalid instruction */
759
	DC_RESET,  /* Reset color */
760
} decompilation_color_e;
761

762
static int disassemble_instruction(const uint16_t instruction, FILE *output, const symbol_table_t * const symbols, const disassemble_color_method_e dcm) {
763
	int r = 0;
764
	char *s = NULL;
765
	assert(output);
766
	assert(dcm < DCM_MAX_DCM);
767

768
	static const char *colors[3][7] = { /* for colorizing decompilation stream with in-band signalling */
769
		/* LITERAL     ALU            CALL        0BRANCH      BRANCH    ERROR      RESET */
770
		[DCM_NONE] = { "",           "",           "",         "",          "",        "",       "" },         /* No-Color */
771
		[DCM_X11]  = { "?HotPink?",  "?SkyBlue?",  "?GreenYellow?",  "?Khaki?",  "?MediumTurquoise?",  "?FireBrick?",  "" },         /* X11/GTKWave */
772
		[DCM_ANSI] = { ANSI_MAGENTA, ANSI_BLUE,    ANSI_GREEN, ANSI_YELLOW, ANSI_CYAN, ANSI_RED, ANSI_RESET }, /* ANSI Escape Sequences */
773
	};
774

775
	const char **color = colors[dcm];
776
	const unsigned short literal = instruction & 0x7FFF;
777
	const unsigned short address = instruction & 0x1FFF;
778

779
	if (IS_LITERAL(instruction))
780
		r = fprintf(output, "%s%hx%s", color[DC_LITERAL], literal, color[DC_RESET]);
781
	else if (IS_ALU_OP(instruction))
782
		r = fprintf(output, "%s%s%s", color[DC_ALU], s = disassembler_alu(instruction), color[DC_RESET]);
783
	else if (IS_CALL(instruction))
784
		r = fprintf(output, "%scall%s %hx %s",  color[DC_CALL], color[DC_RESET], address, disassemble_jump(symbols, SYMBOL_TYPE_CALL, address));
785
	else if (IS_0BRANCH(instruction))
786
		r = fprintf(output, "%s0branch%s %hx %s", color[DC_0BRANCH], color[DC_RESET], address, disassemble_jump(symbols, SYMBOL_TYPE_LABEL, address));
787
	else if (IS_BRANCH(instruction))
788
		r = fprintf(output, "%sbranch%s %hx %s",  color[DC_BRANCH], color[DC_RESET], address, disassemble_jump(symbols, SYMBOL_TYPE_LABEL, address));
789
	else
790
		r = fprintf(output, "%s?(%hx)%s", color[DC_ERROR], instruction, color[DC_RESET]);
791
	free(s);
792
	return r < 0 ? -1 : 0;
793
}
794

795
int h2_disassemble(const disassemble_color_method_e dcm, FILE *input, FILE *output, const symbol_table_t * const symbols) {
796
	assert(input);
797
	assert(output);
798
	assert(dcm < DCM_MAX_DCM);
799
	while (!feof(input)) {
800
		char line[80] = { 0 };
801
		if (fscanf(input, "%79s", line) != 1)
802
			return -1;
803
		if (line[0]) {
804
			uint16_t instruction = 0;
805
			if (string_to_cell(16, &instruction, line)) {
806
				error("invalid input to disassembler: %s", line);
807
				return -1;
808
			}
809
			if (disassemble_instruction(instruction, output, symbols, dcm) < 0) {
810
				error("disassembly failed");
811
				return -1;
812
			}
813
			if (fputc('\n', output) != '\n') {
814
				error("disassembly failed");
815
				return -1;
816
			}
817
			fflush(output);
818
		}
819
	}
820
	return 0;
821
}
822

823
/* ========================== Disassembler ================================= */
824

825
/* ========================== Simulation And Debugger ====================== */
826

827
/* @note At the moment I/O is not cycle accurate, the UART behaves as if reads
828
 * and writes happen instantly, along with the PS/2 keyboard. Also the UART
829
 * has a FIFO which is not simulated. It should be easy enough to delay for
830
 * the roughly the right number of cycles, but not to get exact cycle
831
 * accurate timing. */
832

833
static char to_char(const uint8_t c) {
834
	return isprint(c) ? c : '.';
835
}
836

837
static void memory_print(FILE *out, const uint16_t start, const uint16_t * const p, const uint16_t length, const bool chars) {
838
	const uint16_t line_length = 16;
839
	assert(out);
840
	assert(p);
841
	for (uint16_t i = 0; i < length; i += line_length) {
842
		fprintf(out, "%04"PRIx16 ": ", i + start);
843
		for (uint16_t j = 0; j < line_length && j + i < length; j++)
844
			fprintf(out, "%04"PRIx16 " ", p[j + i]);
845
		fputc('\t', out);
846
		if (chars) /* correct endianess? */
847
			for (uint16_t j = 0; j < line_length && j + i < length; j++)
848
				fprintf(out, "%c%c", to_char(p[j + i] >> 8), to_char(p[j + i]));
849

850
		putc('\n', out);
851
	}
852
	putc('\n', out);
853
}
854

855
static bool break_point_find(const break_point_t * const bp, const uint16_t find_me) {
856
	assert(bp);
857
	for (size_t i = 0; i < bp->length; i++)
858
		if (bp->points[i] == find_me)
859
			return true;
860
	return false;
861
}
862

863
static void break_point_add(break_point_t *bp, const uint16_t point) {
864
	assert(bp);
865
	if (break_point_find(bp, point))
866
		return;
867
	const size_t a = (bp->length + 1) * sizeof(bp->points[0]);
868
	uint16_t *r = realloc(bp->points, a);
869
	if (!r || a < bp->length)
870
		fatal("realloc of size %u failed", (unsigned)a);
871
	r[bp->length] = point;
872
	bp->length++;
873
	bp->points = r;
874
}
875

876
static int break_point_print(FILE *out, const break_point_t * const bp) {
877
	assert(out);
878
	assert(bp);
879
	for (size_t i = 0; i < bp->length; i++)
880
		if (fprintf(out, "\t0x%04"PRIx16 "\n", bp->points[i]) < 0)
881
			return -1;
882
	return 0;
883
}
884

885
#define LED_7_SEGMENT_DISPLAY_CHARSET_HEX  "0123456789AbCdEF"
886
#define LED_7_SEGMENT_DISPLAY_CHARSET_BCD  "0123456789 .-   "
887

888
static char l7seg(const uint8_t c) {
889
	static const char *v = LED_7_SEGMENT_DISPLAY_CHARSET_HEX;
890
	return v[c & 0xf];
891
}
892

893
void soc_print(FILE *out, const h2_soc_state_t * const soc) {
894
	assert(out);
895
	assert(soc);
896
	const unsigned char led0 = l7seg(soc->led_7_segments >> 12);
897
	const unsigned char led1 = l7seg(soc->led_7_segments >>  8);
898
	const unsigned char led2 = l7seg(soc->led_7_segments >>  4);
899
	const unsigned char led3 = l7seg(soc->led_7_segments);
900

901
	fprintf(out, "LEDS:             %02"PRIx8"\n",  soc->leds);
902
	/*fprintf(out, "VGA Cursor:       %04"PRIx16"\n", soc->vga_cursor);
903
	fprintf(out, "VGA Control:      %04"PRIx16"\n", soc->vga_control);*/
904
	fprintf(out, "Timer Control:    %04"PRIx16"\n", soc->timer_control);
905
	fprintf(out, "Timer:            %04"PRIx16"\n", soc->timer);
906
	fprintf(out, "IRC Mask:         %04"PRIx16"\n", soc->irc_mask);
907
	fprintf(out, "UART Input:       %02"PRIx8"\n",  soc->uart_getchar_register);
908
	fprintf(out, "LED 7 segment:    %c%c%c%c\n",    led0, led1, led2, led3);
909
	fprintf(out, "Switches:         %04"PRIx16"\n", soc->switches);
910
	fprintf(out, "Waiting:          %s\n",          soc->wait ? "true" : "false");
911
	fprintf(out, "Flash Control:    %04"PRIx16"\n", soc->mem_control);
912
	fprintf(out, "Flash Address Lo: %04"PRIx16"\n", soc->mem_addr_low);
913
	fprintf(out, "Flash Data Out:   %04"PRIx16"\n", soc->mem_dout);
914
	fprintf(out, "UART TX Baud:     %04"PRIx16"\n", soc->uart_tx_baud);
915
	fprintf(out, "UART RX Baud:     %04"PRIx16"\n", soc->uart_rx_baud);
916
	fprintf(out, "UART Control:     %04"PRIx16"\n", soc->uart_control);
917
}
918

919
static void terminal_default_command_sequence(vt100_t * const t) {
920
	assert(t);
921
	t->n1 = 1;
922
	t->n2 = 1;
923
	t->command_index = 0;
924
}
925

926
static void terminal_at_xy(vt100_t * const t, unsigned x, unsigned y, const bool limit_not_wrap) {
927
	assert(t);
928
	if (limit_not_wrap) {
929
		x = MAX(x, 0);
930
		y = MAX(y, 0);
931
		x = MIN(x, t->width  - 1);
932
		y = MIN(y, t->height - 1);
933
	} else {
934
		x %= t->width;
935
		y %= t->height;
936
	}
937
	t->cursor = (y * t->width) + x;
938
}
939

940
static int terminal_x_current(const vt100_t * const t) {
941
	assert(t);
942
	return t->cursor % t->width;
943
}
944

945
static int terminal_y_current(const vt100_t * const t) {
946
	assert(t);
947
	return t->cursor / t->width;
948
}
949

950
static void terminal_at_xy_relative(vt100_t *t, const int x, const int y, const bool limit_not_wrap) {
951
	assert(t);
952
	const int x_current = terminal_x_current(t);
953
	const int y_current = terminal_y_current(t);
954
	terminal_at_xy(t, x_current + x, y_current + y, limit_not_wrap);
955
}
956

957
static void terminal_parse_attribute(vt100_attribute_t * const a, const unsigned v) {
958
	assert(a);
959
	switch (v) {
960
	case 0:
961
		memset(a, 0, sizeof(*a));
962
		a->foreground_color = WHITE;
963
		a->background_color = BLACK;
964
		return;
965
	case  1: a->bold          = true;  return;
966
	case 22: a->bold          = false; return;
967
	case  4: a->under_score   = true;  return;
968
	case  5: a->blink         = true;  return;
969
	case 25: a->blink         = false; return;
970
	case  7: a->reverse_video = true;  return;
971
	case 39: a->reverse_video = false; return;
972
	case  8: a->conceal       = true;  return;
973
	case 28: a->conceal       = false; return;
974
	default:
975
		if (v >= 30 && v <= 37)
976
			a->foreground_color = v - 30;
977
		if (v >= 40 && v <= 47)
978
			a->background_color = v - 40;
979
	}
980
}
981

982
static const vt100_attribute_t vt100_default_attribute = {
983
	.foreground_color = WHITE,
984
	.background_color = BLACK,
985
};
986

987
static void terminal_attribute_block_set(vt100_t *t, const size_t size, const vt100_attribute_t * const a) {
988
	assert(t);
989
	assert(a);
990
	for (size_t i = 0; i < size; i++)
991
		memcpy(&t->attributes[i], a, sizeof(*a));
992
}
993

994
static int terminal_escape_sequences(vt100_t * const t, const uint8_t c) {
995
	assert(t);
996
	assert(t->state != TERMINAL_NORMAL_MODE);
997
	switch (t->state) {
998
	case TERMINAL_CSI: /* process CSI and some non-CSI Escape Only commands */
999
		switch (c) {
1000
		case '[': t->state = TERMINAL_COMMAND; break;
1001
		case 'c': goto eraser; /*reset display*/ break;
1002
		case '7': t->cursor_saved = t->cursor; t->attribute_saved = t->attribute; break;
1003
		case '8': t->cursor = t->cursor_saved; t->attribute = t->attribute_saved; break;
1004
		default: goto fail;
1005
		}
1006

1007
		break;
1008
	case TERMINAL_COMMAND:
1009
		switch (c) {
1010
		case 's':
1011
			t->cursor_saved = t->cursor;
1012
			goto success;
1013
		case 'n':
1014
			t->cursor = t->cursor_saved;
1015
			goto success;
1016
		case '?':
1017
			terminal_default_command_sequence(t);
1018
			t->state = TERMINAL_DECTCEM;
1019
			break;
1020
		case ';':
1021
			terminal_default_command_sequence(t);
1022
			t->state = TERMINAL_NUMBER_2;
1023
			break;
1024
		default:
1025
			if (isdigit(c)) {
1026
				terminal_default_command_sequence(t);
1027
				t->command_index++;
1028
				t->n1 = c - '0';
1029
				t->state = TERMINAL_NUMBER_1;
1030
			} else {
1031
				goto fail;
1032
			}
1033
		}
1034
		break;
1035
	case TERMINAL_NUMBER_1:
1036
		if (isdigit(c)) {
1037
			if (t->command_index > 3)
1038
				goto fail;
1039
			t->n1 = (t->n1 * (t->command_index ? 10 : 0)) + (c - '0');
1040
			t->command_index++;
1041
			break;
1042
		}
1043

1044
		switch (c) {
1045
		case 'A': terminal_at_xy_relative(t,  0,     -t->n1, true); goto success;/* relative cursor up */
1046
		case 'B': terminal_at_xy_relative(t,  0,      t->n1, true); goto success;/* relative cursor down */
1047
		case 'C': terminal_at_xy_relative(t,  t->n1,  0,     true); goto success;/* relative cursor forward */
1048
		case 'D': terminal_at_xy_relative(t, -t->n1,  0,     true); goto success;/* relative cursor back */
1049
		case 'E': terminal_at_xy(t, 0,  t->n1, false); goto success; /* relative cursor down, beginning of line */
1050
		case 'F': terminal_at_xy(t, 0, -t->n1, false); goto success; /* relative cursor up, beginning of line */
1051
		case 'G': terminal_at_xy(t, t->n1, terminal_y_current(t), true); goto success; /* move the cursor to column n */
1052
		case 'm': /* set attribute, CSI number m */
1053
			terminal_parse_attribute(&t->attribute, t->n1);
1054
			t->attributes[t->cursor] = t->attribute;
1055
			goto success;
1056
		case 'i': /* AUX Port On == 5, AUX Port Off == 4 */
1057
			if (t->n1 == 5 || t->n1 == 4)
1058
				goto success;
1059
			goto fail;
1060
		case 'n': /* Device Status Report */
1061
			/** @note This should transmit to the H2 system the
1062
			 * following "ESC[n;mR", where n is the row and m is the column,
1063
			 * we're not going to do this as the hardware does not, although
1064
			 * 'fifo_push()' on 'uart_rx_fifo' could be called to do this */
1065
			if (t->n1 == 6)
1066
				goto success;
1067
			goto fail;
1068
eraser: /* HAHA: This is clearly the best way of doing things. */
1069
			t->command_index = 1;
1070
			t->n1 = 3; /* fall-through */
1071
		case 'J': /* reset */
1072

1073
			switch (t->n1) {
1074
			case 3: /* fall-through */
1075
			case 2: t->cursor = 0; /* with cursor */ /* fall-through */
1076
			case 1:
1077
				if (t->command_index) {
1078
					memset(t->m, ' ', t->size);
1079
					terminal_attribute_block_set(t, t->size, &vt100_default_attribute);
1080
					goto success;
1081
				} /* fall through if number not supplied */ /* fall-through */
1082
			case 0:
1083
				memset(t->m, ' ', t->cursor);
1084
				terminal_attribute_block_set(t, t->cursor, &vt100_default_attribute);
1085
				goto success;
1086
			}
1087
			goto fail;
1088
		case ';':
1089
			t->command_index = 0;
1090
			t->state = TERMINAL_NUMBER_2;
1091
			break;
1092
		default:
1093
			goto fail;
1094
		}
1095
		break;
1096
	case TERMINAL_NUMBER_2:
1097
		if (isdigit(c)) {
1098
			if (t->command_index > 3)
1099
				goto fail;
1100
			t->n2 = (t->n2 * (t->command_index ? 10 : 0)) + (c - '0');
1101
			t->command_index++;
1102
		} else {
1103
			switch (c) {
1104
			case 'm':
1105
				terminal_parse_attribute(&t->attribute, t->n1);
1106
				terminal_parse_attribute(&t->attribute, t->n2);
1107
				t->attributes[t->cursor] = t->attribute;
1108
				goto success;
1109
			case 'H':
1110
			case 'f':
1111
				terminal_at_xy(t, MIN(t->n2-1,t->n2), MIN(t->n1-1,t->n1), true);
1112
				goto success;
1113
			}
1114
			goto fail;
1115
		}
1116
		break;
1117
	case TERMINAL_DECTCEM:
1118
		if (isdigit(c)) {
1119
			if (t->command_index > 1)
1120
				goto fail;
1121
			t->n1 = (t->n1 * (t->command_index ? 10 : 0)) + (c - '0');
1122
			t->command_index++;
1123
			break;
1124
		}
1125

1126
		if (t->n1 != 25)
1127
			goto fail;
1128
		switch (c) {
1129
		case 'l': t->cursor_on = false; goto success;
1130
		case 'h': t->cursor_on = true;  goto success;
1131
		default:
1132
			goto fail;
1133
		}
1134
	case TERMINAL_STATE_END:
1135
		t->state = TERMINAL_NORMAL_MODE;
1136
		break;
1137
	default:
1138
		fatal("invalid terminal state: %u", (unsigned)t->state);
1139
	}
1140

1141
	return 0;
1142
success:
1143
	t->state = TERMINAL_NORMAL_MODE;
1144
	return 0;
1145
fail:
1146
	t->state = TERMINAL_NORMAL_MODE;
1147
	return -1;
1148
}
1149

1150
void vt100_update(vt100_t *t, const uint8_t c) {
1151
	assert(t);
1152
	assert(t->size <= VT100_MAX_SIZE);
1153
	assert((t->width * t->height) <= VT100_MAX_SIZE);
1154

1155
	if (t->state != TERMINAL_NORMAL_MODE) {
1156
		if (terminal_escape_sequences(t, c)) {
1157
			t->state = TERMINAL_NORMAL_MODE;
1158
			/*warning("invalid ANSI command sequence");*/
1159
		}
1160
	} else {
1161
		switch (c) {
1162
		case ESCAPE:
1163
			t->state = TERMINAL_CSI;
1164
			break;
1165
		case '\t':
1166
			t->cursor += 8;
1167
			t->cursor &= ~0x7;
1168
			break;
1169
		case '\n':
1170
			t->cursor += t->width;
1171
			t->cursor = (t->cursor / t->width) * t->width;
1172
			break;
1173
		case '\r':
1174
			break;
1175
		case BACKSPACE:
1176
			terminal_at_xy_relative(t, -1, 0, true);
1177
			break;
1178
		default:
1179
			assert(t->cursor < t->size);
1180
			t->m[t->cursor] = c;
1181
			memcpy(&t->attributes[t->cursor], &t->attribute, sizeof(t->attribute));
1182
			t->cursor++;
1183
		}
1184
		if (t->cursor >= t->size) {
1185
			const vt100_attribute_t *a = &vt100_default_attribute;
1186
			t->cursor -= t->width;
1187
			memmove(t->m, t->m + t->width, t->size - t->width);
1188
			memset((t->m + t->size) - t->width, ' ', t->width);
1189
			for (size_t i = 0; i < (t->size - t->width); i++)
1190
				t->attributes[i] = t->attributes[i + t->width];
1191
			for (size_t i = t->size - t->width; i < t->size; i++)
1192
				memcpy(&t->attributes[i], a, sizeof(*a));
1193
		}
1194
		t->cursor %= t->size;
1195
	}
1196
}
1197

1198
#define FLASH_WRITE_CYCLES (20)  /* x10ns */
1199
#define FLASH_ERASE_CYCLES (200) /* x10ns */
1200

1201
typedef enum {
1202
	FLASH_STATUS_RESERVED         = 1u << 0,
1203
	FLASH_STATUS_BLOCK_LOCKED     = 1u << 1,
1204
	FLASH_STATUS_PROGRAM_SUSPEND  = 1u << 2,
1205
	FLASH_STATUS_VPP              = 1u << 3,
1206
	FLASH_STATUS_PROGRAM          = 1u << 4,
1207
	FLASH_STATUS_ERASE_BLANK      = 1u << 5,
1208
	FLASH_STATUS_ERASE_SUSPEND    = 1u << 6,
1209
	FLASH_STATUS_DEVICE_READY     = 1u << 7,
1210
} flash_status_register_t;
1211

1212
typedef enum {
1213
	FLASH_READ_ARRAY,
1214
	FLASH_QUERY,
1215
	FLASH_READ_DEVICE_IDENTIFIER,
1216
	FLASH_READ_STATUS_REGISTER,
1217
	FLASH_WORD_PROGRAM,
1218
	FLASH_WORD_PROGRAMMING,
1219
	FLASH_LOCK_OPERATION,
1220
	FLASH_LOCK_OPERATING,
1221
	FLASH_BLOCK_ERASE,
1222
	FLASH_BLOCK_ERASING,
1223
	FLASH_BUFFERED_PROGRAM,
1224
	FLASH_BUFFERED_PROGRAMMING,
1225
} flash_state_t;
1226

1227
/** @note read the PC28F128P33BF60 datasheet to decode this
1228
 * information, this table was actually acquired from reading
1229
 * the data from the actual device. */
1230
static const uint16_t PC28F128P33BF60_CFI_Query_Table[0x200] = {
1231
0x0089, 0x881E, 0x0000, 0xFFFF, 0x0089, 0xBFCF, 0x0000, 0xFFFF,
1232
0x0089, 0x881E, 0x0000, 0x0000, 0x0089, 0xBFCF, 0x0000, 0xFFFF,
1233
0x0051, 0x0052, 0x0059, 0x0001, 0x0000, 0x000A, 0x0001, 0x0000,
1234
0x0000, 0x0000, 0x0000, 0x0023, 0x0036, 0x0085, 0x0095, 0x0006,
1235
0x0009, 0x0009, 0x0000, 0x0002, 0x0002, 0x0003, 0x0000, 0x0018,
1236
0x0001, 0x0000, 0x0009, 0x0000, 0x0002, 0x007E, 0x0000, 0x0000,
1237
0x0002, 0x0003, 0x0000, 0x0080, 0x0000, 0x0000, 0x0000, 0x0000,
1238
0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1239
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1240
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1241
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1242
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1243
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1244
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1245
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1246
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1247
0xFFBE, 0x0396, 0x66A2, 0xA600, 0x395A, 0xFFFF, 0xFFFF, 0xFFFF,
1248
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1249
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1250
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1251
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1252
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1253
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1254
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1255
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1256
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1257
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1258
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1259
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1260
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1261
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1262
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1263
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1264
0xFFFF, 0xFFFF, 0x0050, 0x0052, 0x0049, 0x0031, 0x0035, 0x00E6,
1265
0x0001, 0x0000, 0x0000, 0x0001, 0x0003, 0x0000, 0x0030, 0x0090,
1266
0x0002, 0x0080, 0x0000, 0x0003, 0x0003, 0x0089, 0x0000, 0x0000,
1267
0x0000, 0x0000, 0x0000, 0x0000, 0x0010, 0x0000, 0x0004, 0x0004,
1268
0x0004, 0x0001, 0x0002, 0x0003, 0x0007, 0x0001, 0x0024, 0x0000,
1269
0x0001, 0x0000, 0x0011, 0x0000, 0x0000, 0x0002, 0x007E, 0x0000,
1270
0x0000, 0x0002, 0x0064, 0x0000, 0x0002, 0x0003, 0x0000, 0x0080,
1271
0x0000, 0x0000, 0x0000, 0x0080, 0x0003, 0x0000, 0x0080, 0x0000,
1272
0x0064, 0x0000, 0x0002, 0x0003, 0x0000, 0x0080, 0x0000, 0x0000,
1273
0x0000, 0x0080, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1274
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1275
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1276
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1277
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1278
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1279
0xF020, 0x4DBF, 0x838C, 0xFC08, 0x638F, 0x20E3, 0xFF03, 0xD8D7,
1280
0xC838, 0xFFFF, 0xFFFF, 0xAFFF, 0x3352, 0xB333, 0x3004, 0x1353,
1281
0x0003, 0xA000, 0x80D5, 0x8A03, 0xFF4A, 0xFFFF, 0xFFFF, 0x0FFF,
1282
0x2000, 0x0000, 0x0004, 0x0080, 0x1000, 0x0000, 0x0002, 0x0040,
1283
0x0000, 0x0008, 0x0000, 0x0001, 0x2000, 0x0000, 0x0400, 0x0000,
1284
0x0080, 0x0000, 0x0010, 0x0000, 0x0002, 0x4000, 0x0000, 0x0800,
1285
0x0000, 0x0100, 0x0000, 0x0020, 0x0000, 0x0004, 0x8000, 0x0000,
1286
0x1000, 0x0000, 0x0200, 0x0000, 0x0040, 0x0000, 0x0008, 0x0000,
1287
0x0001, 0x2000, 0x0000, 0x0800, 0x0000, 0x0200, 0x0000, 0x0040,
1288
0x0000, 0x0008, 0x0000, 0x0001, 0x2000, 0x0000, 0x0400, 0x0000,
1289
0x0080, 0x0000, 0x0010, 0x0000, 0x0002, 0x4000, 0x0000, 0x0800,
1290
0x0000, 0x0100, 0x0000, 0x0020, 0x0000, 0x0004, 0x8000, 0x0000,
1291
0x1000, 0x0000, 0x0200, 0x0000, 0x0040, 0x0000, 0x0008, 0x0000,
1292
0x0001, 0x4000, 0x0000, 0x1000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1293
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1294
0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
1295
};
1296

1297
uint16_t PC28F128P33BF60_CFI_Query_Read(uint32_t addr) {
1298
	addr &= 0x3ff;
1299
	if (addr > 0x1ff) {
1300
		addr &= 0x7;
1301
		static const uint16_t r[] = {
1302
			0x0089, 0x881E, 0x0000, 0x0000,
1303
			0x0089, 0xBFCF, 0x0000, 0xFFFF
1304
		};
1305
		return r[addr];
1306
	}
1307
	return PC28F128P33BF60_CFI_Query_Table[addr];
1308
}
1309

1310
static uint16_t h2_io_flash_read(const flash_t * const f, const uint32_t addr, const bool oe, const bool we, const bool rst) {
1311
	if (rst)
1312
		return 0;
1313

1314
	if (oe && we) {
1315
		warning("OE and WE set at the same time");
1316
		return 0;
1317
	}
1318

1319
	if (!oe) {
1320
		warning("flash read with OE not selected");
1321
		return 0;
1322
	}
1323

1324
	switch (f->mode) {
1325
	case FLASH_READ_ARRAY:             return f->nvram[0x7ffffff & addr];
1326
	case FLASH_READ_DEVICE_IDENTIFIER:
1327
	case FLASH_QUERY:                  return PC28F128P33BF60_CFI_Query_Read(addr);
1328
	case FLASH_READ_STATUS_REGISTER:   return f->status;
1329
	case FLASH_WORD_PROGRAMMING:
1330
	case FLASH_WORD_PROGRAM:           return f->status;
1331
	case FLASH_BLOCK_ERASING:
1332
	case FLASH_BLOCK_ERASE:            return f->status;
1333
	case FLASH_LOCK_OPERATING:
1334
	case FLASH_LOCK_OPERATION:         return f->status; /* return what? */
1335
	default:
1336
		fatal("invalid flash state: %u", f->mode);
1337
	}
1338

1339
	return 0;
1340
}
1341

1342
static unsigned addr_to_block(uint32_t addr) {
1343
	const uint32_t lower_64k_blocks_highest_address = 127ul * 64ul * 1024ul; /* 0x7F000 */
1344
	/*assert(addr < 0x7ffffff);*/
1345
	if (addr < lower_64k_blocks_highest_address)
1346
		return addr / (64ul * 1024ul);
1347
	addr -= lower_64k_blocks_highest_address;
1348
	addr /= (16ul * 1024ul);
1349
	return addr + 127ul;
1350
}
1351

1352
static unsigned block_size(const unsigned block) {
1353
	if (block >= 127ul)
1354
		return 16ul * 1024ul;
1355
	return 64ul * 1024ul;
1356
}
1357

1358
static bool block_locked(const flash_t * const f, const unsigned block) {
1359
	assert(f);
1360
	assert(block < FLASH_BLOCK_MAX);
1361
	/* The locks block would probably be best be represented as a bit
1362
	 * vector, the functions to manipulate a bit vector can quite easily be
1363
	 * turned into a useful header only library */
1364
	return !!(f->locks[block]);
1365
}
1366

1367
static bool address_protected(const flash_t *const f, const uint32_t addr) {
1368
	assert(f);
1369
	return block_locked(f, addr_to_block(addr));
1370
}
1371

1372
/* We could implement the full standard for the Common Flash Memory
1373
 * Interface, and make the timing based on a simulated calculated time
1374
 * instead multiples of 10us see:
1375
 * <https://en.wikipedia.org/wiki/Common_Flash_Memory_Interface> with the
1376
 * devices PC28F128P33BF60 and NP8P128A13T1760E. The lock status of a register
1377
 * should be read as well as checking f->arg1_address == f->arg2_address for
1378
 * commands which require this.
1379
 *
1380
 * We *could* do that, however this simulator is 'good enough' for our
1381
 * purposes. */
1382
static void h2_io_flash_update(flash_t * const f, const uint32_t addr, const uint16_t data, const bool oe, const bool we, const bool rst, const bool cs) {
1383
	assert(f);
1384
	if (oe && we)
1385
		warning("OE and WE set at the same time");
1386

1387
	if (rst) {
1388
		f->mode = FLASH_READ_ARRAY;
1389
		return;
1390
	}
1391

1392
	switch (f->mode) {
1393
	case FLASH_READ_ARRAY:
1394
	case FLASH_READ_STATUS_REGISTER:
1395
	case FLASH_QUERY:
1396
	case FLASH_READ_DEVICE_IDENTIFIER:
1397
		f->arg1_address = addr;
1398
		f->cycle = 0;
1399
		f->status |= FLASH_STATUS_DEVICE_READY;
1400

1401
		if (!we && f->we && cs) {
1402
			switch (f->data) {
1403
			case 0x00: break;
1404
			case 0xff: f->mode = FLASH_READ_ARRAY;             break;
1405
			case 0x90: f->mode = FLASH_READ_DEVICE_IDENTIFIER; break;
1406
			case 0x98: f->mode = FLASH_QUERY;                  break;
1407
			case 0x70: f->mode = FLASH_READ_STATUS_REGISTER;   break;
1408
			case 0x50: f->status = FLASH_STATUS_DEVICE_READY;  break; /* changes state? */
1409
			case 0x10:
1410
			case 0x40: f->mode = FLASH_WORD_PROGRAM;           break;
1411
			case 0xE8: f->mode = FLASH_BUFFERED_PROGRAM;       break;
1412
			case 0x20: f->mode = FLASH_BLOCK_ERASE;            break;
1413
			/*case 0xB0: SUSPEND NOT IMPLEMENTED;              break; */
1414
			/*case 0xD0: RESUME NOT IMPLEMENTED;               break; */
1415
			case 0x60: f->mode = FLASH_LOCK_OPERATION;         break;
1416
			/*case 0xC0: PROTECTION PROGRAM NOT IMPLEMENTED;     break; */
1417
			default:
1418
				warning("Common Flash Interface command not implemented: %x", (unsigned)(f->data));
1419
				f->mode = FLASH_READ_ARRAY;
1420
			}
1421
		}
1422
		break;
1423
	case FLASH_WORD_PROGRAM:
1424
		if (!we && f->we && cs) {
1425
			f->cycle   = 0;
1426
			if (address_protected(f, f->arg1_address)) {
1427
				warning("address locked: %u", (unsigned)f->arg1_address);
1428
				f->status |= FLASH_STATUS_BLOCK_LOCKED;
1429
				f->status |= FLASH_STATUS_PROGRAM;
1430
				f->mode    = FLASH_READ_STATUS_REGISTER;
1431
			} else {
1432
				f->status &= ~FLASH_STATUS_DEVICE_READY;
1433
				f->mode    = FLASH_WORD_PROGRAMMING;
1434
			}
1435
		} else if (we && cs) {
1436
			f->arg2_address = addr;
1437
		}
1438
		break;
1439
	case FLASH_WORD_PROGRAMMING:
1440
		if (f->cycle++ > FLASH_WRITE_CYCLES) {
1441
			f->nvram[f->arg1_address] &= f->data;
1442
			f->mode         = FLASH_READ_STATUS_REGISTER;
1443
			f->cycle        = 0;
1444
			f->status |= FLASH_STATUS_DEVICE_READY;
1445
		}
1446
		break;
1447
	case FLASH_LOCK_OPERATION:
1448
		if (!we && f->we && cs) {
1449
			f->mode = FLASH_LOCK_OPERATING;
1450
		} else if (we && cs) {
1451
			f->arg2_address = addr;
1452
		}
1453
		break;
1454
	case FLASH_LOCK_OPERATING:
1455
		if (f->arg1_address > FLASH_BLOCK_MAX) {
1456
			warning("block address invalid: %u", (unsigned)f->arg1_address);
1457
			f->mode = FLASH_READ_STATUS_REGISTER;
1458
			break;
1459
		}
1460

1461
		switch (f->data) {
1462
		case 0xD0:
1463
			if (f->locks[f->arg1_address] != FLASH_LOCKED_DOWN)
1464
				f->locks[f->arg1_address] = FLASH_UNLOCKED;
1465
			else
1466
				warning("block locked down: %u", (unsigned)f->arg1_address);
1467
			break;
1468
		case 0x01:
1469
			if (f->locks[f->arg1_address] != FLASH_LOCKED_DOWN)
1470
				f->locks[f->arg1_address] = FLASH_LOCKED;
1471
			else
1472
				warning("block locked down: %u", (unsigned)f->arg1_address);
1473
			break;
1474
		case 0x2F:
1475
			f->locks[f->arg1_address] = FLASH_LOCKED_DOWN;
1476
			break;
1477
		default:
1478
			warning("Unknown/Unimplemented Common Flash Interface Lock Operation: %x", (unsigned)(f->data));
1479
		}
1480
		f->mode = FLASH_READ_STATUS_REGISTER;
1481
		break;
1482
	case FLASH_BLOCK_ERASE:
1483
		/*f->status &= ~FLASH_STATUS_DEVICE_READY;*/
1484
		if (!we && f->we && cs) {
1485
			if (addr != f->arg1_address)
1486
				warning("block addresses differ: 1(%u) 2(%u)", f->arg1_address, addr);
1487
			if (f->data != 0xD0) /* erase confirm */
1488
				f->mode = FLASH_READ_STATUS_REGISTER;
1489
			else
1490
				f->mode = FLASH_BLOCK_ERASING;
1491

1492
			if (f->mode == FLASH_BLOCK_ERASING && address_protected(f, f->arg1_address)) {
1493
				warning("address locked: %u", (unsigned)f->arg1_address);
1494
				f->status |= FLASH_STATUS_BLOCK_LOCKED;
1495
				f->status |= FLASH_STATUS_ERASE_BLANK;
1496
				f->mode    = FLASH_READ_STATUS_REGISTER;
1497
			}
1498
		} else if (we && cs) {
1499
			f->arg2_address = addr;
1500
		}
1501
		f->cycle = 0;
1502
		break;
1503
	case FLASH_BLOCK_ERASING:
1504
		f->status &= ~FLASH_STATUS_DEVICE_READY;
1505
		if (f->cycle++ > FLASH_ERASE_CYCLES) {
1506
			const unsigned block = f->arg1_address;
1507
			const unsigned size  = block_size(block);
1508
			if (block >= FLASH_BLOCK_MAX) {
1509
				warning("block operation out of range: %u", block);
1510
				f->status |= FLASH_STATUS_ERASE_BLANK;
1511
			} else {
1512
				memset(f->nvram+block*size, 0xff, sizeof(f->nvram[0])*size);
1513
			}
1514
			f->cycle = 0;
1515
			f->mode = FLASH_READ_STATUS_REGISTER;
1516
			f->status |= FLASH_STATUS_DEVICE_READY;
1517
		}
1518
		break;
1519
	case FLASH_BUFFERED_PROGRAM:
1520
	case FLASH_BUFFERED_PROGRAMMING:
1521
		warning("block programming not implemented");
1522
		f->status |= FLASH_STATUS_PROGRAM;
1523
		f->mode = FLASH_READ_STATUS_REGISTER;
1524
		break;
1525
	default:
1526
		fatal("invalid flash state: %u", f->mode);
1527
		return;
1528
	}
1529
	if (we && !oe)
1530
		f->data = data;
1531
	f->we = we;
1532
	f->cs = cs;
1533
}
1534

1535
uint16_t h2_io_memory_read_operation(const h2_soc_state_t * const soc) {
1536
	assert(soc);
1537
	const uint32_t flash_addr = ((uint32_t)(soc->mem_control & FLASH_MASK_ADDR_UPPER_MASK) << 16) | soc->mem_addr_low;
1538
	const bool flash_rst = soc->mem_control & FLASH_MEMORY_RESET;
1539
	const bool flash_cs  = soc->mem_control & FLASH_CHIP_SELECT;
1540
	const bool sram_cs   = soc->mem_control & SRAM_CHIP_SELECT;
1541
	const bool oe        = soc->mem_control & FLASH_MEMORY_OE;
1542
	const bool we        = soc->mem_control & FLASH_MEMORY_WE;
1543

1544
	if (oe && we)
1545
		return 0;
1546

1547
	if (flash_cs && sram_cs)
1548
		warning("SRAM and Flash Chip selects both high");
1549

1550
	if (flash_cs)
1551
		return h2_io_flash_read(&soc->flash, flash_addr >> 1, oe, we, flash_rst);
1552

1553
	if (sram_cs && oe && !we)
1554
		return soc->vram[flash_addr >> 1];
1555
	return 0;
1556
}
1557

1558
static uint16_t h2_io_get_default(h2_soc_state_t * const soc, const uint16_t addr, bool *debug_on) {
1559
	assert(soc);
1560
	debug("IO read addr: %"PRIx16, addr);
1561
	(void)debug_on;
1562
	switch (addr) {
1563
	case iUart:         return UART_TX_FIFO_EMPTY | soc->uart_getchar_register;
1564
	case iVT100:        return UART_TX_FIFO_EMPTY | soc->ps2_getchar_register;
1565
	case iSwitches:     return soc->switches;
1566
	case iTimerDin:     return soc->timer;
1567
	case iMemDin:       return h2_io_memory_read_operation(soc);
1568
	default:
1569
		warning("invalid read from %04"PRIx16, addr);
1570
	}
1571
	return 0;
1572
}
1573

1574
static void h2_io_set_default(h2_soc_state_t *soc, const uint16_t addr, const uint16_t value, bool *debug_on) {
1575
	assert(soc);
1576
	debug("IO write addr/value: %"PRIx16"/%"PRIx16, addr, value);
1577

1578
	switch (addr) {
1579
	case oUart:
1580
			if (value & UART_TX_WE)
1581
				putch(0xFF & value);
1582
			if (value & UART_RX_RE)
1583
				soc->uart_getchar_register = wrap_getch(debug_on);
1584
			break;
1585
	case oLeds:       soc->leds           = value; break;
1586
	case oTimerCtrl:  soc->timer_control  = value; break;
1587
	case oVT100:
1588
		if (value & UART_TX_WE)
1589
			vt100_update(&soc->vt100, value);
1590
		if (value & UART_RX_RE)
1591
			soc->ps2_getchar_register = wrap_getch(debug_on);
1592
		break;
1593
	case o7SegLED:    soc->led_7_segments = value; break;
1594
	case oIrcMask:    soc->irc_mask       = value; break;
1595
	case oMemControl:
1596
	{
1597
		soc->mem_control   = value;
1598
		const bool sram_cs = soc->mem_control & SRAM_CHIP_SELECT;
1599
		const bool oe      = soc->mem_control & FLASH_MEMORY_OE;
1600
		const bool we      = soc->mem_control & FLASH_MEMORY_WE;
1601

1602
		if (sram_cs && !oe && we)
1603
			soc->vram[(((uint32_t)(soc->mem_control & FLASH_MASK_ADDR_UPPER_MASK) << 16) | soc->mem_addr_low) >> 1] = soc->mem_dout;
1604
		break;
1605
	}
1606
	case oMemAddrLow:  soc->mem_addr_low = value; break;
1607
	case oMemDout:     soc->mem_dout     = value; break;
1608
	case oUartTxBaud:  soc->uart_tx_baud = value; break;
1609
	case oUartRxBaud:  soc->uart_rx_baud = value; break;
1610
	case oUartControl: soc->uart_control = value; break;
1611
	default:
1612
		warning("invalid write to %04"PRIx16 ":%04"PRIx16, addr, value);
1613
	}
1614
}
1615

1616
static void h2_io_update_default(h2_soc_state_t * const soc) {
1617
	assert(soc);
1618

1619
	if (soc->timer_control & TIMER_ENABLE) {
1620
		if (soc->timer_control & TIMER_RESET) {
1621
			soc->timer = 0;
1622
			soc->timer_control &= ~TIMER_RESET;
1623
		} else {
1624
			soc->timer++;
1625
			if ((soc->timer > (soc->timer_control & 0x1FFF))) {
1626
				if (soc->timer_control & TIMER_INTERRUPT_ENABLE) {
1627
					soc->interrupt           = soc->irc_mask & (1 << isrTimer);
1628
					soc->interrupt_selector |= soc->irc_mask & (1 << isrTimer);
1629
				}
1630
				soc->timer = 0;
1631
			}
1632
		}
1633
	}
1634

1635
	/* DPAD interrupt on change state */
1636
	const uint16_t prev = soc->switches_previous;
1637
	const uint16_t cur  = soc->switches;
1638
	if ((prev & 0xff00) != (cur & 0xff00)) {
1639
		soc->interrupt           = soc->irc_mask & (1u << isrDPadButton);
1640
		soc->interrupt_selector |= soc->irc_mask & (1u << isrDPadButton);
1641
	}
1642
	soc->switches_previous = soc->switches;
1643

1644
	const uint32_t flash_addr = ((uint32_t)(soc->mem_control & FLASH_MASK_ADDR_UPPER_MASK) << 16) | soc->mem_addr_low;
1645
	const bool flash_rst = soc->mem_control & FLASH_MEMORY_RESET;
1646
	const bool flash_cs  = soc->mem_control & FLASH_CHIP_SELECT;
1647
	const bool oe        = soc->mem_control & FLASH_MEMORY_OE;
1648
	const bool we        = soc->mem_control & FLASH_MEMORY_WE;
1649
	h2_io_flash_update(&soc->flash, flash_addr >> 1, soc->mem_dout, oe, we, flash_rst, flash_cs);
1650
}
1651

1652
h2_soc_state_t *h2_soc_state_new(void) {
1653
	h2_soc_state_t *r = allocate_or_die(sizeof(h2_soc_state_t));
1654
	vt100_t *v = &r->vt100;
1655
	memset(r->flash.nvram, 0xff, sizeof(r->flash.nvram[0])*FLASH_BLOCK_MAX);
1656
	memset(r->flash.locks, FLASH_LOCKED, FLASH_BLOCK_MAX);
1657

1658
	v->width        = VGA_WIDTH;
1659
	v->height       = VGA_HEIGHT;
1660
	v->size         = VGA_WIDTH * VGA_HEIGHT;
1661
	v->state        = TERMINAL_NORMAL_MODE;
1662
	v->cursor_on    = true;
1663
	v->blinks       = false;
1664
	v->n1           = 1;
1665
	v->n2           = 1;
1666
	v->attribute.foreground_color = WHITE;
1667
	v->attribute.background_color = BLACK;
1668
	for (size_t i = 0; i < v->size; i++)
1669
		v->attributes[i] = v->attribute;
1670
	return r;
1671
}
1672

1673
void h2_soc_state_free(h2_soc_state_t *soc) {
1674
	if (!soc)
1675
		return;
1676
	memset(soc, 0, sizeof(*soc));
1677
	free(soc);
1678
}
1679

1680
h2_io_t *h2_io_new(void) {
1681
	h2_io_t *io = allocate_or_die(sizeof(*io));
1682
	io->in      = h2_io_get_default;
1683
	io->out     = h2_io_set_default;
1684
	io->update  = h2_io_update_default;
1685
	io->soc     = h2_soc_state_new();
1686
	return io;
1687
}
1688

1689
void h2_io_free(h2_io_t *io) {
1690
	if (!io)
1691
		return;
1692
	h2_soc_state_free(io->soc);
1693
	memset(io, 0, sizeof(*io));
1694
	free(io);
1695
}
1696

1697
static void dpush(h2_t * const h, const uint16_t v) {
1698
	assert(h);
1699
	h->sp++;
1700
	h->dstk[h->sp % STK_SIZE] = h->tos;
1701
	h->tos = v;
1702
	if (h->sp >= STK_SIZE)
1703
		warning("data stack overflow");
1704
	h->sp %= STK_SIZE;
1705
}
1706

1707
static uint16_t dpop(h2_t * const h) {
1708
	assert(h);
1709
	const uint16_t r = h->tos;
1710
	h->tos = h->dstk[h->sp % STK_SIZE];
1711
	h->sp--;
1712
	if (h->sp >= STK_SIZE)
1713
		warning("data stack underflow");
1714
	h->sp %= STK_SIZE;
1715
	return r;
1716
}
1717

1718
static void rpush(h2_t *h, const uint16_t r) {
1719
	assert(h);
1720
	h->rp++;
1721
	h->rstk[(h->rp) % STK_SIZE] = r;
1722
	if (h->rp >= STK_SIZE)
1723
		warning("return stack overflow");
1724
	h->rp %= STK_SIZE;
1725
}
1726

1727
static uint16_t stack_delta(const uint16_t d) {
1728
	static const uint16_t i[4] = { 0x0000, 0x0001, 0xFFFE, 0xFFFF };
1729
	assert((d & 0xFFFC) == 0);
1730
	return i[d];
1731
}
1732

1733
static inline void reverse(char * const r, const size_t length) {
1734
	const size_t last = length - 1;
1735
	for (size_t i = 0; i < length/2ul; i++) {
1736
		const size_t t = r[i];
1737
		r[i] = r[last - i];
1738
		r[last - i] = t;
1739
	}
1740
}
1741

1742
static inline void unsigned_to_csv(char b[64], unsigned u, const char delimiter) {
1743
	unsigned i = 0;
1744
	do {
1745
		const unsigned base = 10; /* bases 2-10 allowed */
1746
		const unsigned q = u % base;
1747
		const unsigned r = u / base;
1748
		b[i++] = q + '0';
1749
		u = r;
1750
	} while (u);
1751
	b[i] = delimiter;
1752
	b[i+1] = '\0';
1753
	reverse(b, i);
1754
}
1755

1756
static inline void csv_value(FILE *o, const unsigned u) {
1757
	char b[64] = { 0 };
1758
	unsigned_to_csv(b, u, ',');
1759
	fputs(b, o);
1760
}
1761

1762
/* This is a fairly fast trace/CSV generation routine which avoids the use of fprintf,
1763
 * speeding up this routine would greatly improve the speed of the interpreter when
1764
 * tracing is on. The symbol table lookup can be disabled by passing in NULL, this
1765
 * also greatly speeds things up. It can be used in a roundabout way to generate
1766
 * a file viewable by GTKWave, its output can be fed into 'csv2vcd' after some
1767
 * minimal processing with AWK, turning it into a VCD file, which is viewable in
1768
 * the wave form viewer, see:
1769
 * <http://www.ic.unicamp.br/~ducatte/mc542/Docs/gtkwave.pdf> and
1770
 * <https://github.com/carlos-jenkins/csv2vcd> for more details.  */
1771
static int h2_log_csv(FILE *o, const h2_t * const h, const symbol_table_t * const symbols, const bool header) {
1772
	if (!o)
1773
		return 0;
1774
	assert(h);
1775
	if (header) {
1776
		fputs("\"pc[15:0]\",", o);
1777
		fputs("\"tos[15:0]\",", o);
1778
		fputs("\"rp[7:0]\",", o);
1779
		fputs("\"sp[7:0]\",", o);
1780
		fputs("\"ie\",", o);
1781
		fputs("\"instruction[15:0]\",", o);
1782
		if (symbols)
1783
			fputs("\"disassembled\",", o);
1784
		fputs("\"Time\"", o);
1785
		if (fputc('\n', o) != '\n')
1786
			return -1;
1787
		return 0;
1788
	}
1789

1790
	csv_value(o, h->pc);
1791
	csv_value(o, h->tos);
1792
	csv_value(o, h->rp);
1793
	csv_value(o, h->sp);
1794
	csv_value(o, h->ie);
1795
	csv_value(o, h->core[h->pc]);
1796
	if (symbols) {
1797
		fputc('"', o);
1798
		disassemble_instruction(h->core[h->pc], o, symbols, DCM_NONE);
1799
		fputs("\",", o);
1800
	}
1801
	csv_value(o, h->time*10);
1802

1803
	if (fputc('\n', o) != '\n')
1804
		return -1;
1805
	return 0;
1806
}
1807

1808
typedef struct {
1809
	FILE *input;
1810
	FILE *output;
1811
	bool step;
1812
	bool trace_on;
1813
} debug_state_t;
1814

1815
static const char *debug_prompt = "debug> ";
1816

1817
static uint16_t map_char_to_number(int c) {
1818
	if (c >= '0' && c <= '9')
1819
		return c - '0';
1820
	c = tolower(c);
1821
	if (c >= 'a' && c <= 'z')
1822
		return c + 10 - 'a';
1823
	fatal("invalid numeric character: %c", c);
1824
	return 0;
1825
}
1826

1827
static bool numeric(const int c, const int base) {
1828
	assert(base == 10 || base == 16);
1829
	if (base == 10)
1830
		return isdigit(c);
1831
	return isxdigit(c);
1832
}
1833

1834
static int number(const char * const s, uint16_t * const o, const size_t length) {
1835
	size_t i = 0, start = 0;
1836
	uint32_t out = 0;
1837
	int base = 10;
1838
	bool negate = false;
1839
	assert(o);
1840
	if (s[i] == '\0')
1841
		return 0;
1842

1843
	if (s[i] == '-') {
1844
		if (s[i+1] == '\0')
1845
			return 0;
1846
		negate = true;
1847
		start = ++i;
1848
	}
1849

1850
	if (s[i] == '$') {
1851
		base = 16;
1852
		if (s[i+1] == '\0')
1853
			return 0;
1854
		start = i + 1;
1855
	}
1856

1857
	for (i = start; i < length; i++)
1858
		if (!numeric(s[i], base))
1859
			return 0;
1860

1861
	for (i = start; i < length; i++)
1862
		out = out * base + map_char_to_number(s[i]);
1863

1864
	*o = negate ? out * (uint16_t)-1 : out;
1865
	return 1;
1866
}
1867
static void h2_print(FILE *out, const h2_t *const h) {
1868
	assert(h);
1869
	fputs("Return Stack:\n", out);
1870
	memory_print(out, 0, h->rstk, STK_SIZE, false);
1871
	fputs("Variable Stack:\n", out);
1872
	fprintf(out, "tos:  %04"PRIx16"\n", h->tos);
1873
	memory_print(out, 1, h->dstk, STK_SIZE, false);
1874

1875
	fprintf(out, "pc:   %04"PRIx16"\n", h->pc);
1876
	fprintf(out, "rp:   %04"PRIx16" (max %04"PRIx16")\n", h->rp, h->rpm);
1877
	fprintf(out, "dp:   %04"PRIx16" (max %04"PRIx16")\n", h->sp, h->spm);
1878
	fprintf(out, "ie:   %s\n", h->ie ? "true" : "false");
1879
}
1880

1881
typedef enum {
1882
	DBG_CMD_NO_ARG,
1883
	DBG_CMD_NUMBER,
1884
	DBG_CMD_STRING,
1885
	DBG_CMD_EITHER,
1886
} debug_command_type_e;
1887

1888
typedef struct {
1889
	int cmd;
1890
	int argc;
1891
	debug_command_type_e arg1;
1892
	debug_command_type_e arg2;
1893
	char *description;
1894
} debug_command_t;
1895

1896
static const debug_command_t debug_commands[] = {
1897
	{ .cmd = 'b', .argc = 1, .arg1 = DBG_CMD_EITHER, .arg2 = DBG_CMD_NO_ARG, .description = "set break point        " },
1898
	{ .cmd = 'c', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "continue               " },
1899
	{ .cmd = 'd', .argc = 2, .arg1 = DBG_CMD_NUMBER, .arg2 = DBG_CMD_NUMBER, .description = "dump                   " },
1900
	{ .cmd = 'f', .argc = 1, .arg1 = DBG_CMD_EITHER, .arg2 = DBG_CMD_NO_ARG, .description = "save to file           " },
1901
	{ .cmd = 'g', .argc = 1, .arg1 = DBG_CMD_EITHER, .arg2 = DBG_CMD_NO_ARG, .description = "goto address           " },
1902
	{ .cmd = 'h', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "help                   " },
1903
	{ .cmd = 'i', .argc = 1, .arg1 = DBG_CMD_NUMBER, .arg2 = DBG_CMD_NO_ARG, .description = "input (port)           " },
1904
	{ .cmd = 'k', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "list all breakpoints   " },
1905
	{ .cmd = 'l', .argc = 1, .arg1 = DBG_CMD_NUMBER, .arg2 = DBG_CMD_NO_ARG, .description = "set debug level        " },
1906
	{ .cmd = 'o', .argc = 2, .arg1 = DBG_CMD_NUMBER, .arg2 = DBG_CMD_NUMBER, .description = "output (port value)    " },
1907
	{ .cmd = 'p', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "print IO state         " },
1908
	{ .cmd = 'q', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "quit                   " },
1909
	{ .cmd = 'r', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "remove all break points" },
1910
	{ .cmd = 's', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "step                   " },
1911
	{ .cmd = 't', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "toggle tracing         " },
1912
	{ .cmd = 'u', .argc = 2, .arg1 = DBG_CMD_NUMBER, .arg2 = DBG_CMD_NUMBER, .description = "unassemble             " },
1913
	{ .cmd = 'y', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "list symbols           " },
1914
	{ .cmd = 'v', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "print VGA display      " },
1915
	{ .cmd = 'P', .argc = 1, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "push value             " },
1916
	{ .cmd = 'D', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "pop value              " },
1917
	{ .cmd = 'G', .argc = 1, .arg1 = DBG_CMD_EITHER, .arg2 = DBG_CMD_NO_ARG, .description = "call function/location " },
1918
	{ .cmd = '!', .argc = 2, .arg1 = DBG_CMD_NUMBER, .arg2 = DBG_CMD_NUMBER, .description = "set value              " },
1919
	{ .cmd = '.', .argc = 0, .arg1 = DBG_CMD_NO_ARG, .arg2 = DBG_CMD_NO_ARG, .description = "print H2 CPU state     " },
1920
	{ .cmd = -1,  .argc = 0, .arg1 = DBG_CMD_EITHER, .arg2 = DBG_CMD_NO_ARG, .description = NULL },
1921
};
1922

1923
static void debug_command_print_help(FILE *out, const debug_command_t *dc) {
1924
	assert(out);
1925
	assert(dc);
1926

1927
	static const char *debug_help = "\
1928
Debugger Help: \n\n\
1929
Hit 'Escape' when the simulation is and is reading from input to exit \n\
1930
into the back debugger.\n\n\
1931
Command list:\n\n";
1932

1933
	static const char *arg_type[] = {
1934
		[DBG_CMD_NO_ARG] = "             ",
1935
		[DBG_CMD_NUMBER] = "number       ",
1936
		[DBG_CMD_STRING] = "string       ",
1937
		[DBG_CMD_EITHER] = "number/string"
1938
	};
1939
	fputs(debug_help, out);
1940
	for (unsigned i = 0; dc[i].cmd != -1; i++)
1941
		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]);
1942
}
1943

1944
static int debug_command_check(FILE *out, const debug_command_t * const dc, const int cmd, const int argc, const bool is_numeric1, const bool is_numeric2) {
1945
	assert(out);
1946
	assert(dc);
1947
	for (unsigned i = 0; dc[i].cmd != -1 ; i++) {
1948
		if (dc[i].cmd == cmd) {
1949
			if (dc[i].argc != argc) {
1950
				fprintf(out, "command '%c' expects %d arguments, got %d\n", cmd, dc[i].argc, argc);
1951
				return -1;
1952
			}
1953

1954
			if (dc[i].argc == 0)
1955
				return 0;
1956

1957
			if (dc[i].arg1 == DBG_CMD_NUMBER && !is_numeric1) {
1958
				fprintf(out, "command '%c' expects arguments one to be numeric\n", cmd);
1959
				return -1;
1960
			}
1961

1962
			if (dc[i].argc == 1)
1963
				return 0;
1964

1965
			if (dc[i].arg2 == DBG_CMD_NUMBER && !is_numeric2) {
1966
				fprintf(out, "command '%c' expects arguments two to be numeric\n", cmd);
1967
				return -1;
1968
			}
1969

1970
			return 0;
1971
		}
1972
	}
1973
	fprintf(out, "unrecognized command '%c'\n", cmd);
1974
	return -1;
1975
}
1976

1977
static int debug_resolve_symbol(FILE *out, const char *symbol, const symbol_table_t * const symbols, uint16_t * const value) {
1978
	assert(out);
1979
	assert(symbol);
1980
	assert(symbols);
1981
	assert(value);
1982
	*value = 0;
1983
	const symbol_t * const sym = symbol_table_lookup(symbols, symbol);
1984
	if (!sym) {
1985
		fprintf(out, "symbol '%s' not found\n", symbol);
1986
		return -1;
1987
	}
1988
	if (sym->type != SYMBOL_TYPE_LABEL && sym->type != SYMBOL_TYPE_CALL) {
1989
		fprintf(out, "symbol is not call or label\n");
1990
		return -1;
1991
	}
1992
	*value = sym->value;
1993
	return 0;
1994
}
1995

1996
static int h2_debugger(debug_state_t *ds, h2_t *h, h2_io_t *io, symbol_table_t *symbols, const uint16_t point) {
1997
	assert(h);
1998
	assert(ds);
1999

2000
	const bool breaks = break_point_find(&h->bp, point);
2001
	if (breaks)
2002
		fprintf(ds->output, "\n === BREAK(0x%04"PRIx16") ===\n", h->pc);
2003

2004
	if (ds->step || breaks) {
2005
		char line[256];
2006
		char op[256], arg1[256], arg2[256];
2007
		int argc;
2008
		bool is_numeric1, is_numeric2;
2009
		uint16_t num1, num2;
2010

2011
		ds->step = true;
2012

2013
again:
2014
		memset(line, 0, sizeof(line));
2015
		memset(op,   0, sizeof(op));
2016
		memset(arg1, 0, sizeof(arg1));
2017
		memset(arg2, 0, sizeof(arg2));
2018

2019
		fputs(debug_prompt, ds->output);
2020
		if (!fgets(line, sizeof(line), ds->input)) {
2021
			fputs("End Of Input - exiting\n", ds->output);
2022
			return -1;
2023
		}
2024

2025
		argc = sscanf(line, "%255s %255s %255s", op, arg1, arg2);
2026
		if (argc < 1)
2027
			goto again;
2028

2029
		is_numeric1 = number(arg1, &num1, strlen(arg1));
2030
		is_numeric2 = number(arg2, &num2, strlen(arg2));
2031

2032
		if (!(strlen(op) == 1)) {
2033
			fprintf(ds->output, "invalid command '%s'\n", op);
2034
			goto again;
2035
		}
2036

2037
		if (debug_command_check(ds->output, debug_commands, op[0], argc-1, is_numeric1, is_numeric2) < 0)
2038
			goto again;
2039

2040
		switch (op[0]) {
2041
		case ' ':
2042
		case '\t':
2043
		case '\r':
2044
		case '\n':
2045
			break;
2046
		case 'f':
2047
		{
2048
			FILE *o = fopen(arg1, "wb");
2049
			if (!o) {
2050
				fprintf(ds->output, "could not open file '%s 'for writing: %s", arg1, strerror(errno));
2051
				break;
2052
			}
2053
			h2_save(h, o, true);
2054
			fclose(o);
2055
			break;
2056
		}
2057
		case 'd':
2058
			if (((long)num1 + (long)num2) > MAX_CORE)
2059
				fprintf(ds->output, "overflow in RAM dump\n");
2060
			else
2061
				memory_print(ds->output, num1, h->core + num1, num2, true);
2062
			break;
2063
		case 'l':
2064
			if (!is_numeric1) {
2065
				fprintf(ds->output, "set log level expects one numeric argument\n");
2066
				break;
2067
			}
2068
			log_level = num1;
2069
			break;
2070
		case 'b':
2071
			if (!is_numeric1) {
2072
				if (debug_resolve_symbol(ds->output, arg1, symbols, &num1))
2073
					break;
2074
			}
2075
			break_point_add(&h->bp, num1);
2076
			break;
2077

2078
		case 'g':
2079
			if (!is_numeric1) {
2080
				if (debug_resolve_symbol(ds->output, arg1, symbols, &num1))
2081
					break;
2082
			}
2083
			h->pc = num1;
2084
			break;
2085
		case 'G':
2086
			if (!is_numeric1) {
2087
				if (debug_resolve_symbol(ds->output, arg1, symbols, &num1))
2088
					break;
2089
			}
2090
			rpush(h, h->pc);
2091
			h->pc = num1;
2092
			break;
2093
		case '.':
2094
			h2_print(ds->output, h);
2095
			break;
2096

2097
		case '!':
2098
			if (num1 >= MAX_CORE) {
2099
				fprintf(ds->output, "invalid write\n");
2100
				break;
2101
			}
2102
			h->core[num1] = num2;
2103
			break;
2104
		case 'P':
2105
			dpush(h, num1);
2106
			break;
2107
		case 'D':
2108
			fprintf(ds->output, "popped: %04u\n", (unsigned)dpop(h));
2109
			break;
2110

2111
		case 'r':
2112
			free(h->bp.points);
2113
			h->bp.points = NULL;
2114
			h->bp.length = 0;
2115
			break;
2116
		case 'u':
2117
			if (num2 >= MAX_CORE || num1 > num2) {
2118
				fprintf(ds->output, "invalid range\n");
2119
				break;
2120
			}
2121
			for (uint16_t i = num1; i < num2; i++) {
2122
				fprintf(ds->output, "%04"PRIx16 ":\t", i);
2123
				disassemble_instruction(h->core[i], ds->output, symbols, DCM_NONE);
2124
				fputc('\n', ds->output);
2125
			}
2126
			break;
2127

2128
		case 'o':
2129
			if (!io) {
2130
				fprintf(ds->output, "I/O unavailable\n");
2131
				break;
2132
			}
2133
			io->out(io->soc, num1, num2, NULL);
2134

2135
			break;
2136

2137
		case 'i':
2138
			if (!io) {
2139
				fprintf(ds->output, "I/O unavailable\n");
2140
				break;
2141
			}
2142
			fprintf(ds->output, "read: %"PRIx16"\n", io->in(io->soc, num1, NULL));
2143
			break;
2144

2145
		case 'k':
2146
			break_point_print(ds->output, &h->bp);
2147
			break;
2148
		case 'h':
2149
			debug_command_print_help(ds->output, debug_commands);
2150
			break;
2151
		case 's':
2152
			return 0;
2153
		case 'c':
2154
			ds->step = false;
2155
			return 0;
2156
		case 't':
2157
			ds->trace_on = !ds->trace_on;
2158
			fprintf(ds->output, "trace %s\n", ds->trace_on ? "on" : "off");
2159
			break;
2160
		case 'y':
2161
			if (symbols)
2162
				symbol_table_print(symbols, ds->output);
2163
			else
2164
				fprintf(ds->output, "symbol table unavailable\n");
2165
			break;
2166
		case 'v':
2167
			if (!io) {
2168
				fprintf(ds->output, "I/O unavailable\n");
2169
				break;
2170
			}
2171
			for (size_t i = 0; i < VGA_HEIGHT; i++) {
2172
				for (size_t j = 0; j < VGA_WIDTH; j++) {
2173
					unsigned char c = io->soc->vt100.m[i*VGA_WIDTH + j];
2174
					fputc(c < 32 || c > 127 ? '?' : c, ds->output);
2175
				}
2176
				fputc('\n', ds->output);
2177
			}
2178

2179
			break;
2180
		case 'p':
2181
			if (io)
2182
				soc_print(ds->output, io->soc);
2183
			else
2184
				fprintf(ds->output, "I/O unavailable\n");
2185
			break;
2186
		case 'q':
2187
			fprintf(ds->output, "Quiting simulator\n");
2188
			return -1;
2189
		default:
2190
			fprintf(ds->output, "unknown command '%c'\n", op[0]);
2191
		}
2192
		goto again;
2193
	}
2194
	return 0;
2195
}
2196

2197
static uint16_t interrupt_decode(uint8_t *vector) {
2198
	for (unsigned i = 0; i < NUMBER_OF_INTERRUPTS; i++)
2199
		if (*vector & (1u << i)) {
2200
			*vector ^= 1u << i;
2201
			return i;
2202
		}
2203
	return 0;
2204
}
2205

2206
int h2_run(h2_t *h, h2_io_t *io, FILE *output, const unsigned steps, symbol_table_t *symbols, bool run_debugger, FILE *trace) {
2207
	bool turn_debug_on = false;
2208
	assert(h);
2209
	debug_state_t ds = { .input = stdin, .output = stderr, .step = run_debugger, .trace_on = false /*run_debugger*/ };
2210

2211
	if (trace)
2212
		h2_log_csv(trace, h, NULL, true);
2213

2214
	if (run_debugger)
2215
		fputs("Debugger running, type 'h' for a list of command\n", ds.output);
2216

2217
	for (unsigned i = 0; i < steps || steps == 0 || run_debugger; i++) {
2218
		uint16_t instruction,
2219
			 literal,
2220
			 address,
2221
			 pc_plus_one;
2222
		if (log_level >= LOG_DEBUG || ds.trace_on)
2223
		       h2_log_csv(output, h, symbols, false);
2224
		if (trace)
2225
		       h2_log_csv(trace, h, NULL, false);
2226

2227
		if (run_debugger)
2228
			if (h2_debugger(&ds, h, io, symbols, h->pc))
2229
				return 0;
2230

2231
		h->time++;
2232

2233
		if (io) {
2234
			io->update(io->soc);
2235
			if (io->soc->wait)
2236
				continue; /* wait only applies to the H2 core not the rest of the SoC */
2237
		}
2238

2239
		if (h->pc >= MAX_CORE) {
2240
			error("invalid program counter: %04x > %04x", (unsigned)h->pc, MAX_CORE);
2241
			return -1;
2242
		}
2243
		instruction = h->core[h->pc];
2244

2245
		literal = instruction & 0x7FFF;
2246
		address = instruction & 0x1FFF; /* NB. also used for ALU OP */
2247

2248
		if (h->ie && io && io->soc->interrupt) {
2249
			rpush(h, h->pc << 1);
2250
			io->soc->interrupt = false;
2251
			h->pc = interrupt_decode(&io->soc->interrupt_selector);
2252
			continue;
2253
		}
2254

2255
		pc_plus_one = (h->pc + 1) % MAX_CORE;
2256

2257
		/* NB. This is not quite what the hardware is doing, but it should be equivalent */
2258
		/* decode / execute */
2259
		if (IS_LITERAL(instruction)) { /* The hardware actually uses ALU_OP_LITERAL */
2260
			dpush(h, literal);
2261
			h->pc = pc_plus_one;
2262
		} else if (IS_ALU_OP(instruction)) {
2263
			const uint16_t rd  = stack_delta(RSTACK(instruction));
2264
			const uint16_t dd  = stack_delta(DSTACK(instruction));
2265
			const uint16_t nos = h->dstk[h->sp % STK_SIZE];
2266
			uint16_t npc = pc_plus_one;
2267
			uint16_t tos = h->tos;
2268

2269
			if (instruction & R_TO_PC)
2270
				npc = h->rstk[h->rp % STK_SIZE] >> 1;
2271

2272
			switch (ALU_OP(instruction)) {
2273
			case ALU_OP_T:        /* tos = tos; */ break;
2274
			case ALU_OP_N:           tos = nos;    break;
2275
			case ALU_OP_T_PLUS_N:    tos += nos;   break;
2276
			case ALU_OP_T_AND_N:     tos &= nos;   break;
2277
			case ALU_OP_T_OR_N:      tos |= nos;   break;
2278
			case ALU_OP_T_XOR_N:     tos ^= nos;   break;
2279
			case ALU_OP_T_INVERT:    tos = ~tos;   break;
2280
			case ALU_OP_T_EQUAL_N:   tos = -(tos == nos); break;
2281
			case ALU_OP_N_LESS_T:    tos = -((int16_t)nos < (int16_t)tos); break;
2282
			case ALU_OP_N_RSHIFT_T:  tos = nos >> tos; break;
2283
			case ALU_OP_T_DECREMENT: tos--; break;
2284
			case ALU_OP_R:           tos = h->rstk[h->rp % STK_SIZE]; break;
2285
			case ALU_OP_T_LOAD:
2286
				if (h->tos & 0x4000) {
2287
					if (io) {
2288
						if (h->tos & 0x1)
2289
							warning("unaligned register read: %04x", (unsigned)h->tos);
2290
						tos = io->in(io->soc, h->tos & ~0x1, &turn_debug_on);
2291
						if (turn_debug_on) {
2292
							ds.step = true;
2293
							run_debugger = true;
2294
							turn_debug_on = false;
2295
						}
2296
					} else {
2297
						warning("I/O read attempted on addr: %"PRIx16, h->tos);
2298
					}
2299
				} else {
2300
					tos = h->core[(h->tos >> 1) % MAX_CORE];
2301
				}
2302
				break;
2303
			case ALU_OP_N_LSHIFT_T: tos = nos << tos;           break;
2304
			case ALU_OP_DEPTH:      tos = h->sp;                break;
2305
			case ALU_OP_N_ULESS_T:  tos = -(nos < tos);         break;
2306
			case ALU_OP_ENABLE_INTERRUPTS: h->ie = tos & 1; tos = nos; break;
2307
			case ALU_OP_INTERRUPTS_ENABLED: tos = ((1 & h->ie) << 0); break;
2308
			case ALU_OP_RDEPTH:     tos = h->rp;                break;
2309
			case ALU_OP_T_EQUAL_0:  tos = -(tos == 0);          break;
2310
			case ALU_OP_CPU_ID:     tos = H2_CPU_ID_SIMULATION; break;
2311
			case ALU_OP_LITERAL:    tos = instruction & 0x7fffu; break; // This makes more sense in the hardware
2312
			default:
2313
				warning("unknown ALU operation: %u", (unsigned)ALU_OP(instruction));
2314
			}
2315

2316
			h->sp += dd;
2317
			if (h->sp >= STK_SIZE)
2318
				warning("data stack overflow");
2319
			h->sp %= STK_SIZE;
2320

2321
			h->rp += rd;
2322
			if (h->rp >= STK_SIZE)
2323
				warning("return stack overflow");
2324
			h->rp %= STK_SIZE;
2325

2326
			if (instruction & T_TO_R)
2327
				h->rstk[h->rp % STK_SIZE] = h->tos;
2328

2329
			if (instruction & T_TO_N)
2330
				h->dstk[h->sp % STK_SIZE] = h->tos;
2331

2332
			if (instruction & N_TO_ADDR_T) {
2333
				if ((h->tos & 0x4000) && ALU_OP(instruction) != ALU_OP_T_LOAD) {
2334
					if (io) {
2335
						if (h->tos & 0x1)
2336
							warning("unaligned register write: %04x <- %04x", (unsigned)h->tos, (unsigned)nos);
2337
						io->out(io->soc, h->tos & ~0x1, nos, &turn_debug_on);
2338
						if (turn_debug_on) {
2339
							ds.step = true;
2340
							run_debugger = true;
2341
							turn_debug_on = false;
2342
						}
2343
					} else {
2344
						warning("I/O write attempted with addr/value: %"PRIx16 "/%"PRIx16, tos, nos);
2345
					}
2346
				} else {
2347
					h->core[(h->tos >> 1) % MAX_CORE] = nos;
2348
				}
2349
			}
2350

2351
			h->tos = tos;
2352
			h->pc = npc;
2353
		} else if (IS_CALL(instruction)) {
2354
			rpush(h, pc_plus_one << 1);
2355
			h->pc = address;
2356
		} else if (IS_0BRANCH(instruction)) {
2357
			if (!dpop(h))
2358
				h->pc = address % MAX_CORE;
2359
			else
2360
				h->pc = pc_plus_one;
2361
		} else if (IS_BRANCH(instruction)) {
2362
			h->pc = address;
2363
		} else {
2364
			error("invalid instruction: %"PRId16, instruction);
2365
		}
2366

2367
		h->rpm = MAX(h->rpm, h->rp);
2368
		h->spm = MAX(h->spm, h->sp);
2369
	}
2370
	return 0;
2371
}
2372

2373
/* ========================== Simulation And Debugger ====================== */
2374

2375
/* ========================== Main ========================================= */
2376

2377
#ifndef NO_MAIN
2378
typedef enum {
2379
	DEFAULT_COMMAND,
2380
	DISASSEMBLE_COMMAND,
2381
	RUN_COMMAND,
2382
} command_e;
2383

2384
typedef struct {
2385
	command_e cmd;
2386
	long steps;
2387
	bool full_disassembly;
2388
	bool debug_mode;
2389
	bool hacks;
2390
	disassemble_color_method_e dcm;
2391
	const char *nvram;
2392
} command_args_t;
2393

2394
static const char *help = "\
2395
usage ./h2 [-hvdDarRTH] [-sc number] [-L symbol.file] [-S symbol.file] [-e file.fth] (file.hex|file.fth)\n\n\
2396
Brief:     A H2 CPU Assembler, disassembler and Simulator.\n\
2397
Author:    Richard James Howe\n\
2398
Site:      https://github.com/howerj/forth-cpu\n\
2399
License:   MIT\n\
2400
Copyright: Richard James Howe (2017,2018)\n\
2401
Options:\n\n\
2402
\t-\tstop processing options, following arguments are files\n\
2403
\t-h\tprint this help message and exit\n\
2404
\t-v\tincrease logging level\n\
2405
\t-d\tdisassemble input files (default)\n\
2406
\t-D\tfull disassembly of input files\n\
2407
\t-T\tEnter debug mode when running simulation\n\
2408
\t-H\tenable hacks to make the simulation easier to use\n\
2409
\t-r\trun hex file\n\
2410
\t-L #\tload symbol file\n\
2411
\t-S #\tsave symbols to file\n\
2412
\t-s #\tnumber of steps to run simulation (0 = forever)\n\
2413
\t-n #\tspecify nvram file\n\
2414
\t-H #\tenable certain hacks for simulation purposes\n\
2415
\t-c #\tset colorization method for disassembly\n\
2416
\tfile\thex or forth file to process\n\n\
2417
Options must precede any files given, if a file has not been\n\
2418
given as arguments input is taken from stdin. Output is to\n\
2419
stdout. Program returns zero on success, non zero on failure.\n\n\
2420
";
2421

2422
static void debug_note(const command_args_t * const cmd) {
2423
	assert(cmd);
2424
	if (cmd->debug_mode)
2425
		note("entering debug mode");
2426
	else
2427
		note("running for %u cycles (0 = forever)", (unsigned)cmd->steps);
2428
}
2429

2430
static int run_command(const command_args_t * const cmd, FILE *input, FILE *output, symbol_table_t *symbols, uint16_t *vga_initial_contents) {
2431
	assert(input);
2432
	assert(output);
2433
	assert(cmd);
2434
	assert(cmd->nvram);
2435
	int r = 0;
2436

2437
	h2_t *h = h2_new(START_ADDR);
2438
	if (!h)
2439
		return -1;
2440
	if (h2_load(h, input) < 0) {
2441
		h2_free(h);
2442
		return -1;
2443
	}
2444

2445
	h2_io_t * const io = h2_io_new();
2446
	assert(VGA_BUFFER_LENGTH <= VT100_MAX_SIZE);
2447
	for (size_t i = 0; i < VGA_BUFFER_LENGTH; i++) {
2448
		vt100_attribute_t attr;
2449
		memset(&attr, 0, sizeof(attr));
2450
		io->soc->vt100.m[i]   =  vga_initial_contents[i] & 0xff;
2451
		attr.background_color = (vga_initial_contents[i] >> 8)  & 0x7;
2452
		attr.foreground_color = (vga_initial_contents[i] >> 11) & 0x7;
2453
		memcpy(&io->soc->vt100.attributes[i], &attr, sizeof(attr));
2454
	}
2455

2456
	nvram_load_and_transfer(io, cmd->nvram, cmd->hacks);
2457
	h->pc = START_ADDR;
2458
	debug_note(cmd);
2459
	r = h2_run(h, io, output, cmd->steps, symbols, cmd->debug_mode, NULL);
2460
	nvram_save(io, cmd->nvram);
2461

2462
	h2_free(h);
2463
	h2_io_free(io);
2464
	return r;
2465
}
2466

2467
int command(const command_args_t * const cmd, FILE *input, FILE *output, symbol_table_t *symbols, uint16_t *vga_initial_contents) {
2468
	assert(input);
2469
	assert(output);
2470
	assert(cmd);
2471
	assert(vga_initial_contents);
2472
	switch (cmd->cmd) {
2473
	case DEFAULT_COMMAND:      /* fall through */
2474
	case DISASSEMBLE_COMMAND:  return h2_disassemble(cmd->dcm, input, output, symbols);
2475
	case RUN_COMMAND:          return run_command(cmd, input, output, symbols, vga_initial_contents);
2476
	default:                   fatal("invalid command: %d", cmd->cmd);
2477
	}
2478
	return -1;
2479
}
2480

2481
static const char *nvram_file = FLASH_INIT_FILE;
2482

2483
int h2_main(int argc, char **argv) {
2484
	int i;
2485
	const char *optarg = NULL;
2486
	command_args_t cmd;
2487
	symbol_table_t *symbols = NULL;
2488
	FILE *symfile = NULL;
2489
	FILE *input = NULL;
2490
	memset(&cmd, 0, sizeof(cmd));
2491
	cmd.steps = DEFAULT_STEPS;
2492
	cmd.nvram = nvram_file;
2493
	cmd.dcm   = DCM_X11;
2494

2495
	static uint16_t vga_initial_contents[VGA_BUFFER_LENGTH] = { 0 };
2496

2497
	binary(stdin);
2498
	binary(stdout);
2499
	binary(stderr);
2500

2501
	{ /* attempt to load initial contents of VGA memory */
2502
		errno = 0;
2503
		FILE *vga_init = fopen(VGA_INIT_FILE, "rb");
2504
		if (vga_init) {
2505
			memory_load(vga_init, vga_initial_contents, VGA_BUFFER_LENGTH);
2506
			fclose(vga_init);
2507
		} else {
2508
			warning("could not load initial VGA memory file %s: %s", VGA_INIT_FILE, strerror(errno));
2509
		}
2510
	}
2511

2512
	for (i = 1; i < argc && argv[i][0] == '-'; i++) {
2513

2514
		if (strlen(argv[i]) > 2) {
2515
			error("Only one option allowed at a time (got %s)", argv[i]);
2516
			goto fail;
2517
		}
2518

2519
		switch (argv[i][1]) {
2520
		case '\0':
2521
			goto done; /* stop processing options */
2522
		case 'h':
2523
			fprintf(stderr, "%s\n", help);
2524
			return -1;
2525
		case 'v':  /* increase verbosity */
2526
			log_level += log_level < LOG_ALL_MESSAGES ? 1 : 0;
2527
			break;
2528
		case 'D':
2529
			cmd.full_disassembly = true;
2530
			/* fall through */
2531
		case 'd':
2532
			if (cmd.cmd)
2533
				goto fail;
2534
			cmd.cmd = DISASSEMBLE_COMMAND;
2535
			break;
2536
		case 'r':
2537
			if (cmd.cmd)
2538
				goto fail;
2539
			cmd.cmd = RUN_COMMAND;
2540
			break;
2541
		case 'T':
2542
			cmd.debug_mode = true;
2543
			break;
2544
		case 'L':
2545
			if (i >= (argc - 1) || symfile)
2546
				goto fail;
2547
			optarg = argv[++i];
2548
			/* NB. Cannot merge symbol tables */
2549
			symfile = fopen_or_die(optarg, "rb");
2550
			symbols = symbol_table_load(symfile);
2551
			break;
2552
		case 'c':
2553
		{
2554
			long dcm = DCM_NONE;
2555
			if (i >= (argc - 1))
2556
				goto fail;
2557
			optarg = argv[++i];
2558
			if (string_to_long(0, &dcm, optarg))
2559
				goto fail;
2560
			cmd.dcm = dcm;
2561
			if (cmd.dcm >= DCM_MAX_DCM) {
2562
				fprintf(stderr, "Invalid Colorization Method: %u\n", (unsigned)cmd.dcm);
2563
				goto fail;
2564
			}
2565
			break;
2566
		}
2567
		case 's':
2568
			if (i >= (argc - 1))
2569
				goto fail;
2570
			optarg = argv[++i];
2571
			if (string_to_long(0, &cmd.steps, optarg))
2572
				goto fail;
2573
			break;
2574
		case 'n':
2575
			if (i >= (argc - 1))
2576
				goto fail;
2577
			cmd.nvram = argv[++i];
2578
			note("nvram file %s", cmd.nvram);
2579
			break;
2580
		case 'H':
2581
			cmd.hacks = true;
2582
			break;
2583
		default:
2584
		fail:
2585
			fatal("invalid argument '%s'\n%s\n", argv[i], help);
2586
		}
2587
	}
2588
	if (!symbols)
2589
		symbols = symbol_table_new();
2590

2591
done:
2592
	if (i == argc) {
2593
		if (command(&cmd, stdin, stdout, symbols, vga_initial_contents) < 0)
2594
			fatal("failed to process standard input");
2595
		return 0;
2596
	}
2597

2598
	if (i < (argc - 1))
2599
		fatal("more than one file argument given");
2600

2601
	input = fopen_or_die(argv[i], "rb");
2602
	if (command(&cmd, input, stdout, symbols, vga_initial_contents) < 0)
2603
		fatal("failed to process file: %s", argv[i]);
2604
	fclose(input);
2605
	symbol_table_free(symbols);
2606
	if (symfile)
2607
		fclose(symfile);
2608
	return 0;
2609
}
2610

2611
int main(int argc, char **argv) {
2612
	return h2_main(argc, argv);
2613
}
2614
#endif
2615

2616
/* ========================== Main ========================================= */
2617

2618

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.