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

Subversion Repositories forth-cpu

[/] [forth-cpu/] [trunk/] [gui.c] - Blame information for rev 5

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 howe.r.j.8
/**@file      gui.c
2 5 howe.r.j.8
 * @brief     GUI Simulator for the H2 SoC
3
 * @copyright Richard James Howe (2017-2019)
4 3 howe.r.j.8
 * @license   MIT
5 5 howe.r.j.8
 * @note It would have been better to make this in SDL, se
6
 * <https://www.libsdl.org/>.  */
7 3 howe.r.j.8
 
8
#include "h2.h"
9
#include <assert.h>
10
#include <errno.h>
11
#include <ctype.h>
12
#include <stdlib.h>
13
#include <stdio.h>
14
#include <stdbool.h>
15
#include <math.h>
16
#include <string.h>
17
#include <stdint.h>
18
#include <inttypes.h>
19
#include <GL/gl.h>
20
#include <GL/glut.h>
21
#include <GL/freeglut_ext.h> /* for glutStrokeHeight */
22
#include <stdarg.h>
23
 
24 5 howe.r.j.8
#define TRON (0)
25
 
26 3 howe.r.j.8
/* ====================================== Utility Functions ==================================== */
27
 
28
#define PI               (3.1415926535897932384626433832795)
29
#define MAX(X, Y)        ((X) > (Y) ? (X) : (Y))
30
#define MIN(X, Y)        ((X) < (Y) ? (X) : (Y))
31
#define UNUSED(X)        ((void)(X))
32
#define X_MAX            (100.0)
33
#define X_MIN            (0.0)
34
#define Y_MAX            (100.0)
35
#define Y_MIN            (0.0)
36
#define LINE_WIDTH       (0.5)
37
#define CYCLE_MODE_FIXED (false)
38
#define CYCLE_INITIAL    (100000)
39
#define CYCLE_INCREMENT  (10000)
40
#define CYCLE_DECREMENT  (500)
41
#define CYCLE_MINIMUM    (10000)
42
#define CYCLE_HYSTERESIS (2.0)
43
#define TARGET_FPS       (30.0)
44
#define BACKGROUND_ON    (false)
45
#define SIM_HACKS        (true)
46 5 howe.r.j.8
#define TRACE_FILE       ("trace.csv")
47
#define TRACE_BUFFER_LEN (16*4096)
48 3 howe.r.j.8
 
49
typedef struct {
50
        double window_height;
51
        double window_width;
52
        double window_x_starting_position;
53
        double window_y_starting_position;
54
        double window_scale_x;
55
        double window_scale_y;
56 5 howe.r.j.8
        void *font_scaled;
57
        uint64_t cycle_count;
58
        uint64_t cycles;
59 3 howe.r.j.8
        volatile unsigned tick;
60
        unsigned arena_tick_ms;
61 5 howe.r.j.8
        volatile bool halt_simulation;
62 3 howe.r.j.8
        bool use_uart_input;
63
        bool debug_extra;
64
        bool step;
65
        bool debug_mode;
66
} world_t;
67
 
68
static world_t world = {
69
        .window_height               = 800.0,
70
        .window_width                = 800.0,
71
        .window_x_starting_position  = 60.0,
72
        .window_y_starting_position  = 20.0,
73
        .window_scale_x              = 1.0,
74
        .window_scale_y              = 1.0,
75
        .tick                        = 0,
76
        .halt_simulation             = false,
77
        .arena_tick_ms               = 30,
78
        .use_uart_input              = true,
79
        .debug_extra                 = false,
80
        .step                        = false,
81
        .debug_mode                  = false,
82
        .cycle_count                 = 0,
83
        .cycles                      = CYCLE_INITIAL,
84
        .font_scaled                 = GLUT_STROKE_MONO_ROMAN
85
};
86
 
87 5 howe.r.j.8
static FILE *trace_file = NULL; /* NB. !NULL turns tracing on */
88
static char trace_buffer[TRACE_BUFFER_LEN];
89
 
90 3 howe.r.j.8
typedef enum {
91
        TRIANGLE,
92
        SQUARE,
93
        PENTAGON,
94
        HEXAGON,
95
        SEPTAGON,
96
        OCTAGON,
97
        DECAGON,
98
        CIRCLE,
99
        INVALID_SHAPE
100
} shape_e;
101
 
102
typedef shape_e shape_t;
103
 
104
typedef struct {
105
        double x;
106
        double y;
107
} scale_t;
108
 
109
typedef struct {
110
        double x, y;
111
        bool draw_border;
112
        color_t color_text, color_box;
113
        double width, height;
114
} textbox_t;
115
 
116
typedef struct { /**@note it might be worth translating some functions to use points*/
117
        double x, y;
118
} point_t;
119
 
120
 
121
/**@bug not quite correct, arena_tick_ms is what we request, not want the arena
122
 * tick actually is */
123 5 howe.r.j.8
static double seconds_to_ticks(const world_t *world, double s) {
124 3 howe.r.j.8
        assert(world);
125
        return s * (1000. / (double)world->arena_tick_ms);
126
}
127
 
128 5 howe.r.j.8
static double rad2deg(const double rad) {
129 3 howe.r.j.8
        return (rad / (2.0 * PI)) * 360.0;
130
}
131
 
132 5 howe.r.j.8
static void set_color(const color_t color, const bool light) {
133 3 howe.r.j.8
        double ON = light ? 0.8 : 0.4;
134
        static const double OFF = 0.0;
135 5 howe.r.j.8
        switch (color) {      /* RED  GRN  BLU */
136 3 howe.r.j.8
        case WHITE:   glColor3f( ON,  ON,  ON);   break;
137
        case RED:     glColor3f( ON, OFF, OFF);   break;
138
        case YELLOW:  glColor3f( ON,  ON, OFF);   break;
139
        case GREEN:   glColor3f(OFF,  ON, OFF);   break;
140
        case CYAN:    glColor3f(OFF,  ON,  ON);   break;
141
        case BLUE:    glColor3f(OFF, OFF,  ON);   break;
142
        case MAGENTA: glColor3f( ON, OFF,  ON);   break;
143
        case BLACK:   glColor3f(OFF, OFF, OFF);   break;
144
        default:      fatal("invalid color '%d'", color);
145
        }
146
}
147
 
148
/* see: https://www.opengl.org/discussion_boards/showthread.php/160784-Drawing-Circles-in-OpenGL */
149
static void _draw_regular_polygon(
150 5 howe.r.j.8
                const double x, const double y,
151
                const double orientation,
152
                const double radius, const double sides,
153
                const bool lines, const double thickness,
154
                const color_t color) {
155 3 howe.r.j.8
        glMatrixMode(GL_MODELVIEW);
156
        glPushMatrix();
157
                glLoadIdentity();
158
                glTranslatef(x, y, 0.0);
159
                glRotated(rad2deg(orientation), 0, 0, 1);
160
                set_color(color, true);
161 5 howe.r.j.8
                if (lines) {
162 3 howe.r.j.8
                        glLineWidth(thickness);
163
                        glBegin(GL_LINE_LOOP);
164
                } else {
165
                        glBegin(GL_POLYGON);
166
                }
167 5 howe.r.j.8
                        for (double i = 0; i < 2.0 * PI; i += PI / sides)
168 3 howe.r.j.8
                                glVertex3d(cos(i) * radius, sin(i) * radius, 0.0);
169
                glEnd();
170
        glPopMatrix();
171
}
172
 
173 5 howe.r.j.8
static void _draw_rectangle(
174
                const double x, const double y,
175
                const double width, const double height,
176
                const bool lines, const double thickness,
177
                const color_t color) {
178 3 howe.r.j.8
        glMatrixMode(GL_MODELVIEW);
179
        glPushMatrix();
180
                glLoadIdentity();
181
                glRasterPos2d(x, y);
182
                set_color(color, true);
183 5 howe.r.j.8
                if (lines) {
184 3 howe.r.j.8
                        glLineWidth(thickness);
185
                        glBegin(GL_LINE_LOOP);
186
                } else {
187
                        glBegin(GL_POLYGON);
188
                }
189
                glVertex3d(x,       y,        0);
190
                glVertex3d(x+width, y,        0);
191
                glVertex3d(x+width, y+height, 0);
192
                glVertex3d(x,       y+height, 0);
193
                glEnd();
194
        glPopMatrix();
195
}
196
 
197 5 howe.r.j.8
static void draw_rectangle_filled(const double x, const double y, const double width, const double height, const color_t color) {
198
        _draw_rectangle(x, y, width, height, false, 0, color);
199 3 howe.r.j.8
}
200
 
201 5 howe.r.j.8
static void draw_rectangle_line(const double x, const double y, const double width, const double height, const double thickness, const color_t color) {
202
        _draw_rectangle(x, y, width, height, true, thickness, color);
203 3 howe.r.j.8
}
204
 
205 5 howe.r.j.8
static double shape_to_sides(shape_t shape) {
206 3 howe.r.j.8
        static const double sides[] =
207
        {
208
                [TRIANGLE] = 1.5,
209
                [SQUARE]   = 2,
210
                [PENTAGON] = 2.5,
211
                [HEXAGON]  = 3,
212
                [SEPTAGON] = 3.5,
213
                [OCTAGON]  = 4,
214
                [DECAGON]  = 5,
215
                [CIRCLE]   = 24
216
        };
217 5 howe.r.j.8
        if (shape >= INVALID_SHAPE)
218 3 howe.r.j.8
                fatal("invalid shape '%d'", shape);
219
        return sides[shape % INVALID_SHAPE];
220
}
221
 
222 5 howe.r.j.8
static void draw_regular_polygon_filled(const double x, const double y, const double orientation, const double radius, const shape_t shape, const color_t color) {
223
        _draw_regular_polygon(x, y, orientation, radius, shape_to_sides(shape), false, 0, color);
224 3 howe.r.j.8
}
225
 
226 5 howe.r.j.8
static void draw_regular_polygon_line(const double x, const double y, const double orientation, const double radius, const shape_t shape, const double thickness, const color_t color) {
227
        _draw_regular_polygon(x, y, orientation, radius, shape_to_sides(shape), true, thickness, color);
228 3 howe.r.j.8
}
229
 
230 5 howe.r.j.8
static void draw_char(uint8_t c) {
231 3 howe.r.j.8
        c = c >= 32 && c <= 127 ? c : '?';
232
        glutStrokeCharacter(world.font_scaled, c);
233
}
234
 
235
/* see: https://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Text_Rendering_01
236
 *      https://stackoverflow.com/questions/538661/how-do-i-draw-text-with-glut-opengl-in-c
237
 *      https://stackoverflow.com/questions/20866508/using-glut-to-simply-print-text */
238 5 howe.r.j.8
static int draw_block(const uint8_t *msg, const size_t len) {
239 3 howe.r.j.8
        assert(msg);
240 5 howe.r.j.8
        for (size_t i = 0; i < len; i++)
241 3 howe.r.j.8
                draw_char(msg[i]);
242
        return len;
243
}
244
 
245 5 howe.r.j.8
static int draw_string(const char *msg) {
246 3 howe.r.j.8
        assert(msg);
247
        return draw_block((uint8_t*)msg, strlen(msg));
248
}
249
 
250 5 howe.r.j.8
static scale_t font_attributes(void) {
251
        static bool initialized = false;  // @warning static!
252
        static scale_t scale = { 0., 0.}; // @warning static!
253
        if (initialized)
254 3 howe.r.j.8
                return scale;
255
        scale.y = glutStrokeHeight(world.font_scaled);
256
        scale.x = glutStrokeWidth(world.font_scaled, 'M');
257
        initialized = true;
258
        return scale;
259
}
260
 
261 5 howe.r.j.8
static void draw_vt100_char(
262
                const double x, const double y,
263
                const double scale_x, const double scale_y,
264
                const double orientation, const uint8_t c,
265
                const vt100_attribute_t *attr, const bool blink) {
266
        assert(attr);
267 3 howe.r.j.8
        /*scale_t scale = font_attributes();
268
        double char_width  = scale.x / X_MAX;
269
        double char_height = scale.y / Y_MAX;*/
270
 
271 5 howe.r.j.8
        if (blink && attr->blink)
272 3 howe.r.j.8
                return;
273
 
274
        glMatrixMode(GL_MODELVIEW);
275
        glPushMatrix();
276
                glLoadIdentity();
277
                glTranslatef(x, y, 0.0);
278
                glScaled(scale_x, scale_y, 1.0);
279
                glRotated(rad2deg(orientation), 0, 0, 1);
280
                set_color(attr->foreground_color, attr->bold);
281
                draw_char(attr->conceal ? '*' : c);
282
                glEnd();
283
        glPopMatrix();
284 5 howe.r.j.8
        if (BACKGROUND_ON)
285 3 howe.r.j.8
                draw_rectangle_filled(x, y, 1.20, 1.55, attr->background_color);
286
}
287
 
288 5 howe.r.j.8
static int draw_vt100_block(
289
                const double x, const double y,
290
                const double scale_x, const double scale_y,
291
                const double orientation, const uint8_t *msg,
292
                const size_t len, const vt100_attribute_t * const attr, const bool blink) {
293
        assert(attr);
294
        const scale_t scale = font_attributes();
295
        const double char_width = (scale.x / X_MAX)*1.1;
296
        for (size_t i = 0; i < len; i++)
297 3 howe.r.j.8
                draw_vt100_char(x+char_width*i, y, scale_x, scale_y, orientation, msg[i], &attr[i], blink);
298
        return len;
299
}
300
 
301 5 howe.r.j.8
static int draw_block_scaled(
302
                const double x, const double y,
303
                const double scale_x, const double scale_y,
304
                const double orientation, const uint8_t *msg, const size_t len, const color_t color) {
305 3 howe.r.j.8
        assert(msg);
306
        glMatrixMode(GL_MODELVIEW);
307
        glPushMatrix();
308
                glLoadIdentity();
309
                glTranslatef(x, y, 0.0);
310
                glScaled(scale_x, scale_y, 1.0);
311
                glRotated(rad2deg(orientation), 0, 0, 1);
312
                set_color(color, true);
313 5 howe.r.j.8
                for (size_t i = 0; i < len; i++) {
314 3 howe.r.j.8
                        uint8_t c = msg[i];
315
                        c = c >= 32 && c <= 127 ? c : '?';
316
                        glutStrokeCharacter(world.font_scaled, c);
317
                }
318
                glEnd();
319
        glPopMatrix();
320
        return len;
321
}
322
 
323 5 howe.r.j.8
static int draw_string_scaled(
324
                const double x, const double y,
325
                const double scale_x, const double scale_y,
326
                const double orientation, const char *msg, const color_t color) {
327 3 howe.r.j.8
        assert(msg);
328
        return draw_block_scaled(x, y, scale_x, scale_y, orientation, (uint8_t*)msg, strlen(msg), color);
329
}
330
 
331 5 howe.r.j.8
static int vdraw_text(const color_t color, const double x, const double y, const char *fmt, va_list ap) {
332 3 howe.r.j.8
        int r = 0;
333
        assert(fmt);
334
        static const double scale_x = 0.011;
335
        static const double scale_y = 0.011;
336
 
337
        glMatrixMode(GL_MODELVIEW);
338
        glPushMatrix();
339
        set_color(color, true);
340
        glTranslatef(x, y, 0);
341
        glScaled(scale_x, scale_y, 1.0);
342 5 howe.r.j.8
        while (*fmt) {
343
                char f = *fmt++;
344
                if ('%' != f) {
345 3 howe.r.j.8
                        glutStrokeCharacter(world.font_scaled, f);
346
                        r++;
347
                        continue;
348
                }
349 5 howe.r.j.8
                switch ((f = *fmt++)) {
350 3 howe.r.j.8
                case 'c':
351
                {
352
                        char x[2] = {0, 0};
353
                        x[0] = va_arg(ap, int);
354
                        r += draw_string(x);
355
                        break;
356
                }
357
                case 's':
358
                {
359
                        char *s = va_arg(ap, char*);
360
                        r += draw_string(s);
361
                        break;
362
                }
363
                case 'x':
364
                {
365 5 howe.r.j.8
                        const unsigned d = va_arg(ap, unsigned);
366 3 howe.r.j.8
                        char s[64] = {0};
367
                        sprintf(s, "%04x", d);
368
                        r += draw_string(s);
369
                        break;
370
                }
371
                case 'u':
372
                case 'd':
373
                {
374 5 howe.r.j.8
                        const int d = va_arg(ap, int);
375 3 howe.r.j.8
                        char s[64] = {0};
376
                        sprintf(s, f == 'u' ? "%u": "%d", d);
377
                        r += draw_string(s);
378
                        break;
379
                }
380
                case 'f':
381
                {
382 5 howe.r.j.8
                        const double f = va_arg(ap, double);
383 3 howe.r.j.8
                        char s[512] = {0};
384
                        sprintf(s, "%.2f", f);
385
                        r += draw_string(s);
386
                        break;
387
                }
388
                case 0:
389
                default:
390
                        fatal("invalid format specifier '%c'", f);
391
                }
392
 
393
        }
394
        glPopMatrix();
395
        return r;
396
}
397
 
398 5 howe.r.j.8
static void fill_textbox(textbox_t *t, const char *fmt, ...) {
399 3 howe.r.j.8
        va_list ap;
400
        assert(t);
401
        assert(fmt);
402
 
403
        scale_t scale = font_attributes();
404 5 howe.r.j.8
        const double char_width = scale.x / X_MAX;
405
        const double char_height = scale.y / Y_MAX;
406 3 howe.r.j.8
        assert(t && fmt);
407
        va_start(ap, fmt);
408 5 howe.r.j.8
        double r = vdraw_text(t->color_text, t->x, t->y - t->height, fmt, ap);
409 3 howe.r.j.8
        r *= char_width * 1.11;
410
        r += 1;
411
        va_end(ap);
412
        t->width = MAX(t->width, r);
413
        t->height += (char_height); /*correct?*/
414
}
415
 
416 5 howe.r.j.8
static void draw_textbox(textbox_t *t) {
417 3 howe.r.j.8
        assert(t);
418
        scale_t scale = font_attributes();
419 5 howe.r.j.8
        const double char_height = scale.y / Y_MAX;
420
        if (!(t->draw_border))
421 3 howe.r.j.8
                return;
422
        draw_rectangle_line(t->x - LINE_WIDTH, t->y - t->height + char_height - 1, t->width, t->height + 1, LINE_WIDTH, t->color_box);
423
}
424
 
425
static bool detect_circle_circle_collision(
426 5 howe.r.j.8
                const double ax, const double ay, const double aradius,
427
                const double bx, const double by, const double bradius) {
428
        const double dx = ax - bx;
429
        const double dy = ay - by;
430
        const double distance = hypot(dx, dy);
431
        return distance < (aradius + bradius);
432 3 howe.r.j.8
}
433
 
434
/* ====================================== Utility Functions ==================================== */
435
 
436
/* ====================================== Simulator Objects ==================================== */
437
 
438
typedef struct {
439
        double x;
440
        double y;
441
        double angle;
442
        double radius;
443
        bool on;
444
} led_t;
445
 
446 5 howe.r.j.8
static void draw_led(const led_t * const l) {
447 3 howe.r.j.8
        assert(l);
448 5 howe.r.j.8
        const double msz = l->radius * 0.75;
449
        const double off = (l->radius - msz) / 2.0;
450
        draw_rectangle_filled(l->x + off, l->y + off, msz, msz, l->on ? GREEN : RED);
451 3 howe.r.j.8
        draw_rectangle_filled(l->x, l->y, l->radius, l->radius, BLUE);
452
}
453
 
454
typedef struct {
455
        double x;
456
        double y;
457
        double angle;
458
        double radius;
459
        bool on;
460
} switch_t;
461
 
462 5 howe.r.j.8
static void draw_switch(const switch_t * const s) {
463 3 howe.r.j.8
        assert(s);
464 5 howe.r.j.8
        const double msz = s->radius * 0.6;
465
        const double off = (s->radius - msz) / 2.0;
466
        draw_rectangle_filled(s->x + off, s->on ? (s->y + s->radius) - off : s->y+off, msz, msz, s->on ? GREEN : RED);
467
        draw_rectangle_filled(s->x + off, s->y + off, msz, msz * 2., BLACK);
468 3 howe.r.j.8
        draw_rectangle_filled(s->x, s->y, s->radius, s->radius * 2, BLUE);
469
}
470
 
471
typedef enum {
472
        LED_SEGMENT_A,
473
        LED_SEGMENT_B,
474
        LED_SEGMENT_C,
475
        LED_SEGMENT_D,
476
        LED_SEGMENT_E,
477
        LED_SEGMENT_F,
478
        LED_SEGMENT_G,
479
        LED_SEGMENT_DP,
480
} led_segment_e;
481
 
482
typedef struct {
483
        double x;
484
        double y;
485
        /*double angle;*/
486
        double width;
487
        double height;
488
        uint8_t segment;
489
} led_8_segment_t;
490
 
491 5 howe.r.j.8
static uint8_t convert_to_segments(const uint8_t segment) {
492 3 howe.r.j.8
        static const uint8_t c2s[16] = {
493
                0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07,
494
                0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71
495
        };
496
        return c2s[segment & 0xf];
497
}
498
 
499
#define SEG_CLR(SG,BIT) (((SG) & (1 << BIT)) ? RED : BLACK)
500
 
501 5 howe.r.j.8
static void draw_led_8_segment(const led_8_segment_t * const l) {
502 3 howe.r.j.8
        assert(l);
503 5 howe.r.j.8
        const uint8_t sgs = convert_to_segments(l->segment);
504 3 howe.r.j.8
 
505
        draw_rectangle_filled(l->x + l->width * 0.20, l->y + l->height * 0.45, l->width * 0.5, l->height * 0.1, SEG_CLR(sgs, LED_SEGMENT_G)); /* Center */
506
        draw_rectangle_filled(l->x + l->width * 0.20, l->y + l->height * 0.1,  l->width * 0.5, l->height * 0.1, SEG_CLR(sgs, LED_SEGMENT_D)); /* Bottom */
507
        draw_rectangle_filled(l->x + l->width * 0.20, l->y + l->height * 0.8,  l->width * 0.5, l->height * 0.1, SEG_CLR(sgs, LED_SEGMENT_A)); /* Top */
508
 
509
        draw_rectangle_filled(l->x + l->width * 0.05, l->y + l->height * 0.15, l->width * 0.1, l->height * 0.3, SEG_CLR(sgs, LED_SEGMENT_E)); /* Bottom Left */
510
        draw_rectangle_filled(l->x + l->width * 0.75, l->y + l->height * 0.15, l->width * 0.1, l->height * 0.3, SEG_CLR(sgs, LED_SEGMENT_C)); /* Bottom Right */
511
 
512
        draw_rectangle_filled(l->x + l->width * 0.05, l->y + l->height * 0.50, l->width * 0.1, l->height * 0.3, SEG_CLR(sgs, LED_SEGMENT_F)); /* Top Left */
513
        draw_rectangle_filled(l->x + l->width * 0.75, l->y + l->height * 0.50, l->width * 0.1, l->height * 0.3, SEG_CLR(sgs, LED_SEGMENT_B)); /* Top Right */
514
 
515
        draw_regular_polygon_filled(l->x + l->width * 0.9, l->y + l->height * 0.07, 0.0, sqrt(l->width*l->height)*.06, CIRCLE, SEG_CLR(sgs, LED_SEGMENT_DP));
516
 
517
        draw_rectangle_filled(l->x, l->y, l->width, l->height, WHITE);
518
}
519
 
520
typedef struct {
521
        double x;
522
        double y;
523
        double angle;
524
        double radius;
525
 
526
        bool up;
527
        bool down;
528
        bool left;
529
        bool right;
530
        bool center;
531
} dpad_t;
532
 
533 5 howe.r.j.8
static void draw_dpad(const dpad_t * const d) {
534
        assert(d);
535 3 howe.r.j.8
        draw_regular_polygon_filled(d->x + (d->radius*2.0), d->y,                   d->angle,            d->radius, TRIANGLE, d->right  ? GREEN : RED);
536
        draw_regular_polygon_filled(d->x - (d->radius*2.0), d->y,                   d->angle + (PI/3.0), d->radius, TRIANGLE, d->left   ? GREEN : RED);
537
        draw_regular_polygon_filled(d->x,                   d->y - (d->radius*2.0), d->angle - (PI/2.0), d->radius, TRIANGLE, d->down   ? GREEN : RED);
538
        draw_regular_polygon_filled(d->x,                   d->y + (d->radius*2.0), d->angle + (PI/2.0), d->radius, TRIANGLE, d->up     ? GREEN : RED);
539
        draw_regular_polygon_filled(d->x,                   d->y,                   d->angle,            d->radius, CIRCLE,   d->center ? GREEN : RED);
540
 
541
        draw_regular_polygon_line(d->x, d->y, d->angle, d->radius * 3.1, CIRCLE, LINE_WIDTH, WHITE);
542
}
543
 
544
typedef enum {
545
        DPAN_COL_NONE,
546
        DPAN_COL_RIGHT,
547
        DPAN_COL_LEFT,
548
        DPAN_COL_DOWN,
549
        DPAN_COL_UP,
550
        DPAN_COL_CENTER
551
} dpad_collision_e;
552
 
553 5 howe.r.j.8
static dpad_collision_e dpad_collision(const dpad_t * const d, const double x, const double y, const double radius) {
554
        assert(d);
555
        if (detect_circle_circle_collision(x, y, radius, d->x + (d->radius*2.0), d->y,                   d->radius))
556 3 howe.r.j.8
                return DPAN_COL_RIGHT;
557 5 howe.r.j.8
        if (detect_circle_circle_collision(x, y, radius, d->x - (d->radius*2.0), d->y,                   d->radius))
558 3 howe.r.j.8
                return DPAN_COL_LEFT;
559 5 howe.r.j.8
        if (detect_circle_circle_collision(x, y, radius, d->x,                   d->y + (d->radius*2.0), d->radius))
560 3 howe.r.j.8
                return DPAN_COL_UP;
561 5 howe.r.j.8
        if (detect_circle_circle_collision(x, y, radius, d->x,                   d->y - (d->radius*2.0), d->radius))
562 3 howe.r.j.8
                return DPAN_COL_DOWN;
563 5 howe.r.j.8
        if (detect_circle_circle_collision(x, y, radius, d->x,                   d->y,                   d->radius))
564 3 howe.r.j.8
                return DPAN_COL_CENTER;
565
        return DPAN_COL_NONE;
566
}
567
 
568
#define TERMINAL_WIDTH       (80)
569
#define TERMINAL_HEIGHT      (10)
570
#define TERMINAL_SIZE        (TERMINAL_WIDTH*TERMINAL_HEIGHT)
571
 
572
typedef struct {
573
        unsigned width;
574
        unsigned height;
575
        GLuint name;
576
        uint8_t *image;
577
} vt100_background_texture_t;
578
 
579
typedef struct {
580
        uint64_t blink_count;
581
        double x;
582
        double y;
583
        bool blink_on;
584
        color_t color;
585
        vt100_t vt100;
586
        vt100_background_texture_t *texture;
587
} terminal_t;
588
 
589 5 howe.r.j.8
static void texture_background(const terminal_t * const t) {
590 3 howe.r.j.8
        assert(t);
591 5 howe.r.j.8
        const vt100_background_texture_t *v = t->texture;
592
        const vt100_t *vt = &t->vt100;
593
        uint8_t *const img = v->image;
594 3 howe.r.j.8
        const unsigned h = v->height;
595
        const unsigned w = v->width;
596
 
597 5 howe.r.j.8
        for (unsigned i = 0; i < h; i++) {
598
                uint8_t * const row = &img[i * 4];
599
                const unsigned ii = ((h - i - 1) * vt->height) / h;
600
                for (unsigned j = 0; j < w; j++) {
601
                        uint8_t * const column = &row[j * h * 4];
602
                        const unsigned jj = (vt->width * j) / w;
603
                        const unsigned idx = jj + (ii * vt->width);
604 3 howe.r.j.8
                        column[0] = 255 * (vt->attributes[idx].background_color & 1);
605
                        column[1] = 255 * (vt->attributes[idx].background_color & 2);
606
                        column[2] = 255 * (vt->attributes[idx].background_color & 4);
607
                        column[3] = 255;
608
                }
609
        }
610
}
611
 
612
/* See <http://www.glprogramming.com/red/chapter09.html> */
613 5 howe.r.j.8
static void draw_texture(const terminal_t * const t, const bool update) {
614
        assert(t);
615 3 howe.r.j.8
        vt100_background_texture_t *v = t->texture;
616 5 howe.r.j.8
        if (!v)
617 3 howe.r.j.8
                return;
618
 
619 5 howe.r.j.8
        const scale_t scale = font_attributes();
620
        const double char_width  = scale.x / X_MAX;
621
        const double char_height = scale.y / Y_MAX;
622
        const double x = t->x;
623
        const double y = t->y - (char_height * (t->vt100.height-1.0));
624
        const double width  = char_width  * t->vt100.width * 1.10;
625
        const double height = char_height * t->vt100.height;
626 3 howe.r.j.8
 
627
        glEnable(GL_TEXTURE_2D);
628
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
629
 
630 5 howe.r.j.8
        if (update) {
631 3 howe.r.j.8
                glClearColor (0.0, 0.0, 0.0, 0.0);
632
                glShadeModel(GL_FLAT);
633
                glEnable(GL_DEPTH_TEST);
634
 
635
                texture_background(t);
636
                glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
637
 
638
                glGenTextures(1, &v->name);
639
                glBindTexture(GL_TEXTURE_2D, v->name);
640
 
641
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
642
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
643
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
644
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
645
                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, v->width, v->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, v->image);
646
        }
647
 
648
        glBindTexture(GL_TEXTURE_2D, v->name);
649
        glMatrixMode(GL_MODELVIEW);
650
        glBegin(GL_QUADS);
651
                glTexCoord2f(1.0, 0.0); glVertex3f(x,       y+height, 0.0);
652
                glTexCoord2f(1.0, 1.0); glVertex3f(x+width, y+height, 0.0);
653
                glTexCoord2f(0.0, 1.0); glVertex3f(x+width, y,        0.0);
654
                glTexCoord2f(0.0, 0.0); glVertex3f(x,       y,        0.0);
655
        glEnd();
656
        glDisable(GL_TEXTURE_2D);
657
}
658
 
659 5 howe.r.j.8
void draw_terminal(const world_t *world, terminal_t *t, const char * const name) {
660 3 howe.r.j.8
        assert(world);
661
        assert(t);
662
        glMatrixMode(GL_MODELVIEW);
663
        glPushMatrix();
664
 
665
        static const double scale_x = 0.011;
666
        static const double scale_y = 0.011;
667 5 howe.r.j.8
        const vt100_t * const v = &t->vt100;
668
        const scale_t scale = font_attributes();
669
        const double now = world->tick - t->blink_count;
670
        const double char_width  = scale.x / X_MAX;
671
        const double char_height = scale.y / Y_MAX;
672
        const size_t cursor_x = v->cursor % v->width;
673
        const size_t cursor_y = v->cursor / v->width;
674 3 howe.r.j.8
 
675 5 howe.r.j.8
        if (now > seconds_to_ticks(world, 1.0)) {
676 3 howe.r.j.8
                t->blink_on = !(t->blink_on);
677
                t->blink_count = world->tick;
678
        }
679
 
680
        /**@note the cursor is deliberately in a different position compared to draw_vga(), due to how the VGA cursor behaves in hardware */
681 5 howe.r.j.8
        if ((!(v->blinks) || t->blink_on) && v->cursor_on) /* fudge factor of 1.10? */
682 3 howe.r.j.8
                draw_rectangle_filled(t->x + (char_width * 1.10 * (cursor_x)) , t->y - (char_height * cursor_y), char_width, char_height, WHITE);
683
 
684
 
685 5 howe.r.j.8
        for (size_t i = 0; i < t->vt100.height; i++)
686 3 howe.r.j.8
                draw_vt100_block(t->x, t->y - ((double)i * char_height), scale_x, scale_y, 0, v->m + (i*v->width), v->width, v->attributes + (i*v->width), t->blink_on);
687
        draw_string_scaled(t->x, t->y - (v->height * char_height), scale_x, scale_y, 0, name, t->color);
688
 
689
        /* fudge factor = 1/((1/scale_x)/X_MAX) ??? */
690
 
691
        glPopMatrix();
692
 
693
        draw_rectangle_line(t->x, t->y - (char_height * (v->height-1.0)), char_width * v->width * 1.10, char_height * v->height, LINE_WIDTH, t->color);
694
}
695
 
696
/* ====================================== Simulator Objects ==================================== */
697
 
698
/* ====================================== Simulator Instances ================================== */
699
 
700
#define SWITCHES_X       (10.0)
701
#define SWITCHES_SPACING (0.6)
702
#define SWITCHES_Y       (5.0)
703
#define SWITCHES_ANGLE   (0.0)
704
#define SWITCHES_RADIUS  (2.0)
705
#define SWITCHES_COUNT   (8)
706
 
707
static switch_t switches[SWITCHES_COUNT] = {
708
        { .x = SWITCHES_X * SWITCHES_SPACING * 8.0, .y = SWITCHES_Y, .angle = SWITCHES_ANGLE, .radius = SWITCHES_RADIUS, .on = false },
709
        { .x = SWITCHES_X * SWITCHES_SPACING * 7.0, .y = SWITCHES_Y, .angle = SWITCHES_ANGLE, .radius = SWITCHES_RADIUS, .on = false },
710
        { .x = SWITCHES_X * SWITCHES_SPACING * 6.0, .y = SWITCHES_Y, .angle = SWITCHES_ANGLE, .radius = SWITCHES_RADIUS, .on = false },
711
        { .x = SWITCHES_X * SWITCHES_SPACING * 5.0, .y = SWITCHES_Y, .angle = SWITCHES_ANGLE, .radius = SWITCHES_RADIUS, .on = false },
712
        { .x = SWITCHES_X * SWITCHES_SPACING * 4.0, .y = SWITCHES_Y, .angle = SWITCHES_ANGLE, .radius = SWITCHES_RADIUS, .on = false },
713
        { .x = SWITCHES_X * SWITCHES_SPACING * 3.0, .y = SWITCHES_Y, .angle = SWITCHES_ANGLE, .radius = SWITCHES_RADIUS, .on = false },
714
        { .x = SWITCHES_X * SWITCHES_SPACING * 2.0, .y = SWITCHES_Y, .angle = SWITCHES_ANGLE, .radius = SWITCHES_RADIUS, .on = false },
715
        { .x = SWITCHES_X * SWITCHES_SPACING * 1.0, .y = SWITCHES_Y, .angle = SWITCHES_ANGLE, .radius = SWITCHES_RADIUS, .on = false },
716
};
717
 
718
#define LEDS_X       (10.0)
719
#define LEDS_SPACING (0.6)
720
#define LEDS_Y       (10.0)
721
#define LEDS_ANGLE   (0.0)
722
#define LEDS_RADIUS  (2.0)
723
#define LEDS_COUNT   (8)
724
 
725
static led_t leds[LEDS_COUNT] = {
726
        { .x = LEDS_X * LEDS_SPACING * 8.0, .y = LEDS_Y, .angle = LEDS_ANGLE, .radius = LEDS_RADIUS, .on = false },
727
        { .x = LEDS_X * LEDS_SPACING * 7.0, .y = LEDS_Y, .angle = LEDS_ANGLE, .radius = LEDS_RADIUS, .on = false },
728
        { .x = LEDS_X * LEDS_SPACING * 6.0, .y = LEDS_Y, .angle = LEDS_ANGLE, .radius = LEDS_RADIUS, .on = false },
729
        { .x = LEDS_X * LEDS_SPACING * 5.0, .y = LEDS_Y, .angle = LEDS_ANGLE, .radius = LEDS_RADIUS, .on = false },
730
 
731
        { .x = LEDS_X * LEDS_SPACING * 4.0, .y = LEDS_Y, .angle = LEDS_ANGLE, .radius = LEDS_RADIUS, .on = false },
732
        { .x = LEDS_X * LEDS_SPACING * 3.0, .y = LEDS_Y, .angle = LEDS_ANGLE, .radius = LEDS_RADIUS, .on = false },
733
        { .x = LEDS_X * LEDS_SPACING * 2.0, .y = LEDS_Y, .angle = LEDS_ANGLE, .radius = LEDS_RADIUS, .on = false },
734
        { .x = LEDS_X * LEDS_SPACING * 1.0, .y = LEDS_Y, .angle = LEDS_ANGLE, .radius = LEDS_RADIUS, .on = false },
735
};
736
 
737
static dpad_t dpad = {
738
        .x       =  X_MAX - 8.0,
739
        .y       =  Y_MIN + 8.0,
740
        .angle   =  0.0,
741
        .radius  =  2.0,
742
        .up      =  false,
743
        .down    =  false,
744
        .left    =  false,
745
        .right   =  false,
746
        .center  =  false,
747
};
748
 
749
#define VGA_TEXTURE_WIDTH  (256)
750
#define VGA_TEXTURE_HEIGHT (256)
751
static uint8_t vga_background_image[VGA_TEXTURE_WIDTH*VGA_TEXTURE_HEIGHT*4];
752
 
753
static vt100_background_texture_t vga_background_texture = {
754
        .width  = VGA_TEXTURE_WIDTH,
755
        .height = VGA_TEXTURE_HEIGHT,
756
        .name   = 0,
757
        .image  = (uint8_t*)vga_background_image
758
};
759
 
760
static terminal_t vga_terminal = {
761
        .blink_count = 0,
762
        .x           = X_MIN + 2.0,
763
        .y           = Y_MAX - 8.0,
764
        .color       = GREEN,  /* WHITE */
765
        .blink_on    = false,
766
 
767
        .vt100  = {
768
                .width        = VGA_WIDTH,
769
                .height       = VGA_HEIGHT,
770
                .size         = VGA_WIDTH * VGA_HEIGHT,
771
                .cursor       = 0,
772
                .cursor_saved = 0,
773
                .state        = TERMINAL_NORMAL_MODE,
774
                .cursor_on    = true,
775
                .blinks       = false,
776
                .n1           = 1,
777
                .n2           = 1,
778
                .m            = { 0 },
779
                .attribute    = { 0 },
780
                .attributes   = { { 0 } },
781
        },
782
        .texture = &vga_background_texture
783
};
784
 
785
#define SEGMENT_COUNT   (4)
786
#define SEGMENT_SPACING (1.1)
787
#define SEGMENT_X       (50)
788
#define SEGMENT_Y       (3)
789
#define SEGMENT_WIDTH   (6)
790
#define SEGMENT_HEIGHT  (8)
791
 
792
static led_8_segment_t segments[SEGMENT_COUNT] = {
793
        { .x = SEGMENT_X + (SEGMENT_SPACING * SEGMENT_WIDTH * 1.0), .y = SEGMENT_Y, .width = SEGMENT_WIDTH, .height = SEGMENT_HEIGHT, .segment = 0 },
794
        { .x = SEGMENT_X + (SEGMENT_SPACING * SEGMENT_WIDTH * 2.0), .y = SEGMENT_Y, .width = SEGMENT_WIDTH, .height = SEGMENT_HEIGHT, .segment = 0 },
795
        { .x = SEGMENT_X + (SEGMENT_SPACING * SEGMENT_WIDTH * 3.0), .y = SEGMENT_Y, .width = SEGMENT_WIDTH, .height = SEGMENT_HEIGHT, .segment = 0 },
796
        { .x = SEGMENT_X + (SEGMENT_SPACING * SEGMENT_WIDTH * 4.0), .y = SEGMENT_Y, .width = SEGMENT_WIDTH, .height = SEGMENT_HEIGHT, .segment = 0 },
797
};
798
 
799
#define UART_TEXTURE_WIDTH  (256)
800
#define UART_TEXTURE_HEIGHT (256)
801
static uint8_t uart_background_image[UART_TEXTURE_WIDTH*UART_TEXTURE_HEIGHT*4];
802
 
803
static vt100_background_texture_t uart_background_texture = {
804
        .width  = UART_TEXTURE_WIDTH,
805
        .height = UART_TEXTURE_HEIGHT,
806
        .name   = 0,
807
        .image  = (uint8_t*)uart_background_image
808
};
809
 
810
static terminal_t uart_terminal = {
811
        .blink_count = 0,
812
        .x           = X_MIN + 2.0,
813
        .y           = Y_MIN + 28.5,
814
        .color       = BLUE,
815
        .blink_on    = false,
816
 
817
        .vt100 = {
818
                .width        = TERMINAL_WIDTH,
819
                .height       = TERMINAL_HEIGHT,
820
                .size         = TERMINAL_SIZE,
821
                .cursor       = 0,
822
                .cursor_saved = 0,
823
                .state        = TERMINAL_NORMAL_MODE,
824
                .cursor_on    = true,
825
                .n1           = 1,
826
                .n2           = 1,
827
                .blinks      = false,
828
                .m            = { 0 },
829
                .attribute    = { 0 },
830
                .attributes   = { { 0 } },
831
        },
832
        .texture = &uart_background_texture
833
};
834
 
835
static h2_t *h = NULL;
836
static h2_io_t *h2_io = NULL;
837
static fifo_t *uart_rx_fifo = NULL;
838
static fifo_t *uart_tx_fifo = NULL;
839
static fifo_t *ps2_rx_fifo = NULL;
840
 
841
/* ====================================== Simulator Instances ================================== */
842
 
843
/* ====================================== H2 I/O Handling ====================================== */
844
 
845 5 howe.r.j.8
static uint16_t h2_io_get_gui(h2_soc_state_t * const soc, const uint16_t addr, bool *debug_on) {
846 3 howe.r.j.8
        assert(soc);
847
        assert(ps2_rx_fifo);
848
        assert(uart_tx_fifo);
849
        assert(uart_rx_fifo);
850
 
851 5 howe.r.j.8
        if (debug_on)
852 3 howe.r.j.8
                *debug_on = false;
853 5 howe.r.j.8
        switch (addr) {
854 3 howe.r.j.8
        case iUart:
855 5 howe.r.j.8
                return (fifo_is_empty(uart_tx_fifo) << UART_TX_FIFO_EMPTY_BIT)
856
                        | (fifo_is_full(uart_tx_fifo)  << UART_TX_FIFO_FULL_BIT)
857
                        | (fifo_is_empty(uart_rx_fifo) << UART_RX_FIFO_EMPTY_BIT)
858
                        | (fifo_is_full(uart_rx_fifo)  << UART_RX_FIFO_FULL_BIT)
859
                        | soc->uart_getchar_register;
860 3 howe.r.j.8
        case iVT100:
861 5 howe.r.j.8
                return (1u << UART_TX_FIFO_EMPTY_BIT)
862
                        | (0u << UART_TX_FIFO_FULL_BIT)
863
                        | (fifo_is_empty(ps2_rx_fifo) << UART_RX_FIFO_EMPTY_BIT)
864
                        | (fifo_is_full(ps2_rx_fifo)  << UART_RX_FIFO_FULL_BIT)
865
                        | soc->ps2_getchar_register;
866 3 howe.r.j.8
        case iSwitches:
867
                return soc->switches;
868
        case iTimerDin: return soc->timer;
869
        case iMemDin:   return h2_io_memory_read_operation(soc);
870
        default:
871
                warning("invalid read from %04"PRIx16, addr);
872
                break;
873
        }
874
        return 0;
875
}
876
 
877 5 howe.r.j.8
static void h2_io_set_gui(h2_soc_state_t *soc, const uint16_t addr, const uint16_t value, bool *debug_on) {
878 3 howe.r.j.8
        assert(soc);
879
        assert(uart_tx_fifo);
880
        assert(uart_rx_fifo);
881
 
882 5 howe.r.j.8
        if (debug_on)
883 3 howe.r.j.8
                *debug_on = false;
884
 
885 5 howe.r.j.8
        switch (addr) {
886 3 howe.r.j.8
        case oUart:
887 5 howe.r.j.8
                if (value & UART_TX_WE) {
888 3 howe.r.j.8
                        fifo_push(uart_tx_fifo, value);
889
                }
890 5 howe.r.j.8
                if (value & UART_RX_RE) {
891 3 howe.r.j.8
                        uint8_t c = 0;
892
                        fifo_pop(uart_rx_fifo, &c);
893
                        soc->uart_getchar_register = c;
894
                }
895
                break;
896
        case oVT100:
897 5 howe.r.j.8
                if (value & UART_TX_WE) {
898 3 howe.r.j.8
                        vt100_update(&vga_terminal.vt100, value & 0xff);
899
                        vt100_update(&soc->vt100, value & 0xff);
900
                }
901 5 howe.r.j.8
                if (value & UART_RX_RE) {
902 3 howe.r.j.8
                        uint8_t c = 0;
903
                        fifo_pop(ps2_rx_fifo, &c);
904
                        soc->ps2_getchar_register = c;
905
                }
906
                break;
907
        case oLeds:
908
                soc->leds          = value;
909 5 howe.r.j.8
                for (size_t i = 0; i < LEDS_COUNT; i++)
910 3 howe.r.j.8
                        leds[i].on = value & (1 << i);
911
                break;
912
        case oTimerCtrl:
913
                soc->timer_control  = value;
914
                break;
915
        case o7SegLED:
916 5 howe.r.j.8
                for (size_t i = 0; i < SEGMENT_COUNT; i++)
917 3 howe.r.j.8
                        segments[i].segment = (value >> ((SEGMENT_COUNT - i - 1) * 4)) & 0xf;
918
                soc->led_7_segments = value;
919
                break;
920
        case oIrcMask:    soc->irc_mask     = value; break;
921
        case oMemControl:
922
                {
923
                        soc->mem_control    = value;
924 5 howe.r.j.8
                        const bool sram_cs  = soc->mem_control & SRAM_CHIP_SELECT;
925
                        const bool oe       = soc->mem_control & FLASH_MEMORY_OE;
926
                        const bool we       = soc->mem_control & FLASH_MEMORY_WE;
927
                        if (sram_cs && !oe && we)
928 3 howe.r.j.8
                                soc->vram[(((uint32_t)(soc->mem_control & FLASH_MASK_ADDR_UPPER_MASK) << 16) | soc->mem_addr_low) >> 1] = soc->mem_dout;
929
                        break;
930
                }
931 5 howe.r.j.8
        case oMemAddrLow:  soc->mem_addr_low = value; break;
932
        case oMemDout:     soc->mem_dout     = value; break;
933
        case oUartTxBaud:  soc->uart_tx_baud = value; break;
934
        case oUartRxBaud:  soc->uart_rx_baud = value; break;
935
        case oUartControl: soc->uart_control = value; break;
936 3 howe.r.j.8
        default:
937
                warning("invalid write to %04"PRIx16 ":%04"PRIx16, addr, value);
938
                break;
939
        }
940
}
941
 
942
/* ====================================== H2 I/O Handling ====================================== */
943
 
944
/* ====================================== Main Loop ============================================ */
945
 
946 5 howe.r.j.8
static double fps(void) {
947 3 howe.r.j.8
        static unsigned frame = 0, timebase = 0;
948
        static double fps = 0;
949 5 howe.r.j.8
        const int time = glutGet(GLUT_ELAPSED_TIME);
950 3 howe.r.j.8
        frame++;
951 5 howe.r.j.8
        if (time - timebase > 1000) {
952 3 howe.r.j.8
                fps = frame*1000.0/(time-timebase);
953
                timebase = time;
954
                frame = 0;
955
        }
956
        return fps;
957
}
958
 
959 5 howe.r.j.8
static void draw_debug_info(const world_t *world, double fps, double x, double y) {
960 3 howe.r.j.8
        textbox_t t = { .x = x, .y = y, .draw_border = true, .color_text = WHITE, .color_box = WHITE };
961
        assert(world);
962
        fifo_t *f = world->use_uart_input ? uart_rx_fifo : ps2_rx_fifo;
963
        const char *fifo_str = world->use_uart_input ? "UART" : "PS/2";
964
 
965
        fill_textbox(&t, "tick:               %u", world->tick);
966
        //fill_textbox(&t, "seconds:         %f", ticks_to_seconds(world->tick));
967
        fill_textbox(&t, "fps:                %f", fps);
968
 
969 5 howe.r.j.8
        if (world->debug_extra) {
970
                char buf[256] = { 0 };
971 3 howe.r.j.8
                fill_textbox(&t, "Mode:               %s", world->debug_mode ? "step" : "continue");
972 5 howe.r.j.8
                fill_textbox(&t, "%s RX FIFO full:  %s",   fifo_str, fifo_is_full(f)  ? "true" : "false");
973
                fill_textbox(&t, "%s RX FIFO empty: %s",   fifo_str, fifo_is_empty(f) ? "true" : "false");
974
                fill_textbox(&t, "%s RX FIFO count: %u",   fifo_str, (unsigned)fifo_count(f));
975
                fill_textbox(&t, "UART TX FIFO full:  %s", fifo_is_full(uart_tx_fifo)  ? "true" : "false");
976
                fill_textbox(&t, "UART TX FIFO empty: %s", fifo_is_empty(uart_tx_fifo) ? "true" : "false");
977
                fill_textbox(&t, "UART TX FIFO count: %u", (unsigned)fifo_count(uart_tx_fifo));
978 3 howe.r.j.8
 
979
                sprintf(buf, "%08lu", (unsigned long)(world->cycle_count));
980
                fill_textbox(&t, "cycles:             %s", buf);
981 5 howe.r.j.8
                fill_textbox(&t, "cycles/tick:        %u", (unsigned)(world->cycles));
982 3 howe.r.j.8
        }
983
        draw_textbox(&t);
984
}
985
 
986 5 howe.r.j.8
static void fill_textbox_memory(textbox_t *t, const uint16_t * const m, const size_t length) {
987 3 howe.r.j.8
        assert(t);
988
        assert(m);
989
        assert((length % 4) == 0);
990 5 howe.r.j.8
        for (size_t i = 0; i < length; i+=4)
991 3 howe.r.j.8
                fill_textbox(t, "%s%u: %x %x %x %x", i < 10 ? " " : "", i, m[i], m[i+1], m[i+2], m[i+3]);
992
}
993
 
994 5 howe.r.j.8
static void draw_debug_h2_screen_1(h2_t *h, double x, double y) {
995 3 howe.r.j.8
        assert(h);
996
        textbox_t t = { .x = x, .y = y, .draw_border = true, .color_text = WHITE, .color_box = WHITE };
997
        fill_textbox(&t, "H2 CPU State", h->tos);
998
        fill_textbox(&t, "tp: %u", h->tos);
999
        fill_textbox_memory(&t, h->dstk, STK_SIZE);
1000
        fill_textbox(&t, "pc: %u", h->pc);
1001
        fill_textbox(&t, "rp: %u (max %u)", h->rp, h->rpm);
1002
        fill_textbox(&t, "dp: %u (max %u)", h->sp, h->spm);
1003
        fill_textbox(&t, "ie: %s", h->ie ? "true" : "false");
1004
        draw_textbox(&t);
1005
}
1006
 
1007 5 howe.r.j.8
static void draw_debug_h2_screen_2(const h2_t * const h, const double x, const double y) {
1008 3 howe.r.j.8
        textbox_t t = { .x = x, .y = y, .draw_border = true, .color_text = WHITE, .color_box = WHITE };
1009
        assert(h);
1010
        fill_textbox(&t, "H2 CPU Return Stack");
1011
        fill_textbox_memory(&t, h->rstk, STK_SIZE);
1012
        draw_textbox(&t);
1013
}
1014
 
1015 5 howe.r.j.8
static void draw_debug_h2_screen_3(const h2_io_t * const io, const double x, const double y) {
1016 3 howe.r.j.8
        textbox_t t = { .x = x, .y = y, .draw_border = true, .color_text = WHITE, .color_box = WHITE };
1017
        assert(io);
1018
        assert(io->soc);
1019 5 howe.r.j.8
        const h2_soc_state_t * const s = io->soc;
1020 3 howe.r.j.8
        fill_textbox(&t, "I/O");
1021
        fill_textbox(&t, "LED             %x", (unsigned)s->leds);
1022
        /*fill_textbox(&t, "VGA Cursor:     %x", (unsigned)s->vga_cursor);*/
1023
        fill_textbox(&t, "Timer Control:  %x", (unsigned)s->timer_control);
1024
        fill_textbox(&t, "Timer Count:    %x", (unsigned)s->timer);
1025
        fill_textbox(&t, "IRQ Mask:       %x", (unsigned)s->irc_mask);
1026
        fill_textbox(&t, "LED 7 Segments: %x", (unsigned)s->led_7_segments);
1027
        fill_textbox(&t, "Switches:       %x", (unsigned)s->switches);
1028
        fill_textbox(&t, "Memory Control: %x", (unsigned)s->mem_control);
1029
        fill_textbox(&t, "Memory Address: %x", (unsigned)s->mem_addr_low);
1030
        fill_textbox(&t, "Memory Output:  %x", (unsigned)s->mem_dout);
1031
        fill_textbox(&t, "Wait:           %s", s->wait ? "yes" : "no");
1032
        fill_textbox(&t, "Interrupt:      %s", s->interrupt ? "yes" : "no");
1033
        fill_textbox(&t, "IRQ Selector:   %x", (unsigned)s->interrupt_selector);
1034
        fill_textbox(&t, "");
1035
        fill_textbox(&t, "Flash");
1036
        fill_textbox(&t, "we:             %s", s->flash.we ? "on" : "off");
1037
        fill_textbox(&t, "cs:             %s", s->flash.cs ? "on" : "off");
1038
        fill_textbox(&t, "mode:           %x", (unsigned)s->flash.mode);
1039
        fill_textbox(&t, "status:         %x", (unsigned)s->flash.status);
1040
        fill_textbox(&t, "address arg 1:  %x", (unsigned)s->flash.arg1_address);
1041
        fill_textbox(&t, "data            %x", (unsigned)s->flash.data);
1042
        fill_textbox(&t, "cycle:          %x", (unsigned)s->flash.cycle);
1043 5 howe.r.j.8
        fill_textbox(&t, "UART Control");
1044
        fill_textbox(&t, "UART TX Baud:   %x", (unsigned)s->uart_tx_baud);
1045
        fill_textbox(&t, "UART RX Baud:   %x", (unsigned)s->uart_rx_baud);
1046
        fill_textbox(&t, "UART Control:   %x", (unsigned)s->uart_control);
1047 3 howe.r.j.8
        draw_textbox(&t);
1048
}
1049
 
1050 5 howe.r.j.8
static void keyboard_handler(const unsigned char key, const int x, const int y) {
1051 3 howe.r.j.8
        UNUSED(x);
1052
        UNUSED(y);
1053
        assert(uart_tx_fifo);
1054
        assert(ps2_rx_fifo);
1055 5 howe.r.j.8
        if (key == ESCAPE) {
1056 3 howe.r.j.8
                world.halt_simulation = true;
1057
        } else {
1058 5 howe.r.j.8
                if (world.use_uart_input)
1059 3 howe.r.j.8
                        fifo_push(uart_rx_fifo, key);
1060
                else
1061
                        fifo_push(ps2_rx_fifo, key);
1062
        }
1063
}
1064
 
1065 5 howe.r.j.8
static void keyboard_special_handler(const int key, const int x, const int y) {
1066 3 howe.r.j.8
        UNUSED(x);
1067
        UNUSED(y);
1068 5 howe.r.j.8
        switch (key) {
1069 3 howe.r.j.8
        case GLUT_KEY_UP:    dpad.up    = true; break;
1070
        case GLUT_KEY_LEFT:  dpad.left  = true; break;
1071
        case GLUT_KEY_RIGHT: dpad.right = true; break;
1072
        case GLUT_KEY_DOWN:  dpad.down  = true; break;
1073
        case GLUT_KEY_F1:    switches[7].on = !(switches[7].on); break;
1074
        case GLUT_KEY_F2:    switches[6].on = !(switches[6].on); break;
1075
        case GLUT_KEY_F3:    switches[5].on = !(switches[5].on); break;
1076
        case GLUT_KEY_F4:    switches[4].on = !(switches[4].on); break;
1077
        case GLUT_KEY_F5:    switches[3].on = !(switches[3].on); break;
1078
        case GLUT_KEY_F6:    switches[2].on = !(switches[2].on); break;
1079
        case GLUT_KEY_F7:    switches[1].on = !(switches[1].on); break;
1080
        case GLUT_KEY_F8:    switches[0].on = !(switches[0].on); break;
1081
        case GLUT_KEY_F9:    world.step       = true;
1082
                             world.debug_mode = true;
1083
                             break;
1084
        case GLUT_KEY_F10:   world.debug_mode     = !(world.debug_mode);     break;
1085
        case GLUT_KEY_F11:   world.use_uart_input = !(world.use_uart_input); break;
1086
        case GLUT_KEY_F12:   world.debug_extra    = !(world.debug_extra);    break;
1087
        default:
1088
                break;
1089
        }
1090
}
1091
 
1092 5 howe.r.j.8
static void keyboard_special_up_handler(const int key, const int x, const int y) {
1093 3 howe.r.j.8
        UNUSED(x);
1094
        UNUSED(y);
1095 5 howe.r.j.8
        switch (key) {
1096 3 howe.r.j.8
        case GLUT_KEY_UP:    dpad.up    = false; break;
1097
        case GLUT_KEY_LEFT:  dpad.left  = false; break;
1098
        case GLUT_KEY_RIGHT: dpad.right = false; break;
1099
        case GLUT_KEY_DOWN:  dpad.down  = false; break;
1100
        default:
1101
                break;
1102
        }
1103
}
1104
 
1105
typedef struct {
1106
        double x;
1107
        double y;
1108
} coordinate_t;
1109
 
1110 5 howe.r.j.8
static double abs_diff(const double a, const double b) {
1111 3 howe.r.j.8
        return fabsl(fabsl(a) - fabsl(b));
1112
}
1113
 
1114 5 howe.r.j.8
static void resize_window(int w, int h) {
1115 3 howe.r.j.8
        double window_x_min, window_x_max, window_y_min, window_y_max;
1116
        double scale, center;
1117
        world.window_width  = w;
1118
        world.window_height = h;
1119
 
1120
        glViewport(0, 0, w, h);
1121
 
1122
        w = (w == 0) ? 1 : w;
1123
        h = (h == 0) ? 1 : h;
1124
        if ((X_MAX - X_MIN) / w < (Y_MAX - Y_MIN) / h) {
1125
                scale = ((Y_MAX - Y_MIN) / h) / ((X_MAX - X_MIN) / w);
1126
                center = (X_MAX + X_MIN) / 2;
1127
                window_x_min = center - (center - X_MIN) * scale;
1128
                window_x_max = center + (X_MAX - center) * scale;
1129
                world.window_scale_x = scale;
1130
                window_y_min = Y_MIN;
1131
                window_y_max = Y_MAX;
1132
        } else {
1133
                scale = ((X_MAX - X_MIN) / w) / ((Y_MAX - Y_MIN) / h);
1134
                center = (Y_MAX + Y_MIN) / 2;
1135
                window_y_min = center - (center - Y_MIN) * scale;
1136
                window_y_max = center + (Y_MAX - center) * scale;
1137
                world.window_scale_y = scale;
1138
                window_x_min = X_MIN;
1139
                window_x_max = X_MAX;
1140
        }
1141
 
1142
        glMatrixMode(GL_PROJECTION);
1143
        glLoadIdentity();
1144
        glOrtho(window_x_min, window_x_max, window_y_min, window_y_max, -1, 1);
1145
}
1146
 
1147 5 howe.r.j.8
static coordinate_t pixels_to_coordinates(const world_t *world, const int x, const int y) {
1148 3 howe.r.j.8
        assert(world);
1149 5 howe.r.j.8
        const double xd = abs_diff(X_MAX, X_MIN);
1150
        const double yd = abs_diff(Y_MAX, Y_MIN);
1151
        const double xs = world->window_width  / world->window_scale_x;
1152
        const double ys = world->window_height / world->window_scale_y;
1153
        const coordinate_t c = {
1154
                .x = Y_MIN + (xd * ((x - (world->window_width  - xs)/2.) / xs)),
1155
                .y = Y_MAX - (yd * ((y - (world->window_height - ys)/2.) / ys))
1156
        };
1157 3 howe.r.j.8
        return c;
1158
}
1159
 
1160 5 howe.r.j.8
static void mouse_handler(const int button, const int state, const int x, const int y) {
1161
        const coordinate_t c = pixels_to_coordinates(&world, x, y);
1162 3 howe.r.j.8
 
1163 5 howe.r.j.8
        for (size_t i = 0; i < SWITCHES_COUNT; i++) {
1164
                if (detect_circle_circle_collision(c.x, c.y, 0.1, switches[i].x, switches[i].y, switches[i].radius)) {
1165
                        if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
1166 3 howe.r.j.8
                                switches[i].on = true;
1167 5 howe.r.j.8
                        if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
1168 3 howe.r.j.8
                                switches[i].on = false;
1169
                        return;
1170
                }
1171
        }
1172
 
1173 5 howe.r.j.8
        if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
1174
                switch (dpad_collision(&dpad, c.x, c.y, 0.1)) {
1175 3 howe.r.j.8
                case DPAN_COL_NONE:                       break;
1176
                case DPAN_COL_RIGHT:  dpad.right  = true; break;
1177
                case DPAN_COL_LEFT:   dpad.left   = true; break;
1178
                case DPAN_COL_DOWN:   dpad.down   = true; break;
1179
                case DPAN_COL_UP:     dpad.up     = true; break;
1180
                case DPAN_COL_CENTER: dpad.center = true; break;
1181
                }
1182 5 howe.r.j.8
        } else if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
1183 3 howe.r.j.8
                dpad.right  = false;
1184
                dpad.left   = false;
1185
                dpad.down   = false;
1186
                dpad.up     = false;
1187
                dpad.center = false;
1188
        }
1189
}
1190
 
1191 5 howe.r.j.8
static void timer_callback(const int value) {
1192 3 howe.r.j.8
        world.tick++;
1193
        glutTimerFunc(world.arena_tick_ms, timer_callback, value);
1194
}
1195
 
1196 5 howe.r.j.8
static void update_switches(void) {
1197 3 howe.r.j.8
        h2_io->soc->switches = 0;
1198 5 howe.r.j.8
        for (size_t i = 0; i < SWITCHES_COUNT; i++)
1199 3 howe.r.j.8
                h2_io->soc->switches |= switches[i].on << i;
1200
        h2_io->soc->switches |= dpad.center << (SWITCHES_COUNT+0);
1201
        h2_io->soc->switches |= dpad.right  << (SWITCHES_COUNT+1);
1202
        h2_io->soc->switches |= dpad.left   << (SWITCHES_COUNT+2);
1203
        h2_io->soc->switches |= dpad.down   << (SWITCHES_COUNT+3);
1204
        h2_io->soc->switches |= dpad.up     << (SWITCHES_COUNT+4);
1205
}
1206
 
1207 5 howe.r.j.8
static void draw_scene(void) {
1208
        static uint64_t next = 0;  // @warning static!
1209
        static uint64_t count = 0; // @warning static!
1210 3 howe.r.j.8
        double f = fps();
1211 5 howe.r.j.8
        if (world.halt_simulation)
1212 3 howe.r.j.8
                exit(EXIT_SUCCESS);
1213
 
1214
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1215
 
1216
        draw_regular_polygon_line(X_MAX/2, Y_MAX/2, PI/4, sqrt(Y_MAX*Y_MAX/2)*0.99, SQUARE, LINE_WIDTH, WHITE);
1217
 
1218
        update_switches();
1219
 
1220 5 howe.r.j.8
        if (next != world.tick) {
1221 3 howe.r.j.8
                unsigned long increment = 0;
1222
                next = world.tick;
1223
                count++;
1224 5 howe.r.j.8
                for (;!fifo_is_empty(uart_tx_fifo);) {
1225 3 howe.r.j.8
                        uint8_t c = 0;
1226
                        fifo_pop(uart_tx_fifo, &c);
1227
                        vt100_update(&uart_terminal.vt100, c);
1228
                }
1229
 
1230 5 howe.r.j.8
                if (world.debug_mode && world.step)
1231 3 howe.r.j.8
                        increment = 1;
1232 5 howe.r.j.8
                else if (!(world.debug_mode))
1233 3 howe.r.j.8
                        increment = world.cycles;
1234
 
1235 5 howe.r.j.8
                if (!CYCLE_MODE_FIXED && increment) {
1236 3 howe.r.j.8
                        uint64_t n = world.cycles + (f > TARGET_FPS ? CYCLE_INCREMENT : -CYCLE_DECREMENT);
1237 5 howe.r.j.8
                        if (f > (TARGET_FPS + CYCLE_HYSTERESIS)) {
1238 3 howe.r.j.8
                                world.cycles = MIN(((uint64_t)-1), n);
1239 5 howe.r.j.8
                        } else if (f < (TARGET_FPS - CYCLE_HYSTERESIS)) {
1240 3 howe.r.j.8
                                world.cycles = MAX(CYCLE_MINIMUM, n);
1241
                        }
1242
                }
1243
 
1244 5 howe.r.j.8
                if (increment)
1245
                        if (h2_run(h, h2_io, stderr, increment, NULL, false, trace_file) < 0)
1246 3 howe.r.j.8
                                world.halt_simulation = true;
1247
 
1248
                world.step = false;
1249
                world.cycle_count += increment;
1250
        }
1251
        draw_debug_info(&world, f, X_MIN + X_MAX/40., Y_MAX - Y_MAX/40.);
1252 5 howe.r.j.8
        if (world.debug_extra) {
1253 3 howe.r.j.8
                draw_debug_h2_screen_1(h,     X_MIN + X_MAX/40., Y_MAX*0.70);
1254
                draw_debug_h2_screen_2(h,     X_MAX / 3.0,       Y_MAX*0.70);
1255
                draw_debug_h2_screen_3(h2_io, X_MAX / 1.55,  Y_MAX*0.70);
1256
        } else {
1257
                draw_terminal(&world, &vga_terminal, "VGA");
1258
        }
1259
 
1260 5 howe.r.j.8
        for (size_t i = 0; i < SWITCHES_COUNT; i++)
1261 3 howe.r.j.8
                draw_switch(&switches[i]);
1262
 
1263 5 howe.r.j.8
        for (size_t i = 0; i < LEDS_COUNT; i++)
1264 3 howe.r.j.8
                draw_led(&leds[i]);
1265
 
1266 5 howe.r.j.8
        for (size_t i = 0; i < SEGMENT_COUNT; i++)
1267 3 howe.r.j.8
                draw_led_8_segment(&segments[i]);
1268
 
1269
        draw_dpad(&dpad);
1270
 
1271
        draw_terminal(&world, &uart_terminal, world.use_uart_input ? "UART RX / TX" : "PS/2 KBD RX / UART TX");
1272
 
1273
        {
1274
                textbox_t t = { .x = X_MAX-50, .y = Y_MAX-2, .draw_border = false, .color_text = WHITE, .color_box = WHITE };
1275
                fill_textbox(&t, "EXIT/QUIT     ESCAPE");
1276
                fill_textbox(&t, "SWITCHES     F-1...8");
1277
                fill_textbox(&t, "SINGLE STEP      F-9");
1278
        }
1279
        {
1280
                textbox_t t = { .x = X_MAX-25, .y = Y_MAX-2, .draw_border = false, .color_text = WHITE, .color_box = WHITE };
1281
                fill_textbox(&t, "CPU PAUSE/RESUME F-10");
1282
                fill_textbox(&t, "SWITCH INPUT     F-11");
1283
                fill_textbox(&t, "CHANGE DISPLAY   F-12");
1284
        }
1285
 
1286 5 howe.r.j.8
        if (!world.debug_extra)
1287 3 howe.r.j.8
                draw_texture(&vga_terminal,  !(count % 2));
1288
        draw_texture(&uart_terminal, !(count % 2));
1289
 
1290
        glFlush();
1291
        glutSwapBuffers();
1292
        glutPostRedisplay();
1293
}
1294
 
1295 5 howe.r.j.8
static void initialize_rendering(char *arg_0) {
1296 3 howe.r.j.8
        char *glut_argv[] = { arg_0, NULL };
1297
        int glut_argc = 0;
1298
        memset(uart_terminal.vt100.m, ' ', uart_terminal.vt100.size);
1299
        glutInit(&glut_argc, glut_argv);
1300
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
1301
        glutInitWindowPosition(world.window_x_starting_position, world.window_y_starting_position);
1302
        glutInitWindowSize(world.window_width, world.window_height);
1303
        glutCreateWindow("H2 Simulator (GUI)");
1304
        glShadeModel(GL_FLAT);
1305
        glEnable(GL_DEPTH_TEST);
1306
        glutKeyboardFunc(keyboard_handler);
1307
        glutSpecialFunc(keyboard_special_handler);
1308
        glutSpecialUpFunc(keyboard_special_up_handler);
1309
        glutMouseFunc(mouse_handler);
1310
        glutReshapeFunc(resize_window);
1311
        glutDisplayFunc(draw_scene);
1312
        glutTimerFunc(world.arena_tick_ms, timer_callback, 0);
1313
}
1314
 
1315 5 howe.r.j.8
static void vt100_initialize(vt100_t * const v) {
1316 3 howe.r.j.8
        assert(v);
1317
        memset(&v->attribute, 0, sizeof(v->attribute));
1318
        v->attribute.foreground_color = WHITE;
1319
        v->attribute.background_color = BLACK;
1320 5 howe.r.j.8
        for (size_t i = 0; i < v->size; i++)
1321 3 howe.r.j.8
                v->attributes[i] = v->attribute;
1322
}
1323
 
1324 5 howe.r.j.8
static void finalize(void) {
1325
        nvram_save(h2_io, FLASH_INIT_FILE);
1326 3 howe.r.j.8
        h2_free(h);
1327
        h2_io_free(h2_io);
1328
        fifo_free(uart_tx_fifo);
1329
        fifo_free(uart_rx_fifo);
1330
        fifo_free(ps2_rx_fifo);
1331 5 howe.r.j.8
        if (trace_file)
1332
                fclose(trace_file);
1333 3 howe.r.j.8
}
1334
 
1335 5 howe.r.j.8
int main(int argc, char **argv) {
1336 3 howe.r.j.8
        FILE *hexfile = NULL;
1337
        int r = 0;
1338
 
1339
        assert(Y_MAX > 0. && Y_MIN < Y_MAX && Y_MIN >= 0.);
1340
        assert(X_MAX > 0. && X_MIN < X_MAX && X_MIN >= 0.);
1341
 
1342
        log_level = LOG_NOTE;
1343
 
1344 5 howe.r.j.8
        if (argc != 2) {
1345 3 howe.r.j.8
                fprintf(stderr, "usage %s h2.hex\n", argv[0]);
1346
                return -1;
1347
        }
1348
        hexfile = fopen_or_die(argv[1], "rb");
1349
 
1350
        h = h2_new(START_ADDR);
1351
        r = h2_load(h, hexfile);
1352
        fclose(hexfile);
1353 5 howe.r.j.8
        if (r < 0) {
1354 3 howe.r.j.8
                fprintf(stderr, "h2 load failed\n");
1355
                goto fail;
1356
        }
1357
        h2_io      = h2_io_new();
1358
        h2_io->in  = h2_io_get_gui;
1359
        h2_io->out = h2_io_set_gui;
1360
 
1361
        { /* attempt to load initial contents of VGA memory */
1362
                errno = 0;
1363
                FILE *vga_init = fopen(VGA_INIT_FILE, "rb");
1364
                static uint16_t vga_initial_contents[VGA_BUFFER_LENGTH] = { 0 };
1365
                assert(VGA_BUFFER_LENGTH <= VT100_MAX_SIZE);
1366 5 howe.r.j.8
                if (vga_init) {
1367 3 howe.r.j.8
                        memory_load(vga_init, vga_initial_contents, VGA_BUFFER_LENGTH);
1368 5 howe.r.j.8
                        for (size_t i = 0; i < VGA_BUFFER_LENGTH; i++) {
1369 3 howe.r.j.8
                                vga_terminal.vt100.m[i] = vga_initial_contents[i];
1370
                                h2_io->soc->vt100.m[i]  = vga_initial_contents[i];
1371
                        }
1372
                        fclose(vga_init);
1373
                } else {
1374
                        warning("could not load initial VGA memory file %s: %s", VGA_INIT_FILE, strerror(errno));
1375
                }
1376
                vt100_initialize(&vga_terminal.vt100);
1377
                vt100_initialize(&uart_terminal.vt100);
1378
        }
1379
 
1380
        uart_rx_fifo = fifo_new(UART_FIFO_DEPTH);
1381
        uart_tx_fifo = fifo_new(UART_FIFO_DEPTH * 100); /** @note x100 to speed things up */
1382
        ps2_rx_fifo  = fifo_new(8 /** @bug should be 1 - but this does not work, FIFO implementation needs correcting */);
1383
 
1384 5 howe.r.j.8
        nvram_load_and_transfer(h2_io, FLASH_INIT_FILE, true);
1385 3 howe.r.j.8
 
1386 5 howe.r.j.8
        if (TRON) {
1387
                errno = 0;
1388
                trace_file = fopen(TRACE_FILE, "wb");
1389
                if (trace_file)
1390
                        setvbuf(trace_file, trace_buffer, _IOFBF, TRACE_BUFFER_LEN);
1391
                else
1392
                        warning("could not open %s for writing: %s", TRACE_FILE, strerror(errno));
1393
        }
1394
 
1395 3 howe.r.j.8
        atexit(finalize);
1396
        initialize_rendering(argv[0]);
1397
        glutMainLoop();
1398
 
1399
        return 0;
1400
fail:
1401
        h2_free(h);
1402
        return -1;
1403
}
1404
 
1405
 

powered by: WebSVN 2.1.0

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