-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmsp430_c_header_to_gnu_as.py
214 lines (186 loc) · 9.84 KB
/
msp430_c_header_to_gnu_as.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
# Takes a TI MSP430 C header file as an input file and outputs a GNU Assembler compatible header
# it assumes the input files have valid C syntax
import os
import re
import argparse
# parse dev symbols file into a dictionary
# strip PROVIDE(XYZ = 0xXXXX) to "XYZ": "0xXXXX"
def parse_symbols_file(file_path, dict_output):
parse_file = open(file_path , 'r')
for line in parse_file:
if line.find('PROVIDE(') == -1:
continue # get new line, nothing to parse
# otherwise, add key-value pair to dictionary
sym_name = line[line.find('(') + 1 : line.find(' ')]
sym_val = line.split('=')[1] # store RHS of = xxxx
sym_val = sym_val[sym_val.find(' ') + 1 : sym_val.find(')')] # if there is no space the result is still the same
# create dic from list
sym_dict = dict([(sym_name, sym_val)]) # build dictionary from a list of tuples (only one tuple in this case)
dict_output.update(sym_dict) # build dictionary from a list of tuples (only one tuple in this case)
parse_file.close()
return dict_output
def parse_defines(line, dict_output, msp430_comments):
def_name = line.split()[1]
def_dict = {}
line_no_comments = line
if msp430_comments:
if line.find(';') != -1: # if there is a comment then
def_val = line.split(' ', 2)[2].split(';')[0].strip()
line_no_comments = line.split(';')[0].strip()
else:
if (((line.find('*') - line.find('/')) == 1) and (line.rfind('/') - line.rfind('*')) == 1):
def_val = line.split(' ', 2)[2].split('/*')[0].strip()
line_no_comments = line.split('/*')[0].strip()
# if not defining a constant/macro function then
if len(line_no_comments.split()) == 2:
def_dict = dict([(def_name, 1)]) # build dictionary from a list of tuples (only one tuple in this case)
# add comments if there are any
comment_index = line.find('/*')
if msp430_comments:
comment_index = line.find(';')
if (comment_index != -1):
def_dict = dict([(def_name, str(1).ljust(13) + line[comment_index:])]) # build dictionary from a list of tuples (only one tuple in this case)
else:
def_val = line.split(' ', 2)[2].strip()
if (line_no_comments.split(' ', 2)[2].find('(') != -1 and line_no_comments.split(' ', 2)[2].find(')') != -1):
lbr_count = line_no_comments.count('(')
rbr_count = line_no_comments.count(')')
def_val = line.split(' ', 2)[2].strip().replace('(', '', lbr_count).replace(')', '', rbr_count)
def_dict = dict([(def_name, def_val)]) # build dictionary from a list of tuples (only one tuple in this case)
dict_output.update(def_dict) # append to output
def_name_width = 24 # not needed, calculated from header file, distance from first char after define to the first "("
def_value = dict_output.get(def_name)
return dict_output
def replace_comments(line, is_multi_line_comment, msp430_comments):
if (((line.find('*') - line.find('/')) == 1) and (line.rfind('/') - line.rfind('*')) == 1):
if msp430_comments:
line = line.replace('/*', ';', 1).replace('*/', '', 1) # replace start of comment w/ ;
is_multi_line_comment = False
elif line.find('/*') >= 0 and line.find('*/') == -1:
if msp430_comments:
line = line.replace('/*', ';', 1).replace('*/', '', 1).replace('*', ';')
is_multi_line_comment = True
elif (line.find('//') != -1):
if msp430_comments:
line = line.replace('//', ';', 1)
if is_multi_line_comment:
if msp430_comments:
if (line.find('*/') != -1):
is_multi_line_comment = False # needs to be delayed when not replacing comments, set in parse_header() function
line = line.replace('/*', ';', 1).replace('*/', ';', 1).replace('*', ';')
return line, is_multi_line_comment
def write_user_defines(output_file, msp430_comments):
# helpful defines for assembly as they aren't included in the C header files
additional_user_defines_dict = {'PC': 'R0', 'SP': 'R1', 'SR': 'R2', 'CG1': 'R2', 'CG2': 'R3'}
# generate a multi-line comment
if msp430_comments:
padding = ';'
width = 50
output_file.write(f'{"" :{padding}<{width}}\n')
output_file.write(f'{"; ALT REGISTER NAMES (generated by script)"}\n')
output_file.write(f'{"" :{padding}<{width}}\n\n')
else:
padding = '*'
width = 50
output_file.write(f'{"/*" :{padding}<{width}}*/\n')
output_file.write(f'{"/* ALT REGISTER NAMES (generated by script)":{""}<{width}}*/\n')
output_file.write(f'{"/*" :{padding}<{width}}*/\n\n')
def_name_width = 24
for key,value in additional_user_defines_dict.items():
output_file.write('.equ {:<24}, {}\n'.format(key, value))
output_file.write('\n')
return None
def parse_header_file(c_header_path, msp430_comments, symbols, dict_output, gnu_as_header_output):
parse_file = open(c_header_path , 'r')
skip_conditional_define = False
process_conditional_branch = False
is_multi_line_comment = False
write_file = open(gnu_as_header_output, 'w')
for line in parse_file:
[line, is_multi_line_comment] = replace_comments(line, is_multi_line_comment, msp430_comments)
line = line.strip()
if (len(line) == 0): # write newlines to file
write_file.write(line + '\n')
else:
is_only_comment = (line.find('/*') == 0) or (is_multi_line_comment and (line.find('*/') != -1))
if is_multi_line_comment and (line.find('*/') != -1):
is_multi_line_comment = False
if msp430_comments:
is_only_comment = (line[0] == ';')
if (is_only_comment or is_multi_line_comment): # write comments to file
write_file.write(line + '\n')
if (line.find('#define __MSP430_HEADER_VERSION__') != -1):
write_user_defines(write_file, msp430_comments)
if process_conditional_branch:
if skip_conditional_define:
# exit/change condtions
if (line.find('#else')) != -1:
skip_conditional_define = False
continue
elif (line.find('#endif')) != -1:
process_conditional_branch = False
skip_conditional_define = False
continue
continue # skip lines (otherwise if #define lines are processed too)
else:
# exit/change condtions
if (line.find('#else')) != -1:
skip_conditional_define = True
elif (line.find('#endif')) != -1:
process_conditional_branch = False
skip_conditional_define = False
if line.find('#ifdef') == 0:
process_conditional_branch = True
if dict_output.get(line.split(' ', 2)[1]) == None:
skip_conditional_define = True
continue
elif line.find('#ifndef') == 0:
process_conditional_branch = True
if dict_output.get(line.split(' ', 2)[1]) != None:
skip_conditional_define = True
continue
elif line.find('#define') == 0:
parse_defines(line, dict_output, msp430_comments)
def_name = line.split()[1]
write_file.write('.equ {:<24}, {}\n'.format(def_name, dict_output.get(def_name)))
elif (line.find('sfr_b') == 0) or (line.find('sfr_w') == 0):
# write to file here, always assume there is a trailing comment
comment_index = line.find('/*') - 1
if msp430_comments:
comment_index = line.rfind(';') - 1
def_name = line.split('(')[1].split(')')[0]
write_file.write('.equ {:<24}, {:<11} {}\n'.format(def_name, symbols.get(def_name), line[comment_index:]))
continue # do nothing for now, need to add dictionary input here too
else:
continue
parse_file.close()
return dict_output
if __name__ == "__main__":
# inputs:
parser = argparse.ArgumentParser(description="Convert TIs MSP430 C header files to a GNU AS compatible header")
parser.add_argument("-d", "--device",
help="choose your msp430 device (must have a C header, e.g. device.h)",
type=str, default="msp430g2553")
parser.add_argument("--msp430_comments", action="store_true",
help="Set if you would like to not use C/C++ style comments, instead opting for ';' as a comment")
parser.add_argument("-I", "--include",
type=str, default="/opt/ti-msp430/lib/gcc/msp430-elf/9.3.1/include/",
help="Include path, where to search for device.h")
parser.add_argument("-L", "--link_symbols",
type=str, default="/opt/ti-msp430/lib/gcc/msp430-elf/9.3.1/include/",
help="Symbols path, where to search for device_symbold.ld")
args = parser.parse_args()
device = args.device
header_path = args.include
symbols_path = args.link_symbols
dev_header = device + '.h'
dev_symbols = device + '_symbols.ld'
output_path = './'
output_file = device + '_gnu_as.inc'
in_header_file = os.path.join(header_path, dev_header)
in_symbol_file = os.path.join(symbols_path, dev_symbols)
out_header_file = os.path.join(output_path, output_file)
sym_dict = {}
parse_symbols_file(in_symbol_file, sym_dict)
def_dict = {}
parse_header_file(in_header_file, args.msp430_comments, sym_dict, def_dict, output_file)