feat: BitScrambler: Add support for addcti instruction as found in ESP32-C5

This commit is contained in:
Jeroen Domburg
2025-02-12 16:34:14 +08:00
parent 68b79fc138
commit 3aaaa2203a
12 changed files with 169 additions and 21 deletions

View File

@@ -3,6 +3,7 @@
# SPDX-License-Identifier: Apache-2.0
import argparse
import copy
import json
import math
import re
import struct
@@ -66,6 +67,12 @@ class Inst(TypedDict, total=False):
read: int
class Chipcfg(TypedDict, total=False):
chipname: str
extra_instruction_groups: List[str]
support_all: bool
# Parser.
# A bsasm file consists of labels, instruction bundles, meta-instructions
# and comments. Comments start at a # and run to a newline and will be
@@ -104,6 +111,7 @@ class Inst(TypedDict, total=False):
# soul tasked with fixing up this code, feel free to create an issue to
# rewrite this and assign it to me - Jeroen)
def bsasm_parse(src: str) -> List[Element]:
# Small hack: we trigger processing things on a newline. If a file is read without
# a newline at the end of the last instruction, we'd erroneously ignore the last element.
@@ -548,6 +556,18 @@ OP_IF = 0x0010000
OP_IFN = 0x0020000
OP_LDCTD = 0x0030000
OP_LDCTI = 0x0040000
OP_ADDCTI = 0x0050000
def check_chip_supports_inst(chipcfg: Chipcfg, instgroup: str, ele: Element) -> None:
if 'support_all' in chipcfg and chipcfg['support_all']:
return
if instgroup not in chipcfg['extra_instruction_groups']:
name = chipcfg['chipname']
raise bsasm_syntax_error(
ele, f'Chip {name} does not support this instruction'
)
def add_op_to_inst(inst: Inst, op: Opcode, ele: Element) -> None:
@@ -561,7 +581,7 @@ def add_op_to_inst(inst: Inst, op: Opcode, ele: Element) -> None:
# Takes the elements generated by the parse routine and converts it to a
# representation of the bits in the Bitscrambler program.
def bsasm_assemble(elements: List[Element]) -> Tuple[List[Inst], Dict[str, int], List[int]]:
def bsasm_assemble(elements: List[Element], chipcfg: Chipcfg) -> Tuple[List[Inst], Dict[str, int], List[int]]:
# This assembler uses two passes: the first finds and resolves global
# stuff, the second one encodes the actual instructions.
@@ -739,6 +759,19 @@ def bsasm_assemble(elements: List[Element]) -> Tuple[List[Inst], Dict[str, int],
op['h'] = 1 if words[0][6] == 'h' else 0
op['l'] = 1 if words[0][6] == 'l' else 0
add_op_to_inst(inst, op, ele)
elif re.match('addcti[ab]([hl])?$', words[0]):
# ADDCTIc[h|l]
check_chip_supports_inst(chipcfg, 'addcti', ele)
check_arg_ct(ele, words, 1)
op = {'op': OP_ADDCTI}
op['c'] = 1 if words[0][6] == 'b' else 0
if len(words[0]) == 7:
op['h'] = 1
op['l'] = 1
else:
op['h'] = 1 if words[0][7] == 'h' else 0
op['l'] = 1 if words[0][7] == 'l' else 0
add_op_to_inst(inst, op, ele)
elif re.match('jmp', words[0]):
# JMP tgt. Pseudo-op, translates to 'IF h tgt'
check_arg_ct(ele, words, 2)
@@ -955,15 +988,24 @@ if __name__ == '__main__':
description='BitScrambler program assembler')
parser.add_argument('infile', help='File name of assembly source to be assembled into a binary')
parser.add_argument('outfile', help='File name of output binary', nargs='?', default=argparse.SUPPRESS)
parser.add_argument('-c', help='Set chip capabilities json file; if set, returns an error when \
an unsupported instruction is assembled', default=argparse.SUPPRESS)
args = parser.parse_args()
chipcfg = Chipcfg()
if 'c' in args:
with open(args.c) as chipcfg_json:
chipcfg = json.load(chipcfg_json)
else:
chipcfg = {'chipname': 'chip', 'extra_instruction_groups': [], 'support_all': True}
if 'outfile' in args:
outfile = args.outfile
else:
outfile = re.sub('.bsasm', '', args.infile) + '.bsbin'
asm = read_file(args.infile)
tokens = bsasm_parse(asm)
insts, meta, lut = bsasm_assemble(tokens)
insts, meta, lut = bsasm_assemble(tokens, chipcfg)
out_data = insts_to_binary(insts, meta, lut)
write_file(outfile, out_data)
print(f'Written {len(insts)} instructions and {len(lut)} 32-bit words of LUT.')