OR-1 dataflow CPU sketch
1from pathlib import Path
2
3import pytest
4from hypothesis import strategies as st
5from lark import Lark
6
7from cm_inst import ArithOp, LogicOp, MemOp, Port, RoutingOp
8from tokens import CMToken, DyadToken, MonadToken, SMToken
9
10GRAMMAR_PATH = Path(__file__).parent.parent / "dfasm.lark"
11
12uint16 = st.integers(min_value=0, max_value=0xFFFF)
13int16 = st.integers(min_value=-32768, max_value=32767)
14shift_amount = st.integers(min_value=0, max_value=15)
15
16arith_dyadic_ops = st.sampled_from([ArithOp.ADD, ArithOp.SUB])
17arith_monadic_ops = st.sampled_from([ArithOp.INC, ArithOp.DEC])
18shift_ops = st.sampled_from([ArithOp.SHIFT_L, ArithOp.SHIFT_R, ArithOp.ASHFT_R])
19logic_dyadic_ops = st.sampled_from([LogicOp.AND, LogicOp.OR, LogicOp.XOR])
20comparison_ops = st.sampled_from([LogicOp.EQ, LogicOp.LT, LogicOp.LTE, LogicOp.GT, LogicOp.GTE])
21branch_ops = st.sampled_from([RoutingOp.BREQ, RoutingOp.BRGT, RoutingOp.BRGE])
22switch_ops = st.sampled_from([RoutingOp.SWEQ, RoutingOp.SWGT, RoutingOp.SWGE])
23overflow_ops = st.sampled_from([RoutingOp.BROF, RoutingOp.SWOF])
24data_routing_ops = st.sampled_from([RoutingOp.SEL, RoutingOp.MRGE])
25
26
27@st.composite
28def dyad_token(draw, target: int = 0, offset: int | None = None, ctx: int | None = None, gen: int | None = None) -> DyadToken:
29 return DyadToken(
30 target=target,
31 offset=draw(st.integers(min_value=0, max_value=63)) if offset is None else offset,
32 ctx=draw(st.integers(min_value=0, max_value=3)) if ctx is None else ctx,
33 data=draw(uint16),
34 port=draw(st.sampled_from(list(Port))),
35 gen=draw(st.integers(min_value=0, max_value=3)) if gen is None else gen,
36 wide=False,
37 )
38
39
40@st.composite
41def monad_token(draw, target: int = 0, offset: int | None = None, ctx: int | None = None) -> MonadToken:
42 return MonadToken(
43 target=target,
44 offset=draw(st.integers(min_value=0, max_value=63)) if offset is None else offset,
45 ctx=draw(st.integers(min_value=0, max_value=3)) if ctx is None else ctx,
46 data=draw(uint16),
47 inline=False,
48 )
49
50
51# SM ops: implemented for T1 are READ, WRITE, CLEAR, RD_INC, RD_DEC, CMP_SW, ALLOC, FREE, EXEC
52# Unimplemented: SET_PAGE, WRITE_IMM, RAW_READ, EXT
53sm_implemented_ops = [
54 MemOp.READ, MemOp.WRITE, MemOp.CLEAR, MemOp.RD_INC, MemOp.RD_DEC,
55 MemOp.CMP_SW, MemOp.ALLOC, MemOp.FREE, MemOp.EXEC
56]
57sm_all_ops = st.sampled_from(sm_implemented_ops)
58
59
60@st.composite
61def sm_token(draw, addr=None, op=None, data=None):
62 # By default, generate T1 addresses (below tier_boundary of 256)
63 # Tests that specifically need T0 addresses should pass them explicitly
64 _addr = draw(st.integers(min_value=0, max_value=255)) if addr is None else addr
65 _op = draw(sm_all_ops) if op is None else op
66 _data = draw(uint16) if data is None else data
67 ret = CMToken(target=0, offset=0, ctx=0, data=0)
68 return SMToken(
69 target=0,
70 addr=_addr,
71 op=_op,
72 flags=None,
73 data=_data,
74 ret=ret,
75 )
76
77
78@st.composite
79def sm_return_route(draw, target=0):
80 return CMToken(
81 target=target,
82 offset=draw(st.integers(min_value=0, max_value=63)),
83 ctx=draw(st.integers(min_value=0, max_value=3)),
84 data=0,
85 )
86
87
88@pytest.fixture(scope="session")
89def parser():
90 """Get the dfasm parser."""
91 return Lark(
92 GRAMMAR_PATH.read_text(),
93 parser="earley",
94 propagate_positions=True,
95 )