-
Notifications
You must be signed in to change notification settings - Fork 1
/
print-regs.lua
202 lines (183 loc) · 8.57 KB
/
print-regs.lua
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
-- Given a parsed .SVD file (in Lua table form), print out some registers
-- shortcuts
fmt = string.format
-- for debugging, turn printing of parsing process on or off
--debug = function(s) io.stderr:write(s .. "\n") end
debug = function (s) end
-- Function to visit each branch and leaf of a tree.
--
-- Gets passed two functions: a function for branches and a function for
-- leaves. Returns a function that takes a tree and any number of
-- arguments, which are passed along as accumulators or whatever. visit()
-- doesn't know or care about them.
--
-- Also note that visit() does *not* recurse into branches! That's
-- fn_branch's job, if that's what it wants to do. visit() will, by
-- default, only visit the "top-level" nodes of tree.
function visit(fn_branch, fn_leaf)
return function(tree, ...)
for _, node in ipairs(tree) do
local k, v = next(node)
if type(v) == "table" then
-- process branch node
fn_branch(k, v, ...)
else
-- process leaf node
fn_leaf(k, v, ...)
end
end
return ...
end
end
function hex(s)
return tonumber(s, 16)
end
function muhex(num)
return fmt("%04x_%04x", num >> 16, num % (2^16))
end
-- Convert parens to square brackets so muforth comments don't barf
function unparen(s)
return (s:gsub("%(", "[")
:gsub("%)", "]"))
end
function print_regs(chip)
local sensible_gpio = {
PDOR = "OUT", -- Port Data Output Register
PSOR = "SET", -- Port Set Output Register
PCOR = "CLR", -- Port Clear Output Register
PTOR = "TOG", -- Port Toggle Output Register; XXX should this be "TGL" instead?
PDIR = "PIN", -- Port Data Input Register
PDDR = "DIR", -- Port Data Direction Register
PIDR = "DIS", -- Port Input Disable Register
}
local append = table.insert
local as_equates
as_equates = visit(
function(k, v, path, ctx)
local print_reg = function()
local name = (ctx.periph.prepend_to_name or "") .. ctx.reg.name
local addr = tonumber(ctx.periph.base_address) + tonumber(ctx.reg.address_offset)
local descr = (ctx.reg.description and "| "..ctx.reg.description) or ""
if ctx.reg.dim then
-- Print multiple registers
local offset = 0
for i in ctx.reg.dim_index:gmatch "%w+" do
io.write(fmt("%s equ %-28s %s\n",
muhex(addr + offset), fmt(name, i), unparen(descr)))
offset = offset + ctx.reg.dim_increment
end
else
if ctx.periph.name:match "GPIO" and sensible_gpio[ctx.reg.name] then
local sensible_name = ctx.periph.prepend_to_name .. sensible_gpio[ctx.reg.name]
append(ctx.sensibles, { addr = addr, name = sensible_name, descr = descr })
descr = fmt("| DEPRECATED: Use %s instead", sensible_name)
end
io.write(fmt("%s equ %-28s %s\n", muhex(addr), name, unparen(descr)))
end
ctx.reg.printed = true
end
path = path.."/"..k
if path == "/peripherals" then
-- print chip info
io.write "| Automagically generated! DO NOT EDIT!\n|\n"
io.write(fmt("| %s %s %s equates, version %s\n|\n",
ctx.chip.vendor_id, ctx.chip.series, ctx.chip.name, ctx.chip.version))
io.write "| Generated by https://github.com/nimblemachines/kinetis-chip-equates\n"
io.write(fmt("| from CMSIS-SVD source file %s\n\nhex\n", ctx.chip.source_file))
elseif path == "/peripherals/peripheral" then
-- reset context
ctx.periph = {}
ctx.sensibles = {}
elseif path == "/peripherals/peripheral/interrupt" then
-- reset context
ctx.interrupt = {}
elseif path == "/peripherals/peripheral/registers" then
-- print heading for this peripheral
io.write(fmt("\n( %s: %s)\n", ctx.periph.name, unparen(ctx.periph.description)))
elseif path == "/peripherals/peripheral/registers/register" then
-- reset context
ctx.reg = {}
elseif path == "/peripherals/peripheral/registers/register/fields" then
-- Generally fields follow the register def, so print the reg now
print_reg()
elseif path == "/peripherals/peripheral/registers/register/fields/field" then
-- reset context
ctx.field = {}
end
-- Recurse into subtable
as_equates(v, path, ctx)
if path == "/peripherals/peripheral/registers/register/fields/field" then
if not ctx.periph.name:match "GPIO" then
-- Only print register fields for non-GPIO registers.
-- Printing "this is bit 7 of the direction register"
-- is pointless.
-- Registers defined with "dim" also have fields... but
-- printing the fields for each version of the register
-- would be stupid. Let's instead just remove the "%s" from
-- the name.
if ctx.field.bit_width < ctx.reg.size then
local name = (ctx.periph.prepend_to_name or "") ..
ctx.reg.name:gsub("%%s", "") .. "_" .. ctx.field.name
local descr = (ctx.field.description and "| "..ctx.field.description) or ""
io.write(fmt(" #%02d #%02d field %-28s %s\n", ctx.field.bit_offset, ctx.field.bit_width,
name, descr))
end
end
elseif path == "/peripherals/peripheral/registers/register" then
-- If register has no fields, we won't have printed it above. Do it now.
if not ctx.reg.printed then
print_reg()
end
elseif path == "/peripherals/peripheral/interrupt" then
local vector = tonumber(ctx.interrupt.value)
ctx.interrupts[vector] = ctx.interrupt.name
ctx.interrupts.max = math.max(ctx.interrupts.max, vector)
elseif path == "/peripherals/peripheral" then
if #ctx.sensibles > 0 then
io.write(fmt("\n( More sensible %s register names:)\n", ctx.periph.name))
for _, reg in ipairs(ctx.sensibles) do
io.write(fmt("%s equ %-28s %s\n",
muhex(reg.addr), reg.name, unparen(reg.descr)))
end
end
elseif path == "/peripherals" then
-- We've processed all the peripherals; print the interrupt vectors.
io.write "\n( IRQ vectors)\ndecimal\n"
--io.stderr:write(fmt("max interrupt: %d\n", ctx.interrupts.max))
for i = 0, ctx.interrupts.max do
local name = ctx.interrupts[i]
if name then
-- Fix LLW mistake
name = (name == "LLW") and "LLWU" or name
io.write(fmt(" %3d equ %s_IRQ\n", i, name))
else
io.write(fmt("( %3d Reserved)\n", i))
end
end
io.write "hex\n"
end
end,
function(k, v, path, ctx)
if path == "" then
ctx.chip[k] = v
elseif path == "/peripherals/peripheral" then
ctx.periph[k] = v
if k == "name" then debug(v) end
elseif path == "/peripherals/peripheral/interrupt" then
ctx.interrupt[k] = v
elseif path == "/peripherals/peripheral/registers/register" then
ctx.reg[k] = v
if k == "name" then debug(" " .. v) end
elseif path == "/peripherals/peripheral/registers/register/fields/field" then
ctx.field[k] = v
if k == "name" then debug(" " .. v) end
end
end)
as_equates(chip, "", { chip = {}, interrupts = { max = 0 } })
end
-- arg 1 is lua file to process
function doit()
local chip = dofile(arg[1])
print_regs(chip)
end
doit()