373 lines
9.6 KiB
Python
373 lines
9.6 KiB
Python
|
#!/usr/bin/env python3
|
||
|
|
||
|
import argparse
|
||
|
import sys
|
||
|
import re
|
||
|
import os
|
||
|
import csv
|
||
|
|
||
|
KEY_REG_ADDR = "x3"
|
||
|
KEY_REG_VAR = "x4"
|
||
|
KEY_REG_DEFAULT = "x5"
|
||
|
KEY_REG_COMMENT = "x7"
|
||
|
|
||
|
header_block =\
|
||
|
"\
|
||
|
// Copyright 2020-2021 Beken\n\
|
||
|
//\n\
|
||
|
// Licensed under the Apache License, Version 2.0 (the \"License\");\n\
|
||
|
// you may not use this file except in compliance with the License.\n\
|
||
|
// You may obtain a copy of the License at\n\
|
||
|
//\n\
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0\n\
|
||
|
//\n\
|
||
|
// Unless required by applicable law or agreed to in writing, software\n\
|
||
|
// distributed under the License is distributed on an \"AS IS\" BASIS,\n\
|
||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n\
|
||
|
// See the License for the specific language governing permissions and\n\
|
||
|
// limitations under the License.\n\
|
||
|
\n\
|
||
|
#pragma once\n\
|
||
|
\n\
|
||
|
#ifdef __cplusplus\n\
|
||
|
extern \"C\" {\n\
|
||
|
#endif\n\
|
||
|
\n\
|
||
|
"
|
||
|
|
||
|
tailer_block =\
|
||
|
"\n\
|
||
|
#ifdef __cplusplus\n\
|
||
|
}\n\
|
||
|
#endif\n\
|
||
|
"
|
||
|
|
||
|
class DumpGen:
|
||
|
def __init__(self, name=None):
|
||
|
self.name = name
|
||
|
|
||
|
def gen_struct_dump(self):
|
||
|
print('Generate struct dump')
|
||
|
|
||
|
class Bits:
|
||
|
def __init__(self, addr, name=None, start=None, end=None, default_value=None, line=0):
|
||
|
self.addr = addr
|
||
|
self.name = name.lower()
|
||
|
self.start = start
|
||
|
self.end = end
|
||
|
self.default_value = default_value
|
||
|
self.line = line
|
||
|
|
||
|
def set_default_value(self, default_value=0):
|
||
|
self.default_value = default_value
|
||
|
|
||
|
def set_comments(self, comments=None):
|
||
|
self.comments = comments
|
||
|
|
||
|
def dump(self):
|
||
|
print(f'line={self.line}, addr={self.addr}, name={self.name}, start={self.start}, end={self.end}, default={self.default_value}')
|
||
|
|
||
|
class Reg:
|
||
|
def __init__(self):
|
||
|
self.bits_list = []
|
||
|
self.indent = 1
|
||
|
|
||
|
def add_bits(self, bits):
|
||
|
self.bits_list.insert(0, bits)
|
||
|
|
||
|
def gen_reg_code(self):
|
||
|
print(f'Generate reg code')
|
||
|
|
||
|
def is_int(self):
|
||
|
if len(self.bits_list) == 1:
|
||
|
return True
|
||
|
|
||
|
return False
|
||
|
|
||
|
def is_reserved(self):
|
||
|
if len(self.bits_list) == 1:
|
||
|
bits = self.bits_list[0]
|
||
|
if (bits.name == "reserved"):
|
||
|
return True
|
||
|
|
||
|
return False
|
||
|
|
||
|
def get_reserved_num(self):
|
||
|
reserved_num = 0
|
||
|
for bits in self.bits_list:
|
||
|
if (bits.name == "reserved"):
|
||
|
reserved_num = reserved_num + 1
|
||
|
|
||
|
return reserved_num
|
||
|
|
||
|
def adjust_bits_reserved(self):
|
||
|
reserved_num_tmp = 0;
|
||
|
count_tmp = self.get_reserved_num()
|
||
|
#print(count_tmp)
|
||
|
for bits in self.bits_list:
|
||
|
if (bits.name == "reserved" and count_tmp > 1):
|
||
|
bits.name = bits.name + str(reserved_num_tmp)
|
||
|
reserved_num_tmp = reserved_num_tmp + 1
|
||
|
|
||
|
def gen_int_struct(self, struct_file):
|
||
|
bits = self.bits_list[0]
|
||
|
if (bits.comments.strip() != '' and bits.comments != "NC"):
|
||
|
struct_file.write(f'\t/*< {bits.comments} */\n')
|
||
|
addr_str = hex(bits.addr)
|
||
|
code_line = '\tuint32_t ' + bits.name + '; /* ' + addr_str + ' */\n\n'
|
||
|
struct_file.write(code_line)
|
||
|
|
||
|
def gen_bits_struct(self, struct_file):
|
||
|
bit0 = self.bits_list[0]
|
||
|
addr_str = f'{hex(bit0.addr)}'
|
||
|
code_line = '\t/* ' + addr_str + ' */\n'
|
||
|
struct_file.write(code_line)
|
||
|
code_line = '\tunion {\n'
|
||
|
struct_file.write(code_line)
|
||
|
code_line = '\t\tstruct {\n'
|
||
|
struct_file.write(code_line)
|
||
|
|
||
|
for bits in self.bits_list:
|
||
|
width = bits.start - bits.end + 1
|
||
|
width_str = f'{width}'
|
||
|
if (bits.comments.strip() != '' and bits.comments != "NC"):
|
||
|
struct_file.write(f'\t\t\t/*< {bits.comments} */\n')
|
||
|
code_line = '\t\t\tuint32_t ' + bits.name + ': ' + width_str + ';\n'
|
||
|
struct_file.write(code_line)
|
||
|
code_line = '\t\t};\n'
|
||
|
struct_file.write(code_line)
|
||
|
code_line = '\t\tuint32_t v;\n'
|
||
|
struct_file.write(code_line)
|
||
|
code_line = '\t} TODO_union_name;\n\n'
|
||
|
struct_file.write(code_line)
|
||
|
|
||
|
def gen_struct(self, struct_file):
|
||
|
if self.is_int():
|
||
|
self.gen_int_struct(struct_file)
|
||
|
else:
|
||
|
self.gen_bits_struct(struct_file)
|
||
|
|
||
|
class StructGen:
|
||
|
|
||
|
def __init__(self, name=None):
|
||
|
self.csv_file_name = name
|
||
|
self.csv_dict_list = []
|
||
|
self.reg_list = []
|
||
|
self.pre_reg_addr = 0
|
||
|
self.pre_reg = Reg()
|
||
|
self.cur_line = 0
|
||
|
file_base_name = name.replace('.csv', "")
|
||
|
self.struct_file_name = file_base_name + '_struct.h'
|
||
|
print(f'File base = {self.struct_file_name}')
|
||
|
self.struct_file = None
|
||
|
|
||
|
with open(name, 'r') as csvfile:
|
||
|
csv_dict = csv.DictReader(csvfile)
|
||
|
for line in csv_dict:
|
||
|
self.csv_dict_list.append(line)
|
||
|
#self.dump_csv_dict_list()
|
||
|
|
||
|
def dump_csv_dict_list(self):
|
||
|
for line in self.csv_dict_list:
|
||
|
print(line['x3'])
|
||
|
|
||
|
def get_bits_name(self, dict_line):
|
||
|
if KEY_REG_VAR not in dict_line:
|
||
|
return None
|
||
|
|
||
|
bits_var = dict_line[KEY_REG_VAR]
|
||
|
bits_var_list = bits_var.split('[')
|
||
|
if len(bits_var_list) > 1:
|
||
|
bits_var = bits_var_list[0]
|
||
|
|
||
|
return bits_var.lower()
|
||
|
|
||
|
def get_bits_default(self, dict_line):
|
||
|
if KEY_REG_DEFAULT not in dict_line:
|
||
|
return None
|
||
|
|
||
|
bits_default = dict_line[KEY_REG_DEFAULT]
|
||
|
return bits_default
|
||
|
|
||
|
def get_bits_comments(self, dict_line):
|
||
|
if KEY_REG_COMMENT not in dict_line:
|
||
|
return None
|
||
|
|
||
|
return dict_line[KEY_REG_COMMENT]
|
||
|
|
||
|
def get_addr_dict(self, dict_line):
|
||
|
addr_dict = {"addr": None, "start": None, "end": None}
|
||
|
|
||
|
if KEY_REG_ADDR not in dict_line:
|
||
|
print(f'line({self.cur_line}: key {KEY_REG} doesnt exist')
|
||
|
return addr_dict
|
||
|
|
||
|
reg_addr = dict_line[KEY_REG_ADDR]
|
||
|
reg_addr = reg_addr.replace('[', ':')
|
||
|
reg_addr = reg_addr.replace(']', '')
|
||
|
reg_addr = reg_addr.replace('\r', '')
|
||
|
reg_addr = reg_addr.replace('\n', '')
|
||
|
reg_addr_split_list = reg_addr.split(':')
|
||
|
|
||
|
if reg_addr_split_list == None:
|
||
|
print(f'line({self.cur_line}: addr is None')
|
||
|
return addr_dict
|
||
|
|
||
|
if reg_addr_split_list == []:
|
||
|
print(f'line({self.cur_line}: addr is None')
|
||
|
return addr_dict
|
||
|
|
||
|
if (reg_addr_split_list[0] == ''):
|
||
|
print(f'line({self.cur_line}): empty line, ignore')
|
||
|
return addr_dict
|
||
|
|
||
|
addr_dict['addr'] = int(reg_addr_split_list[0], 16)
|
||
|
if (len(reg_addr_split_list) == 1):
|
||
|
addr_dict['start'] = 31
|
||
|
addr_dict['end'] = 0
|
||
|
elif (len(reg_addr_split_list) == 2):
|
||
|
addr_dict['start'] = int(reg_addr_split_list[1], 10)
|
||
|
addr_dict['end'] = int(reg_addr_split_list[1], 10)
|
||
|
else:
|
||
|
addr_dict['start'] = int(reg_addr_split_list[1], 10)
|
||
|
addr_dict['end'] = int(reg_addr_split_list[2], 10)
|
||
|
|
||
|
return addr_dict
|
||
|
|
||
|
def add_reserved_reg(self, start_addr, end_addr):
|
||
|
addr_tmp = start_addr + 1
|
||
|
while (end_addr > addr_tmp):
|
||
|
bits = Bits(addr_tmp, "reserved", 31, 0)
|
||
|
reg = Reg()
|
||
|
reg.add_bits(bits)
|
||
|
self.pre_reg == None
|
||
|
self.reg_list.append(reg)
|
||
|
self.pre_reg_addr = addr_tmp
|
||
|
addr_tmp = addr_tmp + 1
|
||
|
|
||
|
def is_dict_line_empty(self, dict_line):
|
||
|
if dict_line is None:
|
||
|
return True
|
||
|
|
||
|
if KEY_REG_ADDR not in dict_line:
|
||
|
return True
|
||
|
|
||
|
if dict_line[KEY_REG_ADDR] == None:
|
||
|
return True
|
||
|
|
||
|
if dict_line[KEY_REG_ADDR] == '':
|
||
|
return True
|
||
|
|
||
|
return False
|
||
|
|
||
|
def parse_csv_dict_line(self, dict_line):
|
||
|
|
||
|
if self.is_dict_line_empty(dict_line):
|
||
|
print(f'line({self.cur_line}): empty dict_line, ignore')
|
||
|
return
|
||
|
|
||
|
reg_name = self.get_bits_name(dict_line)
|
||
|
reg_default_value = self.get_bits_default(dict_line)
|
||
|
reg_addr_dict = self.get_addr_dict(dict_line)
|
||
|
reg_comments = self.get_bits_comments(dict_line)
|
||
|
|
||
|
if (reg_addr_dict == {}):
|
||
|
print(f'line({self.cur_line}): reg address is empty, ignore')
|
||
|
return
|
||
|
|
||
|
bits = Bits(reg_addr_dict['addr'], reg_name, reg_addr_dict['start'], reg_addr_dict['end'], reg_default_value, self.cur_line)
|
||
|
bits.set_comments(reg_comments)
|
||
|
#bits.dump()
|
||
|
|
||
|
if (self.pre_reg == None):
|
||
|
reg = Reg()
|
||
|
else:
|
||
|
reg = self.pre_reg
|
||
|
|
||
|
reg.add_bits(bits)
|
||
|
|
||
|
if (reg_addr_dict['end'] == 0):
|
||
|
reg.adjust_bits_reserved()
|
||
|
self.pre_reg = None
|
||
|
if (reg_addr_dict['addr'] - self.pre_reg_addr > 1):
|
||
|
self.add_reserved_reg(self.pre_reg_addr, reg_addr_dict['addr'])
|
||
|
self.reg_list.append(reg)
|
||
|
self.pre_reg_addr = reg_addr_dict['addr']
|
||
|
else:
|
||
|
self.pre_reg = reg
|
||
|
|
||
|
def parse_regs(self):
|
||
|
self.cur_line = 1
|
||
|
for line in self.csv_dict_list:
|
||
|
self.cur_line = self.cur_line + 1
|
||
|
self.parse_csv_dict_line(line)
|
||
|
|
||
|
def dump_struct(self):
|
||
|
print(f'Dump struct')
|
||
|
|
||
|
def gen_struct_header_block(self):
|
||
|
self.struct_file.write(header_block)
|
||
|
|
||
|
def gen_struct_tailer_block(self):
|
||
|
self.struct_file.write(tailer_block)
|
||
|
|
||
|
def gen_struct(self):
|
||
|
self.struct_file = open(self.struct_file_name, 'w')
|
||
|
self.gen_struct_header_block()
|
||
|
code_line = "typedef volatile struct {\n"
|
||
|
self.struct_file.write(code_line)
|
||
|
reserved_start = 0
|
||
|
reserved_end = 0
|
||
|
reserved_num = 0;
|
||
|
reserved_index = 0
|
||
|
for reg in self.reg_list:
|
||
|
bits0 = reg.bits_list[0]
|
||
|
if reg.is_reserved():
|
||
|
reserved_start = bits0.addr
|
||
|
reserved_num = reserved_num + 1
|
||
|
else:
|
||
|
reserved_start = reserved_start - reserved_num
|
||
|
reserved_end = bits0.addr
|
||
|
if reserved_num == 1:
|
||
|
self.struct_file.write("\tuint32_t reserved" + str(reserved_index) + ";\n\n")
|
||
|
reserved_index = reserved_index + 1
|
||
|
elif reserved_num > 1:
|
||
|
code_line = "\tuint32_t reserved" + str(reserved_index) + "[" + hex(reserved_end) + " - " + hex(reserved_start) + " - 1];\n\n"
|
||
|
self.struct_file.write(code_line)
|
||
|
reserved_index = reserved_index + 1
|
||
|
reserved_num = 0
|
||
|
reserved_start = 0
|
||
|
reserved_end = 0
|
||
|
reg.gen_struct(self.struct_file)
|
||
|
code_line = "} TODO_hw_t;\n"
|
||
|
self.struct_file.write(code_line)
|
||
|
self.gen_struct_tailer_block()
|
||
|
self.struct_file.close()
|
||
|
|
||
|
def main():
|
||
|
parser = argparse.ArgumentParser(description='armino_gen - a tool to generate code')
|
||
|
|
||
|
parser.add_argument(
|
||
|
'--symbol_file', help='Struct symbol file: xx_reg_struct.S',
|
||
|
default=None,
|
||
|
dest='symbol_file')
|
||
|
|
||
|
parser.add_argument(
|
||
|
'--reg_csv_file', help='Register CSV file: xx_reg.csv',
|
||
|
default=None,
|
||
|
dest='reg_csv_file')
|
||
|
|
||
|
args = parser.parse_args()
|
||
|
|
||
|
if args.symbol_file:
|
||
|
dump_gen = DumpGen(args.symbol_file)
|
||
|
dump_gen.gen_struct_dump()
|
||
|
|
||
|
if args.reg_csv_file:
|
||
|
struct_gen = StructGen(args.reg_csv_file)
|
||
|
struct_gen.parse_regs()
|
||
|
struct_gen.gen_struct()
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
main()
|