Skip to content

Commit

Permalink
Python callbacks: read, write, reti, int mode 2 vector
Browse files Browse the repository at this point in the history
  • Loading branch information
ToniWestbrook committed Aug 6, 2024
1 parent 5185c16 commit e009d7f
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 3 deletions.
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

0 comments on commit e009d7f

Please sign in to comment.