220 lines
6.5 KiB
Python
220 lines
6.5 KiB
Python
import sys
|
|
from collections import defaultdict
|
|
from pprint import pprint
|
|
from dataclasses import dataclass
|
|
from typing import Union
|
|
|
|
from sh7091 import read_input
|
|
from generate import renderer
|
|
|
|
def aggregate_registers(d):
|
|
aggregated = defaultdict(list)
|
|
for row in d:
|
|
assert row["register_name"] != ""
|
|
aggregated[row["register_name"]].append(row)
|
|
return dict(aggregated)
|
|
|
|
def parse_bit_number(s):
|
|
assert '-' not in s
|
|
return int(s, 10)
|
|
|
|
def parse_bit_range(s):
|
|
if '-' in s:
|
|
left, right = map(parse_bit_number, s.split('-', maxsplit=1))
|
|
assert left > right, (left, right)
|
|
return set(range(right, left+1))
|
|
else:
|
|
num = parse_bit_number(s)
|
|
return set([num])
|
|
|
|
def aggregate_enums(aggregated_rows):
|
|
non_enum = []
|
|
enum_aggregated = defaultdict(list)
|
|
all_bits = set()
|
|
enum_bits = dict()
|
|
|
|
def assert_unique_ordered(bits):
|
|
nonlocal all_bits
|
|
assert all(bit not in all_bits for bit in bits), bits
|
|
assert max(all_bits, default=32) > max(bits)
|
|
all_bits |= bits
|
|
|
|
for row in aggregated_rows:
|
|
bits = parse_bit_range(row["bits"])
|
|
assert row["bit_name"] != ""
|
|
if row["enum_name"] == "":
|
|
assert_unique_ordered(bits)
|
|
non_enum.append(row)
|
|
else:
|
|
if row["enum_name"] not in enum_bits:
|
|
assert_unique_ordered(bits)
|
|
non_enum.append(row["enum_name"])
|
|
else:
|
|
assert enum_bits[row["enum_name"]] == bits
|
|
|
|
enum_bits[row["enum_name"]] = bits
|
|
enum_aggregated[row["enum_name"]].append(row)
|
|
|
|
return non_enum, dict(enum_aggregated)
|
|
|
|
@dataclass
|
|
class enum:
|
|
name: str
|
|
defs: list[dict]
|
|
|
|
@dataclass
|
|
class register:
|
|
name: str
|
|
defs: list[Union[dict, enum]]
|
|
|
|
def aggregate_all_enums(aggregated):
|
|
out = []
|
|
for register_name, rows in aggregated.items():
|
|
non_enum, enum_aggregated = aggregate_enums(rows)
|
|
def resolve(row_or_string):
|
|
if type(row_or_string) == str:
|
|
return enum(row_or_string,
|
|
enum_aggregated[row_or_string])
|
|
elif type(row_or_string) == dict:
|
|
return row_or_string
|
|
else:
|
|
assert False, (row_or_string, type(row_or_string))
|
|
out.append(
|
|
register(register_name,
|
|
[resolve(aggregate) for aggregate in non_enum]))
|
|
return out
|
|
|
|
'''
|
|
register(name='SCALER_CTL',
|
|
defs=[enum(name='field_select',
|
|
defs=[{'bit_name': 'field_1',
|
|
'bits': '18',
|
|
'description': '',
|
|
'enum_name': 'field_select',
|
|
'mask': '',
|
|
'register_name': 'SCALER_CTL',
|
|
'value': '0'},
|
|
{...}]),
|
|
{'bit_name': 'interlace',
|
|
'bits': '17',
|
|
'description': '',
|
|
'enum_name': '',
|
|
'mask': '',
|
|
'register_name': 'SCALER_CTL',
|
|
'value': '1'},
|
|
{...},
|
|
...]),
|
|
'''
|
|
|
|
def mask_from_bits(bits):
|
|
mask = 2 ** len(bits) - 1
|
|
return mask
|
|
|
|
def parse_value(value):
|
|
return eval(value)
|
|
|
|
def render_read_only(bit_def):
|
|
assert bit_def["value"] == ""
|
|
assert bit_def["mask"] == ""
|
|
bits = parse_bit_range(bit_def["bits"])
|
|
mask_value = mask_from_bits(bits)
|
|
yield (
|
|
f"constexpr uint32_t {bit_def['bit_name']}(uint32_t reg) {{ "
|
|
f"return (reg >> {min(bits)}) & {hex(mask_value)};"
|
|
" }"
|
|
)
|
|
|
|
def render_float_mask(mask):
|
|
if mask == "float_0_8_23":
|
|
return "_i(__builtin_fabsf(num));"
|
|
elif mask == "float_1_8_23":
|
|
return "_i(num)"
|
|
else:
|
|
assert mask.startswith("float_")
|
|
mask = mask.removeprefix("float_")
|
|
sign, exponent, fraction = map(int, mask.split('_'))
|
|
assert exponent == 8, exponent
|
|
assert sign == 1
|
|
bit_length = (sign + exponent + fraction)
|
|
mask = (2 ** bit_length - 1) << (32 - bit_length)
|
|
return f"_i(num) & {hex(mask)}"
|
|
|
|
def render_mask(bit_def):
|
|
assert bit_def["value"] == ""
|
|
mask = bit_def["mask"]
|
|
bits = parse_bit_range(bit_def["bits"])
|
|
if mask.startswith("float_"):
|
|
yield (
|
|
f"constexpr uint32_t {bit_def['bit_name']}(float num) {{ "
|
|
f"return {render_float_mask(mask)};"
|
|
" }"
|
|
)
|
|
else:
|
|
assert mask.startswith("0x") or mask.startswith("0b") or mask[0] in set(range(0, 9+1)), mask
|
|
mask_value = eval(mask)
|
|
assert mask_value & mask_from_bits(bits) == mask_value, (mask_value, mask_from_bits(bits))
|
|
|
|
yield (
|
|
f"constexpr uint32_t {bit_def['bit_name']}(uint32_t num) {{ "
|
|
f"return (num & {hex(mask_value)}) << {min(bits)};"
|
|
" }"
|
|
)
|
|
|
|
def render_value(bit_def):
|
|
assert bit_def["mask"] == ""
|
|
bits = parse_bit_range(bit_def["bits"])
|
|
assert parse_value(bit_def["value"]) <= mask_from_bits(bits), bit_def["value"]
|
|
bit_ix = min(bits)
|
|
yield f"constexpr uint32_t {bit_def['bit_name']} = {bit_def['value']} << {bit_ix};"
|
|
|
|
def render_defs(bit_def):
|
|
if bit_def["value"] != "":
|
|
yield from render_value(bit_def)
|
|
elif bit_def["mask"] != "":
|
|
yield from render_mask(bit_def)
|
|
else:
|
|
yield from render_read_only(bit_def)
|
|
|
|
def render_enum(enum_def):
|
|
yield f"namespace {enum_def.name.lower()} {{"
|
|
for bit_def in enum_def.defs:
|
|
yield from render_defs(bit_def)
|
|
yield "}"
|
|
|
|
def render_register(register):
|
|
yield f"namespace {register.name.lower()} {{"
|
|
|
|
last = None
|
|
for ix, bit_def in enumerate(register.defs):
|
|
if type(bit_def) is enum:
|
|
if ix != 0:
|
|
yield ""
|
|
yield from render_enum(bit_def)
|
|
else:
|
|
if ix != 0 and type(last) is enum:
|
|
yield ""
|
|
yield from render_defs(bit_def)
|
|
last = bit_def
|
|
|
|
yield "}"
|
|
yield ""
|
|
|
|
def render_registers(registers):
|
|
for register in registers:
|
|
yield from render_register(register)
|
|
|
|
def header():
|
|
yield "#include <cstdint>"
|
|
yield ""
|
|
yield '#include "../float_uint32.h"'
|
|
yield ""
|
|
|
|
if __name__ == "__main__":
|
|
d = read_input(sys.argv[1])
|
|
aggregated = aggregate_registers(d)
|
|
registers = aggregate_all_enums(aggregated)
|
|
render, out = renderer()
|
|
render(header())
|
|
render(render_registers(registers))
|
|
sys.stdout.write(out.getvalue())
|