Running the DMD core.
This commit is contained in:
parent
a2d6cd5369
commit
2f77975f65
|
@ -1,2 +1,3 @@
|
|||
**/*.o
|
||||
lib/target
|
||||
dmd
|
||||
|
|
2
Makefile
2
Makefile
|
@ -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
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"]
|
||||
|
|
347
lib/src/lib.rs
347
lib/src/lib.rs
|
@ -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
139
src/dmd.c
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue