Something went wrong. Try again.
OR-1 dataflow CPU sketch
Something went wrong. Try again.
8.4 kB · 251 lines
Python
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252"""Opcode mnemonic mapping and arity classification for OR1 assembly.
This module provides:- MNEMONIC_TO_OP: Maps assembly mnemonic strings to ALUOp or MemOp enum values- OP_TO_MNEMONIC: Reverse mapping for serialization (handles IntEnum value collisions)- MONADIC_OPS: Set of opcodes that are always monadic- is_monadic() and is_dyadic(): Functions to check operand arity"""
from typing import Optional, Unionfrom cm_inst import ArithOp, LogicOp, MemOp, RoutingOp, is_monadic_alu
# Build mnemonic to opcode mappingMNEMONIC_TO_OP: dict[str, Union[ArithOp, LogicOp, RoutingOp, MemOp]] = { # Arithmetic operations "add": ArithOp.ADD, "sub": ArithOp.SUB, "inc": ArithOp.INC, "dec": ArithOp.DEC, "shl": ArithOp.SHL, "shr": ArithOp.SHR, "asr": ArithOp.ASR, # Logic operations "and": LogicOp.AND, "or": LogicOp.OR, "xor": LogicOp.XOR, "not": LogicOp.NOT, "eq": LogicOp.EQ, "lt": LogicOp.LT, "lte": LogicOp.LTE, "gt": LogicOp.GT, "gte": LogicOp.GTE, # Routing/branch operations "breq": RoutingOp.BREQ, "brgt": RoutingOp.BRGT, "brge": RoutingOp.BRGE, "brof": RoutingOp.BROF, "sweq": RoutingOp.SWEQ, "swgt": RoutingOp.SWGT, "swge": RoutingOp.SWGE, "swof": RoutingOp.SWOF, "gate": RoutingOp.GATE, "sel": RoutingOp.SEL, "merge": RoutingOp.MRGE, "pass": RoutingOp.PASS, "const": RoutingOp.CONST, "free_frame": RoutingOp.FREE_FRAME, # ALU free (deallocate frame slot) "extract_tag": RoutingOp.EXTRACT_TAG, "alloc_remote": RoutingOp.ALLOC_REMOTE, # Memory operations "read": MemOp.READ, "write": MemOp.WRITE, "clear": MemOp.CLEAR, "alloc": MemOp.ALLOC, "free": MemOp.FREE, # SM free "rd_inc": MemOp.RD_INC, "rd_dec": MemOp.RD_DEC, "cmp_sw": MemOp.CMP_SW, "exec": MemOp.EXEC, "raw_read": MemOp.RAW_READ, "set_page": MemOp.SET_PAGE, "write_imm": MemOp.WRITE_IMM, "ext": MemOp.EXT,}
# Build reverse mapping with type information to avoid IntEnum collisions_reverse_mapping: dict[tuple[type, int], str] = {}for mnemonic, op in MNEMONIC_TO_OP.items(): _reverse_mapping[(type(op), int(op))] = mnemonic
class TypeAwareOpToMnemonicDict: """Collision-free reverse mapping from opcodes to mnemonics.
Handles IntEnum cross-type equality by using (type, value) tuples internally. Supports dict-like access: OP_TO_MNEMONIC[ArithOp.ADD] returns "add", OP_TO_MNEMONIC[MemOp.READ] returns "read", etc. """
def __init__(self, mapping: dict[tuple[type, int], str]): """Initialize with a type-indexed mapping.
Args: mapping: dict from (type, value) tuples to mnemonic strings """ self._mapping = mapping
def __getitem__(self, op: Union[ArithOp, LogicOp, RoutingOp, MemOp]) -> str: """Get the mnemonic for an opcode.
Args: op: The opcode enum value
Returns: The mnemonic string
Raises: KeyError: If the opcode is not in the mapping """ key = (type(op), int(op)) if key not in self._mapping: raise KeyError(f"Opcode {op} ({type(op).__name__}) not found in mapping") return self._mapping[key]
def __contains__(self, op: Union[ArithOp, LogicOp, RoutingOp, MemOp]) -> bool: """Check if an opcode is in the mapping.""" return (type(op), int(op)) in self._mapping
def __iter__(self): """Iterate over mnemonic strings.""" return iter(self._mapping.values())
def __len__(self) -> int: """Return the number of opcode-mnemonic pairs.""" return len(self._mapping)
def items(self): """Return an iterator of (opcode_type, mnemonic) pairs for testing.
This reconstructs the original enum instances from the stored types/values. """ result = [] for (op_type, op_val), mnemonic in self._mapping.items(): result.append((op_type(op_val), mnemonic)) return result
OP_TO_MNEMONIC: TypeAwareOpToMnemonicDict = TypeAwareOpToMnemonicDict(_reverse_mapping)
# Set of opcodes that are always monadic (single input operand).# We use a frozenset of (type, value) tuples to avoid IntEnum collisions._MONADIC_OPS_TUPLES: frozenset[tuple[type, int]] = frozenset([ # ALU ops: duplicated from cm_inst.is_monadic_alu() for MONADIC_OPS membership testing. # is_monadic() short-circuits to is_monadic_alu() for ALU ops, so these entries # are only reached via `op in MONADIC_OPS` (TypeAwareMonadicOpsSet). (ArithOp, int(ArithOp.INC)), (ArithOp, int(ArithOp.DEC)), (ArithOp, int(ArithOp.SHL)), (ArithOp, int(ArithOp.SHR)), (ArithOp, int(ArithOp.ASR)), # Logic: single input (LogicOp, int(LogicOp.NOT)), # Routing: single input or no ALU involvement (RoutingOp, int(RoutingOp.PASS)), (RoutingOp, int(RoutingOp.CONST)), (RoutingOp, int(RoutingOp.FREE_FRAME)), (RoutingOp, int(RoutingOp.EXTRACT_TAG)), (RoutingOp, int(RoutingOp.ALLOC_REMOTE)), # Memory: single input (monadic SM operations) (MemOp, int(MemOp.READ)), (MemOp, int(MemOp.ALLOC)), (MemOp, int(MemOp.FREE)), (MemOp, int(MemOp.CLEAR)), (MemOp, int(MemOp.RD_INC)), (MemOp, int(MemOp.RD_DEC)), (MemOp, int(MemOp.EXEC)), (MemOp, int(MemOp.RAW_READ)), (MemOp, int(MemOp.SET_PAGE)), (MemOp, int(MemOp.WRITE_IMM)), (MemOp, int(MemOp.EXT)),])
class TypeAwareMonadicOpsSet: """Collision-free set of monadic opcodes.
Handles IntEnum cross-type equality by using (type, value) tuples internally. Supports membership testing: ArithOp.INC in MONADIC_OPS returns True, but ArithOp.ADD in MONADIC_OPS returns False (collision-free). """
def __init__(self, tuples: frozenset[tuple[type, int]]): """Initialize with type-indexed tuples.
Args: tuples: frozenset of (type, value) tuples """ self._tuples = tuples
def __contains__(self, op: Union[ArithOp, LogicOp, RoutingOp, MemOp]) -> bool: """Check if an opcode is in the set, handling IntEnum collisions.
Args: op: The opcode enum value
Returns: True if the opcode is monadic, False otherwise """ return (type(op), int(op)) in self._tuples
def __iter__(self): """Iterate over opcode instances in the set.""" for op_type, op_val in self._tuples: yield op_type(op_val)
def __len__(self) -> int: """Return the number of monadic opcodes.""" return len(self._tuples)
def __repr__(self) -> str: """Return a string representation of the set.""" ops = list(self) return f"TypeAwareMonadicOpsSet({ops})"
MONADIC_OPS: TypeAwareMonadicOpsSet = TypeAwareMonadicOpsSet(_MONADIC_OPS_TUPLES)
def is_monadic(op: Union[ArithOp, LogicOp, RoutingOp, MemOp], const: Optional[int] = None) -> bool: """Check if an opcode is monadic (single input operand).
Args: op: The ALUOp or MemOp enum value const: Optional const value. Used to determine monadic form of WRITE. If const is not None, WRITE is monadic (cell_addr from const). If const is None, WRITE is dyadic (cell_addr from left operand).
Returns: True if the opcode is always monadic, or if it's WRITE with const set. False for CMP_SW (always dyadic) and WRITE with const=None (dyadic). """ # Use canonical is_monadic_alu for ALU operations if isinstance(op, (ArithOp, LogicOp, RoutingOp)): return is_monadic_alu(op)
# Handle MemOp operations op_tuple = (type(op), int(op)) if op_tuple in _MONADIC_OPS_TUPLES: return True
# Special case: WRITE can be monadic (const given) or dyadic (const not given) if type(op) is MemOp and op == MemOp.WRITE: return const is not None
return False
def is_dyadic(op: Union[ArithOp, LogicOp, RoutingOp, MemOp], const: Optional[int] = None) -> bool: """Check if an opcode is dyadic (two input operands).
Args: op: The ALUOp or MemOp enum value const: Optional const value. Used for context-dependent operations like WRITE.
Returns: True if the opcode is dyadic, False otherwise. """ return not is_monadic(op, const)