mirror of https://github.com/Nonannet/copapy.git
read_value function added to read result variable values
This commit is contained in:
parent
6625da1a47
commit
e8bf9f1a26
|
|
@ -3,6 +3,8 @@ from typing import Generator, Iterable, Any
|
|||
from . import binwrite as binw
|
||||
from .stencil_db import stencil_database
|
||||
from collections import defaultdict, deque
|
||||
from coparun_module import coparun, read_data_mem
|
||||
import struct
|
||||
|
||||
Operand = type['Net'] | float | int
|
||||
|
||||
|
|
@ -60,10 +62,31 @@ class Net:
|
|||
def __rtruediv__(self, other: Any) -> 'Net':
|
||||
return _add_op('div', [other, self])
|
||||
|
||||
def __neg__(self) -> 'Net':
|
||||
return _add_op('sub', [const(0), self])
|
||||
|
||||
def __gt__(self, other: Any) -> 'Net':
|
||||
return _add_op('gt', [self, other])
|
||||
|
||||
def __lt__(self, other: Any) -> 'Net':
|
||||
return _add_op('gt', [other, self])
|
||||
|
||||
def __eq__(self, other: Any) -> 'Net':
|
||||
return _add_op('eq', [self, other])
|
||||
|
||||
def __mod__(self, other: Any) -> 'Net':
|
||||
return _add_op('mod', [self, other])
|
||||
|
||||
def __rmod__(self, other: Any) -> 'Net':
|
||||
return _add_op('mod', [other, self])
|
||||
|
||||
def __repr__(self) -> str:
|
||||
names = get_var_name(self)
|
||||
return f"{'name:' + names[0] if names else 'id:' + str(id(self))[-5:]}"
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return id(self)
|
||||
|
||||
|
||||
class Const(Node):
|
||||
def __init__(self, value: float | int | bool):
|
||||
|
|
@ -239,7 +262,7 @@ def add_read_ops(node_list: list[Node]) -> Generator[tuple[Net | None, Node], No
|
|||
for node in node_list:
|
||||
if not node.name.startswith('const_'):
|
||||
for i, net in enumerate(node.args):
|
||||
if net != registers[i]:
|
||||
if id(net) != id(registers[i]):
|
||||
#if net in registers:
|
||||
# print('x swap registers')
|
||||
type_list = ['int' if r is None else r.dtype for r in registers]
|
||||
|
|
@ -295,12 +318,9 @@ def get_nets(*inputs: Iterable[Iterable[Any]]) -> list[Net]:
|
|||
return list(nets)
|
||||
|
||||
|
||||
def compile_to_instruction_list(end_nodes: Iterable[Node] | Node) -> binw.data_writer:
|
||||
if isinstance(end_nodes, Node):
|
||||
node_list = [end_nodes]
|
||||
else:
|
||||
node_list = list(end_nodes)
|
||||
|
||||
def compile_to_instruction_list(node_list: Iterable[Node], sdb: stencil_database) -> tuple[binw.data_writer, dict[Net, tuple[int, int, str]]]:
|
||||
variables: dict[Net, tuple[int, int, str]] = dict()
|
||||
|
||||
ordered_ops = list(stable_toposort(get_all_dag_edges(node_list)))
|
||||
const_net_list = get_const_nets(ordered_ops)
|
||||
output_ops = list(add_read_ops(ordered_ops))
|
||||
|
|
@ -329,7 +349,7 @@ def compile_to_instruction_list(end_nodes: Iterable[Node] | Node) -> binw.data_w
|
|||
dw.write_int(data_section_lengths)
|
||||
|
||||
for net, out_offs, lengths in object_list:
|
||||
dw.add_variable(net, out_offs, lengths, net.dtype)
|
||||
variables[net] = (out_offs, lengths, net.dtype)
|
||||
if isinstance(net.source, Const):
|
||||
dw.write_com(binw.Command.COPY_DATA)
|
||||
dw.write_int(out_offs)
|
||||
|
|
@ -389,16 +409,72 @@ def compile_to_instruction_list(end_nodes: Iterable[Node] | Node) -> binw.data_w
|
|||
dw.write_int(patch_type)
|
||||
dw.write_int(object_addr, signed=True)
|
||||
|
||||
# set entry point
|
||||
dw.write_com(binw.Command.SET_ENTR_POINT)
|
||||
dw.write_int(0)
|
||||
|
||||
return dw
|
||||
return dw, variables
|
||||
|
||||
|
||||
def read_variable(bw: binw.data_writer, net: Net) -> None:
|
||||
assert net in bw.variables, f"Variable {net} not found in data writer variables"
|
||||
addr, lengths, _ = bw.variables[net]
|
||||
bw.write_com(binw.Command.READ_DATA)
|
||||
bw.write_int(addr)
|
||||
bw.write_int(lengths)
|
||||
class Target():
|
||||
|
||||
def __init__(self, arch: str = 'x86_64', optimization: str = 'O3') -> None:
|
||||
self.sdb = stencil_database(f"src/copapy/obj/stencils_{arch}_{optimization}.o")
|
||||
self._variables: dict[Net, tuple[int, int, str]] = dict()
|
||||
|
||||
|
||||
def compile(self, *variables: list[Net] | list[list[Net]]) -> None:
|
||||
nodes: list[Node] = []
|
||||
for s in variables:
|
||||
if isinstance(s, Net):
|
||||
nodes.append(Write(s))
|
||||
else:
|
||||
for net in s:
|
||||
assert isinstance(net, Net)
|
||||
nodes.append(Write(net))
|
||||
|
||||
|
||||
dw, self._variables = compile_to_instruction_list(nodes, self.sdb)
|
||||
dw.write_com(binw.Command.END_PROG)
|
||||
assert coparun(dw.get_data()) > 0
|
||||
|
||||
|
||||
def run(self) -> None:
|
||||
# set entry point and run code
|
||||
dw = binw.data_writer(self.sdb.byteorder)
|
||||
dw.write_com(binw.Command.SET_ENTR_POINT)
|
||||
dw.write_int(0)
|
||||
dw.write_com(binw.Command.END_PROG)
|
||||
assert coparun(dw.get_data()) > 0
|
||||
|
||||
|
||||
def read_value(self, net: Net) -> float | int:
|
||||
assert net in self._variables, f"Variable {net} not found"
|
||||
addr, lengths, var_type = self._variables[net]
|
||||
data = read_data_mem(addr, lengths)
|
||||
assert data is not None and len(data) == lengths, f"Failed to read variable {net}"
|
||||
en = {'little': '<', 'big': '>'}[self.sdb.byteorder]
|
||||
if var_type == 'float':
|
||||
if lengths == 4:
|
||||
value = struct.unpack(en + 'f', data)[0]
|
||||
assert isinstance(value, float)
|
||||
return value
|
||||
elif lengths == 8:
|
||||
value = struct.unpack(en + 'd', data)[0]
|
||||
assert isinstance(value, float)
|
||||
return value
|
||||
else:
|
||||
raise ValueError(f"Unsupported float length: {lengths}")
|
||||
elif var_type == 'int':
|
||||
if lengths in (1, 2, 4, 8):
|
||||
value = int.from_bytes(data, byteorder=self.sdb.byteorder, signed=True)
|
||||
assert isinstance(value, int)
|
||||
return value
|
||||
else:
|
||||
raise ValueError(f"Unsupported int length: {lengths}")
|
||||
else:
|
||||
raise ValueError(f"Unsupported variable type: {var_type}")
|
||||
|
||||
def read_variable_remote(self, bw: binw.data_writer, net: Net) -> None:
|
||||
assert net in self._variables, f"Variable {net} not found in data writer variables"
|
||||
dw = binw.data_writer(self.sdb.byteorder)
|
||||
addr, lengths, _ = self._variables[net]
|
||||
bw.write_com(binw.Command.READ_DATA)
|
||||
bw.write_int(addr)
|
||||
bw.write_int(lengths)
|
||||
|
|
@ -14,10 +14,6 @@ class data_writer():
|
|||
def __init__(self, byteorder: Literal['little', 'big']):
|
||||
self._data: list[tuple[str, bytes, int]] = list()
|
||||
self.byteorder: Literal['little', 'big'] = byteorder
|
||||
self.variables: dict[Any, tuple[int, int, str]] = dict()
|
||||
|
||||
def add_variable(self, net: Any, addr: int, lengths: int, var_type: str) -> None:
|
||||
self.variables[net] = (addr, lengths, var_type)
|
||||
|
||||
def write_int(self, value: int, num_bytes: int = 4, signed: bool = False) -> None:
|
||||
self._data.append((f"INT {value}", value.to_bytes(length=num_bytes, byteorder=self.byteorder, signed=signed), 0))
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
from typing import Generator
|
||||
|
||||
|
||||
op_signs = {'add': '+', 'sub': '-', 'mul': '*', 'div': '/'}
|
||||
op_signs = {'add': '+', 'sub': '-', 'mul': '*', 'div': '/',
|
||||
'gt': '>', 'eq': '==', 'mod': '%'}
|
||||
|
||||
|
||||
def get_function_start() -> str:
|
||||
|
|
@ -89,7 +90,7 @@ def permutate(*lists: list[str]) -> Generator[list[str], None, None]:
|
|||
|
||||
if __name__ == "__main__":
|
||||
types = ['int', 'float']
|
||||
ops = ['add', 'sub', 'mul', 'div']
|
||||
ops = ['add', 'sub', 'mul', 'div', 'gt', 'eq']
|
||||
|
||||
code = """
|
||||
// Auto-generated stencils for copapy
|
||||
|
|
@ -109,6 +110,8 @@ if __name__ == "__main__":
|
|||
t_out = t1 if t1 == t2 else 'float'
|
||||
code += get_op_code(op, t1, t2, t_out)
|
||||
|
||||
code += get_op_code('mod', 'int', 'int', 'int')
|
||||
|
||||
for t1, t2, t_out in permutate(types, types, types):
|
||||
code += get_read_reg0_code(t1, t2, t_out)
|
||||
code += get_read_reg1_code(t1, t2, t_out)
|
||||
|
|
|
|||
|
|
@ -113,6 +113,60 @@
|
|||
asm volatile (".long 0xF27ECAFE");
|
||||
}
|
||||
|
||||
void gt_int_int(int arg1, int arg2) {
|
||||
asm volatile (".long 0xF17ECAFE");
|
||||
result_int_int(arg1 > arg2, arg2);
|
||||
asm volatile (".long 0xF27ECAFE");
|
||||
}
|
||||
|
||||
void gt_int_float(int arg1, float arg2) {
|
||||
asm volatile (".long 0xF17ECAFE");
|
||||
result_float_float(arg1 > arg2, arg2);
|
||||
asm volatile (".long 0xF27ECAFE");
|
||||
}
|
||||
|
||||
void gt_float_int(float arg1, int arg2) {
|
||||
asm volatile (".long 0xF17ECAFE");
|
||||
result_float_int(arg1 > arg2, arg2);
|
||||
asm volatile (".long 0xF27ECAFE");
|
||||
}
|
||||
|
||||
void gt_float_float(float arg1, float arg2) {
|
||||
asm volatile (".long 0xF17ECAFE");
|
||||
result_float_float(arg1 > arg2, arg2);
|
||||
asm volatile (".long 0xF27ECAFE");
|
||||
}
|
||||
|
||||
void eq_int_int(int arg1, int arg2) {
|
||||
asm volatile (".long 0xF17ECAFE");
|
||||
result_int_int(arg1 == arg2, arg2);
|
||||
asm volatile (".long 0xF27ECAFE");
|
||||
}
|
||||
|
||||
void eq_int_float(int arg1, float arg2) {
|
||||
asm volatile (".long 0xF17ECAFE");
|
||||
result_float_float(arg1 == arg2, arg2);
|
||||
asm volatile (".long 0xF27ECAFE");
|
||||
}
|
||||
|
||||
void eq_float_int(float arg1, int arg2) {
|
||||
asm volatile (".long 0xF17ECAFE");
|
||||
result_float_int(arg1 == arg2, arg2);
|
||||
asm volatile (".long 0xF27ECAFE");
|
||||
}
|
||||
|
||||
void eq_float_float(float arg1, float arg2) {
|
||||
asm volatile (".long 0xF17ECAFE");
|
||||
result_float_float(arg1 == arg2, arg2);
|
||||
asm volatile (".long 0xF27ECAFE");
|
||||
}
|
||||
|
||||
void mod_int_int(int arg1, int arg2) {
|
||||
asm volatile (".long 0xF17ECAFE");
|
||||
result_int_int(arg1 % arg2, arg2);
|
||||
asm volatile (".long 0xF27ECAFE");
|
||||
}
|
||||
|
||||
void read_int_reg0_int_int(int arg1, int arg2) {
|
||||
asm volatile (".long 0xF17ECAFE");
|
||||
result_int_int(dummy_int, arg2);
|
||||
|
|
|
|||
|
|
@ -28,8 +28,33 @@ static PyObject* coparun(PyObject* self, PyObject* args) {
|
|||
return PyLong_FromLong(result);
|
||||
}
|
||||
|
||||
static PyObject* read_data_mem(PyObject* self, PyObject* args) {
|
||||
unsigned long rel_addr;
|
||||
Py_ssize_t length;
|
||||
|
||||
// Parse arguments: unsigned long (relative address), Py_ssize_t (length)
|
||||
if (!PyArg_ParseTuple(args, "nk", &rel_addr, &length)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (length <= 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "Length must be positive");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t *ptr = data_memory + rel_addr;
|
||||
|
||||
PyObject *result = PyBytes_FromStringAndSize((const char *)ptr, length);
|
||||
if (!result) {
|
||||
return PyErr_NoMemory();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static PyMethodDef MyMethods[] = {
|
||||
{"coparun", coparun, METH_VARARGS, "Pass raw command data to coparun"},
|
||||
{"read_data_mem", read_data_mem, METH_VARARGS, "Read memory and return as bytes"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -55,16 +55,16 @@ def test_compile():
|
|||
r2 = i1 + 9
|
||||
out = [Write(r1), Write(r2)]
|
||||
|
||||
il = copapy.compile_to_instruction_list(out)
|
||||
il, _ = copapy.compile_to_instruction_list(out, copapy.sdb)
|
||||
|
||||
copapy.read_variable(il, r1)
|
||||
copapy.read_variable(il, r2)
|
||||
# run program command
|
||||
il.write_com(binwrite.Command.SET_ENTR_POINT)
|
||||
il.write_int(0)
|
||||
|
||||
il.write_com(binwrite.Command.READ_DATA)
|
||||
il.write_int(0)
|
||||
il.write_int(36)
|
||||
|
||||
# run program command
|
||||
il.write_com(binwrite.Command.END_PROG)
|
||||
|
||||
print('* Data to runner:')
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
from coparun_module import coparun
|
||||
from copapy import Write, const
|
||||
from copapy import Write, const, Target
|
||||
import copapy
|
||||
from copapy import binwrite
|
||||
|
||||
|
|
@ -7,32 +7,19 @@ from copapy import binwrite
|
|||
def test_compile():
|
||||
|
||||
c1 = const(4)
|
||||
c2 = const(2)
|
||||
c2 = const(2) * 4
|
||||
|
||||
i1 = c1 * 2
|
||||
r1 = i1 + 7 + (c2 + 7 * 9)
|
||||
i1 = c2 * 2
|
||||
r1 = i1 + 7 + (c1 + 7 * 9)
|
||||
r2 = i1 + 9
|
||||
out = [Write(r1), Write(r2)]
|
||||
|
||||
il = copapy.compile_to_instruction_list(out)
|
||||
tg = Target()
|
||||
tg.compile(r1, r2, c2)
|
||||
tg.run()
|
||||
|
||||
copapy.read_variable(il, r1)
|
||||
copapy.read_variable(il, r2)
|
||||
|
||||
il.write_com(binwrite.Command.READ_DATA)
|
||||
il.write_int(0)
|
||||
il.write_int(36)
|
||||
|
||||
# run program command
|
||||
il.write_com(binwrite.Command.END_PROG)
|
||||
|
||||
#print('* Data to runner:')
|
||||
#il.print()
|
||||
|
||||
print('+ run coparun')
|
||||
result = coparun(il.get_data())
|
||||
|
||||
assert result == 1
|
||||
print(tg.read_value(r1))
|
||||
print(tg.read_value(r2))
|
||||
print(tg.read_value(c2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
from coparun_module import coparun
|
||||
from copapy import Write, const
|
||||
import copapy
|
||||
from copapy import binwrite
|
||||
|
||||
|
||||
def test_compile():
|
||||
|
||||
c1 = const(4)
|
||||
c2 = const(2) * 4
|
||||
|
||||
i1 = c2 * 2
|
||||
r1 = i1 + 7 + (c1 + 7 * 9)
|
||||
r2 = i1 + 9
|
||||
out = [Write(r1), Write(r2), Write(c2)]
|
||||
|
||||
il, _ = copapy.compile_to_instruction_list(out, copapy.sdb)
|
||||
|
||||
# run program command
|
||||
il.write_com(binwrite.Command.SET_ENTR_POINT)
|
||||
il.write_int(0)
|
||||
|
||||
il.write_com(binwrite.Command.READ_DATA)
|
||||
il.write_int(0)
|
||||
il.write_int(36)
|
||||
|
||||
# run program command
|
||||
il.write_com(binwrite.Command.END_PROG)
|
||||
|
||||
#print('* Data to runner:')
|
||||
#il.print()
|
||||
|
||||
print('+ run coparun')
|
||||
result = coparun(il.get_data())
|
||||
|
||||
assert result == 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_compile()
|
||||
Loading…
Reference in New Issue