Skip to content

to_python() #60

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

Closed
wants to merge 6 commits into from
Closed
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
4 changes: 2 additions & 2 deletions example/example/blocks/core/sub_blocks.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
sub_block("adc0", block_path="adc.16_bit")
sub_block("adc1", block_path="adc.8_bit")
SubBlock("adc0", block_path="adc.16_bit")
SubBlock("adc1", block_path="adc.8_bit")
5 changes: 5 additions & 0 deletions example/example/blocks/dut/derivatives/eagle/pins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Pin("porta", width= 2)
Pin("portb", width= 4)
Pin("portc", width=2, reset_data=0b11)
Pin("clk", reset_data=0, reset_action="D")
Alias("clk", "swd_clk", "tclk")
8 changes: 4 additions & 4 deletions example/example/blocks/dut/sub_blocks.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
sub_block("core0", block_path="core")
sub_block("core1", block_path="core")
sub_block("core2", block_path="core")
sub_block("core3", block_path="core")
SubBlock("core0", block_path="core")
SubBlock("core1", block_path="core")
SubBlock("core2", block_path="core")
SubBlock("core3", block_path="core")
83 changes: 60 additions & 23 deletions example/tests/pin_api_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
import _origen # pylint: disable=import-error
import pytest

class MyRandomClass:
pass

def is_pin_group(obj):
assert isinstance(obj, _origen.dut.pins.PinGroup)

Expand Down Expand Up @@ -818,28 +821,62 @@ def test_collecting_with_mixed_inputs():
c = origen.dut.pins.collect("/port.1/", "p1", r)
assert c.pin_names == ["porta1", "portb1", "p1", "porta0", "portb0"]

# def test_pins_have_empty_metadata():
# assert origen.dut.pin("porta1").metadata == {}
# assert origen.dut.physical_pin("porta1").metadata == {}
# assert origen.dut.pin("porta1").physical_pin_metadata == [{}]


def test_physical_pin_has_empty_metadata():
assert origen.dut.physical_pin("porta0").added_metadata == []

def test_adding_metadata_to_physical_pin():
# Essentially just check that nothing here throws an exception
origen.dut.physical_pin("porta0").add_metadata("meta1", 1)
origen.dut.physical_pin("porta0").add_metadata("meta2", "meta2!")
origen.dut.physical_pin("porta0").add_metadata("meta3", {})
origen.dut.physical_pin("porta0").add_metadata("meta4", MyRandomClass())

def test_getting_all_metadata_keys():
assert origen.dut.physical_pin("porta0").added_metadata == ["meta1", "meta2", "meta3", "meta4"]

def test_getting_metadata_from_physical_pin():
assert origen.dut.physical_pin("porta0").get_metadata("meta1") == 1
assert origen.dut.physical_pin("porta0").get_metadata("meta2") == "meta2!"
assert isinstance(origen.dut.physical_pin("porta0").get_metadata("meta3"), dict)
assert isinstance(origen.dut.physical_pin("porta0").get_metadata("meta4"), MyRandomClass)

def test_setting_existing_metadata_on_physical_pin():
assert origen.dut.physical_pin("porta0").set_metadata("meta1", "hi!")
assert origen.dut.physical_pin("porta0").set_metadata("meta2", "meta2 updated!")
assert origen.dut.physical_pin("porta0").get_metadata("meta1") == "hi!"
assert origen.dut.physical_pin("porta0").get_metadata("meta2") == "meta2 updated!"

def test_setting_nonexistant_metadata_adds_it():
assert origen.dut.physical_pin('porta0').get_metadata("meta5") is None
assert origen.dut.physical_pin("porta0").set_metadata("meta5", 5.0) == False
assert origen.dut.physical_pin("porta0").get_metadata("meta5") == 5.0

def test_interacting_with_reference_metadata():
d = origen.dut.physical_pin("porta0").get_metadata("meta3")
assert isinstance(d, dict)
assert "test" not in d
d["test"] = True
assert "test" in d
d2 = origen.dut.physical_pin("porta0").get_metadata("meta3")
assert "test" in d2

# def test_in_progress_pin_api():
# import re
# r = re.compile("port.0")
# print(r.__class__)
# print(r.pattern)
# c = origen.dut.pins.collect(r)
# print(c.pin_names)
# assert 0 == 1
# !!!
# Experimental Stuff. Still in progress.
# Consider this non-official API experimentation.
# !!!
def test_nonetype_on_retrieving_nonexistant_metadata():
assert origen.dut.physical_pin("porta0").get_metadata("blah") is None

# Add pin group. This should add porta0 - porta7
#porta = origen.dut.add_pins("porta", 8)

# Add pin group, with an offset. This should add portb1 - portb5
#portb = origen.dut.add_pins("portb", 4, offset=1)
def test_exception_on_adding_duplicate_metadata():
with pytest.raises(OSError):
origen.dut.physical_pin("porta0").add_metadata("meta1", False)

def test_additional_metadata():
origen.dut.physical_pin('porta1').add_metadata("m1", 1.0)
origen.dut.physical_pin('porta1').add_metadata("m2", -2)
assert origen.dut.physical_pin('porta1').get_metadata("m1") == 1.0
assert origen.dut.physical_pin('porta1').get_metadata("m2") == -2
assert origen.dut.physical_pin('porta0').get_metadata("m1") is None
assert origen.dut.physical_pin('porta0').get_metadata("m2") is None

def test_metadata_with_same_name_on_different_objects():
origen.dut.physical_pin('porta0').add_metadata("index", 0)
origen.dut.physical_pin('porta1').add_metadata("index", 1)
assert origen.dut.physical_pin('porta0').get_metadata("index") == 0
assert origen.dut.physical_pin('porta1').get_metadata("index") == 1
20 changes: 20 additions & 0 deletions example/tests/sub_blocks_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import origen

def test_sub_blocks_can_be_added():
origen.app.instantiate_dut("dut.falcon")
assert origen.dut.sub_blocks.len() == 4
assert list(origen.dut.sub_blocks.keys()) == ['core0', 'core1', 'core2', 'core3']

# Test adding a sub_block to the top-level
block = origen.dut.add_sub_block("core4", block_path="core")
assert origen.dut.sub_blocks.len() == 5
assert list(origen.dut.sub_blocks.keys()) == ['core0', 'core1', 'core2', 'core3', 'core4']
assert block.name == "core4"

# Test adding a sub_block to an embedded block...
assert origen.dut.core0.adc0.sub_blocks.len() == 0
assert list(origen.dut.core0.adc0.sub_blocks.keys()) == []
block = origen.dut.core0.adc0.add_sub_block("my_block", block_path="adc.8_bit")
assert origen.dut.core0.adc0.sub_blocks.len() == 1
assert list(origen.dut.core0.adc0.sub_blocks.keys()) == ["my_block"]
assert block.name == "my_block"
4 changes: 4 additions & 0 deletions python/origen/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ def load_block_files(self, controller, filename):
from origen.sub_blocks import Loader
context = Loader(controller).api()

elif filename == "pins.py":
from origen.pins import Loader
context = Loader(controller).api()

else:
block = controller
context = locals()
Expand Down
12 changes: 12 additions & 0 deletions python/origen/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import _origen
from origen import pins
from origen.registers import Loader as RegLoader
from origen.sub_blocks import Loader as SubBlockLoader
from contextlib import contextmanager

class Proxies:
Expand Down Expand Up @@ -49,6 +50,7 @@ def __init__(self):
self.__proxies__ = Proxies(self)
self.regs_loaded = False
self.sub_blocks_loaded = False
self.pins_loaded = False

# This lazy-loads the block's files the first time a given resource is referenced
def __getattr__(self, name):
Expand All @@ -72,6 +74,7 @@ def __getattr__(self, name):
self.__proxies__["pins"] = proxy
for method in pins.Proxy.api():
self.__setattr__(method, getattr(proxy, method))
self._load_pins()
return eval(f"self.{name}")

elif name == "memory_maps":
Expand Down Expand Up @@ -131,6 +134,10 @@ def add_reg(self, *args, **kwargs):
with RegLoader(self).Reg(*args, **kwargs) as reg:
yield reg

def add_sub_block(self, *args, **kwargs):
self._load_sub_blocks()
return SubBlockLoader(self).sub_block(*args, **kwargs)

def _load_regs(self):
if not self.regs_loaded:
self.app.load_block_files(self, "registers.py")
Expand All @@ -142,6 +149,11 @@ def _load_sub_blocks(self):
self.sub_blocks = Proxy(self)
self.app.load_block_files(self, "sub_blocks.py")
self.sub_blocks_loaded = True

def _load_pins(self):
if not self.pins_loaded:
self.app.load_block_files(self, "pins.py")
self.pins_loaded = True

# The base class of all Origen controller objects which are also
# the top-level (DUT)
Expand Down
14 changes: 13 additions & 1 deletion python/origen/pins.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,16 @@ def api(cls):

class Loader:
def __init__(self, controller):
self.controller = controller
self.controller = controller

def Pin(self, name, **kwargs):
self.controller.add_pin(name, **kwargs)

def Alias(self, name, *aliases):
self.controller.add_pin_alias(name, *aliases)

def api(self):
return {
"Pin": self.Pin,
"Alias": self.Alias,
}
2 changes: 1 addition & 1 deletion python/origen/sub_blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,5 @@ def sub_block(self, name, block_path=None):
# Defines the methods that are accessible within blocks/<block>/sub_blocks.py
def api(self):
return {
"sub_block": self.sub_block,
"SubBlock": self.sub_block,
}
36 changes: 34 additions & 2 deletions rust/origen/pyapi/src/dut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ use crate::pins::PyInit_pins;
use origen::DUT;
use pyo3::prelude::*;
use pyo3::wrap_pymodule;
#[allow(unused_imports)]
use pyo3::types::{PyAny, PyBytes, PyDict, PyIterator, PyList, PySlice, PyTuple};
use origen::error::Error;

/// Implements the module _origen.dut in Python which exposes all
/// DUT-related APIs
Expand All @@ -15,15 +18,17 @@ pub fn dut(_py: Python, m: &PyModule) -> PyResult<()> {

#[pyclass]
#[derive(Debug)]
pub struct PyDUT {}
pub struct PyDUT {
metadata: Vec<PyObject>,
}

#[pymethods]
impl PyDUT {
#[new]
/// Instantiating a new instance of PyDUT means re-loading the target
fn new(obj: &PyRawObject, name: &str) {
DUT.lock().unwrap().change(name);
obj.init({ PyDUT {} });
obj.init({ PyDUT { metadata: vec!() } });
}

/// Creates a new model at the given path
Expand All @@ -43,4 +48,31 @@ impl PyDUT {
.unwrap()
.create_reg(address_block_id, name, offset, size)?)
}

pub fn push_metadata(&mut self, item: &PyAny) -> usize {
let gil = Python::acquire_gil();
let py = gil.python();

self.metadata.push(item.to_object(py));
self.metadata.len() - 1
}

pub fn override_metadata_at(&mut self, idx: usize, item: &PyAny) -> PyResult<()> {
let gil = Python::acquire_gil();
let py = gil.python();
if self.metadata.len() > idx {
self.metadata[idx] = item.to_object(py);
Ok(())
} else {
Err(PyErr::from(Error::new(&format!("Overriding metadata at {} exceeds the size of the current metadata vector!", idx))))
}
}

pub fn get_metadata(&self, idx: usize) -> PyResult<&PyObject> {
Ok(&self.metadata[idx])
}
}

impl PyDUT {

}
Loading