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.
- codecin/__init__.py +27 -0
- codecin/aot.py +229 -0
- codecin/assembler.py +548 -0
- codecin/cache.py +71 -0
- codecin/cin.py +2558 -0
- codecin/cli.py +282 -0
- codecin/config.py +58 -0
- codecin/console.py +183 -0
- codecin/cpu.py +1654 -0
- codecin/crom.py +222 -0
- codecin/debugger.py +659 -0
- codecin/disasm.py +86 -0
- codecin/errors.py +58 -0
- codecin/isa.py +457 -0
- codecin/jit.py +270 -0
- codecin/libcodecin_native.so +0 -0
- codecin/logger.py +145 -0
- codecin/memory.py +348 -0
- codecin/native/aot/aot.go +70 -0
- codecin/native/aot/build.go +219 -0
- codecin/native/aot/stub_main.go.txt +22 -0
- codecin/native/build.ps1 +33 -0
- codecin/native/build.sh +48 -0
- codecin/native/cmd/codecin/main.go +287 -0
- codecin/native/compiler/codegen.go +1938 -0
- codecin/native/compiler/compile_test.go +164 -0
- codecin/native/compiler/parser.go +1071 -0
- codecin/native/compiler/syscalls.go +86 -0
- codecin/native/compiler/tokenizer.go +336 -0
- codecin/native/compiler/types.go +213 -0
- codecin/native/engine/audio.go +152 -0
- codecin/native/engine/audio_other.go +46 -0
- codecin/native/engine/audio_windows.go +43 -0
- codecin/native/engine/canvas.go +271 -0
- codecin/native/engine/crom.go +86 -0
- codecin/native/engine/encode.go +93 -0
- codecin/native/engine/engine_test.go +198 -0
- codecin/native/engine/isa_gen.go +445 -0
- codecin/native/engine/system.go +190 -0
- codecin/native/engine/termux.go +113 -0
- codecin/native/engine/version_gen.go +7 -0
- codecin/native/engine/vm.go +1157 -0
- codecin/native/go.mod +3 -0
- codecin/native/ir/ir.go +48 -0
- codecin/native/main.go +225 -0
- codecin/native.py +336 -0
- codecin/registers.py +130 -0
- codecin/stats.py +235 -0
- codecin-5.4.2.dist-info/METADATA +985 -0
- codecin-5.4.2.dist-info/RECORD +54 -0
- codecin-5.4.2.dist-info/WHEEL +5 -0
- codecin-5.4.2.dist-info/entry_points.txt +2 -0
- codecin-5.4.2.dist-info/licenses/LICENSE +7 -0
- codecin-5.4.2.dist-info/top_level.txt +1 -0
codecin/crom.py
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"""CROM 内存镜像 (v3: zlib 压缩 + CRC32 校验) 与 CPUSA 二进制程序格式。
|
|
2
|
+
|
|
3
|
+
优先调用 Go 原生库 (codecin.native) 进行压缩/解压, 无原生库时回退到 zlib。
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import struct
|
|
7
|
+
import zlib
|
|
8
|
+
from typing import TYPE_CHECKING, Optional
|
|
9
|
+
|
|
10
|
+
from .errors import CPUSimulatorError
|
|
11
|
+
from .isa import Constants
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from .cpu import CPU
|
|
15
|
+
from .logger import Logger
|
|
16
|
+
from .memory import FastMemory
|
|
17
|
+
|
|
18
|
+
CROM_HEADER_SIZE = 16
|
|
19
|
+
# flags bit0: zlib 压缩; bit1: 尾部携带 MMU 页表元数据 (此时校验和覆盖 payload+尾部)
|
|
20
|
+
CROM_FLAG_COMPRESS = 0x01
|
|
21
|
+
CROM_FLAG_MMU = 0x02
|
|
22
|
+
# 解压/载荷允许超出头部 mem_size 的最大余量 (MMU 页表尾部元数据用)
|
|
23
|
+
CROM_MAX_TRAILER = 4 << 20
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _mmu_trailer(mmu) -> bytes:
|
|
27
|
+
"""序列化 MMU 状态: identity(1B) | entries | blacklist (小端)。"""
|
|
28
|
+
parts = [struct.pack('<B', 1 if mmu._identity else 0)]
|
|
29
|
+
entries = sorted(mmu.pages.items())
|
|
30
|
+
parts.append(struct.pack('<I', len(entries)))
|
|
31
|
+
for vpn, (ppn, perms) in entries:
|
|
32
|
+
parts.append(struct.pack('<II3s', vpn, ppn,
|
|
33
|
+
perms.encode('ascii')[:3].ljust(3, b'\x00')))
|
|
34
|
+
black = sorted(mmu._blacklist)
|
|
35
|
+
parts.append(struct.pack('<I', len(black)))
|
|
36
|
+
for vpn in black:
|
|
37
|
+
parts.append(struct.pack('<I', vpn))
|
|
38
|
+
return b''.join(parts)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _restore_mmu_trailer(mmu, data: bytes) -> None:
|
|
42
|
+
pos = 0
|
|
43
|
+
identity = data[pos]
|
|
44
|
+
pos += 1
|
|
45
|
+
mmu._identity = bool(identity)
|
|
46
|
+
n = struct.unpack_from('<I', data, pos)[0]
|
|
47
|
+
pos += 4
|
|
48
|
+
for _ in range(n):
|
|
49
|
+
vpn, ppn = struct.unpack_from('<II', data, pos)
|
|
50
|
+
perms = data[pos + 8:pos + 11].split(b'\x00', 1)[0].decode('ascii')
|
|
51
|
+
pos += 11
|
|
52
|
+
mmu.map(vpn, ppn, perms or 'rwx')
|
|
53
|
+
nb = struct.unpack_from('<I', data, pos)[0]
|
|
54
|
+
pos += 4
|
|
55
|
+
for _ in range(nb):
|
|
56
|
+
vpn = struct.unpack_from('<I', data, pos)[0]
|
|
57
|
+
pos += 4
|
|
58
|
+
mmu.unmap(vpn << 12)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def save_crom(memory: 'FastMemory', path: str, compress: bool = True,
|
|
62
|
+
logger: Optional['Logger'] = None) -> None:
|
|
63
|
+
mem_data = bytes(memory.get_snapshot())
|
|
64
|
+
trailer = _mmu_trailer(memory.mmu) if memory.mmu is not None else b''
|
|
65
|
+
has_mmu = bool(trailer)
|
|
66
|
+
mmu_flag = CROM_FLAG_MMU if has_mmu else 0x00
|
|
67
|
+
|
|
68
|
+
packed = None
|
|
69
|
+
if not has_mmu:
|
|
70
|
+
# MMU 尾部元数据由 Python 端排版; 含 MMU 时跳过 Go 打包保证格式一致
|
|
71
|
+
try:
|
|
72
|
+
from . import native
|
|
73
|
+
engine = native.get_engine(logger)
|
|
74
|
+
if engine is not None:
|
|
75
|
+
packed = engine.crom_pack(mem_data + trailer, compress)
|
|
76
|
+
except Exception:
|
|
77
|
+
packed = None
|
|
78
|
+
|
|
79
|
+
if packed is None:
|
|
80
|
+
flags = (CROM_FLAG_COMPRESS if compress else 0x00) | mmu_flag
|
|
81
|
+
payload = mem_data + trailer
|
|
82
|
+
body = zlib.compress(payload, level=6) if compress else payload
|
|
83
|
+
checksum = zlib.crc32(body) & 0xFFFFFFFF
|
|
84
|
+
header = (Constants.CROM_MAGIC
|
|
85
|
+
+ struct.pack('<B', Constants.CROM_VERSION)
|
|
86
|
+
+ struct.pack('<I', len(mem_data))
|
|
87
|
+
+ struct.pack('<B', flags)
|
|
88
|
+
+ struct.pack('<I', checksum)
|
|
89
|
+
+ b'\x00\x00')
|
|
90
|
+
packed = header + body
|
|
91
|
+
|
|
92
|
+
with open(path, 'wb') as f:
|
|
93
|
+
f.write(packed)
|
|
94
|
+
if logger:
|
|
95
|
+
logger.info(f".crom saved to {path} ({len(packed)} bytes, "
|
|
96
|
+
f"compressed={compress}, mmu={has_mmu})")
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def load_crom(memory: 'FastMemory', path: str,
|
|
100
|
+
logger: Optional['Logger'] = None,
|
|
101
|
+
enable_mmu: bool = False) -> None:
|
|
102
|
+
with open(path, 'rb') as f:
|
|
103
|
+
data = f.read()
|
|
104
|
+
|
|
105
|
+
if len(data) < 8:
|
|
106
|
+
raise CPUSimulatorError(f".crom file too short: {len(data)} bytes")
|
|
107
|
+
|
|
108
|
+
if data[:4] != Constants.CROM_MAGIC:
|
|
109
|
+
# 旧版裸格式: 前 4 字节为 mem_size。
|
|
110
|
+
# 要求声明长度与文件实际内容一致, 否则任意文件 (例如 "NOTACROMFILE")
|
|
111
|
+
# 都会被静默当成内存镜像载入。
|
|
112
|
+
mem_size = struct.unpack('<I', data[:4])[0]
|
|
113
|
+
if mem_size > len(data) - 4:
|
|
114
|
+
raise CPUSimulatorError(
|
|
115
|
+
f"Not a .crom file: 声明的 mem_size={mem_size} "
|
|
116
|
+
f"超过文件实际内容 ({len(data) - 4} bytes)")
|
|
117
|
+
memory.load_bytes(0, data[4:4 + mem_size])
|
|
118
|
+
if logger:
|
|
119
|
+
logger.info(f"Loaded legacy .crom: {min(mem_size, len(data) - 4)} bytes")
|
|
120
|
+
return
|
|
121
|
+
|
|
122
|
+
version = data[4]
|
|
123
|
+
if version != Constants.CROM_VERSION:
|
|
124
|
+
raise CPUSimulatorError(f"Unsupported .crom version: {version}")
|
|
125
|
+
if len(data) < CROM_HEADER_SIZE:
|
|
126
|
+
raise CPUSimulatorError(".crom header incomplete")
|
|
127
|
+
|
|
128
|
+
mem_size = struct.unpack('<I', data[5:9])[0]
|
|
129
|
+
flags = data[9]
|
|
130
|
+
compressed = bool(flags & CROM_FLAG_COMPRESS)
|
|
131
|
+
has_mmu = bool(flags & CROM_FLAG_MMU)
|
|
132
|
+
checksum = struct.unpack('<I', data[10:14])[0]
|
|
133
|
+
body = data[CROM_HEADER_SIZE:]
|
|
134
|
+
|
|
135
|
+
if zlib.crc32(body) & 0xFFFFFFFF != checksum:
|
|
136
|
+
raise CPUSimulatorError(".crom checksum mismatch (file corrupted?)")
|
|
137
|
+
|
|
138
|
+
if compressed:
|
|
139
|
+
# 解压上限 = 头部 mem_size + MMU trailer 余量: 防止 zip bomb
|
|
140
|
+
# (旧实现 zlib.decompress 无上限, 65KB 文件可解出数百 MB)。
|
|
141
|
+
limit = mem_size + CROM_MAX_TRAILER
|
|
142
|
+
try:
|
|
143
|
+
d = zlib.decompressobj()
|
|
144
|
+
raw = d.decompress(body, limit)
|
|
145
|
+
if d.unconsumed_tail:
|
|
146
|
+
raise CPUSimulatorError(
|
|
147
|
+
f".crom 解压超过头部声明的大小 ({limit} bytes): 疑似损坏或恶意文件")
|
|
148
|
+
raw += d.flush()
|
|
149
|
+
except zlib.error as e:
|
|
150
|
+
raise CPUSimulatorError(
|
|
151
|
+
f"Failed to decompress .crom: {e}") from e
|
|
152
|
+
if len(raw) > limit:
|
|
153
|
+
raise CPUSimulatorError(
|
|
154
|
+
f".crom 解压超过头部声明的大小 ({limit} bytes)")
|
|
155
|
+
else:
|
|
156
|
+
raw = body
|
|
157
|
+
if len(raw) > mem_size + CROM_MAX_TRAILER:
|
|
158
|
+
raise CPUSimulatorError(
|
|
159
|
+
f".crom 载荷超过头部声明的大小 ({mem_size} bytes)")
|
|
160
|
+
|
|
161
|
+
memory.load_bytes(0, raw[:min(mem_size, len(raw))])
|
|
162
|
+
if has_mmu and enable_mmu:
|
|
163
|
+
from .memory import Mmu
|
|
164
|
+
mmu = Mmu(max(mem_size, len(memory)))
|
|
165
|
+
_restore_mmu_trailer(mmu, raw[mem_size:])
|
|
166
|
+
memory.attach_mmu(mmu)
|
|
167
|
+
elif has_mmu:
|
|
168
|
+
# 文件带 MMU 元数据但调用方未启用: 忽略之, 仍加载物理内容
|
|
169
|
+
if logger:
|
|
170
|
+
logger.info(".crom 含 MMU 页表但未启用 (enable_mmu=False), 跳过")
|
|
171
|
+
if logger:
|
|
172
|
+
logger.info(f"Loaded .crom v3: {min(mem_size, len(raw))} bytes, "
|
|
173
|
+
f"compressed={compressed}, mmu={has_mmu and enable_mmu}")
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
# ==================== CPUSA 二进制程序 ====================
|
|
177
|
+
|
|
178
|
+
def save_bin(cpu: 'CPU', path: str, logger: Optional['Logger'] = None) -> None:
|
|
179
|
+
from .native import encode_program
|
|
180
|
+
all_labels = dict(cpu.labels)
|
|
181
|
+
all_labels.update(cpu.data_labels)
|
|
182
|
+
bytecode = encode_program(cpu.instructions, cpu.entry_pc, all_labels)
|
|
183
|
+
mem_image = bytes(cpu.memory.get_snapshot())
|
|
184
|
+
|
|
185
|
+
with open(path, 'wb') as f:
|
|
186
|
+
f.write(Constants.MAGIC_NUMBER) # 5B
|
|
187
|
+
f.write(struct.pack('<B', Constants.BIN_VERSION)) # 1B
|
|
188
|
+
f.write(struct.pack('<I', len(mem_image))) # 4B
|
|
189
|
+
f.write(struct.pack('<I', cpu.entry_pc)) # 4B
|
|
190
|
+
f.write(struct.pack('<Q', cpu.sp)) # 8B
|
|
191
|
+
f.write(struct.pack('<I', len(bytecode))) # 4B
|
|
192
|
+
f.write(b'\x00' * 8) # 保留
|
|
193
|
+
f.write(mem_image)
|
|
194
|
+
f.write(bytecode)
|
|
195
|
+
if logger:
|
|
196
|
+
logger.info(f"Binary saved to {path} ({len(bytecode)} bytecode bytes)")
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def load_bin(cpu: 'CPU', path: str) -> None:
|
|
200
|
+
from .native import decode_program
|
|
201
|
+
with open(path, 'rb') as f:
|
|
202
|
+
magic = f.read(5)
|
|
203
|
+
if magic != Constants.MAGIC_NUMBER:
|
|
204
|
+
raise CPUSimulatorError("Invalid binary file (bad magic)")
|
|
205
|
+
version = struct.unpack('<B', f.read(1))[0]
|
|
206
|
+
if version != Constants.BIN_VERSION:
|
|
207
|
+
raise CPUSimulatorError(f"Unsupported binary version: {version}")
|
|
208
|
+
mem_size = struct.unpack('<I', f.read(4))[0]
|
|
209
|
+
entry = struct.unpack('<I', f.read(4))[0]
|
|
210
|
+
sp = struct.unpack('<Q', f.read(8))[0]
|
|
211
|
+
bc_len = struct.unpack('<I', f.read(4))[0]
|
|
212
|
+
f.read(8)
|
|
213
|
+
mem_image = f.read(mem_size)
|
|
214
|
+
bytecode = f.read(bc_len)
|
|
215
|
+
|
|
216
|
+
if len(mem_image) > len(cpu.memory):
|
|
217
|
+
cpu.memory.resize(len(mem_image))
|
|
218
|
+
cpu.config.mem_size = len(mem_image)
|
|
219
|
+
cpu.memory.load_bytes(0, mem_image)
|
|
220
|
+
cpu.instructions, cpu.entry_pc = decode_program(bytecode)
|
|
221
|
+
cpu.pc = entry
|
|
222
|
+
cpu.sp = sp
|