Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python callbacks: read, write, reti, int mode 2 vector #63

Merged
merged 1 commit into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion z80.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ class root {
unsigned on_get_int_mode() const { return 0; }
void on_set_int_mode(unsigned mode) { unused(mode); }
void on_set_is_int_disabled(bool f) { unused(f); }
fast_u8 on_get_int_vector() { return 0xFF; }

void set_i_on_ld(fast_u8 i) { self().on_set_i(i); }

Expand Down Expand Up @@ -3771,7 +3772,7 @@ class internals::executor_base : public B {
break;
case 2: {
// ack(7) w(3) w(3) r(3) r(3)
fast_u16 vector_addr = make16(self().on_get_i(), 0xff);
fast_u16 vector_addr = make16(self().on_get_i(), self().on_get_int_vector());
fast_u8 lo = self().on_read_cycle(vector_addr);
fast_u8 hi = self().on_read_cycle(inc16(vector_addr));
isr_addr = make16(hi, lo); }
Expand Down
96 changes: 94 additions & 2 deletions z80/_z80module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,58 @@ class machine : public B {
}

fast_u8 on_read(fast_u16 addr) {
const fast_u8 default_value = 0xff;
assert(addr < z80::address_space_size);
return state.memory[addr];

if(!on_read_callback) {
return state.memory[addr];
}

PyObject *arg = Py_BuildValue("(i)", addr);
decref_guard arg_guard(arg);

PyObject *result = PyObject_CallObject(on_read_callback, arg);
decref_guard result_guard(result);

if(!result) {
assert(0); // TODO: stop();
return default_value;
}

if(!PyLong_Check(result)) {
PyErr_SetString(PyExc_TypeError, "returning value must be integer");
assert(0); // TODO: stop();
return default_value;
}

return z80::mask8(PyLong_AsUnsignedLong(result));
}

PyObject *set_read_callback(PyObject *callback) {
PyObject *old_callback = on_read_callback;
on_read_callback = callback;
return old_callback;
}

void on_write(fast_u16 addr, fast_u8 n) {
assert(addr < z80::address_space_size);
state.memory[addr] = n;

if(!on_write_callback) {
state.memory[addr] = n;
return;
}

PyObject *args = Py_BuildValue("(i, i)", addr, n);
decref_guard arg_guard(args);

PyObject *result = PyObject_CallObject(on_write_callback, args);
decref_guard result_guard(result);
}

PyObject *set_write_callback(PyObject *callback) {
PyObject *old_callback = on_write_callback;
on_write_callback = callback;
return old_callback;
}

fast_u8 on_input(fast_u16 addr) {
Expand Down Expand Up @@ -129,6 +174,49 @@ class machine : public B {
return old_callback;
}

void on_reti() {
base::on_reti();

if(on_reti_callback) {
PyObject *result = PyObject_CallObject(on_reti_callback, NULL);
decref_guard result_guard(result);
}
}

PyObject *set_reti_callback(PyObject *callback) {
PyObject *old_callback = on_reti_callback;
on_reti_callback = callback;
return old_callback;
}

fast_u8 on_get_int_vector() {
const fast_u8 default_value = 0xff;
if(!on_get_int_vector_callback)
return base::on_get_int_vector();

PyObject *result = PyObject_CallObject(on_get_int_vector_callback, NULL);
decref_guard result_guard(result);

if(!result) {
assert(0); // TODO: stop();
return default_value;
}

if(!PyLong_Check(result)) {
PyErr_SetString(PyExc_TypeError, "returning value must be integer");
assert(0); // TODO: stop();
return default_value;
}

return z80::mask8(PyLong_AsUnsignedLong(result));
}

PyObject *set_get_int_vector_callback(PyObject *callback) {
PyObject *old_callback = on_get_int_vector_callback;
on_get_int_vector_callback = callback;
return old_callback;
}

fast_u8 on_get_b() const { return state.b; }
void on_set_b(fast_u8 n) { state.b = n; }

Expand Down Expand Up @@ -224,8 +312,12 @@ class machine : public B {
machine_state state;

private:
PyObject *on_read_callback = nullptr;
PyObject *on_write_callback = nullptr;
PyObject *on_input_callback = nullptr;
PyObject *on_output_callback = nullptr;
PyObject *on_reti_callback = nullptr;
PyObject *on_get_int_vector_callback = nullptr;
};

static const unsigned max_instr_size = 4;
Expand Down
76 changes: 76 additions & 0 deletions z80/machine.inc
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,40 @@ static PyObject *unmark_addrs(PyObject *self, PyObject *args) {
Py_RETURN_NONE;
}

static PyObject *set_read_callback(PyObject *self, PyObject *args) {
PyObject *new_callback;
if(!PyArg_ParseTuple(args, "O:set_callback", &new_callback))
return nullptr;

if(!PyCallable_Check(new_callback)) {
PyErr_SetString(PyExc_TypeError, "parameter must be callable");
return nullptr;
}

auto &machine = cast_machine(self);
PyObject *old_callback = machine.set_read_callback(new_callback);
Py_XINCREF(new_callback);
Py_XDECREF(old_callback);
Py_RETURN_NONE;
}

static PyObject *set_write_callback(PyObject *self, PyObject *args) {
PyObject *new_callback;
if(!PyArg_ParseTuple(args, "O:set_callback", &new_callback))
return nullptr;

if(!PyCallable_Check(new_callback)) {
PyErr_SetString(PyExc_TypeError, "parameter must be callable");
return nullptr;
}

auto &machine = cast_machine(self);
PyObject *old_callback = machine.set_write_callback(new_callback);
Py_XINCREF(new_callback);
Py_XDECREF(old_callback);
Py_RETURN_NONE;
}

static PyObject *set_input_callback(PyObject *self, PyObject *args) {
PyObject *new_callback;
if(!PyArg_ParseTuple(args, "O:set_callback", &new_callback))
Expand Down Expand Up @@ -231,6 +265,40 @@ static PyObject *set_output_callback(PyObject *self, PyObject *args) {
Py_RETURN_NONE;
}

static PyObject *set_reti_callback(PyObject *self, PyObject *args) {
PyObject *new_callback;
if(!PyArg_ParseTuple(args, "O:set_callback", &new_callback))
return nullptr;

if(!PyCallable_Check(new_callback)) {
PyErr_SetString(PyExc_TypeError, "parameter must be callable");
return nullptr;
}

auto &machine = cast_machine(self);
PyObject *old_callback = machine.set_reti_callback(new_callback);
Py_XINCREF(new_callback);
Py_XDECREF(old_callback);
Py_RETURN_NONE;
}

static PyObject *set_get_int_vector_callback(PyObject *self, PyObject *args) {
PyObject *new_callback;
if(!PyArg_ParseTuple(args, "O:set_callback", &new_callback))
return nullptr;

if(!PyCallable_Check(new_callback)) {
PyErr_SetString(PyExc_TypeError, "parameter must be callable");
return nullptr;
}

auto &machine = cast_machine(self);
PyObject *old_callback = machine.set_get_int_vector_callback(new_callback);
Py_XINCREF(new_callback);
Py_XDECREF(old_callback);
Py_RETURN_NONE;
}

static PyObject *run(PyObject *self, PyObject *args) {
auto &machine = cast_machine(self);
z80::events_mask::type events = machine.on_run();
Expand Down Expand Up @@ -281,10 +349,18 @@ static PyMethodDef methods[] = {
{"unmark_addrs", unmark_addrs, METH_VARARGS,
"Clear the marking on a range of memory bytes that indicates it requires custom "
"processing on reading, writing or executing them."},
{"set_read_callback", set_read_callback, METH_VARARGS,
"Set a callback function handling reading from memory."},
{"set_write_callback", set_write_callback, METH_VARARGS,
"Set a callback function handling writing to memory."},
{"set_input_callback", set_input_callback, METH_VARARGS,
"Set a callback function handling reading from ports."},
{"set_output_callback", set_output_callback, METH_VARARGS,
"Set a callback function handling writing to ports."},
{"set_reti_callback", set_reti_callback, METH_VARARGS,
"Set a callback function handling the reti instruction."},
{"set_get_int_vector_callback", set_get_int_vector_callback, METH_VARARGS,
"Set a callback function handling the interrupt mode 2 vector address."},
{"run", run, METH_NOARGS,
"Run emulator until one or several events are signaled."},
#if defined(Z80_MACHINE)
Expand Down
Loading