Skip to content

Commit c4662b5

Browse files
authored
Merge pull request #24 from Origen-SDK/block_loader
Problem getting a ref to DUT
2 parents 9196393 + 112604d commit c4662b5

File tree

13 files changed

+265
-119
lines changed

13 files changed

+265
-119
lines changed

example/tests/registers_test.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import origen
2+
3+
def test_memory_maps_can_be_fetched():
4+
origen.app.instantiate_dut("dut.falcon")
5+
assert origen.dut.memory_maps
6+
assert len(origen.dut.memory_maps) == 1
7+
#assert origen.dut.memory_map("default") == origen.dut.memory_maps["default"]
8+
9+
def test_address_blocks_can_be_fetched():
10+
pass
11+
12+
def test_regs_can_be_fetched():
13+
pass
14+
15+
def test_register_value_can_be_read():
16+
origen.app.instantiate_dut("dut.falcon")
17+
#assert origen.dut.regs["reg1"].data == 0
18+

python/origen/controller.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ def __getattr__(self, name):
3838
self.app.load_block_files(self, "sub_blocks.py")
3939
return self.sub_blocks
4040

41+
elif name == "memory_maps":
42+
self.regs # Ensure the memory maps for this block have been loaded
43+
return origen.dut.db.memory_maps(self.path)
44+
4145
else:
4246
raise AttributeError(f"The block '{self.block_path}' has no attribute '{name}'")
4347

@@ -53,6 +57,11 @@ def tree_as_str(self):
5357
t = f"dut.{self.parent}.{self.id}"
5458
return t
5559

60+
def memory_map(self, id):
61+
self.regs # Ensure the memory maps for this block have been loaded
62+
return origen.dut.db.memory_map(self.path, id)
63+
64+
5665
# The base class of all Origen controller objects which are also
5766
# the top-level (DUT)
5867
class TopLevel(Base):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

rust/origen/pyapi/src/dut.rs

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use pyo3::prelude::*;
22
//use pyo3::wrap_pyfunction;
3-
use origen::core::dut::DUT;
4-
use pyo3::exceptions;
3+
use crate::register::BitCollection;
4+
use origen::DUT;
55

66
/// Implements the module _origen.dut in Python which exposes all
77
/// DUT-related APIs
@@ -14,55 +14,59 @@ pub fn dut(_py: Python, m: &PyModule) -> PyResult<()> {
1414

1515
#[pyclass]
1616
#[derive(Debug)]
17-
pub struct PyDUT {
18-
dut: DUT,
19-
}
17+
pub struct PyDUT {}
2018

2119
#[pymethods]
2220
impl PyDUT {
2321
#[new]
24-
fn new(obj: &PyRawObject, id: String) {
25-
obj.init({ PyDUT { dut: DUT::new(id) } });
22+
/// Instantiating a new instance of PyDUT means re-loading the target
23+
fn new(obj: &PyRawObject, id: &str) {
24+
DUT.lock().unwrap().change(id);
25+
obj.init({ PyDUT {} });
2626
}
2727

2828
/// Creates a new model at the given path
29-
fn create_sub_block(&mut self, path: &str, id: &str) -> PyResult<()> {
30-
self.dut
31-
.create_sub_block(path, id)
32-
// Can't get the Origen errors to cast properly to a PyErr For some reason,
33-
// so have to do this
34-
.map_err(|e| exceptions::OSError::py_err(e.msg))
29+
fn create_sub_block(&self, path: &str, id: &str) -> PyResult<()> {
30+
Ok(DUT.lock().unwrap().create_sub_block(path, id)?)
3531
}
3632

3733
fn create_reg(
38-
&mut self,
34+
&self,
3935
path: &str,
4036
memory_map: Option<&str>,
4137
address_block: Option<&str>,
4238
id: &str,
4339
offset: u32,
4440
size: Option<u32>,
4541
) -> PyResult<()> {
46-
// Can't get the Origen errors to cast properly to a PyErr For some reason,
47-
// so have to do this
48-
let model = match self.dut.get_mut_model(path) {
49-
Ok(m) => m,
50-
Err(e) => return Err(exceptions::OSError::py_err(e.msg)),
51-
};
52-
model
53-
.create_reg(memory_map, address_block, id, offset, size)
54-
// Can't get the Origen errors to cast properly to a PyErr For some reason,
55-
// so have to do this
56-
.map_err(|e| exceptions::OSError::py_err(e.msg))
42+
let mut dut = DUT.lock().unwrap();
43+
Ok(dut
44+
.get_mut_model(path)?
45+
.create_reg(memory_map, address_block, id, offset, size)?)
5746
}
5847

5948
fn number_of_regs(&self, path: &str) -> PyResult<usize> {
60-
// Can't get the Origen errors to cast properly to a PyErr For some reason,
61-
// so have to do this
62-
let model = match self.dut.get_model(path) {
63-
Ok(m) => m,
64-
Err(e) => return Err(exceptions::OSError::py_err(e.msg)),
65-
};
49+
let dut = DUT.lock().unwrap();
50+
let model = dut.get_model(path)?;
6651
Ok(model.number_of_regs())
6752
}
53+
54+
fn get_reg(
55+
&self,
56+
path: &str,
57+
memory_map: Option<&str>,
58+
address_block: Option<&str>,
59+
id: &str,
60+
) -> PyResult<BitCollection> {
61+
let dut = DUT.lock().unwrap();
62+
let model = dut.get_model(path)?;
63+
let reg = model.get_reg(memory_map, address_block, id)?;
64+
65+
Ok(BitCollection::from_reg(
66+
path,
67+
memory_map,
68+
address_block,
69+
reg,
70+
))
71+
}
6872
}

rust/origen/pyapi/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
mod address_block;
12
mod dut;
23
mod logger;
3-
mod model;
4+
mod memory_map;
5+
mod register;
46

57
use origen::{APPLICATION_CONFIG, ORIGEN_CONFIG, STATUS};
68
use pyo3::prelude::*;
@@ -10,7 +12,6 @@ use pyo3::{wrap_pyfunction, wrap_pymodule};
1012
// Imported pyapi modules
1113
use dut::PyInit_dut;
1214
use logger::PyInit_logger;
13-
use model::PyInit_model;
1415

1516
#[pymodule]
1617
/// This is the top-level _origen module which can be imported by Python
@@ -22,7 +23,6 @@ fn _origen(_py: Python, m: &PyModule) -> PyResult<()> {
2223
m.add_wrapped(wrap_pyfunction!(target_file))?;
2324

2425
m.add_wrapped(wrap_pymodule!(logger))?;
25-
m.add_wrapped(wrap_pymodule!(model))?;
2626
m.add_wrapped(wrap_pymodule!(dut))?;
2727
Ok(())
2828
}

rust/origen/pyapi/src/memory_map.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// This module may be removed soon, replaced by the top-level DUT APIs
2+
use crate::dut::PyDUT;
3+
use origen::DUT;
4+
use pyo3::class::basic::PyObjectProtocol;
5+
use pyo3::class::PyMappingProtocol;
6+
use pyo3::prelude::*;
7+
8+
/// Implements the user APIs dut[.sub_block].memory_map() and
9+
/// dut[.sub_block].memory_maps
10+
#[pymethods]
11+
impl PyDUT {
12+
fn memory_maps(&self, path: &str) -> PyResult<MemoryMaps> {
13+
let dut = DUT.lock().unwrap();
14+
// Verify the model exists, though we don't need it for now
15+
dut.get_model(path)?;
16+
Ok(MemoryMaps {
17+
model_path: path.to_string(),
18+
})
19+
}
20+
}
21+
22+
/// Implements the user API to work with a model's collection of memory maps, an instance
23+
/// of this is returned by dut[.sub_block].memory_maps
24+
#[pyclass]
25+
#[derive(Debug)]
26+
pub struct MemoryMaps {
27+
/// The path to the model which owns the contained memory maps
28+
model_path: String,
29+
}
30+
31+
/// User API methods, available to both Rust and Python
32+
#[pymethods]
33+
impl MemoryMaps {
34+
fn len(&self) -> PyResult<usize> {
35+
let dut = DUT.lock().unwrap();
36+
let model = dut.get_model(&self.model_path)?;
37+
Ok(model.memory_maps.len())
38+
}
39+
}
40+
41+
/// Internal, Rust-only methods
42+
impl MemoryMaps {}
43+
44+
#[pyproto]
45+
impl PyMappingProtocol for MemoryMaps {
46+
fn __len__(&self) -> PyResult<usize> {
47+
self.len()
48+
}
49+
}
50+
51+
#[pyproto]
52+
impl PyObjectProtocol for MemoryMaps {
53+
fn __repr__(&self) -> PyResult<String> {
54+
Ok("Here should be a nice graphic of the memory maps".to_string())
55+
}
56+
}

rust/origen/pyapi/src/model.rs

Lines changed: 0 additions & 61 deletions
This file was deleted.

rust/origen/pyapi/src/register.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use origen::core::model::registers::Register;
2+
use pyo3::prelude::*;
3+
4+
/// A BitCollection represents either a whole register of a subset of a
5+
/// registers bits (not necessarily contiguous bits) and provides the user
6+
/// with the same API to set and consume register data in both cases.
7+
#[pyclass]
8+
#[derive(Debug)]
9+
pub struct BitCollection {
10+
/// The path to the model which owns the parent register
11+
model_path: String,
12+
/// The name of the model's memory map which contains the register
13+
memory_map: String,
14+
/// The name of the memory map's address block which contains the register
15+
address_block: String,
16+
/// The ID of the parent register
17+
reg_id: String,
18+
/// When true the BitCollection contains an entire register's worth of bits
19+
whole: bool,
20+
/// The index numbers of the bits from the register that are included in this
21+
/// collection. Typically this will be mapped to the actual register bits by
22+
/// BitCollection's methods.
23+
bit_numbers: Vec<u16>,
24+
}
25+
26+
/// Rust-private methods, i.e. not accessible from Python
27+
impl BitCollection {
28+
pub fn from_reg(
29+
path: &str,
30+
memory_map: Option<&str>,
31+
address_block: Option<&str>,
32+
reg: &Register,
33+
) -> BitCollection {
34+
BitCollection {
35+
model_path: path.to_string(),
36+
memory_map: memory_map.unwrap_or("default").to_string(),
37+
address_block: address_block.unwrap_or("default").to_string(),
38+
reg_id: reg.id.clone(),
39+
whole: true,
40+
bit_numbers: Vec::new(),
41+
}
42+
}
43+
}
44+
45+
/// Methods available from Rust and Python
46+
#[pymethods]
47+
impl BitCollection {}

rust/origen/src/core/dut.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,27 @@ use crate::error::Error;
33
use crate::Result;
44

55
#[derive(Debug)]
6-
pub struct DUT {
6+
pub struct Dut {
77
pub id: String,
88
pub model: Model,
99
}
1010

11-
impl DUT {
12-
pub fn new(id: String) -> DUT {
13-
DUT {
14-
id: id.clone(),
11+
impl Dut {
12+
pub fn new(id: &str) -> Dut {
13+
Dut {
14+
id: id.to_string(),
1515
model: Model::new("".to_string(), "".to_string()),
1616
}
1717
}
1818

19+
/// Change the DUT, this replaces the existing mode with a fresh one (i.e.
20+
/// deletes all current DUT metadata and state, and updates the name/ID field
21+
/// with the given value
22+
pub fn change(&mut self, id: &str) {
23+
self.id = id.to_string();
24+
self.model = Model::new("".to_string(), "".to_string());
25+
}
26+
1927
/// Get a mutable reference to the model at the given path
2028
/// Note that the path is relative to the DUT, i.e. it should not include 'dut.'
2129
pub fn get_mut_model(&mut self, path: &str) -> Result<&mut Model> {

0 commit comments

Comments
 (0)