OR-1 dataflow CPU sketch
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at ba08ffded3d3b2badb2a7e22816feafaacea5ded 247 lines 8.2 kB view raw
1"""Opcode mnemonic mapping and arity classification for OR1 assembly. 2 3This module provides: 4- MNEMONIC_TO_OP: Maps assembly mnemonic strings to ALUOp or MemOp enum values 5- OP_TO_MNEMONIC: Reverse mapping for serialization (handles IntEnum value collisions) 6- MONADIC_OPS: Set of opcodes that are always monadic 7- is_monadic() and is_dyadic(): Functions to check operand arity 8""" 9 10from typing import Optional, Union 11from cm_inst import ArithOp, LogicOp, MemOp, RoutingOp, is_monadic_alu 12 13 14# Build mnemonic to opcode mapping 15MNEMONIC_TO_OP: dict[str, Union[ArithOp, LogicOp, RoutingOp, MemOp]] = { 16 # Arithmetic operations 17 "add": ArithOp.ADD, 18 "sub": ArithOp.SUB, 19 "inc": ArithOp.INC, 20 "dec": ArithOp.DEC, 21 "shiftl": ArithOp.SHIFT_L, 22 "shiftr": ArithOp.SHIFT_R, 23 "ashiftr": ArithOp.ASHFT_R, 24 # Logic operations 25 "and": LogicOp.AND, 26 "or": LogicOp.OR, 27 "xor": LogicOp.XOR, 28 "not": LogicOp.NOT, 29 "eq": LogicOp.EQ, 30 "lt": LogicOp.LT, 31 "lte": LogicOp.LTE, 32 "gt": LogicOp.GT, 33 "gte": LogicOp.GTE, 34 # Routing/branch operations 35 "breq": RoutingOp.BREQ, 36 "brgt": RoutingOp.BRGT, 37 "brge": RoutingOp.BRGE, 38 "brof": RoutingOp.BROF, 39 "sweq": RoutingOp.SWEQ, 40 "swgt": RoutingOp.SWGT, 41 "swge": RoutingOp.SWGE, 42 "swof": RoutingOp.SWOF, 43 "gate": RoutingOp.GATE, 44 "sel": RoutingOp.SEL, 45 "merge": RoutingOp.MRGE, 46 "pass": RoutingOp.PASS, 47 "const": RoutingOp.CONST, 48 "free_ctx": RoutingOp.FREE_CTX, # ALU free (deallocate context slot) 49 # Memory operations 50 "read": MemOp.READ, 51 "write": MemOp.WRITE, 52 "clear": MemOp.CLEAR, 53 "alloc": MemOp.ALLOC, 54 "free": MemOp.FREE, # SM free 55 "rd_inc": MemOp.RD_INC, 56 "rd_dec": MemOp.RD_DEC, 57 "cmp_sw": MemOp.CMP_SW, 58 "exec": MemOp.EXEC, 59 "raw_read": MemOp.RAW_READ, 60 "set_page": MemOp.SET_PAGE, 61 "write_imm": MemOp.WRITE_IMM, 62 "ext": MemOp.EXT, 63} 64 65 66# Build reverse mapping with type information to avoid IntEnum collisions 67_reverse_mapping: dict[tuple[type, int], str] = {} 68for mnemonic, op in MNEMONIC_TO_OP.items(): 69 _reverse_mapping[(type(op), int(op))] = mnemonic 70 71 72class TypeAwareOpToMnemonicDict: 73 """Collision-free reverse mapping from opcodes to mnemonics. 74 75 Handles IntEnum cross-type equality by using (type, value) tuples internally. 76 Supports dict-like access: OP_TO_MNEMONIC[ArithOp.ADD] returns "add", 77 OP_TO_MNEMONIC[MemOp.READ] returns "read", etc. 78 """ 79 80 def __init__(self, mapping: dict[tuple[type, int], str]): 81 """Initialize with a type-indexed mapping. 82 83 Args: 84 mapping: dict from (type, value) tuples to mnemonic strings 85 """ 86 self._mapping = mapping 87 88 def __getitem__(self, op: Union[ArithOp, LogicOp, RoutingOp, MemOp]) -> str: 89 """Get the mnemonic for an opcode. 90 91 Args: 92 op: The opcode enum value 93 94 Returns: 95 The mnemonic string 96 97 Raises: 98 KeyError: If the opcode is not in the mapping 99 """ 100 key = (type(op), int(op)) 101 if key not in self._mapping: 102 raise KeyError(f"Opcode {op} ({type(op).__name__}) not found in mapping") 103 return self._mapping[key] 104 105 def __contains__(self, op: Union[ArithOp, LogicOp, RoutingOp, MemOp]) -> bool: 106 """Check if an opcode is in the mapping.""" 107 return (type(op), int(op)) in self._mapping 108 109 def __iter__(self): 110 """Iterate over mnemonic strings.""" 111 return iter(self._mapping.values()) 112 113 def __len__(self) -> int: 114 """Return the number of opcode-mnemonic pairs.""" 115 return len(self._mapping) 116 117 def items(self): 118 """Return an iterator of (opcode_type, mnemonic) pairs for testing. 119 120 This reconstructs the original enum instances from the stored types/values. 121 """ 122 result = [] 123 for (op_type, op_val), mnemonic in self._mapping.items(): 124 result.append((op_type(op_val), mnemonic)) 125 return result 126 127 128OP_TO_MNEMONIC: TypeAwareOpToMnemonicDict = TypeAwareOpToMnemonicDict(_reverse_mapping) 129 130 131# Set of opcodes that are always monadic (single input operand). 132# We use a frozenset of (type, value) tuples to avoid IntEnum collisions. 133_MONADIC_OPS_TUPLES: frozenset[tuple[type, int]] = frozenset([ 134 # ALU ops: duplicated from cm_inst.is_monadic_alu() for MONADIC_OPS membership testing. 135 # is_monadic() short-circuits to is_monadic_alu() for ALU ops, so these entries 136 # are only reached via `op in MONADIC_OPS` (TypeAwareMonadicOpsSet). 137 (ArithOp, int(ArithOp.INC)), 138 (ArithOp, int(ArithOp.DEC)), 139 (ArithOp, int(ArithOp.SHIFT_L)), 140 (ArithOp, int(ArithOp.SHIFT_R)), 141 (ArithOp, int(ArithOp.ASHFT_R)), 142 # Logic: single input 143 (LogicOp, int(LogicOp.NOT)), 144 # Routing: single input or no ALU involvement 145 (RoutingOp, int(RoutingOp.PASS)), 146 (RoutingOp, int(RoutingOp.CONST)), 147 (RoutingOp, int(RoutingOp.FREE_CTX)), 148 # Memory: single input (monadic SM operations) 149 (MemOp, int(MemOp.READ)), 150 (MemOp, int(MemOp.ALLOC)), 151 (MemOp, int(MemOp.FREE)), 152 (MemOp, int(MemOp.CLEAR)), 153 (MemOp, int(MemOp.RD_INC)), 154 (MemOp, int(MemOp.RD_DEC)), 155 (MemOp, int(MemOp.EXEC)), 156 (MemOp, int(MemOp.RAW_READ)), 157 (MemOp, int(MemOp.SET_PAGE)), 158 (MemOp, int(MemOp.WRITE_IMM)), 159 (MemOp, int(MemOp.EXT)), 160]) 161 162 163class TypeAwareMonadicOpsSet: 164 """Collision-free set of monadic opcodes. 165 166 Handles IntEnum cross-type equality by using (type, value) tuples internally. 167 Supports membership testing: ArithOp.INC in MONADIC_OPS returns True, 168 but ArithOp.ADD in MONADIC_OPS returns False (collision-free). 169 """ 170 171 def __init__(self, tuples: frozenset[tuple[type, int]]): 172 """Initialize with type-indexed tuples. 173 174 Args: 175 tuples: frozenset of (type, value) tuples 176 """ 177 self._tuples = tuples 178 179 def __contains__(self, op: Union[ArithOp, LogicOp, RoutingOp, MemOp]) -> bool: 180 """Check if an opcode is in the set, handling IntEnum collisions. 181 182 Args: 183 op: The opcode enum value 184 185 Returns: 186 True if the opcode is monadic, False otherwise 187 """ 188 return (type(op), int(op)) in self._tuples 189 190 def __iter__(self): 191 """Iterate over opcode instances in the set.""" 192 for op_type, op_val in self._tuples: 193 yield op_type(op_val) 194 195 def __len__(self) -> int: 196 """Return the number of monadic opcodes.""" 197 return len(self._tuples) 198 199 def __repr__(self) -> str: 200 """Return a string representation of the set.""" 201 ops = list(self) 202 return f"TypeAwareMonadicOpsSet({ops})" 203 204 205MONADIC_OPS: TypeAwareMonadicOpsSet = TypeAwareMonadicOpsSet(_MONADIC_OPS_TUPLES) 206 207 208def is_monadic(op: Union[ArithOp, LogicOp, RoutingOp, MemOp], const: Optional[int] = None) -> bool: 209 """Check if an opcode is monadic (single input operand). 210 211 Args: 212 op: The ALUOp or MemOp enum value 213 const: Optional const value. Used to determine monadic form of WRITE. 214 If const is not None, WRITE is monadic (cell_addr from const). 215 If const is None, WRITE is dyadic (cell_addr from left operand). 216 217 Returns: 218 True if the opcode is always monadic, or if it's WRITE with const set. 219 False for CMP_SW (always dyadic) and WRITE with const=None (dyadic). 220 """ 221 # Use canonical is_monadic_alu for ALU operations 222 if isinstance(op, (ArithOp, LogicOp, RoutingOp)): 223 return is_monadic_alu(op) 224 225 # Handle MemOp operations 226 op_tuple = (type(op), int(op)) 227 if op_tuple in _MONADIC_OPS_TUPLES: 228 return True 229 230 # Special case: WRITE can be monadic (const given) or dyadic (const not given) 231 if type(op) is MemOp and op == MemOp.WRITE: 232 return const is not None 233 234 return False 235 236 237def is_dyadic(op: Union[ArithOp, LogicOp, RoutingOp, MemOp], const: Optional[int] = None) -> bool: 238 """Check if an opcode is dyadic (two input operands). 239 240 Args: 241 op: The ALUOp or MemOp enum value 242 const: Optional const value. Used for context-dependent operations like WRITE. 243 244 Returns: 245 True if the opcode is dyadic, False otherwise. 246 """ 247 return not is_monadic(op, const)