Refactor and cleanup.

- Refactored and cleaned up code
- Renamed project to 'dmd5620'
- Added icon resources
This commit is contained in:
Seth Morabito 2018-12-19 15:21:21 -08:00
parent e45281118a
commit 60c855d45a
9 changed files with 304 additions and 153 deletions

2
.gitignore vendored
View File

@ -1,3 +1,3 @@
**/*.o
lib/target
dmd
dmd5620

View File

@ -3,7 +3,7 @@ LIBDIR = lib
CC = gcc
CFLAGS = $(shell pkg-config --cflags gtk+-3.0) -Wall
GTKLIBS = $(shell pkg-config --libs gtk+-3.0)
EXE = dmd
EXE = dmd5620
CSRC = $(wildcard src/*.c)
OBJ = $(CSRC:.c=.o)
RUSTLIB = $(LIBDIR)/target/release/libdmd_bindings.a

View File

@ -4,14 +4,17 @@ This is a GTK+ 3.0 implementation of an AT&T / Teletype DMD 5620 emulator.
## Status
Version: 0.1
Version: 1.0.0
This is an actively developed project, and is not ready for use yet.
This is an actively developed project.
## Usage
The terminal uses the Telnet protocol to communicate with a remote
host.
```
dmd -h <host> [-p <port>] [-n <nvram_file>]
dmd5620 -h <host> [-p <port>] [-n <nvram_file>] [-v] [-- <gtk-options> ...]
```
If not specified, `<port>` defaults to 23.
@ -19,6 +22,11 @@ If not specified, `<port>` defaults to 23.
`nvram_file` is the name of a file in which to store the contents of NVRAM.
This will preserve the state of the NVRAM between runs.
## To Do
- Terminal bell is not yet implemented.
- Local serial line support is not yet implemented.
## See Also
* [dmd_core](https://github.com/sethm/dmd_core): DMD 5620 core

BIN
assets/dmd5620.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

25
assets/dmd5620.svg Normal file
View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 626 626" style="enable-background:new 0 0 626 626;" xml:space="preserve">
<style type="text/css">
.st0{fill:#333333;}
.st1{fill:#FFFFFF;}
.st2{font-family:'Impact';}
.st3{font-size:249px;}
.st4{fill:#7AC943;}
</style>
<g>
<path class="st0" d="M313,612.5c-80,0-155.21-31.15-211.78-87.72C44.65,468.21,13.5,393,13.5,313c0-80,31.15-155.21,87.72-211.78
C157.79,44.65,233,13.5,313,13.5c80,0,155.21,31.15,211.78,87.72C581.35,157.79,612.5,233,612.5,313
c0,80-31.15,155.21-87.72,211.78S393,612.5,313,612.5z"/>
<path class="st1" d="M313,27c38.62,0,76.07,7.56,111.32,22.46c34.05,14.4,64.64,35.03,90.92,61.3
c26.27,26.27,46.9,56.86,61.3,90.92C591.44,236.93,599,274.38,599,313s-7.56,76.07-22.46,111.32
c-14.4,34.05-35.03,64.64-61.3,90.92c-26.27,26.27-56.86,46.9-90.92,61.3C389.07,591.44,351.62,599,313,599
s-76.07-7.56-111.32-22.46c-34.05-14.4-64.64-35.03-90.92-61.3c-26.27-26.27-46.9-56.86-61.3-90.92C34.56,389.07,27,351.62,27,313
s7.56-76.07,22.46-111.32c14.4-34.05,35.03-64.64,61.3-90.92s56.86-46.9,90.92-61.3C236.93,34.56,274.38,27,313,27 M313,0
C140.13,0,0,140.13,0,313s140.13,313,313,313s313-140.13,313-313S485.87,0,313,0L313,0z"/>
</g>
<text transform="matrix(1 0 0 1 93.1362 408.4092)" class="st2 st3">DMD</text>
<text transform="matrix(1 0 0 1 88.1362 403.4092)" class="st4 st2 st3">DMD</text>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -54,7 +54,7 @@ fn dmd_step() -> c_int {
}
#[no_mangle]
fn dmd_run(steps: usize) -> c_int {
fn dmd_step_loop(steps: usize) -> c_int {
match DMD.lock() {
Ok(mut dmd) => {
dmd.run(steps);

View File

@ -1,3 +1,29 @@
/*
* This file is part of the GTK+ DMD 5620 Emultor.
*
* Copyright 2018, Seth Morabito <web@loomcom.com>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <gtk/gtk.h>
#include <gmodule.h>
@ -18,12 +44,10 @@
#include <stdint.h>
#include <pthread.h>
#include "libtelnet.h"
#define WIDTH 800
#define HEIGHT 1024
#define NVRAM_SIZE 2<<12
#include "version.h"
#include "dmd_5620.h"
static char VERSION_STRING[64];
static GtkWidget *main_window;
static char telnet_buf[90];
static cairo_surface_t *surface = NULL;
@ -33,7 +57,8 @@ static int sock = -1;
static telnet_t *telnet;
static GQueue *telnet_rx_queue;
static char *nvram = NULL;
static volatile int dmd_thread_run = 1;
static volatile gboolean dmd_thread_run = TRUE;
static volatile int sigint_count = 0;
/* Implement a very dumb protocol. */
static const telnet_telopt_t dmd_telopts[] = {
@ -46,24 +71,6 @@ static const telnet_telopt_t dmd_telopts[] = {
{ -1, 0, 0}
};
/* DMD functions */
extern int dmd_reset();
extern uint8_t *dmd_video_ram();
extern int dmd_step();
// extern int dmd_(size_t steps);
extern int dmd_get_pc(uint32_t *pc);
extern int dmd_get_register(uint8_t reg, uint32_t *val);
extern uint8_t dmd_get_duart_output_port();
extern int dmd_rx_char(uint8_t c);
extern int dmd_rx_keyboard(uint8_t c);
extern int dmd_tx_poll(uint8_t *c);
extern int dmd_mouse_move(uint16_t x, uint16_t y);
extern int dmd_mouse_down(uint8_t button);
extern int dmd_mouse_up(uint8_t button);
extern int dmd_set_nvram(uint8_t *buf);
extern int dmd_get_nvram(uint8_t *buf);
volatile int sigint_count = 0;
static void
int_handler(int _signal)
@ -82,29 +89,30 @@ int_handler(int _signal)
sigint_count++;
}
static void
_send(int sock, const char *buffer, size_t size)
static int
tx_send(int sock, const char *buffer, size_t size)
{
int rs;
/* send data */
while (size > 0) {
if ((rs = send(sock, buffer, size, 0)) == -1) {
fprintf(stderr, "send() failed: %s\n", strerror(errno));
exit(1);
return 1;
} else if (rs == 0) {
fprintf(stderr, "send() unexpectedly returned 0\n");
exit(1);
return 1;
}
/* update pointer and size to see if we've got more to send */
buffer += rs;
size -= rs;
}
return 0;
}
static void
telnet_event_handler(telnet_t *telnet, telnet_event_t *ev, void *user_data)
telnet_handler(telnet_t *telnet, telnet_event_t *ev, void *data)
{
switch (ev->type) {
case TELNET_EV_DATA:
@ -116,7 +124,11 @@ telnet_event_handler(telnet_t *telnet, telnet_event_t *ev, void *user_data)
}
break;
case TELNET_EV_SEND:
_send(sock, ev->data.buffer, ev->data.size);
if (tx_send(sock, ev->data.buffer, ev->data.size) != 0) {
/* TODO: It's probably best to offer a clean shutdown and/or
retry here, somehow. */
fprintf(stderr, "ERROR: Could not send telnet buffer!\n");
}
break;
case TELNET_EV_TTYPE:
if (ev->ttype.cmd == TELNET_TTYPE_SEND) {
@ -129,7 +141,7 @@ telnet_event_handler(telnet_t *telnet, telnet_event_t *ev, void *user_data)
}
static int
dmd_telnet_connect(char *host, char *port)
telnet_connect(char *host, char *port)
{
struct addrinfo *ai;
struct addrinfo hints;
@ -176,13 +188,13 @@ dmd_telnet_connect(char *host, char *port)
return -1;
}
telnet = telnet_init(dmd_telopts, telnet_event_handler, 0, &sock);
telnet = telnet_init(dmd_telopts, telnet_handler, 0, &sock);
return 0;
}
int
dmd_telnet_disconnect()
telnet_disconnect()
{
if (sock < 0) {
return -1;
@ -196,38 +208,6 @@ dmd_telnet_disconnect()
return 0;
}
static void
clear_surface()
{
cairo_t *cr;
cr = cairo_create(surface);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_paint(cr);
cairo_destroy(cr);
}
static gboolean
configure_event_cb(GtkWidget *widget, GdkEventConfigure *event, gpointer data)
{
if (surface) {
cairo_surface_destroy(surface);
}
surface = gdk_window_create_similar_surface(gtk_widget_get_window(widget),
CAIRO_CONTENT_COLOR,
gtk_widget_get_allocated_width(widget),
gtk_widget_get_allocated_height(widget));
pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, WIDTH, HEIGHT);
clear_surface();
return TRUE;
}
static void
close_window()
@ -242,8 +222,6 @@ close_window()
} else {
if (fwrite(buf, NVRAM_SIZE, 1, fp) != 1) {
fprintf(stderr, "Could not write full NVRAM file %s\n", nvram);
} else {
printf("Stored NVRAM file %s\n", nvram);
}
}
}
@ -252,12 +230,30 @@ close_window()
cairo_surface_destroy(surface);
}
dmd_telnet_disconnect();
telnet_disconnect();
dmd_thread_run = 0;
gtk_main_quit();
}
static gboolean
draw_cb(GtkWidget *widget, cairo_t *cr, gpointer data)
configure_handler(GtkWidget *widget, GdkEventConfigure *event, gpointer data)
{
if (surface) {
cairo_surface_destroy(surface);
}
surface = gdk_window_create_similar_surface(gtk_widget_get_window(widget),
CAIRO_CONTENT_COLOR,
gtk_widget_get_allocated_width(widget),
gtk_widget_get_allocated_height(widget));
pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, WIDTH, HEIGHT);
return TRUE;
}
static gboolean
draw_handler(GtkWidget *widget, cairo_t *cr, gpointer data)
{
cairo_set_source_surface(cr, surface, 0, 0);
cairo_paint(cr);
@ -265,11 +261,16 @@ draw_cb(GtkWidget *widget, cairo_t *cr, gpointer data)
return FALSE;
}
static gboolean
refresh_display(gpointer data)
{
uint8_t oport;
GtkWidget *widget = (GtkWidget *)data;
const struct color *fg_color;
const struct color *bg_color;
if (widget == NULL || !GTK_IS_WIDGET(widget)) {
return FALSE;
}
@ -283,21 +284,34 @@ refresh_display(gpointer data)
fprintf(stderr, "ERROR: Unable to access video ram!\n");
exit(-1);
} else {
/* Bit 2 of the DUART output port controls whether the
* screen is Dark-on-Light or Light-on-Dark
*/
dmd_get_duart_output_port(&oport);
if (oport & 0x2) {
fg_color = &COLOR_DARK;
bg_color = &COLOR_LIGHT;
} else {
fg_color = &COLOR_LIGHT;
bg_color = &COLOR_DARK;
}
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < byte_width; x++) {
uint8_t b = vram[y*byte_width + x];
for (int i = 0; i < 8; i++) {
int bit = (b >> (7 - i)) & 1;
if (bit) {
p[p_index++] = 0;
p[p_index++] = 0xff;
p[p_index++] = 0;
p[p_index++] = 0xff;
p[p_index++] = fg_color->r;
p[p_index++] = fg_color->g;
p[p_index++] = fg_color->b;
p[p_index++] = fg_color->a;
} else {
p[p_index++] = 0;
p[p_index++] = 0;
p[p_index++] = 0;
p[p_index++] = 0xff;
p[p_index++] = bg_color->r;
p[p_index++] = bg_color->g;
p[p_index++] = bg_color->b;
p[p_index++] = bg_color->a;
}
}
}
@ -349,10 +363,10 @@ mouse_button(GtkWidget *widget, GdkEventButton *event, gpointer data)
/*
* This is the main thread for stepping the DMD emulator.
*/
void *dmd_cpu_thread(void *threadid)
static void *
dmd_cpu_thread(void *threadid)
{
struct timespec sleep_time_req, sleep_time_rem;
long long int steps = 0;
int size;
ssize_t read_count;
uint8_t rxc;
@ -360,7 +374,6 @@ void *dmd_cpu_thread(void *threadid)
uint8_t nvram_buf[NVRAM_SIZE];
char tx_buf[1];
FILE *fp;
uint32_t pc;
sleep_time_req.tv_sec = 0;
sleep_time_req.tv_nsec = 250000;
@ -372,11 +385,7 @@ void *dmd_cpu_thread(void *threadid)
fp = fopen(nvram, "r");
/* If there's no file yet, don't load anything. */
if (fp == NULL) {
fprintf(stderr,
"Could not open NVRAM file %s. Skipping.\n",
nvram);
} else {
if (fp != NULL) {
/* Validate the file size */
fseek(fp, 0, SEEK_END);
size = ftell(fp);
@ -393,59 +402,53 @@ void *dmd_cpu_thread(void *threadid)
nvram);
} else {
dmd_set_nvram(nvram_buf);
printf("Set NVRAM from file %s.\n", nvram);
}
}
}
}
while (dmd_thread_run) {
dmd_step();
dmd_get_pc(&pc);
dmd_step_loop(10000);
/* Stop occasionally to poll for IO and idle. */
if (steps++ % 10000 == 0) {
/* Poll the receive queue for input for the RS-232 line */
if (!g_queue_is_empty(telnet_rx_queue)) {
rxc = (uint8_t)(GPOINTER_TO_UINT(g_queue_pop_tail(telnet_rx_queue)));
dmd_rx_char(rxc);
}
/* Poll the receive queue for input for the RS-232 line */
if (!g_queue_is_empty(telnet_rx_queue)) {
rxc = (uint8_t)(GPOINTER_TO_UINT(g_queue_pop_tail(telnet_rx_queue)));
dmd_rx_char(rxc);
/* If a socket is available... */
if (sock >= 0) {
/* Poll for output from the RS-232 line */
if (dmd_tx_poll(&txc) == 0) {
tx_buf[0] = txc;
telnet_send(telnet, tx_buf, 1);
}
/* If a socket is available... */
if (sock >= 0) {
/* Try to receive more data from Telnet */
read_count = recv(sock, telnet_buf, sizeof(telnet_buf), 0);
/* Poll for output from the RS-232 line */
if (dmd_tx_poll(&txc) == 0) {
tx_buf[0] = txc;
telnet_send(telnet, tx_buf, 1);
}
/* Try to receive more data from Telnet */
read_count = recv(sock, telnet_buf, sizeof(telnet_buf), 0);
if (read_count < 0) {
if (errno == EAGAIN) {
/* No worries, try again. */
} else {
fprintf(stderr,
"ERROR: Could not receive from "
"telnet. Closing connection. "
"rc=%ld err=%s\n",
read_count,
strerror(errno));
dmd_telnet_disconnect();
break;
}
if (read_count < 0) {
if (errno == EAGAIN) {
/* No worries, try again. */
} else {
telnet_recv(telnet, telnet_buf, read_count);
fprintf(stderr,
"ERROR: Could not receive from "
"telnet. Closing connection. "
"rc=%ld err=%s\n",
read_count,
strerror(errno));
telnet_disconnect();
break;
}
} else {
telnet_recv(telnet, telnet_buf, read_count);
}
}
if (nanosleep(&sleep_time_req, &sleep_time_rem)) {
fprintf(stderr, "ERROR: Unable to idle.\n");
break;
}
if (nanosleep(&sleep_time_req, &sleep_time_rem)) {
fprintf(stderr, "ERROR: Unable to idle.\n");
break;
}
}
@ -455,7 +458,7 @@ void *dmd_cpu_thread(void *threadid)
}
static gboolean
keydown_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
keydown(GtkWidget *widget, GdkEventKey *event, gpointer data)
{
gboolean is_ctrl = event->state & GDK_CONTROL_MASK;
gboolean is_shift = event->state & GDK_SHIFT_MASK;
@ -624,12 +627,14 @@ keydown_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
/* Called on startup as a callback */
static void
activate(GtkApplication *app, gpointer user_data)
dmd_setup(int *argc, char ***argv)
{
GtkWidget *frame;
GtkWidget *drawing_area;
main_window = gtk_application_window_new(app);
gtk_init(argc, argv);
main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_icon_name(GTK_WINDOW(main_window), "dmd5620");
gtk_window_set_title(GTK_WINDOW(main_window), "AT&T DMD 5620");
gtk_window_set_resizable(GTK_WINDOW(main_window), FALSE);
@ -637,24 +642,20 @@ activate(GtkApplication *app, gpointer user_data)
gtk_container_set_border_width(GTK_CONTAINER(main_window), 0);
frame = gtk_frame_new(NULL);
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
gtk_container_add(GTK_CONTAINER(main_window), frame);
drawing_area = gtk_drawing_area_new();
gtk_widget_set_size_request(drawing_area, 800, 1024);
gtk_container_add(GTK_CONTAINER(frame), drawing_area);
gtk_container_add(GTK_CONTAINER(main_window), drawing_area);
/* Try for 30 fps */
g_timeout_add(33, refresh_display, drawing_area);
/* Signals used to handle the backing surface */
g_signal_connect(drawing_area, "draw",
G_CALLBACK(draw_cb), NULL);
G_CALLBACK(draw_handler), NULL);
g_signal_connect(drawing_area, "configure-event",
G_CALLBACK(configure_event_cb), NULL);
G_CALLBACK(configure_handler), NULL);
/* UI signals */
g_signal_connect(drawing_area, "button-press-event",
@ -662,7 +663,7 @@ activate(GtkApplication *app, gpointer user_data)
g_signal_connect(drawing_area, "button-release-event",
G_CALLBACK(mouse_button), NULL);
g_signal_connect(G_OBJECT(main_window), "key-press-event",
G_CALLBACK(keydown_event), NULL);
G_CALLBACK(keydown), NULL);
g_signal_connect(drawing_area, "motion-notify-event",
G_CALLBACK(mouse_moved), NULL);
@ -679,20 +680,24 @@ activate(GtkApplication *app, gpointer user_data)
int
main(int argc, char *argv[])
{
GtkApplication *app;
int c, status, errflg = 0;
int c, errflg = 0;
long thread_id = 0;
char *host = NULL, *port = NULL;
int portno;
int rs;
snprintf(VERSION_STRING, 64, "%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD);
signal(SIGINT, int_handler);
extern char *optarg;
extern int optind, optopt;
while ((c = getopt(argc, argv, "h:p:n:")) != -1) {
while ((c = getopt(argc, argv, "vh:p:n:")) != -1) {
switch(c) {
case 'v':
printf("Version: %s\n", VERSION_STRING);
exit(0);
case 'h':
host = optarg;
break;
@ -710,7 +715,7 @@ main(int argc, char *argv[])
}
if (errflg || host == NULL) {
fprintf(stderr, "Usage: dmd -h host [-p port] [-n nvram_file]\n");
fprintf(stderr, "Usage: dmd5620 [-v] -h host [-p port] [-n nvram_file] [-- <gtk_options> ...]\n");
exit(2);
}
@ -728,7 +733,7 @@ main(int argc, char *argv[])
/* Initialize the telnet receive queue. */
telnet_rx_queue = g_queue_new();
if ((rs = dmd_telnet_connect(host, port)) != 0) {
if ((rs = telnet_connect(host, port)) != 0) {
fprintf(stderr, "Unable to connect to %s:%s: %s\n",
host, port, strerror(errno));
exit(-1);
@ -739,10 +744,9 @@ main(int argc, char *argv[])
exit(-1);
}
app = gtk_application_new("com.loomcom.dmd", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
dmd_setup(&argc, &argv);
status = g_application_run(G_APPLICATION(app), 0, NULL);
gtk_main();
void *join_status;
if ((rs = pthread_join(dmd_thread, &join_status)) != 0) {
@ -750,7 +754,5 @@ main(int argc, char *argv[])
exit(-1);
}
g_object_unref(app);
return status;
return 0;
}

82
src/dmd_5620.h Normal file
View File

@ -0,0 +1,82 @@
/*
* This file is part of the GTK+ DMD 5620 Emultor.
*
* Copyright 2018, Seth Morabito <web@loomcom.com>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __DMD_5620_H__
#define __DMD_5620_H__
#include "libtelnet.h"
#define WIDTH 800
#define HEIGHT 1024
#define NVRAM_SIZE 2<<12
struct color
{
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
};
static const struct color COLOR_LIGHT = { 0, 255, 0, 255 };
static const struct color COLOR_DARK = { 0, 0, 0, 255 };
/* dmd_core exported functions */
extern uint8_t *dmd_video_ram();
extern int dmd_reset();
extern int dmd_step();
extern int dmd_step_loop(size_t steps);
extern int dmd_get_pc(uint32_t *pc);
extern int dmd_get_register(uint8_t reg, uint32_t *val);
extern int dmd_get_duart_output_port(uint8_t *val);
extern int dmd_rx_char(uint8_t c);
extern int dmd_rx_keyboard(uint8_t c);
extern int dmd_tx_poll(uint8_t *c);
extern int dmd_mouse_move(uint16_t x, uint16_t y);
extern int dmd_mouse_down(uint8_t button);
extern int dmd_mouse_up(uint8_t button);
extern int dmd_set_nvram(uint8_t *buf);
extern int dmd_get_nvram(uint8_t *buf);
/* function prototypes */
static void int_handler(int signal);
static int tx_send(int sock, const char *buffer, size_t size);
static void telnet_handler(telnet_t *telnet, telnet_event_t *ev, void *data);
static int telnet_connect(char *host, char *port);
static int telnet_disconnect();
static void close_window();
static gboolean configure_handler(GtkWidget *widget,
GdkEventConfigure *event,
gpointer data);
static gboolean draw_handler(GtkWidget *widget, cairo_t *cr, gpointer data);
static gboolean refresh_display(gpointer data);
static gboolean mouse_moved(GtkWidget *widget, GdkEventMotion *event, gpointer data);
static gboolean mouse_button(GtkWidget *widget, GdkEventButton *event, gpointer data);
static void *dmd_cpu_thread(void *threadid);
static gboolean keydown(GtkWidget *widget, GdkEventKey *event, gpointer data);
static void dmd_setup(int *argc, char ***argv);
#endif

34
src/version.h Normal file
View File

@ -0,0 +1,34 @@
/*
* This file is part of the GTK+ DMD 5620 Emultor.
*
* Copyright 2018, Seth Morabito <web@loomcom.com>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef __VERSION_H__
#define __VERSION_H__
#define VERSION_MAJOR 1
#define VERSION_MINOR 0
#define VERSION_BUILD 0
#endif