Line 1... |
Line 1... |
/**@file gui.c
|
/**@file gui.c
|
* @brief GUI Simulator for the H2 SoC
|
* @brief GUI Simulator for the H2 SoC
|
* @copyright Richard James Howe (2017)
|
* @copyright Richard James Howe (2017-2019)
|
* @license MIT
|
* @license MIT
|
*
|
* @note It would have been better to make this in SDL, se
|
* @todo Implement reset/reload, and save/load state */
|
* <https://www.libsdl.org/>. */
|
|
|
|
|
#include "h2.h"
|
#include "h2.h"
|
#include <assert.h>
|
#include <assert.h>
|
#include <errno.h>
|
#include <errno.h>
|
#include <ctype.h>
|
#include <ctype.h>
|
Line 20... |
Line 19... |
#include <GL/gl.h>
|
#include <GL/gl.h>
|
#include <GL/glut.h>
|
#include <GL/glut.h>
|
#include <GL/freeglut_ext.h> /* for glutStrokeHeight */
|
#include <GL/freeglut_ext.h> /* for glutStrokeHeight */
|
#include <stdarg.h>
|
#include <stdarg.h>
|
|
|
|
#define TRON (0)
|
|
|
/* ====================================== Utility Functions ==================================== */
|
/* ====================================== Utility Functions ==================================== */
|
|
|
#define PI (3.1415926535897932384626433832795)
|
#define PI (3.1415926535897932384626433832795)
|
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
|
#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
|
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
|
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
|
Line 40... |
Line 41... |
#define CYCLE_MINIMUM (10000)
|
#define CYCLE_MINIMUM (10000)
|
#define CYCLE_HYSTERESIS (2.0)
|
#define CYCLE_HYSTERESIS (2.0)
|
#define TARGET_FPS (30.0)
|
#define TARGET_FPS (30.0)
|
#define BACKGROUND_ON (false)
|
#define BACKGROUND_ON (false)
|
#define SIM_HACKS (true)
|
#define SIM_HACKS (true)
|
|
#define TRACE_FILE ("trace.csv")
|
|
#define TRACE_BUFFER_LEN (16*4096)
|
|
|
typedef struct {
|
typedef struct {
|
double window_height;
|
double window_height;
|
double window_width;
|
double window_width;
|
double window_x_starting_position;
|
double window_x_starting_position;
|
double window_y_starting_position;
|
double window_y_starting_position;
|
double window_scale_x;
|
double window_scale_x;
|
double window_scale_y;
|
double window_scale_y;
|
|
void *font_scaled;
|
|
uint64_t cycle_count;
|
|
uint64_t cycles;
|
volatile unsigned tick;
|
volatile unsigned tick;
|
volatile bool halt_simulation;
|
|
unsigned arena_tick_ms;
|
unsigned arena_tick_ms;
|
|
volatile bool halt_simulation;
|
bool use_uart_input;
|
bool use_uart_input;
|
bool debug_extra;
|
bool debug_extra;
|
bool step;
|
bool step;
|
bool debug_mode;
|
bool debug_mode;
|
uint64_t cycle_count;
|
|
uint64_t cycles;
|
|
void *font_scaled;
|
|
} world_t;
|
} world_t;
|
|
|
static world_t world = {
|
static world_t world = {
|
.window_height = 800.0,
|
.window_height = 800.0,
|
.window_width = 800.0,
|
.window_width = 800.0,
|
Line 79... |
Line 82... |
.cycle_count = 0,
|
.cycle_count = 0,
|
.cycles = CYCLE_INITIAL,
|
.cycles = CYCLE_INITIAL,
|
.font_scaled = GLUT_STROKE_MONO_ROMAN
|
.font_scaled = GLUT_STROKE_MONO_ROMAN
|
};
|
};
|
|
|
|
static FILE *trace_file = NULL; /* NB. !NULL turns tracing on */
|
|
static char trace_buffer[TRACE_BUFFER_LEN];
|
|
|
typedef enum {
|
typedef enum {
|
TRIANGLE,
|
TRIANGLE,
|
SQUARE,
|
SQUARE,
|
PENTAGON,
|
PENTAGON,
|
HEXAGON,
|
HEXAGON,
|
Line 109... |
Line 115... |
|
|
typedef struct { /**@note it might be worth translating some functions to use points*/
|
typedef struct { /**@note it might be worth translating some functions to use points*/
|
double x, y;
|
double x, y;
|
} point_t;
|
} point_t;
|
|
|
static const char *nvram_file = FLASH_INIT_FILE;
|
|
|
|
/**@bug not quite correct, arena_tick_ms is what we request, not want the arena
|
/**@bug not quite correct, arena_tick_ms is what we request, not want the arena
|
* tick actually is */
|
* tick actually is */
|
static double seconds_to_ticks(const world_t *world, double s)
|
static double seconds_to_ticks(const world_t *world, double s) {
|
{
|
|
assert(world);
|
assert(world);
|
return s * (1000. / (double)world->arena_tick_ms);
|
return s * (1000. / (double)world->arena_tick_ms);
|
}
|
}
|
|
|
static double rad2deg(double rad)
|
static double rad2deg(const double rad) {
|
{
|
|
return (rad / (2.0 * PI)) * 360.0;
|
return (rad / (2.0 * PI)) * 360.0;
|
}
|
}
|
|
|
static void set_color(color_t color, bool light)
|
static void set_color(const color_t color, const bool light) {
|
{
|
|
double ON = light ? 0.8 : 0.4;
|
double ON = light ? 0.8 : 0.4;
|
static const double OFF = 0.0;
|
static const double OFF = 0.0;
|
switch(color) { /* RED GRN BLU */
|
switch(color) { /* RED GRN BLU */
|
case WHITE: glColor3f( ON, ON, ON); break;
|
case WHITE: glColor3f( ON, ON, ON); break;
|
case RED: glColor3f( ON, OFF, OFF); break;
|
case RED: glColor3f( ON, OFF, OFF); break;
|
Line 143... |
Line 145... |
}
|
}
|
}
|
}
|
|
|
/* see: https://www.opengl.org/discussion_boards/showthread.php/160784-Drawing-Circles-in-OpenGL */
|
/* see: https://www.opengl.org/discussion_boards/showthread.php/160784-Drawing-Circles-in-OpenGL */
|
static void _draw_regular_polygon(
|
static void _draw_regular_polygon(
|
double x, double y,
|
const double x, const double y,
|
double orientation,
|
const double orientation,
|
double radius, double sides,
|
const double radius, const double sides,
|
bool lines, double thickness,
|
const bool lines, const double thickness,
|
color_t color)
|
const color_t color) {
|
{
|
|
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
glPushMatrix();
|
glPushMatrix();
|
glLoadIdentity();
|
glLoadIdentity();
|
glTranslatef(x, y, 0.0);
|
glTranslatef(x, y, 0.0);
|
glRotated(rad2deg(orientation), 0, 0, 1);
|
glRotated(rad2deg(orientation), 0, 0, 1);
|
Line 167... |
Line 168... |
glVertex3d(cos(i) * radius, sin(i) * radius, 0.0);
|
glVertex3d(cos(i) * radius, sin(i) * radius, 0.0);
|
glEnd();
|
glEnd();
|
glPopMatrix();
|
glPopMatrix();
|
}
|
}
|
|
|
static void _draw_rectangle(double x, double y, double width, double height, bool lines, double thickness, color_t color)
|
static void _draw_rectangle(
|
{
|
const double x, const double y,
|
|
const double width, const double height,
|
|
const bool lines, const double thickness,
|
|
const color_t color) {
|
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
glPushMatrix();
|
glPushMatrix();
|
glLoadIdentity();
|
glLoadIdentity();
|
glRasterPos2d(x, y);
|
glRasterPos2d(x, y);
|
set_color(color, true);
|
set_color(color, true);
|
Line 188... |
Line 192... |
glVertex3d(x, y+height, 0);
|
glVertex3d(x, y+height, 0);
|
glEnd();
|
glEnd();
|
glPopMatrix();
|
glPopMatrix();
|
}
|
}
|
|
|
static void draw_rectangle_filled(double x, double y, double width, double height, color_t color)
|
static void draw_rectangle_filled(const double x, const double y, const double width, const double height, const color_t color) {
|
{
|
_draw_rectangle(x, y, width, height, false, 0, color);
|
return _draw_rectangle(x, y, width, height, false, 0, color);
|
|
}
|
}
|
|
|
static void draw_rectangle_line(double x, double y, double width, double height, double thickness, color_t color)
|
static void draw_rectangle_line(const double x, const double y, const double width, const double height, const double thickness, const color_t color) {
|
{
|
_draw_rectangle(x, y, width, height, true, thickness, color);
|
return _draw_rectangle(x, y, width, height, true, thickness, color);
|
|
}
|
}
|
|
|
static double shape_to_sides(shape_t shape)
|
static double shape_to_sides(shape_t shape) {
|
{
|
|
static const double sides[] =
|
static const double sides[] =
|
{
|
{
|
[TRIANGLE] = 1.5,
|
[TRIANGLE] = 1.5,
|
[SQUARE] = 2,
|
[SQUARE] = 2,
|
[PENTAGON] = 2.5,
|
[PENTAGON] = 2.5,
|
Line 216... |
Line 217... |
if(shape >= INVALID_SHAPE)
|
if(shape >= INVALID_SHAPE)
|
fatal("invalid shape '%d'", shape);
|
fatal("invalid shape '%d'", shape);
|
return sides[shape % INVALID_SHAPE];
|
return sides[shape % INVALID_SHAPE];
|
}
|
}
|
|
|
static void draw_regular_polygon_filled(double x, double y, double orientation, double radius, shape_t shape, color_t color)
|
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) {
|
{
|
_draw_regular_polygon(x, y, orientation, radius, shape_to_sides(shape), false, 0, color);
|
double sides = shape_to_sides(shape);
|
|
_draw_regular_polygon(x, y, orientation, radius, sides, false, 0, color);
|
|
}
|
}
|
|
|
static void draw_regular_polygon_line(double x, double y, double orientation, double radius, shape_t shape, double thickness, color_t color)
|
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) {
|
{
|
_draw_regular_polygon(x, y, orientation, radius, shape_to_sides(shape), true, thickness, color);
|
double sides = shape_to_sides(shape);
|
|
_draw_regular_polygon(x, y, orientation, radius, sides, true, thickness, color);
|
|
}
|
}
|
|
|
static void draw_char(uint8_t c)
|
static void draw_char(uint8_t c) {
|
{
|
|
c = c >= 32 && c <= 127 ? c : '?';
|
c = c >= 32 && c <= 127 ? c : '?';
|
glutStrokeCharacter(world.font_scaled, c);
|
glutStrokeCharacter(world.font_scaled, c);
|
}
|
}
|
|
|
/* see: https://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Text_Rendering_01
|
/* see: https://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Text_Rendering_01
|
* https://stackoverflow.com/questions/538661/how-do-i-draw-text-with-glut-opengl-in-c
|
* https://stackoverflow.com/questions/538661/how-do-i-draw-text-with-glut-opengl-in-c
|
* https://stackoverflow.com/questions/20866508/using-glut-to-simply-print-text */
|
* https://stackoverflow.com/questions/20866508/using-glut-to-simply-print-text */
|
static int draw_block(const uint8_t *msg, size_t len)
|
static int draw_block(const uint8_t *msg, const size_t len) {
|
{
|
|
assert(msg);
|
assert(msg);
|
for(size_t i = 0; i < len; i++)
|
for(size_t i = 0; i < len; i++)
|
draw_char(msg[i]);
|
draw_char(msg[i]);
|
return len;
|
return len;
|
}
|
}
|
|
|
static int draw_string(const char *msg)
|
static int draw_string(const char *msg) {
|
{
|
|
assert(msg);
|
assert(msg);
|
return draw_block((uint8_t*)msg, strlen(msg));
|
return draw_block((uint8_t*)msg, strlen(msg));
|
}
|
}
|
|
|
static scale_t font_attributes(void)
|
static scale_t font_attributes(void) {
|
{
|
static bool initialized = false; // @warning static!
|
static bool initialized = false;
|
static scale_t scale = { 0., 0.}; // @warning static!
|
static scale_t scale = { 0., 0.};
|
|
if(initialized)
|
if(initialized)
|
return scale;
|
return scale;
|
scale.y = glutStrokeHeight(world.font_scaled);
|
scale.y = glutStrokeHeight(world.font_scaled);
|
scale.x = glutStrokeWidth(world.font_scaled, 'M');
|
scale.x = glutStrokeWidth(world.font_scaled, 'M');
|
initialized = true;
|
initialized = true;
|
return scale;
|
return scale;
|
}
|
}
|
|
|
static void draw_vt100_char(double x, double y, double scale_x, double scale_y, double orientation, uint8_t c, vt100_attribute_t *attr, bool blink)
|
static void draw_vt100_char(
|
{
|
const double x, const double y,
|
|
const double scale_x, const double scale_y,
|
|
const double orientation, const uint8_t c,
|
|
const vt100_attribute_t *attr, const bool blink) {
|
|
assert(attr);
|
/*scale_t scale = font_attributes();
|
/*scale_t scale = font_attributes();
|
double char_width = scale.x / X_MAX;
|
double char_width = scale.x / X_MAX;
|
double char_height = scale.y / Y_MAX;*/
|
double char_height = scale.y / Y_MAX;*/
|
|
|
if(blink && attr->blink)
|
if(blink && attr->blink)
|
Line 286... |
Line 283... |
glPopMatrix();
|
glPopMatrix();
|
if(BACKGROUND_ON)
|
if(BACKGROUND_ON)
|
draw_rectangle_filled(x, y, 1.20, 1.55, attr->background_color);
|
draw_rectangle_filled(x, y, 1.20, 1.55, attr->background_color);
|
}
|
}
|
|
|
static int draw_vt100_block(double x, double y, double scale_x, double scale_y, double orientation, const uint8_t *msg, size_t len, vt100_attribute_t *attr, bool blink)
|
static int draw_vt100_block(
|
{
|
const double x, const double y,
|
scale_t scale = font_attributes();
|
const double scale_x, const double scale_y,
|
double char_width = (scale.x / X_MAX)*1.1;
|
const double orientation, const uint8_t *msg,
|
|
const size_t len, const vt100_attribute_t * const attr, const bool blink) {
|
|
assert(attr);
|
|
const scale_t scale = font_attributes();
|
|
const double char_width = (scale.x / X_MAX)*1.1;
|
for(size_t i = 0; i < len; i++)
|
for(size_t i = 0; i < len; i++)
|
draw_vt100_char(x+char_width*i, y, scale_x, scale_y, orientation, msg[i], &attr[i], blink);
|
draw_vt100_char(x+char_width*i, y, scale_x, scale_y, orientation, msg[i], &attr[i], blink);
|
return len;
|
return len;
|
}
|
}
|
|
|
static int draw_block_scaled(double x, double y, double scale_x, double scale_y, double orientation, const uint8_t *msg, size_t len, color_t color)
|
static int draw_block_scaled(
|
{
|
const double x, const double y,
|
|
const double scale_x, const double scale_y,
|
|
const double orientation, const uint8_t *msg, const size_t len, const color_t color) {
|
assert(msg);
|
assert(msg);
|
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
glPushMatrix();
|
glPushMatrix();
|
glLoadIdentity();
|
glLoadIdentity();
|
glTranslatef(x, y, 0.0);
|
glTranslatef(x, y, 0.0);
|
Line 315... |
Line 318... |
glEnd();
|
glEnd();
|
glPopMatrix();
|
glPopMatrix();
|
return len;
|
return len;
|
}
|
}
|
|
|
static int draw_string_scaled(double x, double y, double scale_x, double scale_y, double orientation, const char *msg, color_t color)
|
static int draw_string_scaled(
|
{
|
const double x, const double y,
|
|
const double scale_x, const double scale_y,
|
|
const double orientation, const char *msg, const color_t color) {
|
assert(msg);
|
assert(msg);
|
return draw_block_scaled(x, y, scale_x, scale_y, orientation, (uint8_t*)msg, strlen(msg), color);
|
return draw_block_scaled(x, y, scale_x, scale_y, orientation, (uint8_t*)msg, strlen(msg), color);
|
}
|
}
|
|
|
static int vdraw_text(color_t color, double x, double y, const char *fmt, va_list ap)
|
static int vdraw_text(const color_t color, const double x, const double y, const char *fmt, va_list ap) {
|
{
|
|
char f;
|
|
int r = 0;
|
int r = 0;
|
assert(fmt);
|
assert(fmt);
|
static const double scale_x = 0.011;
|
static const double scale_x = 0.011;
|
static const double scale_y = 0.011;
|
static const double scale_y = 0.011;
|
|
|
Line 335... |
Line 338... |
glPushMatrix();
|
glPushMatrix();
|
set_color(color, true);
|
set_color(color, true);
|
glTranslatef(x, y, 0);
|
glTranslatef(x, y, 0);
|
glScaled(scale_x, scale_y, 1.0);
|
glScaled(scale_x, scale_y, 1.0);
|
while(*fmt) {
|
while(*fmt) {
|
if('%' != (f = *fmt++)) {
|
char f = *fmt++;
|
|
if ('%' != f) {
|
glutStrokeCharacter(world.font_scaled, f);
|
glutStrokeCharacter(world.font_scaled, f);
|
r++;
|
r++;
|
continue;
|
continue;
|
}
|
}
|
switch(f = *fmt++) {
|
switch ((f = *fmt++)) {
|
case 'c':
|
case 'c':
|
{
|
{
|
char x[2] = {0, 0};
|
char x[2] = {0, 0};
|
x[0] = va_arg(ap, int);
|
x[0] = va_arg(ap, int);
|
r += draw_string(x);
|
r += draw_string(x);
|
Line 356... |
Line 360... |
r += draw_string(s);
|
r += draw_string(s);
|
break;
|
break;
|
}
|
}
|
case 'x':
|
case 'x':
|
{
|
{
|
unsigned d = va_arg(ap, unsigned);
|
const unsigned d = va_arg(ap, unsigned);
|
char s[64] = {0};
|
char s[64] = {0};
|
sprintf(s, "%04x", d);
|
sprintf(s, "%04x", d);
|
r += draw_string(s);
|
r += draw_string(s);
|
break;
|
break;
|
}
|
}
|
case 'u':
|
case 'u':
|
case 'd':
|
case 'd':
|
{
|
{
|
int d = va_arg(ap, int);
|
const int d = va_arg(ap, int);
|
char s[64] = {0};
|
char s[64] = {0};
|
sprintf(s, f == 'u' ? "%u": "%d", d);
|
sprintf(s, f == 'u' ? "%u": "%d", d);
|
r += draw_string(s);
|
r += draw_string(s);
|
break;
|
break;
|
}
|
}
|
case 'f':
|
case 'f':
|
{
|
{
|
double f = va_arg(ap, double);
|
const double f = va_arg(ap, double);
|
char s[512] = {0};
|
char s[512] = {0};
|
sprintf(s, "%.2f", f);
|
sprintf(s, "%.2f", f);
|
r += draw_string(s);
|
r += draw_string(s);
|
break;
|
break;
|
}
|
}
|
Line 389... |
Line 393... |
}
|
}
|
glPopMatrix();
|
glPopMatrix();
|
return r;
|
return r;
|
}
|
}
|
|
|
static void fill_textbox(textbox_t *t, const char *fmt, ...)
|
static void fill_textbox(textbox_t *t, const char *fmt, ...) {
|
{
|
|
double r;
|
|
va_list ap;
|
va_list ap;
|
assert(t);
|
assert(t);
|
assert(fmt);
|
assert(fmt);
|
|
|
scale_t scale = font_attributes();
|
scale_t scale = font_attributes();
|
double char_width = scale.x / X_MAX;
|
const double char_width = scale.x / X_MAX;
|
double char_height = scale.y / Y_MAX;
|
const double char_height = scale.y / Y_MAX;
|
assert(t && fmt);
|
assert(t && fmt);
|
va_start(ap, fmt);
|
va_start(ap, fmt);
|
r = vdraw_text(t->color_text, t->x, t->y - t->height, fmt, ap);
|
double r = vdraw_text(t->color_text, t->x, t->y - t->height, fmt, ap);
|
r *= char_width * 1.11;
|
r *= char_width * 1.11;
|
r += 1;
|
r += 1;
|
va_end(ap);
|
va_end(ap);
|
t->width = MAX(t->width, r);
|
t->width = MAX(t->width, r);
|
t->height += (char_height); /*correct?*/
|
t->height += (char_height); /*correct?*/
|
}
|
}
|
|
|
static void draw_textbox(textbox_t *t)
|
static void draw_textbox(textbox_t *t) {
|
{
|
|
assert(t);
|
assert(t);
|
scale_t scale = font_attributes();
|
scale_t scale = font_attributes();
|
double char_height = scale.y / Y_MAX;
|
const double char_height = scale.y / Y_MAX;
|
if(!(t->draw_border))
|
if(!(t->draw_border))
|
return;
|
return;
|
draw_rectangle_line(t->x - LINE_WIDTH, t->y - t->height + char_height - 1, t->width, t->height + 1, LINE_WIDTH, t->color_box);
|
draw_rectangle_line(t->x - LINE_WIDTH, t->y - t->height + char_height - 1, t->width, t->height + 1, LINE_WIDTH, t->color_box);
|
}
|
}
|
|
|
static bool detect_circle_circle_collision(
|
static bool detect_circle_circle_collision(
|
double ax, double ay, double aradius,
|
const double ax, const double ay, const double aradius,
|
double bx, double by, double bradius)
|
const double bx, const double by, const double bradius) {
|
{
|
const double dx = ax - bx;
|
double dx = ax - bx;
|
const double dy = ay - by;
|
double dy = ay - by;
|
const double distance = hypot(dx, dy);
|
double distance = hypot(dx, dy);
|
return distance < (aradius + bradius);
|
return (distance < (aradius + bradius));
|
|
}
|
}
|
|
|
/* ====================================== Utility Functions ==================================== */
|
/* ====================================== Utility Functions ==================================== */
|
|
|
/* ====================================== Simulator Objects ==================================== */
|
/* ====================================== Simulator Objects ==================================== */
|
Line 441... |
Line 441... |
double angle;
|
double angle;
|
double radius;
|
double radius;
|
bool on;
|
bool on;
|
} led_t;
|
} led_t;
|
|
|
static void draw_led(led_t *l)
|
static void draw_led(const led_t * const l) {
|
{
|
|
assert(l);
|
assert(l);
|
double msz = l->radius * 0.75;
|
const double msz = l->radius * 0.75;
|
double off = (l->radius - msz) / 2.0;
|
const double off = (l->radius - msz) / 2.0;
|
draw_rectangle_filled(l->x+off, l->y+off, msz, msz, l->on ? GREEN : RED);
|
draw_rectangle_filled(l->x+off, l->y+off, msz, msz, l->on ? GREEN : RED);
|
draw_rectangle_filled(l->x, l->y, l->radius, l->radius, BLUE);
|
draw_rectangle_filled(l->x, l->y, l->radius, l->radius, BLUE);
|
}
|
}
|
|
|
typedef struct {
|
typedef struct {
|
Line 458... |
Line 457... |
double angle;
|
double angle;
|
double radius;
|
double radius;
|
bool on;
|
bool on;
|
} switch_t;
|
} switch_t;
|
|
|
static void draw_switch(switch_t *s)
|
static void draw_switch(const switch_t * const s) {
|
{
|
|
assert(s);
|
assert(s);
|
double msz = s->radius * 0.6;
|
const double msz = s->radius * 0.6;
|
double off = (s->radius - msz) / 2.0;
|
const double off = (s->radius - msz) / 2.0;
|
draw_rectangle_filled(s->x+off, s->on ? (s->y + s->radius) - off : s->y+off, msz, msz, s->on ? GREEN : RED);
|
draw_rectangle_filled(s->x+off, s->on ? (s->y + s->radius) - off : s->y+off, msz, msz, s->on ? GREEN : RED);
|
draw_rectangle_filled(s->x+off, s->y + off, msz, msz*2., BLACK);
|
draw_rectangle_filled(s->x+off, s->y + off, msz, msz*2., BLACK);
|
draw_rectangle_filled(s->x, s->y, s->radius, s->radius * 2, BLUE);
|
draw_rectangle_filled(s->x, s->y, s->radius, s->radius * 2, BLUE);
|
}
|
}
|
|
|
Line 488... |
Line 486... |
double width;
|
double width;
|
double height;
|
double height;
|
uint8_t segment;
|
uint8_t segment;
|
} led_8_segment_t;
|
} led_8_segment_t;
|
|
|
static uint8_t convert_to_segments(uint8_t segment) {
|
static uint8_t convert_to_segments(const uint8_t segment) {
|
static const uint8_t c2s[16] = {
|
static const uint8_t c2s[16] = {
|
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07,
|
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07,
|
0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71
|
0x7F, 0x6F, 0x77, 0x7C, 0x39, 0x5E, 0x79, 0x71
|
};
|
};
|
return c2s[segment & 0xf];
|
return c2s[segment & 0xf];
|
}
|
}
|
|
|
#define SEG_CLR(SG,BIT) (((SG) & (1 << BIT)) ? RED : BLACK)
|
#define SEG_CLR(SG,BIT) (((SG) & (1 << BIT)) ? RED : BLACK)
|
|
|
static void draw_led_8_segment(led_8_segment_t *l)
|
static void draw_led_8_segment(const led_8_segment_t * const l) {
|
{
|
|
assert(l);
|
assert(l);
|
uint8_t sgs = convert_to_segments(l->segment);
|
const uint8_t sgs = convert_to_segments(l->segment);
|
|
|
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 */
|
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 */
|
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 */
|
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 */
|
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 */
|
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 */
|
|
|
Line 531... |
Line 528... |
bool left;
|
bool left;
|
bool right;
|
bool right;
|
bool center;
|
bool center;
|
} dpad_t;
|
} dpad_t;
|
|
|
static void draw_dpad(dpad_t *d)
|
static void draw_dpad(const dpad_t * const d) {
|
{
|
assert(d);
|
draw_regular_polygon_filled(d->x + (d->radius*2.0), d->y, d->angle, d->radius, TRIANGLE, d->right ? GREEN : RED);
|
draw_regular_polygon_filled(d->x + (d->radius*2.0), d->y, d->angle, d->radius, TRIANGLE, d->right ? GREEN : RED);
|
draw_regular_polygon_filled(d->x - (d->radius*2.0), d->y, d->angle + (PI/3.0), d->radius, TRIANGLE, d->left ? GREEN : RED);
|
draw_regular_polygon_filled(d->x - (d->radius*2.0), d->y, d->angle + (PI/3.0), d->radius, TRIANGLE, d->left ? GREEN : RED);
|
draw_regular_polygon_filled(d->x, d->y - (d->radius*2.0), d->angle - (PI/2.0), d->radius, TRIANGLE, d->down ? GREEN : RED);
|
draw_regular_polygon_filled(d->x, d->y - (d->radius*2.0), d->angle - (PI/2.0), d->radius, TRIANGLE, d->down ? GREEN : RED);
|
draw_regular_polygon_filled(d->x, d->y + (d->radius*2.0), d->angle + (PI/2.0), d->radius, TRIANGLE, d->up ? GREEN : RED);
|
draw_regular_polygon_filled(d->x, d->y + (d->radius*2.0), d->angle + (PI/2.0), d->radius, TRIANGLE, d->up ? GREEN : RED);
|
draw_regular_polygon_filled(d->x, d->y, d->angle, d->radius, CIRCLE, d->center ? GREEN : RED);
|
draw_regular_polygon_filled(d->x, d->y, d->angle, d->radius, CIRCLE, d->center ? GREEN : RED);
|
Line 551... |
Line 548... |
DPAN_COL_DOWN,
|
DPAN_COL_DOWN,
|
DPAN_COL_UP,
|
DPAN_COL_UP,
|
DPAN_COL_CENTER
|
DPAN_COL_CENTER
|
} dpad_collision_e;
|
} dpad_collision_e;
|
|
|
static dpad_collision_e dpad_collision(dpad_t *d, double x, double y, double radius)
|
static dpad_collision_e dpad_collision(const dpad_t * const d, const double x, const double y, const double radius) {
|
{
|
assert(d);
|
if(detect_circle_circle_collision(x, y, radius, d->x + (d->radius*2.0), d->y, d->radius))
|
if(detect_circle_circle_collision(x, y, radius, d->x + (d->radius*2.0), d->y, d->radius))
|
return DPAN_COL_RIGHT;
|
return DPAN_COL_RIGHT;
|
if(detect_circle_circle_collision(x, y, radius, d->x - (d->radius*2.0), d->y, d->radius))
|
if(detect_circle_circle_collision(x, y, radius, d->x - (d->radius*2.0), d->y, d->radius))
|
return DPAN_COL_LEFT;
|
return DPAN_COL_LEFT;
|
if(detect_circle_circle_collision(x, y, radius, d->x, d->y + (d->radius*2.0), d->radius))
|
if(detect_circle_circle_collision(x, y, radius, d->x, d->y + (d->radius*2.0), d->radius))
|
Line 587... |
Line 584... |
color_t color;
|
color_t color;
|
vt100_t vt100;
|
vt100_t vt100;
|
vt100_background_texture_t *texture;
|
vt100_background_texture_t *texture;
|
} terminal_t;
|
} terminal_t;
|
|
|
static void texture_background(terminal_t *t)
|
static void texture_background(const terminal_t * const t) {
|
{
|
|
assert(t);
|
assert(t);
|
vt100_background_texture_t *v = t->texture;
|
const vt100_background_texture_t *v = t->texture;
|
vt100_t *vt = &t->vt100;
|
const vt100_t *vt = &t->vt100;
|
unsigned i, j;
|
uint8_t *const img = v->image;
|
uint8_t *img = v->image;
|
|
const unsigned h = v->height;
|
const unsigned h = v->height;
|
const unsigned w = v->width;
|
const unsigned w = v->width;
|
|
|
for (i = 0; i < h; i++) {
|
for (unsigned i = 0; i < h; i++) {
|
uint8_t *row = &img[i*4];
|
uint8_t * const row = &img[i * 4];
|
unsigned ii = ((h - i - 1)*vt->height) / h;
|
const unsigned ii = ((h - i - 1) * vt->height) / h;
|
for (j = 0; j < w; j++) {
|
for (unsigned j = 0; j < w; j++) {
|
uint8_t *column = &row[j*h*4];
|
uint8_t * const column = &row[j * h * 4];
|
const unsigned jj = (vt->width*j) / w;
|
const unsigned jj = (vt->width*j) / w;
|
const unsigned idx = jj+(ii*vt->width);
|
const unsigned idx = jj+(ii*vt->width);
|
column[0] = 255 * (vt->attributes[idx].background_color & 1);
|
column[0] = 255 * (vt->attributes[idx].background_color & 1);
|
column[1] = 255 * (vt->attributes[idx].background_color & 2);
|
column[1] = 255 * (vt->attributes[idx].background_color & 2);
|
column[2] = 255 * (vt->attributes[idx].background_color & 4);
|
column[2] = 255 * (vt->attributes[idx].background_color & 4);
|
Line 613... |
Line 608... |
}
|
}
|
}
|
}
|
}
|
}
|
|
|
/* See <http://www.glprogramming.com/red/chapter09.html> */
|
/* See <http://www.glprogramming.com/red/chapter09.html> */
|
static void draw_texture(terminal_t *t, bool update)
|
static void draw_texture(const terminal_t * const t, const bool update) {
|
{
|
assert(t);
|
vt100_background_texture_t *v = t->texture;
|
vt100_background_texture_t *v = t->texture;
|
if(!v)
|
if(!v)
|
return;
|
return;
|
|
|
scale_t scale = font_attributes();
|
const scale_t scale = font_attributes();
|
double char_width = scale.x / X_MAX;
|
const double char_width = scale.x / X_MAX;
|
double char_height = scale.y / Y_MAX;
|
const double char_height = scale.y / Y_MAX;
|
double x = t->x;
|
const double x = t->x;
|
double y = t->y - (char_height * (t->vt100.height-1.0));
|
const double y = t->y - (char_height * (t->vt100.height-1.0));
|
double width = char_width * t->vt100.width * 1.10;
|
const double width = char_width * t->vt100.width * 1.10;
|
double height = char_height * t->vt100.height;
|
const double height = char_height * t->vt100.height;
|
|
|
glEnable(GL_TEXTURE_2D);
|
glEnable(GL_TEXTURE_2D);
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
|
|
|
if(update) {
|
if(update) {
|
Line 659... |
Line 654... |
glTexCoord2f(0.0, 0.0); glVertex3f(x, y, 0.0);
|
glTexCoord2f(0.0, 0.0); glVertex3f(x, y, 0.0);
|
glEnd();
|
glEnd();
|
glDisable(GL_TEXTURE_2D);
|
glDisable(GL_TEXTURE_2D);
|
}
|
}
|
|
|
void draw_terminal(const world_t *world, terminal_t *t, char *name)
|
void draw_terminal(const world_t *world, terminal_t *t, const char * const name) {
|
{
|
|
assert(world);
|
assert(world);
|
assert(t);
|
assert(t);
|
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
glPushMatrix();
|
glPushMatrix();
|
|
|
static const double scale_x = 0.011;
|
static const double scale_x = 0.011;
|
static const double scale_y = 0.011;
|
static const double scale_y = 0.011;
|
vt100_t *v = &t->vt100;
|
const vt100_t * const v = &t->vt100;
|
double now = world->tick - t->blink_count;
|
const scale_t scale = font_attributes();
|
scale_t scale = font_attributes();
|
const double now = world->tick - t->blink_count;
|
double char_width = scale.x / X_MAX;
|
const double char_width = scale.x / X_MAX;
|
double char_height = scale.y / Y_MAX;
|
const double char_height = scale.y / Y_MAX;
|
size_t cursor_x = v->cursor % v->width;
|
const size_t cursor_x = v->cursor % v->width;
|
size_t cursor_y = v->cursor / v->width;
|
const size_t cursor_y = v->cursor / v->width;
|
|
|
if(now > seconds_to_ticks(world, 1.0)) {
|
if(now > seconds_to_ticks(world, 1.0)) {
|
t->blink_on = !(t->blink_on);
|
t->blink_on = !(t->blink_on);
|
t->blink_count = world->tick;
|
t->blink_count = world->tick;
|
}
|
}
|
Line 846... |
Line 840... |
|
|
/* ====================================== Simulator Instances ================================== */
|
/* ====================================== Simulator Instances ================================== */
|
|
|
/* ====================================== H2 I/O Handling ====================================== */
|
/* ====================================== H2 I/O Handling ====================================== */
|
|
|
static uint16_t h2_io_get_gui(h2_soc_state_t *soc, uint16_t addr, bool *debug_on)
|
static uint16_t h2_io_get_gui(h2_soc_state_t * const soc, const uint16_t addr, bool *debug_on) {
|
{
|
|
assert(soc);
|
assert(soc);
|
assert(ps2_rx_fifo);
|
assert(ps2_rx_fifo);
|
assert(uart_tx_fifo);
|
assert(uart_tx_fifo);
|
assert(uart_rx_fifo);
|
assert(uart_rx_fifo);
|
|
|
if(debug_on)
|
if(debug_on)
|
*debug_on = false;
|
*debug_on = false;
|
switch(addr) {
|
switch(addr) {
|
case iUart:
|
case iUart:
|
{
|
return (fifo_is_empty(uart_tx_fifo) << UART_TX_FIFO_EMPTY_BIT)
|
uint16_t r = 0;
|
| (fifo_is_full(uart_tx_fifo) << UART_TX_FIFO_FULL_BIT)
|
r |= fifo_is_empty(uart_tx_fifo) << UART_TX_FIFO_EMPTY_BIT;
|
| (fifo_is_empty(uart_rx_fifo) << UART_RX_FIFO_EMPTY_BIT)
|
r |= fifo_is_full(uart_tx_fifo) << UART_TX_FIFO_FULL_BIT;
|
| (fifo_is_full(uart_rx_fifo) << UART_RX_FIFO_FULL_BIT)
|
r |= fifo_is_empty(uart_rx_fifo) << UART_RX_FIFO_EMPTY_BIT;
|
| soc->uart_getchar_register;
|
r |= fifo_is_full(uart_rx_fifo) << UART_RX_FIFO_FULL_BIT;
|
|
r |= soc->uart_getchar_register;
|
|
return r;
|
|
}
|
|
case iVT100:
|
case iVT100:
|
{
|
return (1u << UART_TX_FIFO_EMPTY_BIT)
|
uint16_t r = 0;
|
| (0u << UART_TX_FIFO_FULL_BIT)
|
r |= 1u << UART_TX_FIFO_EMPTY_BIT;
|
| (fifo_is_empty(ps2_rx_fifo) << UART_RX_FIFO_EMPTY_BIT)
|
r |= 0u << UART_TX_FIFO_FULL_BIT;
|
| (fifo_is_full(ps2_rx_fifo) << UART_RX_FIFO_FULL_BIT)
|
r |= fifo_is_empty(ps2_rx_fifo) << UART_RX_FIFO_EMPTY_BIT;
|
| soc->ps2_getchar_register;
|
r |= fifo_is_full(ps2_rx_fifo) << UART_RX_FIFO_FULL_BIT;
|
|
r |= soc->uart_getchar_register;
|
|
return r;
|
|
}
|
|
case iSwitches:
|
case iSwitches:
|
return soc->switches;
|
return soc->switches;
|
case iTimerDin: return soc->timer;
|
case iTimerDin: return soc->timer;
|
case iMemDin: return h2_io_memory_read_operation(soc);
|
case iMemDin: return h2_io_memory_read_operation(soc);
|
default:
|
default:
|
Line 887... |
Line 872... |
break;
|
break;
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/**@warning uses variables of static storage duration! */
|
static void h2_io_set_gui(h2_soc_state_t *soc, const uint16_t addr, const uint16_t value, bool *debug_on) {
|
static void h2_io_set_gui(h2_soc_state_t *soc, uint16_t addr, uint16_t value, bool *debug_on)
|
|
{
|
|
assert(soc);
|
assert(soc);
|
assert(uart_tx_fifo);
|
assert(uart_tx_fifo);
|
assert(uart_rx_fifo);
|
assert(uart_rx_fifo);
|
|
|
if(debug_on)
|
if(debug_on)
|
Line 936... |
Line 919... |
break;
|
break;
|
case oIrcMask: soc->irc_mask = value; break;
|
case oIrcMask: soc->irc_mask = value; break;
|
case oMemControl:
|
case oMemControl:
|
{
|
{
|
soc->mem_control = value;
|
soc->mem_control = value;
|
|
const bool sram_cs = soc->mem_control & SRAM_CHIP_SELECT;
|
bool sram_cs = soc->mem_control & SRAM_CHIP_SELECT;
|
const bool oe = soc->mem_control & FLASH_MEMORY_OE;
|
bool oe = soc->mem_control & FLASH_MEMORY_OE;
|
const bool we = soc->mem_control & FLASH_MEMORY_WE;
|
bool we = soc->mem_control & FLASH_MEMORY_WE;
|
|
|
|
if(sram_cs && !oe && we)
|
if(sram_cs && !oe && we)
|
soc->vram[(((uint32_t)(soc->mem_control & FLASH_MASK_ADDR_UPPER_MASK) << 16) | soc->mem_addr_low) >> 1] = soc->mem_dout;
|
soc->vram[(((uint32_t)(soc->mem_control & FLASH_MASK_ADDR_UPPER_MASK) << 16) | soc->mem_addr_low) >> 1] = soc->mem_dout;
|
break;
|
break;
|
}
|
}
|
case oMemAddrLow: soc->mem_addr_low = value; break;
|
case oMemAddrLow: soc->mem_addr_low = value; break;
|
case oMemDout: soc->mem_dout = value; break;
|
case oMemDout: soc->mem_dout = value; break;
|
|
case oUartTxBaud: soc->uart_tx_baud = value; break;
|
|
case oUartRxBaud: soc->uart_rx_baud = value; break;
|
|
case oUartControl: soc->uart_control = value; break;
|
default:
|
default:
|
warning("invalid write to %04"PRIx16 ":%04"PRIx16, addr, value);
|
warning("invalid write to %04"PRIx16 ":%04"PRIx16, addr, value);
|
break;
|
break;
|
}
|
}
|
}
|
}
|
|
|
/* ====================================== H2 I/O Handling ====================================== */
|
/* ====================================== H2 I/O Handling ====================================== */
|
|
|
/* ====================================== Main Loop ============================================ */
|
/* ====================================== Main Loop ============================================ */
|
|
|
static double fps(void)
|
static double fps(void) {
|
{
|
|
static unsigned frame = 0, timebase = 0;
|
static unsigned frame = 0, timebase = 0;
|
static double fps = 0;
|
static double fps = 0;
|
int time = glutGet(GLUT_ELAPSED_TIME);
|
const int time = glutGet(GLUT_ELAPSED_TIME);
|
frame++;
|
frame++;
|
if(time - timebase > 1000) {
|
if(time - timebase > 1000) {
|
fps = frame*1000.0/(time-timebase);
|
fps = frame*1000.0/(time-timebase);
|
timebase = time;
|
timebase = time;
|
frame = 0;
|
frame = 0;
|
}
|
}
|
return fps;
|
return fps;
|
}
|
}
|
|
|
static void draw_debug_info(const world_t *world, double fps, double x, double y)
|
static void draw_debug_info(const world_t *world, double fps, double x, double y) {
|
{
|
|
textbox_t t = { .x = x, .y = y, .draw_border = true, .color_text = WHITE, .color_box = WHITE };
|
textbox_t t = { .x = x, .y = y, .draw_border = true, .color_text = WHITE, .color_box = WHITE };
|
assert(world);
|
assert(world);
|
fifo_t *f = world->use_uart_input ? uart_rx_fifo : ps2_rx_fifo;
|
fifo_t *f = world->use_uart_input ? uart_rx_fifo : ps2_rx_fifo;
|
const char *fifo_str = world->use_uart_input ? "UART" : "PS/2";
|
const char *fifo_str = world->use_uart_input ? "UART" : "PS/2";
|
char buf[256] = { 0 };
|
|
|
|
fill_textbox(&t, "tick: %u", world->tick);
|
fill_textbox(&t, "tick: %u", world->tick);
|
//fill_textbox(&t, "seconds: %f", ticks_to_seconds(world->tick));
|
//fill_textbox(&t, "seconds: %f", ticks_to_seconds(world->tick));
|
fill_textbox(&t, "fps: %f", fps);
|
fill_textbox(&t, "fps: %f", fps);
|
|
|
if(world->debug_extra) {
|
if(world->debug_extra) {
|
|
char buf[256] = { 0 };
|
fill_textbox(&t, "Mode: %s", world->debug_mode ? "step" : "continue");
|
fill_textbox(&t, "Mode: %s", world->debug_mode ? "step" : "continue");
|
fill_textbox(&t, "%s RX fifo full: %s", fifo_str, fifo_is_full(f) ? "true" : "false");
|
fill_textbox(&t, "%s RX FIFO full: %s", fifo_str, fifo_is_full(f) ? "true" : "false");
|
fill_textbox(&t, "%s RX fifo empty: %s", fifo_str, fifo_is_empty(f) ? "true" : "false");
|
fill_textbox(&t, "%s RX FIFO empty: %s", fifo_str, fifo_is_empty(f) ? "true" : "false");
|
fill_textbox(&t, "%s RX fifo count: %u", fifo_str, (unsigned)fifo_count(f));
|
fill_textbox(&t, "%s RX FIFO count: %u", fifo_str, (unsigned)fifo_count(f));
|
fill_textbox(&t, "UART TX fifo full: %s", fifo_is_full(uart_tx_fifo) ? "true" : "false");
|
fill_textbox(&t, "UART TX FIFO full: %s", fifo_is_full(uart_tx_fifo) ? "true" : "false");
|
fill_textbox(&t, "UART TX fifo empty: %s", fifo_is_empty(uart_tx_fifo) ? "true" : "false");
|
fill_textbox(&t, "UART TX FIFO empty: %s", fifo_is_empty(uart_tx_fifo) ? "true" : "false");
|
fill_textbox(&t, "UART TX fifo count: %u", (unsigned)fifo_count(uart_tx_fifo));
|
fill_textbox(&t, "UART TX FIFO count: %u", (unsigned)fifo_count(uart_tx_fifo));
|
|
|
sprintf(buf, "%08lu", (unsigned long)(world->cycle_count));
|
sprintf(buf, "%08lu", (unsigned long)(world->cycle_count));
|
fill_textbox(&t, "cycles: %s", buf);
|
fill_textbox(&t, "cycles: %s", buf);
|
fill_textbox(&t, "cycles/tick %u", (unsigned)(world->cycles));
|
fill_textbox(&t, "cycles/tick: %u", (unsigned)(world->cycles));
|
}
|
}
|
draw_textbox(&t);
|
draw_textbox(&t);
|
}
|
}
|
|
|
static void fill_textbox_memory(textbox_t *t, uint16_t *m, size_t length)
|
static void fill_textbox_memory(textbox_t *t, const uint16_t * const m, const size_t length) {
|
{
|
|
assert(t);
|
assert(t);
|
assert(m);
|
assert(m);
|
assert((length % 4) == 0);
|
assert((length % 4) == 0);
|
for(size_t i = 0; i < length; i+=4)
|
for(size_t i = 0; i < length; i+=4)
|
fill_textbox(t, "%s%u: %x %x %x %x", i < 10 ? " " : "", i, m[i], m[i+1], m[i+2], m[i+3]);
|
fill_textbox(t, "%s%u: %x %x %x %x", i < 10 ? " " : "", i, m[i], m[i+1], m[i+2], m[i+3]);
|
}
|
}
|
|
|
static void draw_debug_h2_screen_1(h2_t *h, double x, double y)
|
static void draw_debug_h2_screen_1(h2_t *h, double x, double y) {
|
{
|
|
assert(h);
|
assert(h);
|
textbox_t t = { .x = x, .y = y, .draw_border = true, .color_text = WHITE, .color_box = WHITE };
|
textbox_t t = { .x = x, .y = y, .draw_border = true, .color_text = WHITE, .color_box = WHITE };
|
fill_textbox(&t, "H2 CPU State", h->tos);
|
fill_textbox(&t, "H2 CPU State", h->tos);
|
fill_textbox(&t, "tp: %u", h->tos);
|
fill_textbox(&t, "tp: %u", h->tos);
|
fill_textbox_memory(&t, h->dstk, STK_SIZE);
|
fill_textbox_memory(&t, h->dstk, STK_SIZE);
|
Line 1022... |
Line 1002... |
fill_textbox(&t, "dp: %u (max %u)", h->sp, h->spm);
|
fill_textbox(&t, "dp: %u (max %u)", h->sp, h->spm);
|
fill_textbox(&t, "ie: %s", h->ie ? "true" : "false");
|
fill_textbox(&t, "ie: %s", h->ie ? "true" : "false");
|
draw_textbox(&t);
|
draw_textbox(&t);
|
}
|
}
|
|
|
static void draw_debug_h2_screen_2(h2_t *h, double x, double y)
|
static void draw_debug_h2_screen_2(const h2_t * const h, const double x, const double y) {
|
{
|
|
textbox_t t = { .x = x, .y = y, .draw_border = true, .color_text = WHITE, .color_box = WHITE };
|
textbox_t t = { .x = x, .y = y, .draw_border = true, .color_text = WHITE, .color_box = WHITE };
|
assert(h);
|
assert(h);
|
fill_textbox(&t, "H2 CPU Return Stack");
|
fill_textbox(&t, "H2 CPU Return Stack");
|
fill_textbox_memory(&t, h->rstk, STK_SIZE);
|
fill_textbox_memory(&t, h->rstk, STK_SIZE);
|
draw_textbox(&t);
|
draw_textbox(&t);
|
}
|
}
|
|
|
static void draw_debug_h2_screen_3(h2_io_t *io, double x, double y)
|
static void draw_debug_h2_screen_3(const h2_io_t * const io, const double x, const double y) {
|
{
|
|
textbox_t t = { .x = x, .y = y, .draw_border = true, .color_text = WHITE, .color_box = WHITE };
|
textbox_t t = { .x = x, .y = y, .draw_border = true, .color_text = WHITE, .color_box = WHITE };
|
assert(io);
|
assert(io);
|
assert(io->soc);
|
assert(io->soc);
|
h2_soc_state_t *s = io->soc;
|
const h2_soc_state_t * const s = io->soc;
|
fill_textbox(&t, "I/O");
|
fill_textbox(&t, "I/O");
|
fill_textbox(&t, "LED %x", (unsigned)s->leds);
|
fill_textbox(&t, "LED %x", (unsigned)s->leds);
|
/*fill_textbox(&t, "VGA Cursor: %x", (unsigned)s->vga_cursor);*/
|
/*fill_textbox(&t, "VGA Cursor: %x", (unsigned)s->vga_cursor);*/
|
fill_textbox(&t, "Timer Control: %x", (unsigned)s->timer_control);
|
fill_textbox(&t, "Timer Control: %x", (unsigned)s->timer_control);
|
fill_textbox(&t, "Timer Count: %x", (unsigned)s->timer);
|
fill_textbox(&t, "Timer Count: %x", (unsigned)s->timer);
|
Line 1060... |
Line 1038... |
fill_textbox(&t, "mode: %x", (unsigned)s->flash.mode);
|
fill_textbox(&t, "mode: %x", (unsigned)s->flash.mode);
|
fill_textbox(&t, "status: %x", (unsigned)s->flash.status);
|
fill_textbox(&t, "status: %x", (unsigned)s->flash.status);
|
fill_textbox(&t, "address arg 1: %x", (unsigned)s->flash.arg1_address);
|
fill_textbox(&t, "address arg 1: %x", (unsigned)s->flash.arg1_address);
|
fill_textbox(&t, "data %x", (unsigned)s->flash.data);
|
fill_textbox(&t, "data %x", (unsigned)s->flash.data);
|
fill_textbox(&t, "cycle: %x", (unsigned)s->flash.cycle);
|
fill_textbox(&t, "cycle: %x", (unsigned)s->flash.cycle);
|
|
fill_textbox(&t, "UART Control");
|
|
fill_textbox(&t, "UART TX Baud: %x", (unsigned)s->uart_tx_baud);
|
|
fill_textbox(&t, "UART RX Baud: %x", (unsigned)s->uart_rx_baud);
|
|
fill_textbox(&t, "UART Control: %x", (unsigned)s->uart_control);
|
draw_textbox(&t);
|
draw_textbox(&t);
|
}
|
}
|
|
|
static void keyboard_handler(unsigned char key, int x, int y)
|
static void keyboard_handler(const unsigned char key, const int x, const int y) {
|
{
|
|
UNUSED(x);
|
UNUSED(x);
|
UNUSED(y);
|
UNUSED(y);
|
assert(uart_tx_fifo);
|
assert(uart_tx_fifo);
|
assert(ps2_rx_fifo);
|
assert(ps2_rx_fifo);
|
if(key == ESCAPE) {
|
if(key == ESCAPE) {
|
Line 1079... |
Line 1060... |
else
|
else
|
fifo_push(ps2_rx_fifo, key);
|
fifo_push(ps2_rx_fifo, key);
|
}
|
}
|
}
|
}
|
|
|
static void keyboard_special_handler(int key, int x, int y)
|
static void keyboard_special_handler(const int key, const int x, const int y) {
|
{
|
|
UNUSED(x);
|
UNUSED(x);
|
UNUSED(y);
|
UNUSED(y);
|
switch(key) {
|
switch(key) {
|
case GLUT_KEY_UP: dpad.up = true; break;
|
case GLUT_KEY_UP: dpad.up = true; break;
|
case GLUT_KEY_LEFT: dpad.left = true; break;
|
case GLUT_KEY_LEFT: dpad.left = true; break;
|
Line 1107... |
Line 1087... |
default:
|
default:
|
break;
|
break;
|
}
|
}
|
}
|
}
|
|
|
static void keyboard_special_up_handler(int key, int x, int y)
|
static void keyboard_special_up_handler(const int key, const int x, const int y) {
|
{
|
|
UNUSED(x);
|
UNUSED(x);
|
UNUSED(y);
|
UNUSED(y);
|
switch(key) {
|
switch(key) {
|
case GLUT_KEY_UP: dpad.up = false; break;
|
case GLUT_KEY_UP: dpad.up = false; break;
|
case GLUT_KEY_LEFT: dpad.left = false; break;
|
case GLUT_KEY_LEFT: dpad.left = false; break;
|
Line 1126... |
Line 1105... |
typedef struct {
|
typedef struct {
|
double x;
|
double x;
|
double y;
|
double y;
|
} coordinate_t;
|
} coordinate_t;
|
|
|
static double abs_diff(double a, double b)
|
static double abs_diff(const double a, const double b) {
|
{
|
|
return fabsl(fabsl(a) - fabsl(b));
|
return fabsl(fabsl(a) - fabsl(b));
|
}
|
}
|
|
|
static void resize_window(int w, int h)
|
static void resize_window(int w, int h) {
|
{
|
|
double window_x_min, window_x_max, window_y_min, window_y_max;
|
double window_x_min, window_x_max, window_y_min, window_y_max;
|
double scale, center;
|
double scale, center;
|
world.window_width = w;
|
world.window_width = w;
|
world.window_height = h;
|
world.window_height = h;
|
|
|
Line 1165... |
Line 1142... |
glMatrixMode(GL_PROJECTION);
|
glMatrixMode(GL_PROJECTION);
|
glLoadIdentity();
|
glLoadIdentity();
|
glOrtho(window_x_min, window_x_max, window_y_min, window_y_max, -1, 1);
|
glOrtho(window_x_min, window_x_max, window_y_min, window_y_max, -1, 1);
|
}
|
}
|
|
|
static coordinate_t pixels_to_coordinates(const world_t *world, int x, int y)
|
static coordinate_t pixels_to_coordinates(const world_t *world, const int x, const int y) {
|
{
|
|
assert(world);
|
assert(world);
|
coordinate_t c = { .0, .0 };
|
const double xd = abs_diff(X_MAX, X_MIN);
|
double xd = abs_diff(X_MAX, X_MIN);
|
const double yd = abs_diff(Y_MAX, Y_MIN);
|
double yd = abs_diff(Y_MAX, Y_MIN);
|
const double xs = world->window_width / world->window_scale_x;
|
double xs = world->window_width / world->window_scale_x;
|
const double ys = world->window_height / world->window_scale_y;
|
double ys = world->window_height / world->window_scale_y;
|
const coordinate_t c = {
|
c.x = Y_MIN + (xd * ((x - (world->window_width - xs)/2.) / xs));
|
.x = Y_MIN + (xd * ((x - (world->window_width - xs)/2.) / xs)),
|
c.y = Y_MAX - (yd * ((y - (world->window_height - ys)/2.) / ys));
|
.y = Y_MAX - (yd * ((y - (world->window_height - ys)/2.) / ys))
|
|
};
|
return c;
|
return c;
|
}
|
}
|
|
|
static void mouse_handler(int button, int state, int x, int y)
|
static void mouse_handler(const int button, const int state, const int x, const int y) {
|
{
|
const coordinate_t c = pixels_to_coordinates(&world, x, y);
|
coordinate_t c = pixels_to_coordinates(&world, x, y);
|
|
|
|
for(size_t i = 0; i < SWITCHES_COUNT; i++) {
|
for(size_t i = 0; i < SWITCHES_COUNT; i++) {
|
if(detect_circle_circle_collision(c.x, c.y, 0.1, switches[i].x, switches[i].y, switches[i].radius)) {
|
if(detect_circle_circle_collision(c.x, c.y, 0.1, switches[i].x, switches[i].y, switches[i].radius)) {
|
if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
|
if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
|
switches[i].on = true;
|
switches[i].on = true;
|
Line 1210... |
Line 1186... |
dpad.up = false;
|
dpad.up = false;
|
dpad.center = false;
|
dpad.center = false;
|
}
|
}
|
}
|
}
|
|
|
static void timer_callback(int value)
|
static void timer_callback(const int value) {
|
{
|
|
world.tick++;
|
world.tick++;
|
glutTimerFunc(world.arena_tick_ms, timer_callback, value);
|
glutTimerFunc(world.arena_tick_ms, timer_callback, value);
|
}
|
}
|
|
|
static void update_switches(void)
|
static void update_switches(void) {
|
{
|
|
h2_io->soc->switches = 0;
|
h2_io->soc->switches = 0;
|
for(size_t i = 0; i < SWITCHES_COUNT; i++)
|
for(size_t i = 0; i < SWITCHES_COUNT; i++)
|
h2_io->soc->switches |= switches[i].on << i;
|
h2_io->soc->switches |= switches[i].on << i;
|
h2_io->soc->switches |= dpad.center << (SWITCHES_COUNT+0);
|
h2_io->soc->switches |= dpad.center << (SWITCHES_COUNT+0);
|
h2_io->soc->switches |= dpad.right << (SWITCHES_COUNT+1);
|
h2_io->soc->switches |= dpad.right << (SWITCHES_COUNT+1);
|
h2_io->soc->switches |= dpad.left << (SWITCHES_COUNT+2);
|
h2_io->soc->switches |= dpad.left << (SWITCHES_COUNT+2);
|
h2_io->soc->switches |= dpad.down << (SWITCHES_COUNT+3);
|
h2_io->soc->switches |= dpad.down << (SWITCHES_COUNT+3);
|
h2_io->soc->switches |= dpad.up << (SWITCHES_COUNT+4);
|
h2_io->soc->switches |= dpad.up << (SWITCHES_COUNT+4);
|
}
|
}
|
|
|
static void draw_scene(void)
|
static void draw_scene(void) {
|
{
|
static uint64_t next = 0; // @warning static!
|
static uint64_t next = 0;
|
static uint64_t count = 0; // @warning static!
|
static uint64_t count = 0;
|
|
double f = fps();
|
double f = fps();
|
if(world.halt_simulation)
|
if(world.halt_simulation)
|
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
Line 1267... |
Line 1240... |
world.cycles = MAX(CYCLE_MINIMUM, n);
|
world.cycles = MAX(CYCLE_MINIMUM, n);
|
}
|
}
|
}
|
}
|
|
|
if(increment)
|
if(increment)
|
if(h2_run(h, h2_io, stderr, increment, NULL, false) < 0)
|
if (h2_run(h, h2_io, stderr, increment, NULL, false, trace_file) < 0)
|
world.halt_simulation = true;
|
world.halt_simulation = true;
|
|
|
world.step = false;
|
world.step = false;
|
world.cycle_count += increment;
|
world.cycle_count += increment;
|
}
|
}
|
Line 1317... |
Line 1290... |
glFlush();
|
glFlush();
|
glutSwapBuffers();
|
glutSwapBuffers();
|
glutPostRedisplay();
|
glutPostRedisplay();
|
}
|
}
|
|
|
static void initialize_rendering(char *arg_0)
|
static void initialize_rendering(char *arg_0) {
|
{
|
|
char *glut_argv[] = { arg_0, NULL };
|
char *glut_argv[] = { arg_0, NULL };
|
int glut_argc = 0;
|
int glut_argc = 0;
|
memset(uart_terminal.vt100.m, ' ', uart_terminal.vt100.size);
|
memset(uart_terminal.vt100.m, ' ', uart_terminal.vt100.size);
|
glutInit(&glut_argc, glut_argv);
|
glutInit(&glut_argc, glut_argv);
|
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
|
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
|
Line 1338... |
Line 1310... |
glutReshapeFunc(resize_window);
|
glutReshapeFunc(resize_window);
|
glutDisplayFunc(draw_scene);
|
glutDisplayFunc(draw_scene);
|
glutTimerFunc(world.arena_tick_ms, timer_callback, 0);
|
glutTimerFunc(world.arena_tick_ms, timer_callback, 0);
|
}
|
}
|
|
|
static void vt100_initialize(vt100_t *v)
|
static void vt100_initialize(vt100_t * const v) {
|
{
|
|
assert(v);
|
assert(v);
|
memset(&v->attribute, 0, sizeof(v->attribute));
|
memset(&v->attribute, 0, sizeof(v->attribute));
|
v->attribute.foreground_color = WHITE;
|
v->attribute.foreground_color = WHITE;
|
v->attribute.background_color = BLACK;
|
v->attribute.background_color = BLACK;
|
for(size_t i = 0; i < v->size; i++)
|
for(size_t i = 0; i < v->size; i++)
|
v->attributes[i] = v->attribute;
|
v->attributes[i] = v->attribute;
|
}
|
}
|
|
|
static void finalize(void)
|
static void finalize(void) {
|
{
|
nvram_save(h2_io, FLASH_INIT_FILE);
|
nvram_save(h2_io, nvram_file);
|
|
h2_free(h);
|
h2_free(h);
|
h2_io_free(h2_io);
|
h2_io_free(h2_io);
|
fifo_free(uart_tx_fifo);
|
fifo_free(uart_tx_fifo);
|
fifo_free(uart_rx_fifo);
|
fifo_free(uart_rx_fifo);
|
fifo_free(ps2_rx_fifo);
|
fifo_free(ps2_rx_fifo);
|
|
if (trace_file)
|
|
fclose(trace_file);
|
}
|
}
|
|
|
int main(int argc, char **argv)
|
int main(int argc, char **argv) {
|
{
|
|
FILE *hexfile = NULL;
|
FILE *hexfile = NULL;
|
int r = 0;
|
int r = 0;
|
|
|
assert(Y_MAX > 0. && Y_MIN < Y_MAX && Y_MIN >= 0.);
|
assert(Y_MAX > 0. && Y_MIN < Y_MAX && Y_MIN >= 0.);
|
assert(X_MAX > 0. && X_MIN < X_MAX && X_MIN >= 0.);
|
assert(X_MAX > 0. && X_MIN < X_MAX && X_MIN >= 0.);
|
Line 1408... |
Line 1379... |
|
|
uart_rx_fifo = fifo_new(UART_FIFO_DEPTH);
|
uart_rx_fifo = fifo_new(UART_FIFO_DEPTH);
|
uart_tx_fifo = fifo_new(UART_FIFO_DEPTH * 100); /** @note x100 to speed things up */
|
uart_tx_fifo = fifo_new(UART_FIFO_DEPTH * 100); /** @note x100 to speed things up */
|
ps2_rx_fifo = fifo_new(8 /** @bug should be 1 - but this does not work, FIFO implementation needs correcting */);
|
ps2_rx_fifo = fifo_new(8 /** @bug should be 1 - but this does not work, FIFO implementation needs correcting */);
|
|
|
nvram_load_and_transfer(h2_io, nvram_file, true);
|
nvram_load_and_transfer(h2_io, FLASH_INIT_FILE, true);
|
|
|
|
if (TRON) {
|
|
errno = 0;
|
|
trace_file = fopen(TRACE_FILE, "wb");
|
|
if (trace_file)
|
|
setvbuf(trace_file, trace_buffer, _IOFBF, TRACE_BUFFER_LEN);
|
|
else
|
|
warning("could not open %s for writing: %s", TRACE_FILE, strerror(errno));
|
|
}
|
|
|
atexit(finalize);
|
atexit(finalize);
|
initialize_rendering(argv[0]);
|
initialize_rendering(argv[0]);
|
glutMainLoop();
|
glutMainLoop();
|
|
|