Something went wrong. Try again.
OR-1 dataflow CPU sketch
Something went wrong. Try again.
10 kB · 338 lines
Python
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339"""Tests for Enhancement 2: Parameterized placement and port qualifiers (macro-enh.E2.*).
Tests verify:- macro-enh.E2.1: Grammar accepts param_ref in placement position- macro-enh.E2.2: Grammar accepts param_ref in port position- macro-enh.E2.3: Context slot bracket syntax parses- macro-enh.E2.4: Expand pass resolves placement ParamRef- macro-enh.E2.5: Expand pass resolves port ParamRef- macro-enh.E2.6: Expand pass resolves context slot ParamRef- macro-enh.E2.7: Full pipeline with placement/port params
Note: Placement qualifiers attach to the LHS qualified_ref in inst_def,not to the opcode. So `&n|${pe} <| add` is the correct syntax, not`&n <| add|${pe}`."""
from pathlib import Path
from lark import Lark
from asm import assemble, run_pipelinefrom asm.expand import expandfrom asm.lower import lowerfrom asm.errors import ErrorCategoryfrom asm.ir import ( IRNode, ParamRef, PlacementRef, PortRef, ActSlotRef, ActSlotRange,)from cm_inst import ArithOp, Port
def _get_parser(): grammar_path = Path(__file__).parent.parent / "dfasm.lark" return Lark( grammar_path.read_text(), parser="earley", propagate_positions=True, )
def parse_and_lower(source: str): parser = _get_parser() tree = parser.parse(source) return lower(tree)
def parse_lower_expand(source: str): graph = parse_and_lower(source) return expand(graph)
class TestE21_PlacementParamRef: """E2.1: Grammar accepts param_ref in placement position."""
def test_placement_param_ref_in_macro_body(self): """&n|${pe} <| add parses and lowers to PlacementRef.""" source = """ @system pe=1, sm=1 #place pe |> { &n|${pe} <| add } """ graph = parse_and_lower(source) assert not graph.errors body_nodes = graph.macro_defs[0].body.nodes node = list(body_nodes.values())[0] assert isinstance(node.pe, PlacementRef) assert node.pe.param.param == "pe"
class TestE22_PortParamRef: """E2.2: Grammar accepts param_ref in port position."""
def test_port_param_ref_in_edge(self): """&src |> &dst:${port} parses and lowers to PortRef.""" source = """ @system pe=1, sm=1 #wire port |> { &src <| pass &dst <| add &src |> &dst:${port} } """ graph = parse_and_lower(source) assert not graph.errors body_edges = graph.macro_defs[0].body.edges port_ref_edges = [e for e in body_edges if isinstance(e.port, PortRef)] assert len(port_ref_edges) == 1 assert port_ref_edges[0].port.param.param == "port"
class TestE23_CtxSlotSyntax: """E2.3: Context slot bracket syntax parses."""
def test_literal_ctx_slot(self): """&node[2] parses — literal context slot in bracket syntax.""" source = """ @system pe=1, sm=1 #slot_macro |> { &n[2] <| add } """ graph = parse_and_lower(source) assert not graph.errors body_nodes = graph.macro_defs[0].body.nodes node = list(body_nodes.values())[0] assert isinstance(node.act_slot, ActSlotRange) assert node.act_slot.start == 2 assert node.act_slot.end == 2
def test_full_qualifier_chain(self): """&node|pe0[2]:L parses — placement + ctx_slot + port.""" source = """ @system pe=1, sm=1 &n|pe0[2]:L <| add """ graph = parse_and_lower(source) assert not graph.errors node = list(graph.nodes.values())[0] assert node.pe == 0 assert isinstance(node.act_slot, ActSlotRange) assert node.act_slot.start == 2 assert node.act_slot.end == 2
def test_parameterized_ctx_slot(self): """&node[${ctx}] parses — parameterized context slot.""" source = """ @system pe=1, sm=1 #ctx_macro ctx |> { &n[${ctx}] <| add } """ graph = parse_and_lower(source) assert not graph.errors body_nodes = graph.macro_defs[0].body.nodes node = list(body_nodes.values())[0] assert isinstance(node.act_slot, ActSlotRef) assert node.act_slot.param.param == "ctx"
def test_ctx_slot_range(self): """&node[0..4] parses — range reservation.""" source = """ @system pe=1, sm=1 &n[0..4] <| add """ graph = parse_and_lower(source) assert not graph.errors node = list(graph.nodes.values())[0] assert isinstance(node.act_slot, ActSlotRange) assert node.act_slot.start == 0 assert node.act_slot.end == 4
class TestE24_ExpandResolvesPlacement: """E2.4: Expand pass resolves placement ParamRef."""
def test_resolve_pe0(self): """Placement param 'pe0' resolves to PE 0.""" source = """ @system pe=2, sm=1 #place pe |> { &n|${pe} <| add } #place pe0 """ graph = parse_lower_expand(source) assert not graph.errors node = list(graph.nodes.values())[0] assert node.pe == 0
def test_resolve_pe1(self): """Placement param 'pe1' resolves to PE 1.""" source = """ @system pe=2, sm=1 #place pe |> { &n|${pe} <| add } #place pe1 """ graph = parse_lower_expand(source) assert not graph.errors node = list(graph.nodes.values())[0] assert node.pe == 1
def test_invalid_placement_error(self): """Invalid placement value produces MACRO error.""" source = """ @system pe=1, sm=1 #place pe |> { &n|${pe} <| add } #place &banana """ graph = parse_lower_expand(source) macro_errors = [e for e in graph.errors if e.category == ErrorCategory.MACRO] assert len(macro_errors) >= 1 assert "placement" in macro_errors[0].message.lower()
class TestE25_ExpandResolvesPort: """E2.5: Expand pass resolves port ParamRef."""
def test_resolve_port_L(self): """Port param 'L' resolves to Port.L.""" source = """ @system pe=1, sm=1 #wire port |> { &src <| pass &dst <| add &src |> &dst:${port} } #wire L """ graph = parse_lower_expand(source) assert not graph.errors edges = [e for e in graph.edges if e.dest.endswith("&dst")] assert len(edges) >= 1 assert edges[0].port == Port.L
def test_resolve_port_R(self): """Port param 'R' resolves to Port.R.""" source = """ @system pe=1, sm=1 #wire port |> { &src <| pass &dst <| add &src |> &dst:${port} } #wire R """ graph = parse_lower_expand(source) assert not graph.errors edges = [e for e in graph.edges if e.dest.endswith("&dst")] assert len(edges) >= 1 assert edges[0].port == Port.R
def test_invalid_port_value_produces_error(self): """E2.5c: Invalid port value produces MACRO error.""" source = """ @system pe=1, sm=1 #wire port |> { &src <| pass &dst <| add &src |> &dst:${port} } #wire X """ graph = parse_lower_expand(source) macro_errors = [e for e in graph.errors if e.category == ErrorCategory.MACRO] assert len(macro_errors) >= 1 assert "port" in macro_errors[0].message.lower()
def test_invalid_source_port_value_produces_error(self): """Invalid source port value produces MACRO error.""" source = """ @system pe=1, sm=1 #wire port |> { &src <| pass &dst <| add &src:${port} |> &dst } #wire Z """ graph = parse_lower_expand(source) macro_errors = [e for e in graph.errors if e.category == ErrorCategory.MACRO] assert len(macro_errors) >= 1 assert "port" in macro_errors[0].message.lower()
class TestE26_ExpandResolvesCtxSlot: """E2.6: Expand pass resolves context slot ParamRef."""
def test_resolve_ctx_slot_int(self): """Ctx slot param resolves to CtxSlotRange.""" source = """ @system pe=1, sm=1 #ctx_macro ctx |> { &n[${ctx}] <| add } #ctx_macro 2 """ graph = parse_lower_expand(source) assert not graph.errors node = list(graph.nodes.values())[0] assert isinstance(node.act_slot, ActSlotRange) assert node.act_slot.start == 2 assert node.act_slot.end == 2
def test_non_numeric_ctx_slot_error(self): """Non-numeric ctx slot value produces MACRO error.""" source = """ @system pe=1, sm=1 #ctx_macro ctx |> { &n[${ctx}] <| add } #ctx_macro &banana """ graph = parse_lower_expand(source) macro_errors = [e for e in graph.errors if e.category == ErrorCategory.MACRO] assert len(macro_errors) >= 1 assert "act_slot" in macro_errors[0].message.lower() or "ctx_slot" in macro_errors[0].message.lower()
class TestE27_FullPipeline: """E2.7: Full pipeline with placement/port params."""
def test_full_pipeline_placement_param(self): """Placement-parameterized macro assembles; node on correct PE.""" source = """ @system pe=2, sm=1 #place pe |> { &n|${pe} <| add } &seed <| const, 5 #place pe1 &seed |> #place_0.&n:L &seed |> #place_0.&n:R """ graph = run_pipeline(source) assert not graph.errors placed_node = graph.nodes["#place_0.&n"] assert placed_node.pe == 1
def test_full_pipeline_port_param(self): """Port-parameterized macro assembles; edge targets correct port.""" source = """ @system pe=1, sm=1 #wire port |> { &src <| pass &dst <| add &src |> &dst:${port} } &seed <| const, 5 #wire L &seed |> #wire_0.&src &seed |> #wire_0.&dst:R """ result = assemble(source) assert result is not None