1use super::pins::pin_header::PinHeader;
2use super::timesets::timeset::Timeset;
3use crate::pins::vec_to_ppin_ids;
4use origen::core::tester::TesterSource;
5use origen::testers::SupportedTester;
6use origen::Error;
7use origen::{Operation, STATUS, TEST};
8use pyo3::prelude::*;
9use pyo3::types::{PyAny, PyDict, PyTuple};
10use std::collections::HashMap;
11
12pub fn define(py: Python, m: &PyModule) -> PyResult<()> {
13 let subm = PyModule::new(py, "tester")?;
14 subm.add_class::<PyTester>()?;
15 pyapi_metal::alias_method_apply_to_set!(subm, "PyTester", "timeset");
16 pyapi_metal::alias_method_apply_to_set!(subm, "PyTester", "pin_header");
17
18 m.add_submodule(subm)?;
19 Ok(())
20}
21
22#[pyclass(subclass)]
23pub struct PyTester {
25 python_testers: HashMap<SupportedTester, PyObject>,
26 instantiated_testers: HashMap<SupportedTester, PyObject>,
27 _metadata: Vec<PyObject>,
29}
30
31#[pymethods]
32impl PyTester {
33 #[new]
34 fn new() -> PyResult<Self> {
35 origen::tester().init()?;
36 Ok(PyTester {
37 python_testers: HashMap::new(),
38 instantiated_testers: HashMap::new(),
39 _metadata: vec![],
40 })
41 }
42
43 fn _start_eq_block(&self, testers: Vec<&str>) -> PyResult<(usize, usize, Vec<String>)> {
44 let mut ts: Vec<SupportedTester> = vec![];
45 let mut clean_testers: Vec<String> = vec![];
46 for t in testers {
47 let st = SupportedTester::new(t)?;
48 clean_testers.push(st.to_string());
49 ts.push(st);
50 }
51 let refs = origen::tester().start_tester_eq_block(ts)?;
52 Ok((refs.0, refs.1, clean_testers))
53 }
54
55 fn _end_eq_block(&self, pat_ref_id: usize, prog_ref_id: usize) -> PyResult<()> {
56 origen::tester().end_tester_eq_block(pat_ref_id, prog_ref_id)?;
57 Ok(())
58 }
59
60 fn _start_neq_block(&self, testers: Vec<&str>) -> PyResult<(usize, usize, Vec<String>)> {
61 let mut ts: Vec<SupportedTester> = vec![];
62 let mut clean_testers: Vec<String> = vec![];
63 for t in testers {
64 let st = SupportedTester::new(t)?;
65 clean_testers.push(st.to_string());
66 ts.push(st);
67 }
68 let refs = origen::tester().start_tester_neq_block(ts)?;
69 Ok((refs.0, refs.1, clean_testers))
70 }
71
72 fn _end_neq_block(&self, pat_ref_id: usize, prog_ref_id: usize) -> PyResult<()> {
73 origen::tester().end_tester_neq_block(pat_ref_id, prog_ref_id)?;
74 Ok(())
75 }
76
77 #[getter]
79 fn ast(&self) -> PyResult<()> {
80 if Operation::GenerateFlow == STATUS.operation() {
81 println!("{}", origen_metal::FLOW.to_string());
82 } else {
83 println!("{}", origen::TEST.to_string());
84 }
85 Ok(())
86 }
87
88 fn ast_to_file(&self, file: &str) -> PyResult<()> {
90 let contents = {
91 if Operation::GenerateFlow == STATUS.operation() {
92 origen_metal::FLOW.to_string()
93 } else {
94 origen::TEST.to_string()
95 }
96 };
97 std::fs::write(file, contents)?;
98 Ok(())
99 }
100
101 fn reset(_self: PyRef<Self>) -> PyResult<()> {
106 Ok(origen::tester().reset()?)
107 }
108
109 fn _prepare_for_generate(&self) -> PyResult<()> {
112 origen::tester().prepare_for_generate()?;
113 Ok(())
114 }
115
116 fn _stats(&self) -> PyResult<Vec<u8>> {
117 Ok(origen::tester().stats.to_pickle())
118 }
119
120 #[getter]
121 fn get_timeset(&self, py: Python) -> PyResult<PyObject> {
146 let tester = origen::tester();
147 let dut = origen::dut();
148 if let Some(t) = tester.get_timeset(&dut) {
149 Ok(Py::new(
150 py,
151 Timeset {
152 name: t.name.clone(),
153 model_id: t.model_id,
154 },
155 )
156 .unwrap()
157 .to_object(py))
158 } else {
159 Ok(py.None())
160 }
161 }
162
163 #[setter]
164 fn timeset(&self, py: Python, timeset: &PyAny) -> PyResult<()> {
166 let (model_id, timeset_name);
167
168 if let Ok(_timeset) = timeset.extract::<String>() {
172 model_id = 0;
173 timeset_name = _timeset;
174 } else {
175 if timeset.get_type().qualname()? == "NoneType" {
176 {
177 let mut tester = origen::TESTER.lock().unwrap();
178 tester.clear_timeset()?;
179 }
180 self.issue_callbacks(py, "clear_timeset")?;
181 return Ok(());
182 } else if timeset.get_type().qualname()? == "Timeset" {
183 let obj = timeset.to_object(py);
184 model_id = obj
185 .getattr(py, "__origen__model_id__")?
186 .extract::<usize>(py)?;
187 timeset_name = obj.getattr(py, "name")?.extract::<String>(py)?;
188 } else {
189 return type_error!(format!("Could not interpret 'timeset' argument as String or _origen.dut.timesets.Timeset object! (class '{}')", timeset.get_type().qualname()?));
190 }
191 }
192
193 {
194 {
195 let mut tester = origen::TESTER.lock().unwrap();
196 let dut = origen::DUT.lock().unwrap();
197 tester.set_timeset(&dut, model_id, ×et_name)?;
198 }
199 self.issue_callbacks(py, "set_timeset")?;
200 }
201 Ok(())
202 }
203
204 fn apply_timeset(&self, py: Python, timeset: &PyAny) -> PyResult<PyObject> {
220 self.timeset(py, timeset)?;
221 self.get_timeset(py)
222 }
223
224 #[getter]
225 fn get_pin_header(&self, py: Python) -> PyResult<PyObject> {
226 let tester = origen::tester();
227 let dut = origen::dut();
228
229 if let Some(header) = tester.get_pin_header(&dut) {
230 Ok(Py::new(
231 py,
232 PinHeader {
233 name: header.name.clone(),
234 model_id: header.model_id,
235 },
236 )
237 .unwrap()
238 .to_object(py))
239 } else {
240 Ok(py.None())
241 }
242 }
243
244 #[setter]
245 fn pin_header(&self, py: Python, pin_header: &PyAny) -> PyResult<()> {
246 let (model_id, pin_header_name);
247
248 if pin_header.get_type().qualname()? == "NoneType" {
249 {
250 let mut tester = origen::TESTER.lock().unwrap();
251 tester.clear_pin_header()?;
252 }
253 self.issue_callbacks(py, "clear_pin_header")?;
254 return Ok(());
255 } else if pin_header.get_type().qualname()? == "PinHeader" {
256 let obj = pin_header.to_object(py);
257 model_id = obj
258 .getattr(py, "__origen__model_id__")?
259 .extract::<usize>(py)?;
260 pin_header_name = obj.getattr(py, "name")?.extract::<String>(py)?;
261 } else {
262 return type_error!(format!("Could not interpret 'pin_header' argument as _origen.dut.Pins.PinHeader object! (class '{}')", pin_header.get_type().qualname()?));
263 }
264
265 {
266 {
267 let mut tester = origen::TESTER.lock().unwrap();
268 let dut = origen::DUT.lock().unwrap();
269 tester.set_pin_header(&dut, model_id, &pin_header_name)?;
270 }
271 self.issue_callbacks(py, "set_pin_header")?;
272 }
273 Ok(())
274 }
275
276 fn apply_pin_header(&self, py: Python, pin_header: &PyAny) -> PyResult<PyObject> {
277 self.pin_header(py, pin_header)?;
278 self.get_pin_header(py)
279 }
280
281 fn cc(slf: PyRef<Self>, py: Python, comment: &str) -> PyResult<Py<Self>> {
295 {
296 let mut tester = origen::tester();
297 tester.cc(&comment)?;
298 }
299 slf.issue_callbacks(py, "cc")?;
300 Ok(slf.into())
301 }
302
303 #[pyo3(text_signature = "($self, header_comments)")]
304 pub fn generate_pattern_header(&self, header_comments: &PyDict) -> PyResult<()> {
305 let tester = origen::tester();
306 Ok(tester.generate_pattern_header(
307 match header_comments.get_item("app")? {
308 Some(comments) => Some(comments.extract::<Vec<String>>()?),
309 None => None,
310 },
311 match header_comments.get_item("pattern")? {
312 Some(comments) => Some(comments.extract::<Vec<String>>()?),
313 None => None,
314 },
315 )?)
316 }
317
318 fn end_pattern(&self) -> PyResult<()> {
319 let tester = origen::tester();
320 Ok(tester.end_pattern()?)
321 }
322
323 fn issue_callbacks(&self, py: Python, func: &str) -> PyResult<()> {
324 let targets;
326 {
327 let tester = origen::tester();
328 targets = tester.targets().clone();
329 }
330
331 for (i, t) in targets.iter().enumerate() {
333 match t {
334 TesterSource::External(g) => {
335 match self.instantiated_testers.get(g) {
337 Some(inst) => {
338 let last_node = TEST.get(0).unwrap().to_pickle();
341 let args =
342 PyTuple::new(py, &[func.to_object(py), last_node.to_object(py)]);
343
344 inst.call_method1(py, "__origen__issue_callback__", args)?;
348 }
349 None => {
350 return Err(PyErr::from(Error::new(&format!(
351 "Something's gone wrong and Python tester {} cannot be found!",
352 g
353 ))))
354 }
355 }
356 }
357 _ => {
358 let mut tester = origen::tester();
359 tester.issue_callback_at(i)?;
360 }
361 }
362 }
363 Ok(())
364 }
365
366 #[pyo3(signature=(**kwargs))]
368 fn cycle(slf: PyRef<Self>, py: Python, kwargs: Option<&PyDict>) -> PyResult<Py<Self>> {
369 {
370 let mut tester = origen::tester();
371 let mut repeat = None;
372 if let Some(_kwargs) = kwargs {
373 if let Some(_kwarg) = _kwargs.get_item("repeat")? {
374 repeat = Some(_kwarg.extract::<usize>()?);
375 }
376 }
377 tester.cycle(repeat)?;
378 }
379 slf.issue_callbacks(py, "cycle")?;
380
381 Ok(slf.into())
382 }
383
384 fn repeat(slf: PyRef<Self>, py: Python, count: usize) -> PyResult<Py<Self>> {
385 let kwargs = PyDict::new(py);
386 kwargs.set_item("repeat", count)?;
387 Self::cycle(slf, py, Some(&kwargs))
388 }
389
390 #[pyo3(signature=(
391 label = None,
392 symbol = None,
393 pins = None,
394 cycles = None,
395 mask = None,
396 ))]
397 fn overlay(
398 slf: PyRef<Self>,
399 py: Python,
400 label: Option<String>,
401 symbol: Option<String>,
402 pins: Option<Vec<&PyAny>>,
403 cycles: Option<usize>,
404 mask: Option<num_bigint::BigUint>,
405 ) -> PyResult<Py<Self>> {
406 let pin_ids;
407 {
408 if let Some(p) = pins {
409 crate::dut::PyDUT::ensure_pins("dut")?;
410 let dut = origen::dut();
411 pin_ids = Some(vec_to_ppin_ids(&dut, p)?);
412 } else {
413 pin_ids = None
414 }
415 }
416 {
417 let tester = origen::tester();
418 tester.overlay(&origen::Overlay::new(label, symbol, cycles, mask, pin_ids)?)?;
419 }
420 slf.issue_callbacks(py, "overlay")?;
421 Ok(slf.into())
422 }
423
424 #[pyo3(signature=(symbol=None, cycles=None, mask=None, pins=None))]
425 fn capture(
426 slf: PyRef<Self>,
427 py: Python,
428 symbol: Option<String>,
429 cycles: Option<usize>,
430 mask: Option<num_bigint::BigUint>,
431 pins: Option<Vec<&PyAny>>,
432 ) -> PyResult<Py<Self>> {
433 let pin_ids;
434 {
435 if let Some(p) = pins {
436 crate::dut::PyDUT::ensure_pins("dut")?;
437 let dut = origen::dut();
438 pin_ids = Some(vec_to_ppin_ids(&dut, p)?);
439 } else {
440 pin_ids = None
441 }
442 }
443 {
444 let tester = origen::tester();
445 tester.capture(&origen::Capture::new(symbol, cycles, mask, pin_ids)?)?;
446 }
447 slf.issue_callbacks(py, "capture")?;
448 Ok(slf.into())
449 }
450
451 fn register_tester(&mut self, py: Python, g: &PyAny) -> PyResult<()> {
452 let mut tester = origen::tester();
453
454 let obj = g.to_object(py);
455 let mut n = obj.getattr(py, "__module__")?.extract::<String>(py)?;
456 n.push_str(&format!(
457 ".{}",
458 obj.getattr(py, "__qualname__")?.extract::<String>(py)?
459 ));
460
461 let t_id = tester.register_external_tester(&n)?;
462 self.python_testers.insert(t_id, obj);
463 Ok(())
464 }
465
466 #[pyo3(signature=(*testers))]
467 fn target(&mut self, py: Python, testers: &PyTuple) -> PyResult<Vec<String>> {
468 if testers.len() > 0 {
469 let mut tester = origen::tester();
470 for g in testers.iter() {
471 if let Ok(name) = g.extract::<String>() {
473 tester.target(SupportedTester::new(&name)?)?;
474 } else {
475 let obj = g.to_object(py);
476 let mut n = obj.getattr(py, "__module__")?.extract::<String>(py)?;
477 n.push_str(&format!(
478 ".{}",
479 obj.getattr(py, "__qualname__")?.extract::<String>(py)?
480 ));
481 let t = tester.target(SupportedTester::new(&format!("CUSTOM::{}", n))?)?;
483 match t {
484 TesterSource::External(gen) => {
485 let klass = self.python_testers.get(gen).unwrap();
486 let inst = klass.call0(py)?;
487 self.instantiated_testers.insert(gen.to_owned(), inst);
488 }
489 _ => {}
490 }
491 }
492 }
493 }
494 self.targets()
495 }
496
497 #[getter]
498 fn targets(&self) -> PyResult<Vec<String>> {
499 let tester = origen::tester();
500 Ok(tester.targets_as_strs().clone())
501 }
502
503 #[pyo3(signature=(continue_on_fail=false))]
510 fn render_pattern(&self, py: Python, continue_on_fail: bool) -> PyResult<Vec<String>> {
511 if origen::LOGGER.has_keyword("show_unprocessed_ast") {
512 origen::LOGGER.info("Showing Unprocessed AST");
513 origen::LOGGER.info(&format!("{:?}", origen::TEST));
514 }
515 let mut rendered_patterns: Vec<String> = vec![];
516 let targets;
517 {
518 let tester = origen::tester();
519 targets = tester.targets().clone();
520 }
521 for (i, t) in targets.iter().enumerate() {
522 match t {
523 TesterSource::External(g) => {
524 match self.instantiated_testers.get(g) {
526 Some(inst) => {
527 let _pat = inst.call_method0(py, "render_pattern")?;
530 }
532 None => {
533 let msg = format!(
535 "Something's gone wrong and Python tester {} cannot be found!",
536 g
537 );
538 return Err(PyErr::from(Error::new(&msg)));
539 }
540 }
541 }
542 _ => {
543 let mut tester = origen::tester();
544 let pat = tester.render_pattern_for_target_at(i, true);
545 match pat {
546 Err(e) => {
547 let msg = e.to_string();
548 if continue_on_fail {
549 STATUS.inc_unhandled_error_count();
550 log_error!("{}", &msg);
551 } else {
552 return Err(PyErr::from(Error::new(&msg)));
553 }
554 }
555 Ok(paths) => {
556 for path in &paths {
557 rendered_patterns.push(format!("{}", path.display()));
558 }
559 }
560 }
561 }
562 }
563 }
564 Ok(rendered_patterns)
565 }
566
567 #[getter]
568 fn testers(&self) -> PyResult<Vec<String>> {
569 Ok(SupportedTester::all_names())
570 }
571}