128 lines
3.2 KiB
Python
128 lines
3.2 KiB
Python
import csv
|
|
import sys
|
|
from dataclasses import dataclass
|
|
from generate import renderer
|
|
import re
|
|
|
|
@dataclass
|
|
class RegisterBitDef:
|
|
name: str
|
|
bits: tuple[int, int]
|
|
bit_prefix: str
|
|
bit_name: str
|
|
enum_name: str
|
|
enum_value: str
|
|
description: str
|
|
|
|
def parse_bit(s):
|
|
if ':' in s:
|
|
a, b = s.split(':')
|
|
return int(a, 10), int(b, 10)
|
|
else:
|
|
return int(s, 10), int(s, 10)
|
|
|
|
last_def = None
|
|
|
|
def parse_value(s):
|
|
if not s:
|
|
return None
|
|
elif s.startswith("0x"):
|
|
return int(s.removeprefix("0x"), 16)
|
|
else:
|
|
return int(s.removeprefix("0x"), 10)
|
|
|
|
def parse_csv_row(row):
|
|
global last_def
|
|
name, bits, bit_prefix, bit_name, enum_name, enum_value, description = row
|
|
if not name:
|
|
assert last_def is not None
|
|
assert not bits
|
|
assert not bit_prefix
|
|
assert not bit_name
|
|
assert enum_name
|
|
assert enum_value != ''
|
|
assert not description
|
|
|
|
assert last_def.enum_name
|
|
assert last_def.enum_value is not None
|
|
|
|
name = last_def.name
|
|
bits = last_def.bits
|
|
bit_prefix = last_def.bit_prefix
|
|
bit_name = last_def.bit_name
|
|
description = last_def.description
|
|
else:
|
|
bits = parse_bit(bits)
|
|
|
|
assert name, name
|
|
assert bit_name, bit_name
|
|
if enum_name:
|
|
assert enum_value, (enum_name, enum_value)
|
|
assert description, description
|
|
|
|
bit_def = RegisterBitDef(
|
|
name,
|
|
bits,
|
|
bit_prefix or None,
|
|
bit_name,
|
|
enum_name or None,
|
|
parse_value(enum_value),
|
|
description
|
|
)
|
|
last_def = bit_def
|
|
return bit_def
|
|
|
|
def filter_row(row):
|
|
if row == ['', '', '', '', '', '', '']:
|
|
return False
|
|
name, bits, bit_prefix, bit_name, enum_name, enum_value, description = row
|
|
return description != 'reserved' and (bit_name or enum_name)
|
|
|
|
def bit_mask(d):
|
|
high, low = d.bits
|
|
return (1 << ((high - low) + 1)) - 1
|
|
|
|
def is_function_bit(d):
|
|
infer_by_name = re.match("^.*_[0-9]$", d.bit_name) and "gpio_" not in d.bit_name.lower()
|
|
return bit_mask(d) != 1 or infer_by_name
|
|
|
|
def format_value(d):
|
|
if d.enum_name is not None:
|
|
assert d.enum_value is not None
|
|
assert d.enum_value <= bit_mask(d)
|
|
return f"({d.enum_value} << {d.bits[1]})"
|
|
elif is_function_bit(d):
|
|
return f"(((n) & {hex(bit_mask(d))}) << {d.bits[1]})"
|
|
else:
|
|
return f"(1 << {d.bits[1]})"
|
|
|
|
def format_macro(d):
|
|
macro = f"{d.name.upper()}"
|
|
if d.bit_prefix is not None:
|
|
macro += f"__{d.bit_prefix.upper()}"
|
|
macro += f"__{d.bit_name.upper()}"
|
|
if d.enum_name is not None:
|
|
macro += f"__{d.enum_name.upper()}"
|
|
elif is_function_bit(d):
|
|
macro += "(n)"
|
|
return macro
|
|
|
|
def format_def(d):
|
|
return f"#define {format_macro(d)} {format_value(d)}"
|
|
|
|
def render_defs(defs):
|
|
last_name = None
|
|
for d in defs:
|
|
if last_name is not None and d.name != last_name:
|
|
yield ""
|
|
yield format_def(d)
|
|
last_name = d.name
|
|
|
|
with open(sys.argv[1], 'r') as f:
|
|
reader = csv.reader(f)
|
|
defs = list(map(parse_csv_row, filter(filter_row, reader)))
|
|
|
|
render, out = renderer()
|
|
render(render_defs(defs))
|
|
sys.stdout.write(out.getvalue())
|