codecin 5.4.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. codecin/__init__.py +27 -0
  2. codecin/aot.py +229 -0
  3. codecin/assembler.py +548 -0
  4. codecin/cache.py +71 -0
  5. codecin/cin.py +2558 -0
  6. codecin/cli.py +282 -0
  7. codecin/config.py +58 -0
  8. codecin/console.py +183 -0
  9. codecin/cpu.py +1654 -0
  10. codecin/crom.py +222 -0
  11. codecin/debugger.py +659 -0
  12. codecin/disasm.py +86 -0
  13. codecin/errors.py +58 -0
  14. codecin/isa.py +457 -0
  15. codecin/jit.py +270 -0
  16. codecin/libcodecin_native.so +0 -0
  17. codecin/logger.py +145 -0
  18. codecin/memory.py +348 -0
  19. codecin/native/aot/aot.go +70 -0
  20. codecin/native/aot/build.go +219 -0
  21. codecin/native/aot/stub_main.go.txt +22 -0
  22. codecin/native/build.ps1 +33 -0
  23. codecin/native/build.sh +48 -0
  24. codecin/native/cmd/codecin/main.go +287 -0
  25. codecin/native/compiler/codegen.go +1938 -0
  26. codecin/native/compiler/compile_test.go +164 -0
  27. codecin/native/compiler/parser.go +1071 -0
  28. codecin/native/compiler/syscalls.go +86 -0
  29. codecin/native/compiler/tokenizer.go +336 -0
  30. codecin/native/compiler/types.go +213 -0
  31. codecin/native/engine/audio.go +152 -0
  32. codecin/native/engine/audio_other.go +46 -0
  33. codecin/native/engine/audio_windows.go +43 -0
  34. codecin/native/engine/canvas.go +271 -0
  35. codecin/native/engine/crom.go +86 -0
  36. codecin/native/engine/encode.go +93 -0
  37. codecin/native/engine/engine_test.go +198 -0
  38. codecin/native/engine/isa_gen.go +445 -0
  39. codecin/native/engine/system.go +190 -0
  40. codecin/native/engine/termux.go +113 -0
  41. codecin/native/engine/version_gen.go +7 -0
  42. codecin/native/engine/vm.go +1157 -0
  43. codecin/native/go.mod +3 -0
  44. codecin/native/ir/ir.go +48 -0
  45. codecin/native/main.go +225 -0
  46. codecin/native.py +336 -0
  47. codecin/registers.py +130 -0
  48. codecin/stats.py +235 -0
  49. codecin-5.4.2.dist-info/METADATA +985 -0
  50. codecin-5.4.2.dist-info/RECORD +54 -0
  51. codecin-5.4.2.dist-info/WHEEL +5 -0
  52. codecin-5.4.2.dist-info/entry_points.txt +2 -0
  53. codecin-5.4.2.dist-info/licenses/LICENSE +7 -0
  54. codecin-5.4.2.dist-info/top_level.txt +1 -0
codecin/registers.py ADDED
@@ -0,0 +1,130 @@
1
+ from typing import Any, Dict, List, Optional
2
+
3
+ from .console import Console, Table
4
+ from .errors import ExecutionError
5
+ from .isa import Constants
6
+
7
+ MASK64 = 0xFFFFFFFFFFFFFFFF
8
+
9
+
10
+ class RegisterFile:
11
+ def __init__(self, console: Optional[Console] = None,
12
+ num_regs: int = Constants.NUM_REGISTERS):
13
+ self.console = console or Console()
14
+ self.num_regs = num_regs
15
+ self._regs = [0] * num_regs
16
+
17
+ def read(self, idx: int) -> int:
18
+ if idx == 31:
19
+ return 0
20
+ if not 0 <= idx < self.num_regs:
21
+ raise ExecutionError(f"Invalid register index: X{idx}")
22
+ return self._regs[idx]
23
+
24
+ def write(self, idx: int, value: int, pc: int = 0) -> None:
25
+ if idx == 31:
26
+ return
27
+ if not 0 <= idx < self.num_regs:
28
+ raise ExecutionError(f"Invalid register index: X{idx}")
29
+ self._regs[idx] = value & MASK64
30
+
31
+ def get_all(self) -> List[int]:
32
+ return self._regs.copy()
33
+
34
+ def set_all(self, values: List[int]) -> None:
35
+ for i, v in enumerate(values[:self.num_regs]):
36
+ self._regs[i] = v & MASK64
37
+
38
+ def reset(self) -> None:
39
+ self._regs = [0] * self.num_regs
40
+
41
+ def display_registers(self, title: str = "Registers",
42
+ extra_info: Optional[Dict[str, Any]] = None,
43
+ console: Optional[Console] = None) -> None:
44
+ if console is None:
45
+ console = self.console
46
+ table = Table(title=title)
47
+ table.add_column("Register")
48
+ table.add_column("Value (Dec)")
49
+ table.add_column("Value (Hex)")
50
+ for i in range(16):
51
+ val = self._regs[i]
52
+ table.add_row(f"X{i}", str(val), f"0x{val:x}")
53
+ table.add_row("", "", "")
54
+ for i in range(16, 31):
55
+ val = self._regs[i]
56
+ table.add_row(f"X{i}", str(val), f"0x{val:x}")
57
+ table.add_row("XZR", "0", "0x0")
58
+ if extra_info:
59
+ for key, value in extra_info.items():
60
+ table.add_row(key, str(value),
61
+ f"0x{value:x}" if isinstance(value, int) else "")
62
+ console.print(str(table))
63
+
64
+
65
+ class VectorRegisterFile:
66
+
67
+ def __init__(self, num_regs: int = Constants.NUM_VECTOR_REGISTERS,
68
+ lanes: int = Constants.VECTOR_LANES):
69
+ self.num_regs = num_regs
70
+ self.lanes = lanes
71
+ self._regs = [[0.0] * lanes for _ in range(num_regs)]
72
+
73
+ def read_vector(self, idx: int) -> List[float]:
74
+ if idx == 31:
75
+ return [0.0] * self.lanes
76
+ if not 0 <= idx < self.num_regs:
77
+ raise ExecutionError(f"Invalid vector register index: V{idx}")
78
+ return self._regs[idx].copy()
79
+
80
+ def write_vector(self, idx: int, values: List[float]) -> None:
81
+ if idx == 31:
82
+ return
83
+ if not 0 <= idx < self.num_regs:
84
+ raise ExecutionError(f"Invalid vector register index: V{idx}")
85
+ if len(values) != self.lanes:
86
+ raise ExecutionError(f"Need {self.lanes} values, got {len(values)}")
87
+ self._regs[idx] = list(values)
88
+
89
+ def read_scalar(self, idx: int, lane: int = 0) -> float:
90
+ if idx == 31:
91
+ return 0.0
92
+ if not 0 <= idx < self.num_regs:
93
+ raise ExecutionError(f"Invalid vector register index: V{idx}")
94
+ if not 0 <= lane < self.lanes:
95
+ raise ExecutionError(f"Invalid lane index: {lane}")
96
+ return self._regs[idx][lane]
97
+
98
+ def write_scalar(self, idx: int, value: float, lane: int = 0) -> None:
99
+ if idx == 31:
100
+ return
101
+ if not 0 <= idx < self.num_regs:
102
+ raise ExecutionError(f"Invalid vector register index: V{idx}")
103
+ if not 0 <= lane < self.lanes:
104
+ raise ExecutionError(f"Invalid lane index: {lane}")
105
+ self._regs[idx][lane] = float(value)
106
+
107
+ def get_all(self) -> List[List[float]]:
108
+ return [v.copy() for v in self._regs]
109
+
110
+ def set_all(self, values: List[List[float]]) -> None:
111
+ for i, v in enumerate(values[:self.num_regs]):
112
+ self._regs[i] = [float(x) for x in v[:self.lanes]]
113
+
114
+ def reset(self) -> None:
115
+ self._regs = [[0.0] * self.lanes for _ in range(self.num_regs)]
116
+
117
+ def display_vector_registers(self, title: str = "Vector Registers",
118
+ console: Optional[Console] = None) -> None:
119
+ if console is None:
120
+ return
121
+ table = Table(title=title)
122
+ table.add_column("Register")
123
+ for lane in range(self.lanes):
124
+ table.add_column(f"Lane {lane}")
125
+ for i in range(self.num_regs):
126
+ vec = self._regs[i]
127
+ if any(v != 0.0 for v in vec):
128
+ table.add_row(f"V{i}", *[f"{v:.4g}" for v in vec])
129
+ if table.rows:
130
+ console.print(str(table))
codecin/stats.py ADDED
@@ -0,0 +1,235 @@
1
+ import time
2
+ from collections import defaultdict
3
+ from typing import Any, Dict, List, Optional, Tuple
4
+
5
+ from .console import Console, Table
6
+ from .isa import Constants
7
+
8
+
9
+ class BranchPredictor:
10
+
11
+ def __init__(self):
12
+ self.saturating_counters: Dict[int, int] = {}
13
+ self.correct_predictions = 0
14
+ self.total_predictions = 0
15
+
16
+ def predict(self, pc: int) -> bool:
17
+ return self.saturating_counters.get(pc, 2) >= 2
18
+
19
+ def update(self, pc: int, taken: bool) -> None:
20
+ counter = self.saturating_counters.get(pc, 2)
21
+ counter = min(3, counter + 1) if taken else max(0, counter - 1)
22
+ self.saturating_counters[pc] = counter
23
+
24
+ def record_prediction(self, predicted: bool, actual: bool) -> None:
25
+ self.total_predictions += 1
26
+ if predicted == actual:
27
+ self.correct_predictions += 1
28
+
29
+ def get_accuracy(self) -> float:
30
+ if self.total_predictions == 0:
31
+ return 1.0
32
+ return self.correct_predictions / self.total_predictions
33
+
34
+
35
+ class PerformanceCounters:
36
+ def __init__(self):
37
+ self.counters = {
38
+ 'cycles': 0,
39
+ 'instructions': 0,
40
+ 'branches': 0,
41
+ 'branch_mispredictions': 0,
42
+ 'cache_hits': 0,
43
+ 'cache_misses': 0,
44
+ 'memory_reads': 0,
45
+ 'memory_writes': 0,
46
+ 'stalls': 0,
47
+ 'flops': 0,
48
+ }
49
+ self.branch_predictor = BranchPredictor()
50
+
51
+ def record_instruction(self, opcode: str) -> None:
52
+ self.counters['instructions'] += 1
53
+ if opcode in Constants.BRANCH_OPS:
54
+ self.counters['branches'] += 1
55
+ if opcode in Constants.FP_OPS:
56
+ self.counters['flops'] += 1
57
+
58
+ def record_branch_result(self, pc: int, taken: bool, predicted: bool) -> None:
59
+ self.branch_predictor.record_prediction(predicted, taken)
60
+ if taken != predicted:
61
+ self.counters['branch_mispredictions'] += 1
62
+ self.branch_predictor.update(pc, taken)
63
+
64
+ def record_cache(self, hit: bool) -> None:
65
+ if hit:
66
+ self.counters['cache_hits'] += 1
67
+ else:
68
+ self.counters['cache_misses'] += 1
69
+
70
+ def record_memory_read(self) -> None:
71
+ self.counters['memory_reads'] += 1
72
+
73
+ def record_memory_write(self) -> None:
74
+ self.counters['memory_writes'] += 1
75
+
76
+ def add_cycles(self, n: int) -> None:
77
+ self.counters['cycles'] += n
78
+
79
+ def get_ipc(self) -> float:
80
+ if self.counters['cycles'] == 0:
81
+ return 0
82
+ return self.counters['instructions'] / self.counters['cycles']
83
+
84
+ def get_stats(self) -> Dict[str, Any]:
85
+ stats = self.counters.copy()
86
+ stats['ipc'] = self.get_ipc()
87
+ stats['branch_accuracy'] = self.branch_predictor.get_accuracy()
88
+ total_cache = stats['cache_hits'] + stats['cache_misses']
89
+ stats['cache_hit_rate'] = stats['cache_hits'] / total_cache if total_cache > 0 else 0
90
+ return stats
91
+
92
+ def display(self, console: Console) -> None:
93
+ stats = self.get_stats()
94
+ table = Table(title="Performance Counters")
95
+ table.add_column("Metric")
96
+ table.add_column("Value")
97
+ for key, value in stats.items():
98
+ if key in ('branch_accuracy', 'cache_hit_rate'):
99
+ table.add_row(key.replace('_', ' ').title(), f"{value * 100:.1f}%")
100
+ elif key == 'ipc':
101
+ table.add_row("Instructions Per Cycle", f"{value:.2f}")
102
+ else:
103
+ table.add_row(key.replace('_', ' ').title(), str(value))
104
+ console.print(str(table))
105
+
106
+
107
+ class InstructionProfiler:
108
+
109
+ def __init__(self):
110
+ self.cycles: Dict[str, int] = defaultdict(int)
111
+ self.latency: Dict[str, int] = {
112
+ 'ADD': 1, 'SUB': 1, 'MUL': 3, 'DIV': 10,
113
+ 'LOAD': 4, 'STORE': 4, 'FADD': 3, 'FMUL': 5,
114
+ 'FDIV': 10, 'VADD': 2, 'VMUL': 4, 'VDIV': 8,
115
+ 'LSL': 1, 'LSR': 1, 'AND': 1, 'OR': 1, 'XOR': 1,
116
+ 'LD': 4, 'SD': 4, 'LDR': 4, 'STR': 4,
117
+ 'LB': 4, 'LH': 4, 'LW': 4, 'SB': 4, 'SH': 4, 'SW': 4,
118
+ }
119
+
120
+ def record(self, opcode: str) -> None:
121
+ self.cycles[opcode] += self.latency.get(opcode, 1)
122
+
123
+ def get_total_cycles(self) -> int:
124
+ return sum(self.cycles.values())
125
+
126
+ def display_report(self, console: Optional[Console] = None) -> None:
127
+ if console is None:
128
+ return
129
+ total = self.get_total_cycles()
130
+ table = Table(title="Instruction Cycle Profile")
131
+ table.add_column("Instruction")
132
+ table.add_column("Cycles")
133
+ table.add_column("Percentage")
134
+ for op, cycles in sorted(self.cycles.items(), key=lambda x: x[1], reverse=True)[:20]:
135
+ pct = (cycles / total * 100) if total > 0 else 0
136
+ table.add_row(op, str(cycles), f"{pct:.1f}%")
137
+ console.print(str(table))
138
+
139
+
140
+ class Statistics:
141
+ def __init__(self):
142
+ self.reset()
143
+
144
+ def reset(self):
145
+ self.instruction_count = 0
146
+ self.opcode_count: Dict[str, int] = defaultdict(int)
147
+ self.execution_time = 0.0
148
+ self.start_time: Optional[float] = None
149
+ self.memory_reads = 0
150
+ self.memory_writes = 0
151
+ self.inst_profiler = InstructionProfiler()
152
+ self.hot_instructions: Dict[str, int] = defaultdict(int)
153
+ self.performance_counters = PerformanceCounters()
154
+
155
+ def start(self):
156
+ self.start_time = time.time()
157
+
158
+ def stop(self):
159
+ if self.start_time:
160
+ self.execution_time = time.time() - self.start_time
161
+
162
+ def record_instruction(self, opcode: str):
163
+ self.instruction_count += 1
164
+ self.opcode_count[opcode] += 1
165
+ self.inst_profiler.record(opcode)
166
+ self.hot_instructions[opcode] += 1
167
+ self.performance_counters.record_instruction(opcode)
168
+
169
+ def record_memory_read(self):
170
+ self.memory_reads += 1
171
+ self.performance_counters.record_memory_read()
172
+
173
+ def record_memory_write(self):
174
+ self.memory_writes += 1
175
+ self.performance_counters.record_memory_write()
176
+
177
+ def record_cache(self, hit: bool):
178
+ self.performance_counters.record_cache(hit)
179
+
180
+ def record_branch(self, pc: int, taken: bool, predicted: bool):
181
+ self.performance_counters.record_branch_result(pc, taken, predicted)
182
+
183
+ def get_hot_instructions(self, top_n: int = 10) -> List[Tuple[str, int]]:
184
+ return sorted(self.hot_instructions.items(),
185
+ key=lambda x: x[1], reverse=True)[:top_n]
186
+
187
+ def display_summary(self, console: Optional[Console] = None,
188
+ cache_stats: Optional[Dict] = None,
189
+ jit_stats: Optional[Dict] = None,
190
+ native_used: bool = False) -> None:
191
+ if console is None:
192
+ return
193
+
194
+ table = Table(title="Execution Statistics")
195
+ table.add_column("Metric")
196
+ table.add_column("Value")
197
+ table.add_row("Engine", "Go native" if native_used else "Python interpreter")
198
+ table.add_row("Total Instructions", str(self.instruction_count))
199
+ table.add_row("Total Cycles", str(self.inst_profiler.get_total_cycles()))
200
+ if self.instruction_count > 0:
201
+ table.add_row("CPI (Cycles/Inst)",
202
+ f"{self.inst_profiler.get_total_cycles() / self.instruction_count:.2f}")
203
+ table.add_row("Execution Time", f"{self.execution_time:.4f}s")
204
+ if self.execution_time > 0:
205
+ table.add_row("Instructions/sec",
206
+ f"{self.instruction_count / self.execution_time:,.0f}")
207
+ table.add_row("Memory Reads", str(self.memory_reads))
208
+ table.add_row("Memory Writes", str(self.memory_writes))
209
+
210
+ perf_stats = self.performance_counters.get_stats()
211
+ table.add_row("Branch Accuracy", f"{perf_stats['branch_accuracy'] * 100:.1f}%")
212
+
213
+ if cache_stats:
214
+ table.add_row("Cache Hit Rate", f"{cache_stats.get('hit_rate', 0) * 100:.1f}%")
215
+
216
+ if jit_stats:
217
+ table.add_row("JIT Hit Rate", f"{jit_stats.get('hit_rate', 0) * 100:.1f}%")
218
+ table.add_row("JIT Blocks Compiled", str(jit_stats.get('blocks_compiled', 0)))
219
+
220
+ console.print(str(table))
221
+
222
+ if self.opcode_count:
223
+ op_table = Table(title="Instruction Usage")
224
+ op_table.add_column("Instruction")
225
+ op_table.add_column("Count")
226
+ op_table.add_column("Percentage")
227
+ total = sum(self.opcode_count.values())
228
+ for op, count in sorted(self.opcode_count.items(),
229
+ key=lambda x: x[1], reverse=True)[:20]:
230
+ pct = (count / total * 100) if total > 0 else 0
231
+ op_table.add_row(op, str(count), f"{pct:.1f}%")
232
+ console.print(str(op_table))
233
+
234
+ self.inst_profiler.display_report(console)
235
+ self.performance_counters.display(console)