Running the DMD core.

This commit is contained in:
Seth Morabito 2018-12-14 22:53:45 -08:00
parent a2d6cd5369
commit 2f77975f65
6 changed files with 459 additions and 42 deletions

1
.gitignore vendored
View File

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

View File

@ -7,7 +7,7 @@ EXE = dmd
CSRC = $(wildcard src/*.c)
OBJ = $(CSRC:.c=.o)
RUSTLIB = $(LIBDIR)/target/release/libdmd_bindings.a
LDFLAGS = $(GTKLIBS) -lm
LDFLAGS = $(GTKLIBS) -lm -lpthread -lc -ldl
.PHONY: all clean

8
lib/Cargo.lock generated
View File

@ -3,6 +3,8 @@ name = "dmd_bindings"
version = "0.1.0"
dependencies = [
"dmd_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -18,6 +20,12 @@ name = "lazy_static"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum dmd_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c715644dc46b8c0cc639350ebb522fba81856939f7a0f786f7d10c2ed7734076"
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
"checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74"

View File

@ -6,6 +6,8 @@ edition = "2018"
[dependencies]
dmd_core = "^0.2"
lazy_static = "1.2.0"
libc = "0.2"
[lib]
crate-type = ["staticlib"]
crate-type = ["staticlib"]

View File

@ -1,5 +1,350 @@
#[macro_use]
extern crate lazy_static;
extern crate dmd_core;
extern crate libc;
use libc::*;
use std::sync::Mutex;
use std::ptr;
use dmd_core::dmd::Dmd;
use dmd_core::err::DuartError;
struct DmdState {
pub dmd: Option<Dmd>,
}
impl DmdState {
pub fn new() -> DmdState {
DmdState {
dmd: None,
}
}
}
lazy_static! {
static ref DMD_STATE: Mutex<DmdState> = Mutex::new(DmdState::new());
}
#[no_mangle]
fn test_function() -> u8 {
fn dmd_init() -> bool {
match DMD_STATE.lock() {
Ok(mut dmd_guard) => {
match dmd_guard.dmd {
Some(_) => {
println!("[DMD ERROR] DMD already initialized");
false
}
None => {
dmd_guard.dmd = Some(Dmd::new());
println!("[DMD] Created new DMD");
true
}
}
}
Err(e) => {
println!("[DMD ERROR] Could not lock DMD. Error={:?}", e);
false
}
}
}
#[no_mangle]
fn dmd_reset() -> bool {
match DMD_STATE.lock() {
Ok(mut dmd_guard) => {
match &mut dmd_guard.dmd {
Some(dmd) => {
match dmd.reset() {
Ok(()) => {
println!("[DMD] Reset Success.");
true
},
Err(e) => {
println!("[DMD ERROR] DMD reset error: {:?}", e);
false
}
}
},
None => {
println!("[DMD ERROR] DMD not initialized.");
false
}
}
},
Err(e) => {
println!("[DMD ERROR] Could not lock DMD. Error={:?}", e);
false
}
}
}
#[no_mangle]
fn dmd_video_ram() -> *const u8 {
match DMD_STATE.lock() {
Ok(mut dmd_guard) => {
match &mut dmd_guard.dmd {
Some(dmd) => {
match dmd.video_ram() {
Ok(video_ram) => {
let ptr: *const u8 = video_ram.as_ptr();
return ptr;
},
Err(e) => {
println!("DMD video ram error: {:?}", e);
return ptr::null();
}
}
},
None => {
println!("DMD not initialized.");
return ptr::null();
}
}
},
Err(e) => {
println!("Could not lock DMD. Error={:?}", e);
return ptr::null();
}
}
}
#[no_mangle]
fn dmd_step() -> bool {
match DMD_STATE.lock() {
Ok(mut dmd_guard) => {
match &mut dmd_guard.dmd {
Some(dmd) => {
match dmd.step_with_error() {
Ok(()) => {
true
},
Err(e) => {
println!("Could not step DMD. PC=0x{:08x}, Error={:?}", dmd.get_pc(), e);
false
}
}
}
None => {
println!("DMD not initialized.");
false
}
}
},
Err(e) => {
println!("Could not lock DMD. Error={:?}", e);
false
}
}
}
#[no_mangle]
fn dmd_get_pc() -> uint32_t {
match DMD_STATE.lock() {
Ok(mut dmd_guard) => {
match &mut dmd_guard.dmd {
Some(dmd) => {
dmd.get_pc()
}
None => {
println!("DMD not initialized.");
0
}
}
},
Err(e) => {
println!("Could not lock DMD. Error={:?}", e);
0
}
}
}
#[no_mangle]
fn dmd_get_duart_output_port() -> uint8_t {
match DMD_STATE.lock() {
Ok(mut dmd_guard) => {
match &mut dmd_guard.dmd {
Some(dmd) => {
dmd.duart_output()
}
None => {
println!("DMD not initialized.");
0
}
}
},
Err(e) => {
println!("Could not lock DMD. Error={:?}", e);
0
}
}
}
#[no_mangle]
fn dmd_rx_char(c: uint8_t) -> bool {
match DMD_STATE.lock() {
Ok(mut dmd_guard) => {
match &mut dmd_guard.dmd {
Some(dmd) => {
match dmd.rx_char(c as u8) {
Ok(()) => {
true
},
Err(DuartError::ReceiverNotReady) => {
false
}
}
}
None => {
println!("DMD not initialized.");
false
}
}
},
Err(e) => {
println!("Could not lock DMD. Error={:?}", e);
false
}
}
}
#[no_mangle]
fn dmd_rx_keyboard(c: uint8_t) -> bool {
match DMD_STATE.lock() {
Ok(mut dmd_guard) => {
match &mut dmd_guard.dmd {
Some(dmd) => {
match dmd.rx_keyboard(c) {
Ok(()) => {
println!("[DMD] Received character 0x{:02x}", c);
true
},
Err(DuartError::ReceiverNotReady) => {
false
}
}
}
None => {
println!("DMD not initialized.");
false
}
}
},
Err(e) => {
println!("Could not lock DMD. Error={:?}", e);
false
}
}
}
#[no_mangle]
fn dmd_mouse_move(x: uint16_t, y: uint16_t) -> bool {
match DMD_STATE.lock() {
Ok(mut dmd_guard) => {
match &mut dmd_guard.dmd {
Some(dmd) => {
dmd.mouse_move(x, y);
true
}
None => {
println!("DMD not initialized.");
false
}
}
},
Err(e) => {
println!("Could not lock DMD. Error={:?}", e);
false
}
}
}
#[no_mangle]
fn dmd_mouse_down(button: uint8_t) -> bool {
match DMD_STATE.lock() {
Ok(mut dmd_guard) => {
match &mut dmd_guard.dmd {
Some(dmd) => {
dmd.mouse_down(button);
true
}
None => {
println!("DMD not initialized.");
false
}
}
},
Err(e) => {
println!("Could not lock DMD. Error={:?}", e);
false
}
}
}
#[no_mangle]
fn dmd_mouse_up(button: uint8_t) -> bool {
match DMD_STATE.lock() {
Ok(mut dmd_guard) => {
match &mut dmd_guard.dmd {
Some(dmd) => {
dmd.mouse_up(button as u8);
true
}
None => {
println!("DMD not initialized.");
false
}
}
},
Err(e) => {
println!("Could not lock DMD. Error={:?}", e);
false
}
}
}
// #[no_mangle]
// fn tx_poll(mut cx: FunctionContext) -> JsResult<JsObject> {
// let o = JsObject::new(&mut cx);
// match DMD_STATE.lock() {
// Ok(mut dmd_guard) => {
// match &mut dmd_guard.dmd {
// Some(dmd) => {
// match dmd.tx_poll() {
// Some(c) => {
// let success = cx.boolean(true);
// let char = cx.number(c);
// o.set(&mut cx, "success", success)?;
// o.set(&mut cx, "char", char)?;
// },
// None => {
// let success = cx.boolean(false);
// let char = cx.number(0);
// o.set(&mut cx, "success", success)?;
// o.set(&mut cx, "char", char)?;
// }
// }
// }
// None => {
// let success = cx.boolean(false);
// let char = cx.number(0);
// o.set(&mut cx, "success", success)?;
// o.set(&mut cx, "char", char)?;
// }
// }
// },
// Err(_) => {
// let success = cx.boolean(false);
// let char = cx.number(0);
// o.set(&mut cx, "success", success)?;
// o.set(&mut cx, "char", char)?;
// }
// }
// Ok(o)
// }
#[no_mangle]
fn test_function() -> int8_t {
return 0x5a;
}

139
src/dmd.c
View File

@ -2,9 +2,20 @@
#include <math.h>
#include <time.h>
#include <stdint.h>
static cairo_surface_t *surface = NULL;
extern int dmd_init();
extern int dmd_reset();
extern uint8_t *dmd_video_ram();
extern int dmd_step();
extern uint32_t dmd_get_pc();
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_mouse_move(uint16_t x, uint16_t y);
static void
clear_surface()
{
@ -42,6 +53,7 @@ static void
close_window(void)
{
printf("[close_window]\n");
gtk_main_quit();
if (surface) {
cairo_surface_destroy(surface);
}
@ -70,23 +82,9 @@ long get_current_time_ms()
return (s * 1000) + ms;
}
static gboolean
button_press_event_cb(GtkWidget *widget, GdkEventButton *event, gpointer *data)
static void
refresh_display(GtkWidget *widget)
{
if (surface == NULL) {
printf("[button_press] WARNING! SURFACE IS NULL!\n");
return FALSE;
}
long start_time = get_current_time_ms();
int width = gtk_widget_get_allocated_width(widget);
int height = gtk_widget_get_allocated_height(widget);
printf("[button_press] Width=%d, Height=%d\n", width, height);
srand(time(NULL));
GdkPixbuf *pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB,
TRUE,
8,
@ -96,21 +94,32 @@ button_press_event_cb(GtkWidget *widget, GdkEventButton *event, gpointer *data)
int rowstride = gdk_pixbuf_get_rowstride(pixbuf);
guchar *pixels = gdk_pixbuf_get_pixels(pixbuf);
int n_channels = gdk_pixbuf_get_n_channels(pixbuf);
guchar *p;
guchar *p = pixels;
uint32_t p_index = 0;
uint8_t *vram = dmd_video_ram();
for (int y = 0; y < 1024; y++) {
for (int x = 0; x < 800; x++) {
p = pixels + y * rowstride + x * n_channels;
if (y % 2 == 0 && x % 2 == 0) {
p[0] = 0;
p[1] = 0xff;
p[2] = 0;
p[3] = 0xff;
} else {
p[0] = 0xff;
p[1] = 0xff;
p[2] = 0xff;
p[3] = 0xff;
if (vram == NULL) {
printf("[WARNING] Video Ram is NULL!");
} else {
for (int y = 0; y < 1024; y++) {
for (int x = 0; x < 100; x++) {
// Get the byte
uint8_t b = vram[y * 100 + x];
for (int i = 0; i < 8; i++) {
uint8_t bit = (b >> (7-i)) & 1;
if (bit) {
p[p_index++] = 0;
p[p_index++] = 0xff;
p[p_index++] = 0;
p[p_index++] = 0xff;
} else {
p[p_index++] = 0;
p[p_index++] = 0;
p[p_index++] = 0;
p[p_index++] = 0xff;
}
}
}
}
}
@ -123,11 +132,47 @@ button_press_event_cb(GtkWidget *widget, GdkEventButton *event, gpointer *data)
cairo_destroy(cr);
gtk_widget_queue_draw(widget);
}
long end_time = get_current_time_ms();
static gboolean
mouse_moved(GtkWidget *widget, GdkEventMotion *event, gpointer data)
{
dmd_mouse_move((uint16_t) event->x, (uint16_t) (1024 - event->y));
printf("Drawing took: %lu ms\n", end_time - start_time);
return TRUE;
}
static gboolean
button_press_event_cb(GtkWidget *widget, GdkEventButton *event, gpointer data)
{
return TRUE;
}
uint8_t last_kb_char;
uint8_t kb_pending = 0;
static gboolean
run_dmd(gpointer user_data)
{
for (int i = 0; i < 40000; i++) {
dmd_step();
}
// Poll.
if (kb_pending && dmd_rx_keyboard(last_kb_char)) {
printf("[run_dmd] Just sent char 0x%02x\n", last_kb_char);
kb_pending = 0;
}
refresh_display((GtkWidget *)user_data);
return G_SOURCE_CONTINUE;
}
static gboolean
keydown_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
{
last_kb_char = 0xae;
kb_pending = 1;
return TRUE;
}
@ -147,18 +192,20 @@ activate(GtkApplication *app, gpointer user_data)
g_signal_connect(window, "destroy", G_CALLBACK(close_window), NULL);
// gtk_container_set_border_width(GTK_CONTAINER(window), 0);
gtk_container_set_border_width(GTK_CONTAINER(window), 0);
frame = gtk_frame_new(NULL);
gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
gtk_container_add(GTK_CONTAINER(window), frame);
drawing_area = gtk_drawing_area_new();
/* set a minimum size */
gtk_widget_set_size_request(drawing_area, 800, 1024);
gtk_container_add(GTK_CONTAINER(frame), drawing_area);
g_timeout_add(33, run_dmd, drawing_area);
/* Signals used to handle the backing surface */
g_signal_connect(drawing_area, "draw",
G_CALLBACK(draw_cb), NULL);
@ -168,16 +215,26 @@ activate(GtkApplication *app, gpointer user_data)
/* UI signals */
g_signal_connect(drawing_area, "button-press-event",
G_CALLBACK(button_press_event_cb), NULL);
g_signal_connect(G_OBJECT(window), "key_press_event",
G_CALLBACK(keydown_event), NULL);
g_signal_connect(drawing_area, "motion-notify-event",
G_CALLBACK(mouse_moved), NULL);
gtk_widget_set_events(drawing_area,
gtk_widget_get_events(drawing_area) | GDK_BUTTON_PRESS_MASK);
gtk_widget_get_events(drawing_area)
| GDK_BUTTON_PRESS_MASK
| GDK_KEY_PRESS_MASK
| GDK_POINTER_MOTION_MASK);
gtk_widget_show_all(window);
/* Hide the cursor */
/* GdkWindow *gdk_window = gtk_widget_get_window(window); */
/* GdkDisplay *gdk_display = gdk_display_get_default(); */
/* gdk_window_set_cursor(gdk_window, gdk_cursor_new_for_display(gdk_display, GDK_BLANK_CURSOR)); */
}
extern unsigned char test_function();
int
main(int argc, char *argv[])
{
@ -185,7 +242,11 @@ main(int argc, char *argv[])
GtkApplication *app;
int status;
printf("TEST_FUNCTION: %02x\n", test_function());
dmd_init();
dmd_reset();
for (int i = 0; i < 1000000; i++) {
dmd_step();
}
app = gtk_application_new("com.loomcom.dmd", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);