UNPKG

9.98 kBJavaScriptView Raw
1/* global Promise */
2
3const pro = require("util").promisify;
4const fs = require("fs");
5const xml2js = require("xml2js");
6const codeGen = require("./code-gen.js");
7const rmDir = require("./rmdir.js");
8
9module.exports = async config => {
10
11 async function parseSvd(svdFile) {
12 let svdData = await pro(fs.readFile)(svdFile, "utf8");
13 return (await pro(new xml2js.Parser().parseString)(svdData)).device;
14 }
15
16 return {
17 async init(cli) {
18 return cli.command("svd <svdFile>");
19 },
20
21 async start(command, svdFile) {
22
23 console.info("Generating sources from", svdFile);
24
25 let device = await parseSvd(svdFile);
26 let cpu = (device.cpu || [{ name: [] }])[0].name[0];
27 if (!cpu) {
28 console.info("Warning: Undefined cpu - assuming CM0");
29 cpu = "CM0";
30 }
31
32 let stdDevice = await parseSvd(`${__dirname}/../arm-std-svd/ARM${cpu}.svd`);
33 let sysTick = stdDevice.peripherals[0].peripheral.find(p => p.name[0] === "SysTick");
34 device.peripherals[0].peripheral.push(sysTick);
35
36 if (device.width[0] !== "32") {
37 throw "SVD error: device.width is expected to be 32";
38 }
39
40 let nonDerived = [];
41
42 device.peripherals[0].peripheral.forEach(peripheral => {
43
44 if (!(peripheral.$ || {}).derivedFrom) {
45
46 let derived = device.peripherals[0].peripheral.filter(dp => (dp.$ || {}).derivedFrom === peripheral.name[0]);
47
48 let groupName = (peripheral.groupName || peripheral.name)[0];
49
50 let typeName;
51 if (derived.length > 0) {
52 let allNames = derived.map(dp => dp.name[0]).concat(peripheral.name[0]).sort();
53
54 if (allNames.some(n => !n.startsWith(groupName))) {
55 typeName = allNames[0] + "_" + allNames[allNames.length - 1];
56 } else {
57 typeName = groupName + "_" + allNames[0].slice(groupName.length) + "_" + allNames[allNames.length - 1].slice(groupName.length);
58 }
59 } else {
60 let name = peripheral.name[0];
61 if (name.startsWith(groupName) && name !== groupName) {
62 typeName = groupName + "_" + name.slice(groupName.length);
63 } else {
64 typeName = name;
65 }
66 }
67
68 nonDerived.push({
69 typeName,
70 groupName,
71 peripheral,
72 derived
73 });
74 }
75 });
76
77 nonDerived.forEach(p => {
78 if (!nonDerived.some(p2 => p2.groupName === p.groupName && p2 !== p)) {
79 p.typeName = p.groupName;
80 }
81 p.typeName = p.typeName.toLowerCase();
82 });
83
84 function svdInt(element) {
85 return parseInt(element[0]);
86 }
87
88 function inlineDescription(element) {
89 return element.description[0].replace(/[ \r\n]+/g, " ");
90 }
91
92 function fieldOffset(field) {
93 return svdInt(field.bitOffset);
94 }
95
96 function fieldWidth(field) {
97 return svdInt(field.bitWidth);
98 }
99
100 await rmDir("generated");
101
102 await pro(fs.mkdir)("generated");
103
104 var sources = [];
105 var symbols = {};
106
107 var writes = nonDerived.map(type => {
108 let fileName = "generated/" + type.typeName + ".cpp";
109 sources.push(fileName);
110
111 let code = codeGen();
112
113 code.begin("namespace target {");
114 code.begin("namespace", type.typeName, "{");
115
116 code.begin("namespace reg {");
117
118 type.peripheral.registers[0].register.forEach(register => {
119
120 let registerSize = svdInt(register.size);
121 if (registerSize !== 32) {
122 throw `Register ${type.peripheral.name}.${register.name[0]} has size ${registerSize}`;
123 }
124
125 //console.info(register);
126 code.wl();
127 code.begin("/**");
128 code.wl(inlineDescription(register));
129 code.end("*/");
130 code.begin("class", register.name, "{");
131
132 code.wl("volatile unsigned long raw;");
133 code.wl("public:");
134
135 code.begin("__attribute__((always_inline)) void operator= (unsigned long value) volatile {");
136 code.wl("raw = value;");
137 code.end("}");
138 code.begin("__attribute__((always_inline)) operator unsigned long () volatile {");
139 code.wl("return raw;");
140 code.end("}");
141
142 // find field vectors, e.g. STM32F GPIO MODER0..MODER15
143
144 let vectors = {};
145 register.fields[0].field.forEach(f1 => {
146 let m1 = f1.name[0].match(/([a-zA-Z]+)([0-9]+)([a-zA-Z]*)$/);
147 if (m1) {
148 let prefix = m1[1];
149 let suffix = m1[3];
150 register.fields[0].field.forEach(f2 => {
151 if (f1 !== f2) {
152 let m2 = f2.name[0].match(/([a-zA-Z]+)([0-9]+)([a-zA-Z]*)$/);
153 if (m2 && m2[1] === prefix && m2[3] === suffix) {
154 let i1 = parseInt(m1[2]);
155 let i2 = parseInt(m2[2]);
156 let min = Math.min(i1, i2);
157 let max = Math.max(i1, i2);
158 let key = m1[1] + "#" + m1[3];
159 let v = vectors[key];
160 if (!v) {
161 v = {
162 min,
163 max,
164 prefix,
165 suffix,
166 fields: []
167 };
168 vectors[key] = v;
169 } else {
170 v.min = Math.min(v.min, min);
171 v.max = Math.max(v.max, max);
172 }
173 v.fields[i1] = f1;
174 v.fields[i2] = f2;
175 }
176 }
177 });
178 }
179 });
180
181 function writeAccessors(fieldName, bitOffset, bitWidth, description, firstIndex, lastIndex) {
182
183 let indexed = firstIndex !== undefined;
184
185 let valueRange = "value in range 0.." + (Math.pow(2, bitWidth) - 1);
186 let indexRange = "index in range " + firstIndex + ".." + lastIndex;
187 let mask = "0x" + (Math.pow(2, bitWidth) - 1).toString(16).toUpperCase();
188
189 code.begin("/**");
190 code.wl("Gets", description);
191 if (indexed) {
192 code.wl("@param", indexRange);
193 }
194 code.wl("@return", valueRange);
195 code.end("*/");
196 if (indexed) {
197 code.begin("__attribute__((always_inline)) unsigned long", "get" + fieldName + "(int index) volatile {");
198 code.wl("return (raw & (" + mask + " << " + bitOffset + ")) >> " + bitOffset + ";");
199 } else {
200 code.begin("__attribute__((always_inline)) unsigned long", "get" + fieldName + "() volatile {");
201 code.wl("return (raw & (" + mask + " << " + bitOffset + ")) >> " + bitOffset + ";");
202 }
203 code.end("}");
204
205 code.begin("/**");
206 code.wl("Sets", description);
207 if (indexed) {
208 code.wl("@param", indexRange);
209 }
210 code.wl("@param", valueRange);
211 code.end("*/");
212 if (indexed) {
213 code.begin("__attribute__((always_inline)) unsigned long", "set" + fieldName + "(int index, unsigned long value) volatile {");
214 code.wl("raw = (raw & ~(" + mask + " << " + bitOffset + ")) | ((value << " + bitOffset + ") & (" + mask + " << " + bitOffset + "));");
215 } else {
216 code.begin("__attribute__((always_inline)) unsigned long", "set" + fieldName + "(unsigned long value) volatile {");
217 code.wl("raw = (raw & ~(" + mask + " << " + bitOffset + ")) | ((value << " + bitOffset + ") & (" + mask + " << " + bitOffset + "));");
218 }
219 code.end("}");
220 }
221
222 Object.entries(vectors).forEach(([k, v]) => {
223
224 let firstIsMarked;
225 let firstIndex;
226 let firstOffset;
227 let firstDistance;
228 let lastIndex;
229
230 for (let c = 0; c < v.fields.length; c++) {
231 let field = v.fields[c];
232 if (field) {
233 let bitOffset = fieldOffset(field);
234
235 if (firstIndex === undefined) {
236 firstIndex = c;
237 firstOffset = bitOffset;
238 } else {
239 if (firstDistance === undefined) {
240 firstDistance = bitOffset - firstOffset;
241 }
242 let expectedOffset = firstOffset + firstDistance * (c - firstIndex);
243 if (expectedOffset === bitOffset) {
244 if (!firstIsMarked) {
245 v.fields[firstIndex].inVector = v;
246 firstIsMarked = true;
247 }
248 field.inVector = v;
249 lastIndex = c;
250 } else {
251 v.fields[c] = undefined;
252 }
253 }
254 }
255 }
256
257
258 if (firstIsMarked) {
259 let field = v.fields[firstIndex];
260 let fieldName = field.inVector.prefix + (field.inVector.suffix ? "_" + field.inVector.suffix : "");
261 writeAccessors(
262 fieldName,
263 "(" + firstOffset + " + " + firstDistance + " * (index - " + firstIndex + "))",
264 fieldWidth(field),
265 inlineDescription(field),
266 firstIndex,
267 lastIndex
268 );
269 writeAccessors(fieldName, fieldOffset(field), fieldWidth(field) * (lastIndex - firstIndex + 1), inlineDescription(field));
270 }
271
272 });
273
274 register.fields[0].field.filter(field => !field.inVector).forEach(field => {
275 writeAccessors(field.name, fieldOffset(field), fieldWidth(field), inlineDescription(field));
276 });
277
278 code.end("};");
279 });
280 code.end("};");
281
282 code.begin("class Peripheral {");
283 code.wl("public:");
284 code.begin("union {");
285
286 type.peripheral.registers[0].register.forEach(register => {
287
288 let regOffset = svdInt(register.addressOffset);
289
290 code.begin("struct {");
291 if (regOffset > 0) {
292 code.wl(`volatile char _space_${register.name}[${regOffset}];`);
293 }
294
295 code.begin("/**");
296 code.wl(inlineDescription(register));
297 code.end("*/");
298 code.wl(`volatile reg::${register.name} ${register.name};`);
299
300 code.end("};");
301 });
302
303 code.end("};");
304 code.end("};");
305
306 code.end("}");
307
308 code.wl();
309
310 [type.peripheral].concat(type.derived).forEach(p => {
311 let symbol = p.name[0].toUpperCase();
312 code.wl("extern " + type.typeName + "::Peripheral", symbol + ";");
313 symbols["_ZN6target" + symbol.length + symbol + "E"] = p.baseAddress[0];
314 });
315
316 code.end("}");
317
318 return code.toFile(fileName);
319 });
320
321 await Promise.all(writes);
322
323 let package = JSON.parse(await pro(fs.readFile)("package.json", "utf8"));
324
325 let interrupts = {};
326 device.peripherals[0].peripheral.forEach(p => {
327 (p.interrupt || []).forEach(i => {
328 interrupts[i.value[0]] = i.name[0];
329 });
330 });
331
332 Object.assign(package, {
333 silicon: {
334 target: {
335 name: device.name[0],
336 cpu,
337 },
338 sources,
339 symbols,
340 interrupts
341 }
342 });
343
344 await pro(fs.writeFile)("package.json", JSON.stringify(package, null, 2));
345 }
346 };
347
348};
\No newline at end of file