init (v0.1.0a4)
This commit is contained in:
commit
48e39bc2bd
11 changed files with 495 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
/dist
|
||||
*.egg-info/
|
||||
__pycache__/
|
9
CHANGELOG.md
Normal file
9
CHANGELOG.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# supGecko
|
||||
## 0.1.0a4
|
||||
- Added `compile_flags` property to `Gecko` class
|
||||
## 0.1.0a3
|
||||
- Added C/ASM compilation support for C0, C2, c\_kit
|
||||
## 0.1.0a2
|
||||
- Added `indent` parameter for `Gecko#dump_txt()`
|
||||
## 0.1.0a1
|
||||
- Initialized
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2023 sup39
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
16
README.md
Normal file
16
README.md
Normal file
|
@ -0,0 +1,16 @@
|
|||
# supGecko
|
||||
A helper library to write Gecko code
|
||||
|
||||
## Installation
|
||||
```
|
||||
pip install supGecko
|
||||
```
|
||||
|
||||
## Usage
|
||||
```python
|
||||
from supGecko import Gecko
|
||||
|
||||
g = Gecko()
|
||||
# TODO: usage of the Gecko class
|
||||
print(g.dump_txt())
|
||||
```
|
3
pyproject.toml
Normal file
3
pyproject.toml
Normal file
|
@ -0,0 +1,3 @@
|
|||
[build-system]
|
||||
requires = ["setuptools>=42"]
|
||||
build-backend = "setuptools.build_meta"
|
23
setup.cfg
Normal file
23
setup.cfg
Normal file
|
@ -0,0 +1,23 @@
|
|||
[metadata]
|
||||
name = supGecko
|
||||
version = 0.1.0a4
|
||||
author = sup39
|
||||
author_email = sms@sup39.dev
|
||||
description = A helper library to write Gecko code
|
||||
long_description = file: README.md
|
||||
long_description_content_type = text/markdown
|
||||
url = https://github.com/sup39/supGecko
|
||||
license = MIT
|
||||
project_urls =
|
||||
Bug Tracker = https://github.com/sup39/supGecko/issues
|
||||
classifiers =
|
||||
Programming Language :: Python :: 3
|
||||
License :: OSI Approved :: MIT License
|
||||
|
||||
[options]
|
||||
include_package_data = True
|
||||
packages = find:
|
||||
python_requires = >=3.8
|
||||
|
||||
[options.packages.find]
|
||||
where = src
|
4
src/supGecko/__init__.py
Normal file
4
src/supGecko/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
# Copyright (c) 2023 sup39
|
||||
|
||||
from .gecko import Gecko
|
108
src/supGecko/asm.py
Normal file
108
src/supGecko/asm.py
Normal file
|
@ -0,0 +1,108 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
# Copyright (c) 2023 sup39
|
||||
|
||||
import shutil
|
||||
from distutils import spawn
|
||||
import tempfile
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
def system(argv, *args, **kwargs):
|
||||
r = subprocess.run(argv, *args, capture_output=True, text=True, **kwargs)
|
||||
if r.returncode:
|
||||
raise Exception(f'Fail to run {argv[0]} (code={r.returncode}): {r.stderr}')
|
||||
return r.stdout
|
||||
|
||||
def write_extra_input(x, file):
|
||||
if type(x) == str:
|
||||
print(x, file=file)
|
||||
else:
|
||||
for line in x:
|
||||
print(line, file=file)
|
||||
|
||||
def compile(
|
||||
input_path, addr=None,
|
||||
extra_c_flags=[],
|
||||
extra_as_input=[], extra_as_flags=[],
|
||||
extra_ld_input=[], extra_ld_flags=[],
|
||||
):
|
||||
distDir = tempfile.mkdtemp()
|
||||
distASM, distOBJ, distLD, distLOBJ, distBIN = (f'{distDir}/_.{ext}' for ext in ['s', 'o', 'ld', 'l.o', 'bin'])
|
||||
|
||||
try:
|
||||
input_name = input_path.rsplit('.', 1)[0]
|
||||
|
||||
if input_path.endswith('.c'):
|
||||
# compile to OBJ
|
||||
system([
|
||||
'powerpc-eabi-gcc',
|
||||
'-fno-asynchronous-unwind-tables',
|
||||
','.join((
|
||||
'-Wa', '-mregnames', '-mgekko',
|
||||
*extra_as_flags,
|
||||
)),
|
||||
'-c', '-o', distOBJ,
|
||||
*extra_c_flags,
|
||||
input_path,
|
||||
])
|
||||
else: # treat as ASM file
|
||||
# make ASM file
|
||||
with open(distASM, 'w') as fw, open(input_path, 'r') as fr:
|
||||
write_extra_input(extra_as_input, file=fw)
|
||||
for line in fr: fw.write(line)
|
||||
# assemble to OBJ
|
||||
system([
|
||||
'powerpc-eabi-as',
|
||||
'-mregnames', '-mgekko',
|
||||
'-o', distOBJ,
|
||||
*extra_as_flags,
|
||||
distASM,
|
||||
])
|
||||
|
||||
# link
|
||||
with open(distLD, 'w') as fw:
|
||||
inputLD = input_name+'.ld'
|
||||
## extra ld
|
||||
if os.path.isfile(inputLD):
|
||||
with open(inputLD) as f:
|
||||
fw.write(f.read())
|
||||
## section
|
||||
print('SECTIONS {', file=fw)
|
||||
if addr is not None: print(f' . = {addr};', file=fw)
|
||||
print(' .text : ALIGN(4) { *(.text) }', file=fw)
|
||||
if addr is not None: print('.rodata : ALIGN(4) { *(.rodata) }', file=fw)
|
||||
print('}', file=fw)
|
||||
write_extra_input(extra_ld_input, file=fw)
|
||||
system([
|
||||
'powerpc-eabi-ld',
|
||||
'-o', distLOBJ,
|
||||
'-T', distLD,
|
||||
*extra_ld_flags,
|
||||
distOBJ,
|
||||
])
|
||||
|
||||
# gecko symbols
|
||||
symbols = {}
|
||||
lines = system([
|
||||
'powerpc-eabi-objdump',
|
||||
'-tj.text', distLOBJ,
|
||||
]).split('\n')
|
||||
for line in lines[4:-3]:
|
||||
ch1, ch2 = line.split('\t')
|
||||
addr = int(ch1.split(None, 2)[0], 16)
|
||||
name = ch2.split()[1]
|
||||
symbols[name] = addr
|
||||
|
||||
# binary
|
||||
system([
|
||||
'powerpc-eabi-objcopy',
|
||||
'-O', 'binary',
|
||||
distLOBJ, distBIN,
|
||||
])
|
||||
with open(distBIN, 'rb') as f:
|
||||
codeBin = f.read()
|
||||
|
||||
return codeBin, symbols
|
||||
|
||||
finally:
|
||||
shutil.rmtree(distDir)
|
22
src/supGecko/consts.py
Normal file
22
src/supGecko/consts.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
# Copyright (c) 2023 sup39
|
||||
|
||||
CMP_IDX = {'==': 0, '!=': 2, '>': 4, '<': 6}
|
||||
UNIT_IDX = {
|
||||
8: 0, 'b': 0, 'byte': 0,
|
||||
16: 1, 'h': 1, 'halfword': 1,
|
||||
32: 2, 'w': 2, 'word': 2,
|
||||
}
|
||||
REGOP_IDX = {
|
||||
'add': 0, '+': 0,
|
||||
'mul': 1, '*': 1,
|
||||
'or' : 2, '|': 2,
|
||||
'and': 3, '&': 3,
|
||||
'xor': 4, '^': 4,
|
||||
'slw': 5, '<<': 5,
|
||||
'srw': 6, '>>': 6,
|
||||
'rol': 7,
|
||||
'asr': 8,
|
||||
'fadds': 9,
|
||||
'fmuls': 10,
|
||||
}
|
248
src/supGecko/gecko.py
Normal file
248
src/supGecko/gecko.py
Normal file
|
@ -0,0 +1,248 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
# Copyright (c) 2023 sup39
|
||||
|
||||
from .asm import compile
|
||||
from .utils import *
|
||||
from .consts import *
|
||||
|
||||
# TODO: assert range of arg
|
||||
class Gecko():
|
||||
def __init__(self, compile_flags={}):
|
||||
self.code = bytearray()
|
||||
self.compile_flags = compile_flags
|
||||
def append(self, *payloads):
|
||||
self.code += b''.join(map(parse_binarg, payloads))
|
||||
return self
|
||||
def dump_txt(self, indent=''):
|
||||
if type(indent) == int: indent = ' '*indent
|
||||
return '\n'.join(
|
||||
indent+' '.join(self.code[j:j+4].hex().upper() for j in [i, i+4])
|
||||
for i in range(0, len(self.code), 8)
|
||||
)
|
||||
def compile(self, input_path, addr=None, **kwargs0):
|
||||
kwargs = {'extra_'+k: v for k, v in self.compile_flags.items()}
|
||||
for k, v in kwargs0.items():
|
||||
if type(v) == str: v = [v]
|
||||
kwargs[k] = kwargs[k] + v if k in kwargs else v
|
||||
return compile(input_path, addr, **kwargs)
|
||||
''' 00 '''
|
||||
def write8(self, addr, val, count=1, po=False):
|
||||
return self.append(
|
||||
cw_addr(0x00, addr, po),
|
||||
((count-1)&0xffff) << 16 | val&0xff,
|
||||
)
|
||||
''' 02 '''
|
||||
def write16(self, addr, val, count=1, po=False):
|
||||
return self.append(
|
||||
cw_addr(0x02, addr, po),
|
||||
((count-1)&0xffff) << 16 | val&0xffff,
|
||||
)
|
||||
''' 04 '''
|
||||
def write32(self, addr, val, po=False):
|
||||
return self.append(
|
||||
cw_addr(0x04, addr, po),
|
||||
val & 0xffffffff,
|
||||
)
|
||||
''' 06 '''
|
||||
def write_string(self, addr, payload, po=False):
|
||||
if type(payload) == str: payload = bytes.fromhex(payload)
|
||||
size = len(payload)
|
||||
rsize = size%8
|
||||
if rsize: payload += b'\x00'*(8-rsize)
|
||||
return self.append(cw_addr(0x06, addr, po), size, payload)
|
||||
''' 08 '''
|
||||
def write_addr(self, addr, n, unit, val, addr_step, val_step, po=False):
|
||||
t = UNIT_IDX[unit]
|
||||
return self.append(
|
||||
cw_addr(0x08, addr, po),
|
||||
val,
|
||||
t<<28 | (n&0xfff)<<16 | (addr_step&0xffff),
|
||||
val_step & 0xffffffff,
|
||||
)
|
||||
''' 20-27 '''
|
||||
def if32(self, addr, op, val, po=False, endif=False):
|
||||
ct = 0x20 | CMP_IDX[op]
|
||||
return self.append(
|
||||
cw_addr(ct, addr, po, endif),
|
||||
val & 0xffffffff,
|
||||
)
|
||||
''' 28-2F '''
|
||||
def if16(self, addr, op, val, mask=-1, po=False, endif=False):
|
||||
ct = 0x28 | CMP_IDX[op]
|
||||
return self.append(
|
||||
cw_addr(ct, addr, po, endif),
|
||||
(~mask & 0xffff)<<16 | val & 0xffff,
|
||||
)
|
||||
''' 4_TYZ '''
|
||||
def sl_bapo(self, action, target, op, addr, bapo=None, gr=None):
|
||||
cw = ({'ba': 0x40000, 'po': 0x48000}[target] \
|
||||
| {'load': 0x00000, 'set': 0x02000, 'store': 0x04000} \
|
||||
| {'+=': 0x00100, '=': 0}[op] \
|
||||
| {'ba': 0x00010, 'po': 0x10010, None: 0}[bapo]
|
||||
) << 12
|
||||
if action == 'store':
|
||||
assert op == '=', '`op` should be "=" when storing ba/po'
|
||||
if gr is not None:
|
||||
cw |= 0x1_000 | gr
|
||||
return self.append(cw, addr&0xffffffff)
|
||||
def load_ba(self, *args, **kwargs):
|
||||
return self.sl_bapo('load', 'ba', *args, **kwargs)
|
||||
def set_ba(self, *args, **kwargs):
|
||||
return self.sl_bapo('set', 'ba', *args, **kwargs)
|
||||
def store_ba(self, *args, **kwargs):
|
||||
return self.sl_bapo('store', 'ba', *args, **kwargs)
|
||||
def load_po(self, *args, **kwargs):
|
||||
return self.sl_bapo('load', 'po', *args, **kwargs)
|
||||
def set_po(self, *args, **kwargs):
|
||||
return self.sl_bapo('set', 'po', *args, **kwargs)
|
||||
def store_po(self, *args, **kwargs):
|
||||
return self.sl_bapo('store', 'po', *args, **kwargs)
|
||||
''' 46, 4E '''
|
||||
def store_ncl(self, target, offset):
|
||||
ct = {'ba': 0x46, 'po': 0x4E}[target]
|
||||
return self.append(ct<<24 | offset&0xffff, 0)
|
||||
''' 60 '''
|
||||
def set_repeat(self, n, p):
|
||||
return self.append(0x60<<24 | n&0xffff, p&0xf)
|
||||
''' 62 '''
|
||||
def execute_repeat(self, p):
|
||||
return self.append(0x62<<24, p&0xf)
|
||||
''' 64 '''
|
||||
def return_(self, p, if_=None):
|
||||
return self.append(cw_go(0x64, if_, n=0), p&0xf)
|
||||
''' 66 '''
|
||||
def goto(self, n, p, if_=None):
|
||||
return self.append(cw_go(0x66, if_, n), p&0xf)
|
||||
''' 68 '''
|
||||
def gosub(self, n, p, if_=None):
|
||||
return self.append(cw_go(0x68, if_, n), p&0xf)
|
||||
|
||||
''' 80 '''
|
||||
def set_reg(self, gr, op, addr, bapo=None):
|
||||
c = {'ba': 0x8001, 'po': 0x9001, None: 0x8000}[bapo] \
|
||||
| {'+=': 0x0010, '=': 0}[op]
|
||||
return self.append(c<<16 | gr&0xf, addr&0xffffffff)
|
||||
def load_reg(self, gr, addr, unit=None):
|
||||
c = {'ba': 0x8201, 'po': 0x9201, None: 0x8200}[bapo]
|
||||
u = UNIT_IDX[unit]
|
||||
return self.append(c<<16 | u<<20 | gr&0xf, addr&0xffffffff)
|
||||
def store_reg(self, gr, addr, unit=None, count=1):
|
||||
c = {'ba': 0x8401, 'po': 0x9401, None: 0x8400}[bapo]
|
||||
t = UNIT_IDX[unit]
|
||||
y = (count - 1) & 0xfff
|
||||
return self.append(
|
||||
c<<16 | t<<20 | y<<4 | gr&0xf,
|
||||
addr & 0xffffffff,
|
||||
)
|
||||
''' 86 '''
|
||||
def reg_op_imm(self, lhs, op, rhs):
|
||||
cw, rhs = parse_regop(0x86, lhs, op, rhs)
|
||||
return self.append(cw, rhs & 0xffffffff)
|
||||
''' 88 '''
|
||||
def reg_op_reg(self, lhs, op, rhs):
|
||||
cw, rhs = parse_regop(0x88, lhs, op, rhs)
|
||||
return self.append(cw, rhs & 0xf)
|
||||
'''
|
||||
[8A] (K, XXXXXXXX) <- N
|
||||
[8C] K <- (N, XXXXXXXX)
|
||||
'''
|
||||
def memcpy(self, dst, src, n):
|
||||
if type(src) == int:
|
||||
assert type(dst)==tuple and len(dst)==2, \
|
||||
'`dst` should be in form of "(K, XXXXXXXX)"'
|
||||
N = src&0xf
|
||||
K, off = dst
|
||||
ct, K = parse_regidx(0x8A, K)
|
||||
else:
|
||||
assert type(dst) == int, \
|
||||
'`dst` and `src` cannot be tuple at the same time'
|
||||
assert len(src)==2, '`src` should be in form of "(N, XXXXXXXX)"'
|
||||
ct = 0x8C
|
||||
N, off = src
|
||||
K = dst&0xf
|
||||
ct, N = parse_regidx(0x8C, N)
|
||||
return self.append(
|
||||
ct<<24 | (n & 0xffff)<<8 | N<<4 | K,
|
||||
off & 0xffffffff,
|
||||
)
|
||||
''' A0-A7 '''
|
||||
def if16_reg(self, N, op, K, offset=None, mask=-1, endif=False):
|
||||
ct = 0xA0 | CMP_IDX[op]
|
||||
ctK, K = parse_regidx(ct, K)
|
||||
ctN, N = parse_regidx(ct, N)
|
||||
if K==0xf or N==0xf:
|
||||
assert offset is not None, '`offset` should be set if ba/po is used'
|
||||
else:
|
||||
offset = 0
|
||||
assert ctK == ctN, 'ba and po cannot be used at the same time'
|
||||
ct = ctN
|
||||
return self.append(
|
||||
cw_addr(ct, addr, po=False, endif=endif)
|
||||
(K<<28 | N<<24 | ~mask&0xffff),
|
||||
)
|
||||
''' A8-AF '''
|
||||
def if16_cnt(self, cnt, op, val, reset_on_true, mask=-1, endif=False):
|
||||
T = (8 if reset_on_true else 0) + (1 if endif else 0)
|
||||
return self.append(
|
||||
(0xA8 | CMP_IDX[op])<<24 | (cnt&0xffff)<<4 | T,
|
||||
~mask<<16 | val&0xffff,
|
||||
)
|
||||
''' C0 '''
|
||||
def C0(self, input_path=None, raw=None, **kwargs):
|
||||
code = make_asm_code(self.compile, input_path, raw, kwargs)
|
||||
if len(code)%8 == 4: # pad code with blr
|
||||
code += b'\x4E\x80\x00\x20'
|
||||
return self.append(0xC000_0000, len(code)>>3, code)
|
||||
''' C2 '''
|
||||
def C2(self, addr, input_path, raw=None, po=False, **kwargs):
|
||||
code = make_asm_code(self.compile, input_path, raw, kwargs)
|
||||
if len(code)%8 == 0: # pad code with nop
|
||||
code += b'\x60\x00\x00\x00'
|
||||
code += b'\x00\x00\x00\x00' # append 0
|
||||
return self.append(cw_addr(0xC2, addr, po), len(code)>>3, code)
|
||||
''' C6 '''
|
||||
def branch(self, addr, dst, po=False):
|
||||
return self.append(cw_addr(0xC6, addr, po), dst&0xffffffff)
|
||||
''' CC '''
|
||||
def onoff_switch(self):
|
||||
return self.append(0xCC00_0000, 0)
|
||||
''' CE '''
|
||||
def addr_range_check(self, l, u, endif=False):
|
||||
return self.append(
|
||||
cw_addr(0xCE, 0, po, endif),
|
||||
(l&0xffff)<<16 | (u&0xffff),
|
||||
)
|
||||
''' E0 '''
|
||||
def full_terminator(self, ba=0, po=0):
|
||||
return self.append(0xE000_0000, (ba&0xffff)<<16 | (po&0xffff))
|
||||
''' E2 '''
|
||||
def endif(self, count=None, else_=False, ba=0, po=0):
|
||||
if count is None:
|
||||
if else_: count = 1
|
||||
else: return self.full_terminator(ba, po)
|
||||
return self.append(
|
||||
0xE200_0000 | (0x1_000_00 if else_ else 0) | count&0xff,
|
||||
(ba&0xffff)<<16 | (po&0xffff),
|
||||
)
|
||||
''' F0 '''
|
||||
def end_of_code(self):
|
||||
return self.append(0xF000_0000, 0)
|
||||
|
||||
''' C Kit '''
|
||||
def c_kit(self, addr_code, input_path, entries, **kwargs):
|
||||
code, symbols = self.compile(input_path, addr_code, **kwargs)
|
||||
# 06
|
||||
self.write_string(addr_code, code, po=False)
|
||||
# 04/C6
|
||||
for addr_src, action, name in entries:
|
||||
assert name in symbols, f'symbol "{name}" is not found in the .text section of {input_path}'
|
||||
addr_dst = symbols[name]
|
||||
if action == 'b':
|
||||
self.branch(addr_src, addr_dst, po=False)
|
||||
elif action == 'bl':
|
||||
d_addr = addr_dst - addr_src
|
||||
assert -0x200_0000 <= d_addr < 0x200_0000, 'cannot bl from %08X to %08X'%(addr_src, addr_dst)
|
||||
inst = 0x4800_0001 | d_addr&0x3ff_fffc
|
||||
self.write32(addr_src, inst, po=False)
|
||||
else: assert False, '`action` should be "b" or "bl", got "{action}"'
|
||||
return self
|
38
src/supGecko/utils.py
Normal file
38
src/supGecko/utils.py
Normal file
|
@ -0,0 +1,38 @@
|
|||
# SPDX-License-Identifier: MIT
|
||||
# Copyright (c) 2023 sup39
|
||||
|
||||
def cw_addr(ct, addr, po, endif=False):
|
||||
return (ct+0x10 if po else ct)<<24 | (addr+1 if endif else addr)&0x1ff_ffff
|
||||
def cw_go(ct, if_, n):
|
||||
return ct<<24 | [True, False, None].index(if_)<<20 | n&0xffff
|
||||
|
||||
def parse_regop(ct, lhs, op, rhs):
|
||||
if op.endswith('='): op = op[:-1] # drop trailing =
|
||||
lhs, lhs_flag = parse_bracket_operand(lhs, 'lhs')
|
||||
rhs, rhs_flag = parse_bracket_operand(rhs, 'rhs')
|
||||
cw = ct<<24 | REGOP_IDX[op]<<20 | lhs_flag<<16 | rhs_flag<<17 | lhs&0xf
|
||||
return cw, rhs
|
||||
def parse_regidx(ct, x, name):
|
||||
if x == 'ba': x = 0xf
|
||||
elif x == 'po': x = 0xf; ct |= 0x10
|
||||
else: x &= 0xf; assert x!=0xf, f'{name} cannot be F'
|
||||
return ct, x
|
||||
def parse_bracket_operand(x, name): # returns (value, hasBracket)
|
||||
if type(x) == list:
|
||||
assert len(x)==1, f'`{name}` must be "x" or "[x]"'
|
||||
return x, 1
|
||||
return x, 0
|
||||
def parse_binarg(x):
|
||||
return b''.join(map(parse_binarg, x)) if type(x)==list else \
|
||||
bytes.fromhex(x) if type(x)==str else \
|
||||
x.to_bytes(4, 'big') if type(x)==int else x
|
||||
|
||||
def make_asm_code(compile, input_path, raw, kwargs):
|
||||
if raw is not None: # raw code
|
||||
code = parse_binarg(raw)
|
||||
assert len(code)%4 == 0, \
|
||||
f'len(raw) should a multiple of 4, got {len(raw)}'
|
||||
else: # compile from file
|
||||
assert input_path is not None, 'either `input_path` or `raw` should be set'
|
||||
code, symbols = compile(input_path, **kwargs)
|
||||
return code
|
Loading…
Reference in a new issue