summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2016-02-06 15:01:24 +0000
committerAmaury Pouly <amaury.pouly@gmail.com>2016-02-06 15:12:55 +0000
commit0f701a64bee43e79f95970ae9c0ec43ea7fcdf17 (patch)
treec8ac6b5516eac120797eb6a06f633919e9f48f9b
parent16c915ec1826dcef2e58ecc055a3f5dfcefb235a (diff)
downloadrockbox-0f701a64bee43e79f95970ae9c0ec43ea7fcdf17.tar.gz
rockbox-0f701a64bee43e79f95970ae9c0ec43ea7fcdf17.zip
regtools: update v2 specification, library and tools
A v2 register description file can now include register variants and instances addresses can now be a list (previously it could only be a stride or a formula). Update the library to deal with that. The convert option of swiss_knife was updated and one incompatible change was introduce: if a v1 device has several addresses, those are converted to a single v2 instance with list (instead of several single instances). This should have been the behaviour from the start. Swiss_knife can now also convert regdumps, in which case it needs to be given both the dump and register description file. Also introduce two register descriptions files (vsoc1000 and vsoc2000) which give more complicated examples of v2 register description files. Change-Id: Id9415b8363269ffaf9216abfc6dd1bd1adbfcf8d
-rw-r--r--utils/regtools/desc/regs-example-v1.xml2
-rw-r--r--utils/regtools/desc/regs-example.xml153
-rw-r--r--utils/regtools/desc/regs-vsoc1000.xml248
-rw-r--r--utils/regtools/desc/regs-vsoc2000.xml396
-rw-r--r--utils/regtools/desc/spec-2.0.txt30
-rw-r--r--utils/regtools/include/soc_desc.hpp139
-rw-r--r--utils/regtools/include/soc_desc_v1.hpp2
-rw-r--r--utils/regtools/lib/soc_desc.cpp473
-rw-r--r--utils/regtools/swiss_knife.cpp259
9 files changed, 1491 insertions, 211 deletions
diff --git a/utils/regtools/desc/regs-example-v1.xml b/utils/regtools/desc/regs-example-v1.xml
index 4f3cf81ff2..fcb9f7f55e 100644
--- a/utils/regtools/desc/regs-example-v1.xml
+++ b/utils/regtools/desc/regs-example-v1.xml
@@ -1,5 +1,5 @@
1<?xml version="1.0"?> 1<?xml version="1.0"?>
2<soc name="imx233" desc="i.MX233"> 2<soc name="example" desc="i.MX233">
3 <dev name="APBH" long_name="APHB DMA" desc="AHB-to-APBH Bridge with DMA" version="3.2.0"> 3 <dev name="APBH" long_name="APHB DMA" desc="AHB-to-APBH Bridge with DMA" version="3.2.0">
4 <addr name="APBH" addr="0x80004000"/> 4 <addr name="APBH" addr="0x80004000"/>
5 <reg name="CTRL0" desc="" sct="yes"> 5 <reg name="CTRL0" desc="" sct="yes">
diff --git a/utils/regtools/desc/regs-example.xml b/utils/regtools/desc/regs-example.xml
deleted file mode 100644
index 6fb8f759fe..0000000000
--- a/utils/regtools/desc/regs-example.xml
+++ /dev/null
@@ -1,153 +0,0 @@
1<?xml version="1.0"?>
2<soc version="2">
3 <name>vsoc</name>
4 <title>Virtual SOC</title>
5 <desc>Virtual SoC is a nice and powerful chip.</desc>
6 <author>Amaury Pouly</author>
7 <isa>ARM</isa>
8 <version>0.5</version>
9 <node>
10 <name>int</name>
11 <title>Interrupt Collector</title>
12 <desc>The interrupt collector controls the routing of interrupt to the processor</desc>
13 <instance>
14 <name>ICOLL</name>
15 <title>Interrupt collector</title>
16 <address>0x80000000</address>
17 </instance>
18 <node>
19 <name>status</name>
20 <access>read-only</access>
21 <title>Interrupt status register</title>
22 <instance>
23 <name>STATUS</name>
24 <address>0x4</address>
25 </instance>
26 <register>
27 <width>8</width>
28 <field>
29 <name>VDDIO_BO</name>
30 <desc>VDDIO brownout interrupt status</desc>
31 <position>0</position>
32 </field>
33 </register>
34 </node>
35 <node>
36 <name>enable</name>
37 <title>Interrupt enable register</title>
38 <instance>
39 <name>ENABLE</name>
40 <address>0x8</address>
41 </instance>
42 <register>
43 <width>16</width>
44 <field>
45 <name>VDDIO_BO</name>
46 <desc>VDDIO brownout interrupt enable</desc>
47 <position>0</position>
48 <width>2</width>
49 <enum>
50 <name>DISABLED</name>
51 <desc>Interrupt is disabled</desc>
52 <value>0</value>
53 </enum>
54 <enum>
55 <name>ENABLED</name>
56 <desc>Interrupt is enabled</desc>
57 <value>1</value>
58 </enum>
59 <enum>
60 <name>NMI</name>
61 <desc>Interrupt is non-maskable</desc>
62 <value>2</value>
63 </enum>
64 </field>
65 </register>
66 <variant>
67 <type>set</type>
68 <offset>4</offset>
69 </variant>
70 <variant>
71 <type>clr</type>
72 <offset>8</offset>
73 </variant>
74 </node>
75 </node>
76 <node>
77 <name>gpio</name>
78 <title>GPIO controller</title>
79 <desc>A GPIO controller manages several ports</desc>
80 <instance>
81 <name>CPU_GPIO</name>
82 <title>CPU GPIO controller 1 through 3</title>
83 <range>
84 <first>1</first>
85 <count>3</count>
86 <formula variable="n">0x80001000+(n-1)*0x1000</formula>
87 </range>
88 </instance>
89 <instance>
90 <name>COP_GPIO</name>
91 <title>Companion processor GPIO controller</title>
92 <desc>Although the companion processor GPIO controller is accessible from the CPU, it incurs an extra penalty on the bus</desc>
93 <address>0x90000000</address>
94 </instance>
95 <node>
96 <name>port</name>
97 <title>GPIO port</title>
98 <instance>
99 <name>PORT</name>
100 <range>
101 <first>0</first>
102 <count>4</count>
103 <base>0</base>
104 <stride>0x100</stride>
105 </range>
106 </instance>
107 <node>
108 <name>input</name>
109 <title>Input register</title>
110 <instance>
111 <name>IN</name>
112 <address>0</address>
113 </instance>
114 <register>
115 <width>8</width>
116 <field>
117 <name>VALUE</name>
118 <position>0</position>
119 <width>8</width>
120 </field>
121 </register>
122 </node>
123 <node>
124 <name>output_enable</name>
125 <title>Output enable register</title>
126 <instance>
127 <name>OE</name>
128 <address>0x10</address>
129 </instance>
130 <register>
131 <width>8</width>
132 <field>
133 <name>ENABLE</name>
134 <position>0</position>
135 <width>8</width>
136 </field>
137 </register>
138 <variant>
139 <type>set</type>
140 <address>4</address>
141 </variant>
142 <variant>
143 <type>clr</type>
144 <address>8</address>
145 </variant>
146 <variant>
147 <type>mask</type>
148 <address>12</address>
149 </variant>
150 </node>
151 </node>
152 </node>
153</soc> \ No newline at end of file
diff --git a/utils/regtools/desc/regs-vsoc1000.xml b/utils/regtools/desc/regs-vsoc1000.xml
new file mode 100644
index 0000000000..d909d85b53
--- /dev/null
+++ b/utils/regtools/desc/regs-vsoc1000.xml
@@ -0,0 +1,248 @@
1<?xml version="1.0"?>
2<soc version="2">
3 <name>vsoc1000</name>
4 <title>Virtual SOC 1000</title>
5 <desc>Virtual SoC 1000 is a nice chip. Its dual-core architecture makes it super powerful.</desc>
6 <author>Amaury Pouly</author>
7 <isa>ARM</isa>
8 <version>0.5</version>
9 <node>
10 <name>int</name>
11 <title>Interrupt Collector</title>
12 <desc>The interrupt collector controls the routing of the interrupts to the processors. It has 32 interrupts sources, which can be routed as FIQ or IRQ to the main processor or the coprocessor.</desc>
13 <instance>
14 <name>ICOLL</name>
15 <title>Interrupt collector</title>
16 <address>0x80000000</address>
17 </instance>
18 <node>
19 <name>ctrl</name>
20 <title>Control register</title>
21 <instance>
22 <name>CTRL</name>
23 <address>0x0</address>
24 </instance>
25 <register>
26 <width>8</width>
27 <field>
28 <name>CLKGATE</name>
29 <desc>Clock gating control</desc>
30 <position>7</position>
31 </field>
32 <field>
33 <name>SFTRST</name>
34 <desc>Soft reset, the bit will automatically reset to 0 when reset is completed</desc>
35 <position>6</position>
36 </field>
37 <variant>
38 <type>set</type>
39 <offset>4</offset>
40 </variant>
41 <variant>
42 <type>clr</type>
43 <offset>8</offset>
44 </variant>
45 </register>
46 </node>
47 <node>
48 <name>status</name>
49 <title>Interrupt status register</title>
50 <instance>
51 <name>STATUS</name>
52 <address>0x10</address>
53 </instance>
54 <register>
55 <field>
56 <name>STATUS</name>
57 <desc>Bit is set to 1 is the interrupt is pending, write a 1 to the clear variant to clear it</desc>
58 <position>0</position>
59 <width>32</width>
60 </field>
61 <variant>
62 <type>clr</type>
63 <offset>8</offset>
64 </variant>
65 </register>
66 </node>
67 <node>
68 <name>enable</name>
69 <title>Interrupt enable register</title>
70 <instance>
71 <name>ENABLE</name>
72 <range>
73 <first>0</first>
74 <count>32</count>
75 <base>0x20</base>
76 <stride>0x10</stride>
77 </range>
78 </instance>
79 <register>
80 <width>16</width>
81 <desc>This register controls the routing of the interrupt</desc>
82 <field>
83 <name>COP_PRIO</name>
84 <desc>Coprocessor priority</desc>
85 <position>5</position>
86 <width>2</width>
87 <enum>
88 <name>MASKED</name>
89 <desc>Interrupt is masked</desc>
90 <value>0x0</value>
91 </enum>
92 <enum>
93 <name>LOW</name>
94 <value>0x1</value>
95 </enum>
96 <enum>
97 <name>HIGH</name>
98 <value>0x2</value>
99 </enum>
100 <enum>
101 <name>NMI</name>
102 <desc>Interrupt is non maskable</desc>
103 <value>0x3</value>
104 </enum>
105 </field>
106 <field>
107 <name>COP_TYPE</name>
108 <desc>Interrupt type</desc>
109 <position>4</position>
110 <enum>
111 <name>IRQ</name>
112 <value>0x0</value>
113 </enum>
114 <enum>
115 <name>FIQ</name>
116 <value>0x1</value>
117 </enum>
118 </field>
119 <field>
120 <name>CPU_PRIO</name>
121 <desc>CPU priority</desc>
122 <position>2</position>
123 <width>2</width>
124 <enum>
125 <name>MASKED</name>
126 <desc>Interrupt will never be sent to the CPU</desc>
127 <value>0x0</value>
128 </enum>
129 <enum>
130 <name>LOW</name>
131 <value>0x1</value>
132 </enum>
133 <enum>
134 <name>HIGH</name>
135 <value>0x2</value>
136 </enum>
137 <enum>
138 <name>NMI</name>
139 <desc>Interrupt is non maskable</desc>
140 <value>0x3</value>
141 </enum>
142 </field>
143 <field>
144 <name>CPU_TYPE</name>
145 <desc>Interrupt type</desc>
146 <position>1</position>
147 <enum>
148 <name>IRQ</name>
149 <value>0x0</value>
150 </enum>
151 <enum>
152 <name>FIQ</name>
153 <value>0x1</value>
154 </enum>
155 </field>
156 <field>
157 <name>ENABLE</name>
158 <position>0</position>
159 </field>
160 <variant>
161 <type>set</type>
162 <offset>4</offset>
163 </variant>
164 <variant>
165 <type>clr</type>
166 <offset>8</offset>
167 </variant>
168 </register>
169 </node>
170 </node>
171 <node>
172 <name>gpio</name>
173 <title>GPIO controller</title>
174 <desc>A GPIO controller manages several ports</desc>
175 <instance>
176 <name>CPU_GPIO</name>
177 <title>CPU GPIO controller 1 through 3</title>
178 <range>
179 <first>1</first>
180 <count>3</count>
181 <formula variable="n">0x80001000+(n-1)*0x1000</formula>
182 </range>
183 </instance>
184 <instance>
185 <name>COP_GPIO</name>
186 <title>Companion processor GPIO controller</title>
187 <desc>Although the companion processor GPIO controller is accessible from the CPU, it incurs an extra penalty on the bus</desc>
188 <address>0x90000000</address>
189 </instance>
190 <node>
191 <name>port</name>
192 <title>GPIO port</title>
193 <instance>
194 <name>PORT</name>
195 <range>
196 <first>0</first>
197 <count>2</count>
198 <base>0x0</base>
199 <stride>0x100</stride>
200 </range>
201 </instance>
202 <node>
203 <name>input</name>
204 <title>Input register</title>
205 <instance>
206 <name>IN</name>
207 <address>0x0</address>
208 </instance>
209 <register>
210 <width>8</width>
211 <field>
212 <name>VALUE</name>
213 <position>0</position>
214 <width>8</width>
215 </field>
216 </register>
217 </node>
218 <node>
219 <name>output_enable</name>
220 <title>Output enable register</title>
221 <instance>
222 <name>OE</name>
223 <address>0x10</address>
224 </instance>
225 <register>
226 <width>8</width>
227 <field>
228 <name>ENABLE</name>
229 <position>0</position>
230 <width>8</width>
231 </field>
232 <variant>
233 <type>set</type>
234 <offset>4</offset>
235 </variant>
236 <variant>
237 <type>clr</type>
238 <offset>8</offset>
239 </variant>
240 <variant>
241 <type>mask</type>
242 <offset>12</offset>
243 </variant>
244 </register>
245 </node>
246 </node>
247 </node>
248</soc>
diff --git a/utils/regtools/desc/regs-vsoc2000.xml b/utils/regtools/desc/regs-vsoc2000.xml
new file mode 100644
index 0000000000..bcd6d08d38
--- /dev/null
+++ b/utils/regtools/desc/regs-vsoc2000.xml
@@ -0,0 +1,396 @@
1<?xml version="1.0"?>
2<soc version="2">
3 <name>vsoc2000</name>
4 <title>Virtual SOC 2000</title>
5 <desc>Virtual SoC 2000 is a nice chip. Its quad-core architecture with trustzone makes it super powerful.</desc>
6 <author>Amaury Pouly</author>
7 <isa>ARM</isa>
8 <version>0.5</version>
9 <node>
10 <name>int</name>
11 <title>Interrupt Collector</title>
12 <desc>The interrupt collector controls the routing of the interrupts to the processors. It has 32 interrupts sources, which can be routed as FIQ or IRQ to the either processor.</desc>
13 <instance>
14 <name>ICOLL</name>
15 <title>Interrupt collector</title>
16 <address>0x80000000</address>
17 </instance>
18 <node>
19 <name>ctrl</name>
20 <title>Control register</title>
21 <instance>
22 <name>CTRL</name>
23 <address>0x0</address>
24 </instance>
25 <register>
26 <width>8</width>
27 <field>
28 <name>CLKGATE</name>
29 <desc>Clock gating control. This bit can be protected by TZ lock.</desc>
30 <position>7</position>
31 </field>
32 <field>
33 <name>SFTRST</name>
34 <desc>Soft reset, the bit will automatically reset to 0 when reset is completed. This bit can be protected by TZ lock.</desc>
35 <position>6</position>
36 </field>
37 <field>
38 <name>TZ_LOCK</name>
39 <desc>Trust Zone lock</desc>
40 <position>5</position>
41 <enum>
42 <name>UNLOCKED</name>
43 <value>0x0</value>
44 </enum>
45 <enum>
46 <name>LOCKED</name>
47 <desc>When the interrupt collector is locked, only a secured processor can modify protected fields.</desc>
48 <value>0x1</value>
49 </enum>
50 </field>
51 <variant>
52 <type>set</type>
53 <offset>4</offset>
54 </variant>
55 <variant>
56 <type>clr</type>
57 <offset>8</offset>
58 </variant>
59 </register>
60 </node>
61 <node>
62 <name>status</name>
63 <title>Interrupt status register</title>
64 <instance>
65 <name>STATUS</name>
66 <address>0x10</address>
67 </instance>
68 <register>
69 <field>
70 <name>STATUS</name>
71 <desc>Bit is set to 1 is the interrupt is pending, write a 1 to the clear variant to clear it. Secured interrupts can only be cleared or polled by secured processors (non-secure will always read 0 for those).</desc>
72 <position>0</position>
73 <width>32</width>
74 </field>
75 <variant>
76 <type>clr</type>
77 <offset>8</offset>
78 </variant>
79 </register>
80 </node>
81 <node>
82 <name>enable</name>
83 <title>Interrupt enable register</title>
84 <instance>
85 <name>ENABLE</name>
86 <range>
87 <first>0</first>
88 <count>32</count>
89 <base>0x20</base>
90 <stride>0x10</stride>
91 </range>
92 </instance>
93 <register>
94 <width>16</width>
95 <desc>This register controls the routing of the interrupt</desc>
96 <field>
97 <name>CPU3_PRIO</name>
98 <desc>Interrupt priority</desc>
99 <position>14</position>
100 <width>2</width>
101 <enum>
102 <name>MASKED</name>
103 <desc>Interrupt is masked</desc>
104 <value>0x0</value>
105 </enum>
106 <enum>
107 <name>LOW</name>
108 <value>0x1</value>
109 </enum>
110 <enum>
111 <name>HIGH</name>
112 <value>0x2</value>
113 </enum>
114 <enum>
115 <name>NMI</name>
116 <desc>Interrupt is non maskable</desc>
117 <value>0x3</value>
118 </enum>
119 </field>
120 <field>
121 <name>CPU3_TYPE</name>
122 <desc>Interrupt type</desc>
123 <position>13</position>
124 <enum>
125 <name>IRQ</name>
126 <value>0x0</value>
127 </enum>
128 <enum>
129 <name>FIQ</name>
130 <value>0x1</value>
131 </enum>
132 </field>
133 <field>
134 <name>CPU3_TZ</name>
135 <desc>Trust Zone interrupt: when set, only a secured processor can modify the parameters for secured interrupts.</desc>
136 <position>12</position>
137 </field>
138 <field>
139 <name>CPU2_PRIO</name>
140 <position>10</position>
141 <width>2</width>
142 <enum>
143 <name>MASKED</name>
144 <desc>Interrupt is masked</desc>
145 <value>0x0</value>
146 </enum>
147 <enum>
148 <name>LOW</name>
149 <value>0x1</value>
150 </enum>
151 <enum>
152 <name>HIGH</name>
153 <value>0x2</value>
154 </enum>
155 <enum>
156 <name>NMI</name>
157 <desc>Interrupt is non maskable</desc>
158 <value>0x3</value>
159 </enum>
160 </field>
161 <field>
162 <name>CPU2_TYPE</name>
163 <desc>Interrupt type</desc>
164 <position>9</position>
165 <enum>
166 <name>IRQ</name>
167 <value>0x0</value>
168 </enum>
169 <enum>
170 <name>FIQ</name>
171 <value>0x1</value>
172 </enum>
173 </field>
174 <field>
175 <name>CPU2_TZ</name>
176 <desc>Trust Zone interrupt: when set, only a secured processor can modify the parameters for secured interrupts.</desc>
177 <position>8</position>
178 </field>
179 <field>
180 <name>CPU1_PRIO</name>
181 <desc>Interrupt priority</desc>
182 <position>6</position>
183 <width>2</width>
184 <enum>
185 <name>MASKED</name>
186 <desc>Interrupt is masked</desc>
187 <value>0x0</value>
188 </enum>
189 <enum>
190 <name>LOW</name>
191 <value>0x1</value>
192 </enum>
193 <enum>
194 <name>HIGH</name>
195 <value>0x2</value>
196 </enum>
197 <enum>
198 <name>NMI</name>
199 <desc>Interrupt is non maskable</desc>
200 <value>0x3</value>
201 </enum>
202 </field>
203 <field>
204 <name>CPU1_TYPE</name>
205 <desc>Interrupt type</desc>
206 <position>5</position>
207 <enum>
208 <name>IRQ</name>
209 <value>0x0</value>
210 </enum>
211 <enum>
212 <name>FIQ</name>
213 <value>0x1</value>
214 </enum>
215 </field>
216 <field>
217 <name>CPU1_TZ</name>
218 <desc>Trust Zone interrupt: when set, only a secured processor can modify the parameters for secured interrupts.</desc>
219 <position>4</position>
220 </field>
221 <field>
222 <name>CPU0_PRIO</name>
223 <desc>Interrupt priority</desc>
224 <position>2</position>
225 <width>2</width>
226 <enum>
227 <name>MASKED</name>
228 <desc>Interrupt will never be sent to the CPU</desc>
229 <value>0x0</value>
230 </enum>
231 <enum>
232 <name>LOW</name>
233 <value>0x1</value>
234 </enum>
235 <enum>
236 <name>HIGH</name>
237 <value>0x2</value>
238 </enum>
239 <enum>
240 <name>NMI</name>
241 <desc>Interrupt is non maskable</desc>
242 <value>0x3</value>
243 </enum>
244 </field>
245 <field>
246 <name>CPU0_TYPE</name>
247 <desc>Interrupt type</desc>
248 <position>1</position>
249 <enum>
250 <name>IRQ</name>
251 <value>0x0</value>
252 </enum>
253 <enum>
254 <name>FIQ</name>
255 <value>0x1</value>
256 </enum>
257 </field>
258 <field>
259 <name>CPU0_TZ</name>
260 <desc>Trust Zone interrupt: when set, only a secured processor can modify the parameters for secured interrupts.</desc>
261 <position>0</position>
262 </field>
263 <variant>
264 <type>set</type>
265 <offset>4</offset>
266 </variant>
267 <variant>
268 <type>clr</type>
269 <offset>8</offset>
270 </variant>
271 </register>
272 </node>
273 </node>
274 <node>
275 <name>gpio</name>
276 <title>GPIO controller</title>
277 <desc>A GPIO controller manages several ports.</desc>
278 <instance>
279 <name>CPU_GPIO</name>
280 <title>CPU GPIO controllers 1 through 7</title>
281 <range>
282 <first>1</first>
283 <count>8</count>
284 <formula variable="n">0x80001000+(n-1)*0x1000</formula>
285 </range>
286 </instance>
287 <node>
288 <name>port</name>
289 <title>GPIO port</title>
290 <instance>
291 <name>PORT</name>
292 <range>
293 <first>0</first>
294 <count>2</count>
295 <base>0x0</base>
296 <stride>0x100</stride>
297 </range>
298 </instance>
299 <node>
300 <name>input</name>
301 <title>Input register</title>
302 <instance>
303 <name>IN</name>
304 <address>0x0</address>
305 </instance>
306 <register>
307 <width>8</width>
308 <field>
309 <name>VALUE</name>
310 <position>0</position>
311 <width>8</width>
312 </field>
313 </register>
314 </node>
315 <node>
316 <name>output_enable</name>
317 <title>Output enable register</title>
318 <instance>
319 <name>OE</name>
320 <address>0x10</address>
321 </instance>
322 <register>
323 <width>8</width>
324 <field>
325 <name>ENABLE</name>
326 <position>0</position>
327 <width>8</width>
328 </field>
329 <variant>
330 <type>set</type>
331 <offset>4</offset>
332 </variant>
333 <variant>
334 <type>clr</type>
335 <offset>8</offset>
336 </variant>
337 <variant>
338 <type>mask</type>
339 <offset>12</offset>
340 </variant>
341 </register>
342 </node>
343 </node>
344 </node>
345 <node>
346 <name>tz</name>
347 <title>Trust Zone</title>
348 <instance>
349 <name>TZ</name>
350 <address>0xa0000000</address>
351 </instance>
352 <node>
353 <name>ctrl</name>
354 <title>Control Register</title>
355 <instance>
356 <name>CTRL</name>
357 <address>0x0</address>
358 </instance>
359 <register>
360 <width>8</width>
361 <field>
362 <name>SCRATCH</name>
363 <desc>TZ protected scratch value</desc>
364 <position>4</position>
365 <width>4</width>
366 </field>
367 <field>
368 <name>DISABLE</name>
369 <desc>One bit per CPU: set to 1 to prevent the processor from being able to enter TZ mode. Can only be set by a secured processor. By default all processors can enter TZ mode.</desc>
370 <position>0</position>
371 <width>4</width>
372 </field>
373 </register>
374 </node>
375 <node>
376 <name>debug</name>
377 <title>Debug register</title>
378 <instance>
379 <name>DEBUG</name>
380 <title>Debug register</title>
381 <desc>Don't touch it!</desc>
382 <range>
383 <first>42</first>
384 <address>0x50</address>
385 <address>0x60</address>
386 <address>0x90</address>
387 <address>0x110</address>
388 <address>0x130</address>
389 </range>
390 </instance>
391 <register>
392 <width>8</width>
393 </register>
394 </node>
395 </node>
396</soc>
diff --git a/utils/regtools/desc/spec-2.0.txt b/utils/regtools/desc/spec-2.0.txt
index 79b9f6be44..be97fbc41a 100644
--- a/utils/regtools/desc/spec-2.0.txt
+++ b/utils/regtools/desc/spec-2.0.txt
@@ -120,6 +120,23 @@ usual arithmetic operators. The example below illustrate such a use:
120 </instance> 120 </instance>
121</node> 121</node>
122 122
123In the case when the addresses do not follow a regular pattern or a formula would
124be too complicated, it is always possible to specify the addresses as a list:
125
126<node>
127 <name>N</name>
128 <instance>
129 <name>F</name>
130 <range>
131 <first>0</first>
132 <address>0x50</address>
133 <address>0x60</address>
134 <address>0x90</address>
135 <address>0x110</address>
136 </range>
137 </instance>
138</node>
139
123In this example we generate four nodes F[0], ..., F[3] with a formula. Here "/" 140In this example we generate four nodes F[0], ..., F[3] with a formula. Here "/"
124is the euclidian division and "%" is the modulo operator. Note the use of an 141is the euclidian division and "%" is the modulo operator. Note the use of an
125attribute to specify which variable represents the index. The generated addresses 142attribute to specify which variable represents the index. The generated addresses
@@ -177,6 +194,7 @@ and an optional description. The example below illustrates all these concepts:
177 194
178<register> 195<register>
179 <width>8</width> 196 <width>8</width>
197 <desc>This register controls the parameters of the interrupt: priority, IRQ/FIQ and enable</desc>
180 <field> 198 <field>
181 <name>MODE</name> 199 <name>MODE</name>
182 <desc>Interrupt mode</desc> 200 <desc>Interrupt mode</desc>
@@ -218,6 +236,10 @@ and an optional description. The example below illustrates all these concepts:
218 <value>1</value> 236 <value>1</value>
219 </enum> 237 </enum>
220 </field> 238 </field>
239 <variant>
240 <type>set</type>
241 <offset>0x4</offset>
242 </variant>
221</register> 243</register>
222 244
223In this example, the 8-bit registers has three fields: 245In this example, the 8-bit registers has three fields:
@@ -350,7 +372,15 @@ Element: register
350It can contain at most one of each of the following tags: 372It can contain at most one of each of the following tags:
351- width: width in bits (positive number) 373- width: width in bits (positive number)
352It can contain any number of the following tags: 374It can contain any number of the following tags:
375- desc: free form description of the register
353- field: field description 376- field: field description
377- variant: variant description
378
379Element: variant
380--------------
381It must contain the following tags:
382- type: name of type, only made of alphanumerical characters
383- offset: offset with respect to register address
354 384
355Element: field 385Element: field
356-------------- 386--------------
diff --git a/utils/regtools/include/soc_desc.hpp b/utils/regtools/include/soc_desc.hpp
index 66f2e3b6e1..f6c5cca28f 100644
--- a/utils/regtools/include/soc_desc.hpp
+++ b/utils/regtools/include/soc_desc.hpp
@@ -125,11 +125,30 @@ struct field_t
125 } 125 }
126}; 126};
127 127
128/** Register variant information
129 *
130 * A register variant provides an alternative access to the register, potentially
131 * we special semantics. Although there are no constraints on the type string,
132 * the following types have well-defined semantics:
133 * - alias: the same register at another address
134 * - set: writing to this register will set the 1s bits and ignore the 0s
135 * - clr: writing to this register will clear the 1s bits and ignore the 0s
136 * - tog: writing to this register will toggle the 1s bits and ignore the 0s
137 */
138struct variant_t
139{
140 soc_id_t id; /** ID (must be unique among register variants) */
141 std::string type; /** type of the variant */
142 soc_addr_t offset; /** offset of the variant */
143};
144
128/** Register information */ 145/** Register information */
129struct register_t 146struct register_t
130{ 147{
131 size_t width; /** Size in bits */ 148 size_t width; /** Size in bits */
149 std::string desc; /** Optional description of the register */
132 std::vector< field_t > field; /** List of fields */ 150 std::vector< field_t > field; /** List of fields */
151 std::vector< variant_t > variant; /** List of variants */
133}; 152};
134 153
135/** Node address range information */ 154/** Node address range information */
@@ -138,16 +157,24 @@ struct range_t
138 enum type_t 157 enum type_t
139 { 158 {
140 STRIDE, /** Addresses are given by a base address and a stride */ 159 STRIDE, /** Addresses are given by a base address and a stride */
141 FORMULA /** Addresses are given by a formula */ 160 FORMULA, /** Addresses are given by a formula */
161 LIST, /** Addresses are given by a list */
142 }; 162 };
143 163
144 type_t type; /** Range type */ 164 type_t type; /** Range type */
145 size_t first; /** First index in the range */ 165 size_t first; /** First index in the range */
146 size_t count; /** Number of indexes in the range */ 166 size_t count; /** Number of indexes in the range (for STRIDE and RANGE) */
147 soc_word_t base; /** Base address (for STRIDE) */ 167 soc_word_t base; /** Base address (for STRIDE) */
148 soc_word_t stride; /** Stride value (for STRIDE) */ 168 soc_word_t stride; /** Stride value (for STRIDE) */
149 std::string formula; /** Formula (for FORMULA) */ 169 std::string formula; /** Formula (for FORMULA) */
150 std::string variable; /** Formula variable name (for FORMULA) */ 170 std::string variable; /** Formula variable name (for FORMULA) */
171 std::vector< soc_word_t > list; /** Address list (for LIST) */
172
173 /** Return the number of indexes (based on count or list) */
174 size_t size()
175 {
176 return type == LIST ? list.size() : count;
177 }
151}; 178};
152 179
153/** Node instance information */ 180/** Node instance information */
@@ -197,6 +224,12 @@ bool parse_xml(const std::string& filename, soc_t& soc, error_context_t& error_c
197/** Write a SoC description to a XML file, overwriting it. A file can contain 224/** Write a SoC description to a XML file, overwriting it. A file can contain
198 * multiple Soc descriptions */ 225 * multiple Soc descriptions */
199bool produce_xml(const std::string& filename, const soc_t& soc, error_context_t& error_ctx); 226bool produce_xml(const std::string& filename, const soc_t& soc, error_context_t& error_ctx);
227/** Normalise a soc description by reordering elements so that:
228 * - nodes are sorted by lowest address of an instance
229 * - instances are sorted by lowest address
230 * - fields are sorted by last bit
231 * - enum are sorted by value */
232void normalize(soc_t& soc);
200/** Formula parser: try to parse and evaluate a formula with some variables */ 233/** Formula parser: try to parse and evaluate a formula with some variables */
201bool evaluate_formula(const std::string& formula, 234bool evaluate_formula(const std::string& formula,
202 const std::map< std::string, soc_word_t>& var, soc_word_t& result, 235 const std::map< std::string, soc_word_t>& var, soc_word_t& result,
@@ -219,6 +252,8 @@ class soc_ref_t;
219class node_ref_t; 252class node_ref_t;
220class register_ref_t; 253class register_ref_t;
221class field_ref_t; 254class field_ref_t;
255class enum_ref_t;
256class variant_ref_t;
222class node_inst_t; 257class node_inst_t;
223 258
224/** SoC reference */ 259/** SoC reference */
@@ -241,6 +276,9 @@ public:
241 /** Compare this reference to another */ 276 /** Compare this reference to another */
242 bool operator==(const soc_ref_t& r) const; 277 bool operator==(const soc_ref_t& r) const;
243 inline bool operator!=(const soc_ref_t& r) const { return !operator==(r); } 278 inline bool operator!=(const soc_ref_t& r) const { return !operator==(r); }
279 bool operator<(const soc_ref_t& r) const { return m_soc < r.m_soc; }
280 /** Make this reference invalid */
281 void reset();
244}; 282};
245 283
246/** SoC node reference 284/** SoC node reference
@@ -265,8 +303,10 @@ public:
265 node_t *get() const; 303 node_t *get() const;
266 /** Returns a reference to the soc */ 304 /** Returns a reference to the soc */
267 soc_ref_t soc() const; 305 soc_ref_t soc() const;
268 /** Returns a reference to the parent node */ 306 /** Returns a reference to the n-th parent node, 0-th is itself, 1-th is parent */
269 node_ref_t parent() const; 307 node_ref_t parent(unsigned level = 1) const;
308 /** Returns reference depth, root is 0, below root is 1 and so on */
309 unsigned depth() const;
270 /** Returns a reference to the register (which may be on a parent node) */ 310 /** Returns a reference to the register (which may be on a parent node) */
271 register_ref_t reg() const; 311 register_ref_t reg() const;
272 /** Returns a list of references to the sub-nodes */ 312 /** Returns a list of references to the sub-nodes */
@@ -280,6 +320,16 @@ public:
280 /** Compare this reference to another */ 320 /** Compare this reference to another */
281 bool operator==(const node_ref_t& r) const; 321 bool operator==(const node_ref_t& r) const;
282 inline bool operator!=(const node_ref_t& r) const { return !operator==(r); } 322 inline bool operator!=(const node_ref_t& r) const { return !operator==(r); }
323 /** Delete the node (and children) pointed by the reference, invalidating it
324 * NOTE: if reference points to the root node, deletes all nodes
325 * NOTE: does nothing if the reference is not valid */
326 void remove();
327 /** Create a new child node and returns a reference to it */
328 node_ref_t create() const;
329 /** Create a register and returns a reference to it */
330 register_ref_t create_reg(size_t width = 32) const;
331 /** Make this reference invalid */
332 void reset();
283}; 333};
284 334
285/** SoC register reference */ 335/** SoC register reference */
@@ -300,11 +350,24 @@ public:
300 node_ref_t node() const; 350 node_ref_t node() const;
301 /** Returns a list of references to the fields of the register */ 351 /** Returns a list of references to the fields of the register */
302 std::vector< field_ref_t > fields() const; 352 std::vector< field_ref_t > fields() const;
353 /** Returns a list of references to the variants of the register */
354 std::vector< variant_ref_t > variants() const;
303 /** Returns a reference to a particular field */ 355 /** Returns a reference to a particular field */
304 field_ref_t field(const std::string& name) const; 356 field_ref_t field(const std::string& name) const;
357 /** Returns a reference to a particular variant */
358 variant_ref_t variant(const std::string& type) const;
305 /** Compare this reference to another */ 359 /** Compare this reference to another */
306 bool operator==(const register_ref_t& r) const; 360 bool operator==(const register_ref_t& r) const;
307 inline bool operator!=(const register_ref_t& r) const { return !operator==(r); } 361 inline bool operator!=(const register_ref_t& r) const { return !operator==(r); }
362 /** Delete the register pointed by the reference, invalidating it
363 * NOTE: does nothing if the reference is not valid */
364 void remove();
365 /** Create a new field and returns a reference to it */
366 field_ref_t create_field() const;
367 /** Create a new variant and returns a reference to it */
368 variant_ref_t create_variant() const;
369 /** Make this reference invalid */
370 void reset();
308}; 371};
309 372
310/** SoC register field reference */ 373/** SoC register field reference */
@@ -312,7 +375,7 @@ class field_ref_t
312{ 375{
313 friend class register_ref_t; 376 friend class register_ref_t;
314 register_ref_t m_reg; /* reference to the register */ 377 register_ref_t m_reg; /* reference to the register */
315 soc_id_t m_id; /* field name */ 378 soc_id_t m_id; /* field id */
316 379
317 field_ref_t(register_ref_t reg, soc_id_t id); 380 field_ref_t(register_ref_t reg, soc_id_t id);
318public: 381public:
@@ -324,9 +387,67 @@ public:
324 field_t *get() const; 387 field_t *get() const;
325 /** Returns a reference to the register containing the field */ 388 /** Returns a reference to the register containing the field */
326 register_ref_t reg() const; 389 register_ref_t reg() const;
390 /** Returns a list of references to the enums of the field */
391 std::vector< enum_ref_t > enums() const;
392 /** Compare this reference to another */
393 bool operator==(const field_ref_t& r) const;
394 inline bool operator!=(const field_ref_t& r) const { return !operator==(r); }
395 /** Make this reference invalid */
396 void reset();
397 /** Create a new enum and returns a reference to it */
398 enum_ref_t create_enum() const;
399};
400
401/** SoC register field enum reference */
402class enum_ref_t
403{
404 friend class field_ref_t;
405 field_ref_t m_field; /* reference to the field */
406 soc_id_t m_id; /* enum id */
407
408 enum_ref_t(field_ref_t reg, soc_id_t id);
409public:
410 /** Builds an invalid reference */
411 enum_ref_t();
412 /** Check whether this reference is valid/exists */
413 bool valid() const;
414 /** Returns a pointer to the enum, or 0 */
415 enum_t *get() const;
416 /** Returns a reference to the field containing the enum */
417 field_ref_t field() const;
327 /** Compare this reference to another */ 418 /** Compare this reference to another */
328 bool operator==(const field_ref_t& r) const; 419 bool operator==(const field_ref_t& r) const;
329 inline bool operator!=(const field_ref_t& r) const { return !operator==(r); } 420 inline bool operator!=(const field_ref_t& r) const { return !operator==(r); }
421 /** Make this reference invalid */
422 void reset();
423};
424
425/** SoC register variant reference */
426class variant_ref_t
427{
428 friend class register_ref_t;
429 register_ref_t m_reg; /* reference to the register */
430 soc_id_t m_id; /* variant name */
431
432 variant_ref_t(register_ref_t reg, soc_id_t id);
433public:
434 /** Builds an invalid reference */
435 variant_ref_t();
436 /** Check whether this reference is valid/exists */
437 bool valid() const;
438 /** Returns a pointer to the variant, or 0 */
439 variant_t *get() const;
440 /** Returns a reference to the register containing the field */
441 register_ref_t reg() const;
442 /** Returns variant type */
443 std::string type() const;
444 /** Returns variant offset */
445 soc_word_t offset() const;
446 /** Compare this reference to another */
447 bool operator==(const variant_ref_t& r) const;
448 inline bool operator!=(const variant_ref_t& r) const { return !operator==(r); }
449 /** Make this reference invalid */
450 void reset();
330}; 451};
331 452
332/** SoC node instance 453/** SoC node instance
@@ -353,8 +474,10 @@ public:
353 node_ref_t node() const; 474 node_ref_t node() const;
354 /** Check whether this reference is the root node instance */ 475 /** Check whether this reference is the root node instance */
355 bool is_root() const; 476 bool is_root() const;
356 /** Returns a reference to the parent instance */ 477 /** Returns a reference to the n-th parent instance, 0-th is itself, and so on */
357 node_inst_t parent() const; 478 node_inst_t parent(unsigned level = 1) const;
479 /** Returns reference depth, 0 is root, and so on */
480 unsigned depth() const;
358 /** Returns a pointer to the instance of the node, or 0 */ 481 /** Returns a pointer to the instance of the node, or 0 */
359 instance_t *get() const; 482 instance_t *get() const;
360 /** Returns the address of this instance */ 483 /** Returns the address of this instance */
@@ -377,6 +500,8 @@ public:
377 /** Compare this reference to another */ 500 /** Compare this reference to another */
378 bool operator==(const node_inst_t& r) const; 501 bool operator==(const node_inst_t& r) const;
379 inline bool operator!=(const node_inst_t& r) const { return !operator==(r); } 502 inline bool operator!=(const node_inst_t& r) const { return !operator==(r); }
503 /** Make this reference invalid */
504 void reset();
380}; 505};
381 506
382} // soc_desc 507} // soc_desc
diff --git a/utils/regtools/include/soc_desc_v1.hpp b/utils/regtools/include/soc_desc_v1.hpp
index 33368e88d4..b9185e35dd 100644
--- a/utils/regtools/include/soc_desc_v1.hpp
+++ b/utils/regtools/include/soc_desc_v1.hpp
@@ -214,7 +214,7 @@ bool parse_xml(const std::string& filename, soc_t& soc);
214/** Write a SoC description to a XML file, overwriting it. A file can contain 214/** Write a SoC description to a XML file, overwriting it. A file can contain
215 * multiple Soc descriptions */ 215 * multiple Soc descriptions */
216bool produce_xml(const std::string& filename, const soc_t& soc); 216bool produce_xml(const std::string& filename, const soc_t& soc);
217/** Normalise a soc description by reordering elemnts so that: 217/** Normalise a soc description by reordering elements so that:
218 * - devices are sorted by first name 218 * - devices are sorted by first name
219 * - registers are sorted by first address 219 * - registers are sorted by first address
220 * - fields are sorted by last bit 220 * - fields are sorted by last bit
diff --git a/utils/regtools/lib/soc_desc.cpp b/utils/regtools/lib/soc_desc.cpp
index 4e0e46f00e..e6c58d4814 100644
--- a/utils/regtools/lib/soc_desc.cpp
+++ b/utils/regtools/lib/soc_desc.cpp
@@ -308,13 +308,28 @@ bool parse_field_elem(xmlNode *node, field_t& field, error_context_t& ctx)
308 return ret; 308 return ret;
309} 309}
310 310
311bool parse_variant_elem(xmlNode *node, variant_t& variant, error_context_t& ctx)
312{
313 bool ret = true;
314 bool has_type = false, has_offset = false;
315 BEGIN_NODE_MATCH(node->children)
316 MATCH_UNIQUE_TEXT_NODE("type", variant.type, has_type, parse_name_elem, ctx)
317 MATCH_UNIQUE_TEXT_NODE("offset", variant.offset, has_offset, parse_unsigned_elem, ctx)
318 END_NODE_MATCH()
319 CHECK_HAS(node, "type", has_type, ctx)
320 CHECK_HAS(node, "offset", has_offset, ctx)
321 return ret;
322}
323
311bool parse_register_elem(xmlNode *node, register_t& reg, error_context_t& ctx) 324bool parse_register_elem(xmlNode *node, register_t& reg, error_context_t& ctx)
312{ 325{
313 bool ret = true; 326 bool ret = true;
314 bool has_width = false; 327 bool has_width = false, has_desc = false;
315 BEGIN_NODE_MATCH(node->children) 328 BEGIN_NODE_MATCH(node->children)
329 MATCH_UNIQUE_TEXT_NODE("desc", reg.desc, has_desc, parse_text_elem, ctx)
316 MATCH_UNIQUE_TEXT_NODE("width", reg.width, has_width, parse_unsigned_elem, ctx) 330 MATCH_UNIQUE_TEXT_NODE("width", reg.width, has_width, parse_unsigned_elem, ctx)
317 MATCH_ELEM_NODE("field", reg.field, parse_field_elem, ctx) 331 MATCH_ELEM_NODE("field", reg.field, parse_field_elem, ctx)
332 MATCH_ELEM_NODE("variant", reg.variant, parse_variant_elem, ctx)
318 END_NODE_MATCH() 333 END_NODE_MATCH()
319 if(!has_width) 334 if(!has_width)
320 reg.width = 32; 335 reg.width = 32;
@@ -344,21 +359,37 @@ bool parse_range_elem(xmlNode *node, range_t& range, error_context_t& ctx)
344 MATCH_UNIQUE_TEXT_NODE("stride", range.stride, has_stride, parse_unsigned_elem, ctx) 359 MATCH_UNIQUE_TEXT_NODE("stride", range.stride, has_stride, parse_unsigned_elem, ctx)
345 MATCH_UNIQUE_ELEM_NODE("formula", range, has_formula_attr, parse_formula_elem, ctx) 360 MATCH_UNIQUE_ELEM_NODE("formula", range, has_formula_attr, parse_formula_elem, ctx)
346 MATCH_UNIQUE_TEXT_NODE("formula", range.formula, has_formula, parse_text_elem, ctx) 361 MATCH_UNIQUE_TEXT_NODE("formula", range.formula, has_formula, parse_text_elem, ctx)
362 MATCH_TEXT_NODE("address", range.list, parse_unsigned_elem, ctx)
347 END_NODE_MATCH() 363 END_NODE_MATCH()
348 CHECK_HAS(node, "first", has_first, ctx) 364 CHECK_HAS(node, "first", has_first, ctx)
349 CHECK_HAS(node, "count", has_count, ctx) 365 if(range.list.size() == 0)
350 if(!has_base && !has_formula) 366 {
351 ret = ret && parse_missing_error(node, "base> or <formula", ctx); 367 CHECK_HAS(node, "count", has_count, ctx)
352 if(has_base && has_formula) 368 if(!has_base && !has_formula)
353 return parse_conflict_error(node, "base", "formula", ctx); 369 ret = ret && parse_missing_error(node, "base> or <formula", ctx);
354 if(has_base) 370 if(has_base && has_formula)
355 CHECK_HAS(node, "stride", has_stride, ctx) 371 return parse_conflict_error(node, "base", "formula", ctx);
356 if(has_stride && !has_base) 372 if(has_base)
357 ret = ret && parse_conflict_error(node, "stride", "formula", ctx); 373 CHECK_HAS(node, "stride", has_stride, ctx)
358 if(has_stride) 374 if(has_stride && !has_base)
359 range.type = range_t::STRIDE; 375 ret = ret && parse_conflict_error(node, "stride", "formula", ctx);
376 if(has_stride)
377 range.type = range_t::STRIDE;
378 else
379 range.type = range_t::FORMULA;
380 }
360 else 381 else
361 range.type = range_t::FORMULA; 382 {
383 if(has_base)
384 ret = ret && parse_conflict_error(node, "base", "addr", ctx);
385 if(has_count)
386 ret = ret && parse_conflict_error(node, "count", "addr", ctx);
387 if(has_formula)
388 ret = ret && parse_conflict_error(node, "formula", "addr", ctx);
389 if(has_stride)
390 ret = ret && parse_conflict_error(node, "stride", "addr", ctx);
391 range.type = range_t::LIST;
392 }
362 return ret; 393 return ret;
363} 394}
364 395
@@ -400,7 +431,6 @@ bool parse_node_elem(xmlNode *node_, node_t& node, error_context_t& ctx)
400 MATCH_ELEM_NODE("instance", node.instance, parse_instance_elem, ctx) 431 MATCH_ELEM_NODE("instance", node.instance, parse_instance_elem, ctx)
401 END_NODE_MATCH() 432 END_NODE_MATCH()
402 CHECK_HAS(node_, "name", has_name, ctx) 433 CHECK_HAS(node_, "name", has_name, ctx)
403 CHECK_HAS(node_, "instance", !node.instance.empty(), ctx)
404 if(has_register) 434 if(has_register)
405 node.register_.push_back(reg); 435 node.register_.push_back(reg);
406 return ret; 436 return ret;
@@ -466,6 +496,93 @@ bool parse_xml(const std::string& filename, soc_t& soc,
466} 496}
467 497
468/** 498/**
499 * Normalizer
500 */
501
502namespace
503{
504
505struct soc_sorter
506{
507 /* returns the first (lowest) address of an instance */
508 soc_addr_t first_addr(const instance_t& inst) const
509 {
510 if(inst.type == instance_t::SINGLE)
511 return inst.addr;
512 if(inst.range.type == range_t::STRIDE)
513 return inst.range.base;
514 soc_word_t res;
515 std::map< std::string, soc_word_t > vars;
516 vars[inst.range.variable] = inst.range.first;
517 error_context_t ctx;
518 if(!evaluate_formula(inst.range.formula, vars, res, "", ctx))
519 return 0xffffffff;
520 return res;
521 }
522
523 /* sort instances by first address */
524 bool operator()(const instance_t& a, const instance_t& b) const
525 {
526 return first_addr(a) < first_addr(b);
527 }
528
529 /* sort nodes by first address of first instance (which is the lowest of
530 * any instance if instances are sorted) */
531 bool operator()(const node_t& a, const node_t& b) const
532 {
533 /* borderline cases: no instances is lower than with instances */
534 if(a.instance.size() == 0)
535 return b.instance.size() > 0;
536 if(b.instance.size() == 0)
537 return false;
538 return first_addr(a.instance[0]) < first_addr(b.instance[0]);
539 }
540
541 /* sort fields by decreasing position */
542 bool operator()(const field_t& a, const field_t& b) const
543 {
544 return a.pos > b.pos;
545 }
546
547 /* sort enum values by value */
548 bool operator()(const enum_t& a, const enum_t& b) const
549 {
550 return a.value < b.value;
551 }
552};
553
554void normalize(field_t& field)
555{
556 std::sort(field.enum_.begin(), field.enum_.end(), soc_sorter());
557}
558
559void normalize(register_t& reg)
560{
561 for(size_t i = 0; i < reg.field.size(); i++)
562 normalize(reg.field[i]);
563 std::sort(reg.field.begin(), reg.field.end(), soc_sorter());
564}
565
566void normalize(node_t& node)
567{
568 for(size_t i = 0; i < node.register_.size(); i++)
569 normalize(node.register_[i]);
570 for(size_t i = 0; i < node.node.size(); i++)
571 normalize(node.node[i]);
572 std::sort(node.node.begin(), node.node.end(), soc_sorter());
573 std::sort(node.instance.begin(), node.instance.end(), soc_sorter());
574}
575
576}
577
578void normalize(soc_t& soc)
579{
580 for(size_t i = 0; i < soc.node.size(); i++)
581 normalize(soc.node[i]);
582 std::sort(soc.node.begin(), soc.node.end(), soc_sorter());
583}
584
585/**
469 * Producer 586 * Producer
470 */ 587 */
471 588
@@ -488,17 +605,20 @@ int produce_range(xmlTextWriterPtr writer, const range_t& range, error_context_t
488 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "range")); 605 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "range"));
489 /* <first/> */ 606 /* <first/> */
490 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "first", "%lu", range.first)); 607 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "first", "%lu", range.first));
491 /* <count/> */
492 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "count", "%lu", range.count));
493 /* <base/><stride/> */
494 if(range.type == range_t::STRIDE) 608 if(range.type == range_t::STRIDE)
495 { 609 {
610 /* <count/> */
611 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "count", "%lu", range.count));
612 /* <base/> */
496 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "base", "0x%x", range.base)); 613 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "base", "0x%x", range.base));
614 /* <stride/> */
497 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "stride", "0x%x", range.stride)); 615 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "stride", "0x%x", range.stride));
498 } 616 }
499 /* <formula> */ 617 /* <formula> */
500 else if(range.type == range_t::FORMULA) 618 else if(range.type == range_t::FORMULA)
501 { 619 {
620 /* <count/> */
621 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "count", "%lu", range.count));
502 /* <formula> */ 622 /* <formula> */
503 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "formula")); 623 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "formula"));
504 /* variable */ 624 /* variable */
@@ -508,6 +628,11 @@ int produce_range(xmlTextWriterPtr writer, const range_t& range, error_context_t
508 /* </formula> */ 628 /* </formula> */
509 SAFE(xmlTextWriterEndElement(writer)); 629 SAFE(xmlTextWriterEndElement(writer));
510 } 630 }
631 else if(range.type == range_t::LIST)
632 {
633 for(size_t i = 0; i < range.list.size(); i++)
634 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "address", "0x%x", range.list[i]));
635 }
511 /* </range> */ 636 /* </range> */
512 SAFE(xmlTextWriterEndElement(writer)); 637 SAFE(xmlTextWriterEndElement(writer));
513 638
@@ -575,6 +700,19 @@ int produce_field(xmlTextWriterPtr writer, const field_t& field, error_context_t
575 return 0; 700 return 0;
576} 701}
577 702
703int produce_variant(xmlTextWriterPtr writer, const variant_t& variant, error_context_t& ctx)
704{
705 /* <variant> */
706 SAFE(xmlTextWriterStartElement(writer, BAD_CAST "variant"));
707 /* <name/> */
708 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "type", BAD_CAST variant.type.c_str()));
709 /* <position/> */
710 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "offset", "%lu", (unsigned long)variant.offset));
711 /* </variant> */
712 SAFE(xmlTextWriterEndElement(writer));
713 return 0;
714}
715
578int produce_register(xmlTextWriterPtr writer, const register_t& reg, error_context_t& ctx) 716int produce_register(xmlTextWriterPtr writer, const register_t& reg, error_context_t& ctx)
579{ 717{
580 /* <register> */ 718 /* <register> */
@@ -582,9 +720,15 @@ int produce_register(xmlTextWriterPtr writer, const register_t& reg, error_conte
582 /* <width/> */ 720 /* <width/> */
583 if(reg.width != 32) 721 if(reg.width != 32)
584 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "width", "%lu", reg.width)); 722 SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "width", "%lu", reg.width));
723 /* <desc/> */
724 if(!reg.desc.empty())
725 SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "desc", BAD_CAST reg.desc.c_str()));
585 /* fields */ 726 /* fields */
586 for(size_t i = 0; i < reg.field.size(); i++) 727 for(size_t i = 0; i < reg.field.size(); i++)
587 SAFE(produce_field(writer, reg.field[i], ctx)); 728 SAFE(produce_field(writer, reg.field[i], ctx));
729 /* variants */
730 for(size_t i = 0; i < reg.variant.size(); i++)
731 SAFE(produce_variant(writer, reg.variant[i], ctx));
588 /* </register> */ 732 /* </register> */
589 SAFE(xmlTextWriterEndElement(writer)); 733 SAFE(xmlTextWriterEndElement(writer));
590 return 0; 734 return 0;
@@ -671,6 +815,24 @@ Lerr:
671} 815}
672 816
673/** 817/**
818 * utils
819 */
820
821namespace
822{
823
824template< typename T >
825soc_id_t gen_fresh_id(const std::vector< T >& list)
826{
827 soc_id_t id = 0;
828 for(size_t i = 0; i < list.size(); i++)
829 id = std::max(id, list[i].id);
830 return id + 1;
831}
832
833}
834
835/**
674 * soc_ref_t 836 * soc_ref_t
675 */ 837 */
676 838
@@ -707,6 +869,11 @@ node_inst_t soc_ref_t::root_inst() const
707 return node_inst_t(*this); 869 return node_inst_t(*this);
708} 870}
709 871
872void soc_ref_t::reset()
873{
874 m_soc = 0;
875}
876
710/** 877/**
711 * node_ref_t */ 878 * node_ref_t */
712 879
@@ -733,6 +900,11 @@ bool node_ref_t::is_root() const
733 return m_path.empty(); 900 return m_path.empty();
734} 901}
735 902
903void node_ref_t::reset()
904{
905 m_soc.reset();
906}
907
736namespace 908namespace
737{ 909{
738 910
@@ -789,14 +961,20 @@ soc_ref_t node_ref_t::soc() const
789 return m_soc; 961 return m_soc;
790} 962}
791 963
792node_ref_t node_ref_t::parent() const 964node_ref_t node_ref_t::parent(unsigned level) const
793{ 965{
966 if(level > depth())
967 return node_ref_t();
794 std::vector< soc_id_t > path = m_path; 968 std::vector< soc_id_t > path = m_path;
795 if(!path.empty()) 969 path.resize(depth() - level);
796 path.pop_back();
797 return node_ref_t(m_soc, path); 970 return node_ref_t(m_soc, path);
798} 971}
799 972
973unsigned node_ref_t::depth() const
974{
975 return m_path.size();
976}
977
800register_ref_t node_ref_t::reg() const 978register_ref_t node_ref_t::reg() const
801{ 979{
802 node_t *n = get(); 980 node_t *n = get();
@@ -808,6 +986,18 @@ register_ref_t node_ref_t::reg() const
808 return register_ref_t(*this); 986 return register_ref_t(*this);
809} 987}
810 988
989register_ref_t node_ref_t::create_reg(size_t width) const
990{
991 node_t *n = get();
992 if(n == 0)
993 return register_ref_t();
994 if(!n->register_.empty())
995 return register_ref_t();
996 n->register_.resize(1);
997 n->register_[0].width = width;
998 return register_ref_t(*this);
999}
1000
811node_ref_t node_ref_t::child(const std::string& name) const 1001node_ref_t node_ref_t::child(const std::string& name) const
812{ 1002{
813 /* check the node exists */ 1003 /* check the node exists */
@@ -867,6 +1057,41 @@ bool node_ref_t::operator==(const node_ref_t& ref) const
867 return m_soc == ref.m_soc && m_path == ref.m_path; 1057 return m_soc == ref.m_soc && m_path == ref.m_path;
868} 1058}
869 1059
1060void node_ref_t::remove()
1061{
1062 if(is_root())
1063 {
1064 soc_t *s = soc().get();
1065 if(s)
1066 s->node.clear();
1067 }
1068 else
1069 {
1070 std::vector< node_t > *list = get_children(parent());
1071 if(list == 0)
1072 return;
1073 for(size_t i = 0; i < list->size(); i++)
1074 if((*list)[i].id == m_path.back())
1075 {
1076 list->erase(list->begin() + i);
1077 return;
1078 }
1079 }
1080}
1081
1082node_ref_t node_ref_t::create() const
1083{
1084 std::vector< node_t > *list = get_children(*this);
1085 if(list == 0)
1086 return node_ref_t();
1087 node_t n;
1088 n.id = gen_fresh_id(*list);
1089 list->push_back(n);
1090 std::vector< soc_id_t > path = m_path;
1091 path.push_back(n.id);
1092 return node_ref_t(soc(), path);
1093}
1094
870/** 1095/**
871 * register_ref_t 1096 * register_ref_t
872 */ 1097 */
@@ -885,6 +1110,11 @@ bool register_ref_t::valid() const
885 return get() != 0; 1110 return get() != 0;
886} 1111}
887 1112
1113void register_ref_t::reset()
1114{
1115 m_node.reset();
1116}
1117
888register_t *register_ref_t::get() const 1118register_t *register_ref_t::get() const
889{ 1119{
890 node_t *n = m_node.get(); 1120 node_t *n = m_node.get();
@@ -909,6 +1139,17 @@ std::vector< field_ref_t > register_ref_t::fields() const
909 return fields; 1139 return fields;
910} 1140}
911 1141
1142std::vector< variant_ref_t > register_ref_t::variants() const
1143{
1144 std::vector< variant_ref_t > variants;
1145 register_t *r = get();
1146 if(r == 0)
1147 return variants;
1148 for(size_t i = 0; i < r->variant.size(); i++)
1149 variants.push_back(variant_ref_t(*this, r->variant[i].id));
1150 return variants;
1151}
1152
912field_ref_t register_ref_t::field(const std::string& name) const 1153field_ref_t register_ref_t::field(const std::string& name) const
913{ 1154{
914 register_t *r = get(); 1155 register_t *r = get();
@@ -920,6 +1161,46 @@ field_ref_t register_ref_t::field(const std::string& name) const
920 return field_ref_t(); 1161 return field_ref_t();
921} 1162}
922 1163
1164variant_ref_t register_ref_t::variant(const std::string& type) const
1165{
1166 register_t *r = get();
1167 if(r == 0)
1168 return variant_ref_t();
1169 for(size_t i = 0; i < r->variant.size(); i++)
1170 if(r->variant[i].type == type)
1171 return variant_ref_t(*this, r->variant[i].id);
1172 return variant_ref_t();
1173}
1174
1175void register_ref_t::remove()
1176{
1177 node_t *n = node().get();
1178 if(n)
1179 n->register_.clear();
1180}
1181
1182field_ref_t register_ref_t::create_field() const
1183{
1184 register_t *r = get();
1185 if(r == 0)
1186 return field_ref_t();
1187 field_t f;
1188 f.id = gen_fresh_id(r->field);
1189 r->field.push_back(f);
1190 return field_ref_t(*this, f.id);
1191}
1192
1193variant_ref_t register_ref_t::create_variant() const
1194{
1195 register_t *r = get();
1196 if(r == 0)
1197 return variant_ref_t();
1198 variant_t v;
1199 v.id = gen_fresh_id(r->variant);
1200 r->variant.push_back(v);
1201 return variant_ref_t(*this, v.id);
1202}
1203
923/** 1204/**
924 * field_ref_t 1205 * field_ref_t
925 */ 1206 */
@@ -938,6 +1219,11 @@ bool field_ref_t::valid() const
938 return get() != 0; 1219 return get() != 0;
939} 1220}
940 1221
1222void field_ref_t::reset()
1223{
1224 m_reg.reset();
1225}
1226
941field_t *field_ref_t::get() const 1227field_t *field_ref_t::get() const
942{ 1228{
943 register_t *reg = m_reg.get(); 1229 register_t *reg = m_reg.get();
@@ -949,11 +1235,123 @@ field_t *field_ref_t::get() const
949 return 0; 1235 return 0;
950} 1236}
951 1237
1238std::vector< enum_ref_t > field_ref_t::enums() const
1239{
1240 std::vector< enum_ref_t > enums;
1241 field_t *f = get();
1242 if(f == 0)
1243 return enums;
1244 for(size_t i = 0; i < f->enum_.size(); i++)
1245 enums.push_back(enum_ref_t(*this, f->enum_[i].id));
1246 return enums;
1247}
1248
952register_ref_t field_ref_t::reg() const 1249register_ref_t field_ref_t::reg() const
953{ 1250{
954 return m_reg; 1251 return m_reg;
955} 1252}
956 1253
1254enum_ref_t field_ref_t::create_enum() const
1255{
1256 field_t *f = get();
1257 if(f == 0)
1258 return enum_ref_t();
1259 enum_t e;
1260 e.id = gen_fresh_id(f->enum_);
1261 f->enum_.push_back(e);
1262 return enum_ref_t(*this, e.id);
1263}
1264
1265/**
1266 * enum_ref_t
1267 */
1268
1269enum_ref_t::enum_ref_t(field_ref_t field, soc_id_t id)
1270 :m_field(field), m_id(id)
1271{
1272}
1273
1274enum_ref_t::enum_ref_t()
1275{
1276}
1277
1278bool enum_ref_t::valid() const
1279{
1280 return get() != 0;
1281}
1282
1283void enum_ref_t::reset()
1284{
1285 m_field.reset();
1286}
1287
1288enum_t *enum_ref_t::get() const
1289{
1290 field_t *field = m_field.get();
1291 if(field == 0)
1292 return 0;
1293 for(size_t i = 0; i < field->enum_.size(); i++)
1294 if(field->enum_[i].id == m_id)
1295 return &field->enum_[i];
1296 return 0;
1297}
1298
1299field_ref_t enum_ref_t::field() const
1300{
1301 return m_field;
1302}
1303
1304/**
1305 * variant_ref_t
1306 */
1307
1308variant_ref_t::variant_ref_t(register_ref_t reg, soc_id_t id)
1309 :m_reg(reg), m_id(id)
1310{
1311}
1312
1313variant_ref_t::variant_ref_t()
1314{
1315}
1316
1317bool variant_ref_t::valid() const
1318{
1319 return get() != 0;
1320}
1321
1322void variant_ref_t::reset()
1323{
1324 m_reg.reset();
1325}
1326
1327variant_t *variant_ref_t::get() const
1328{
1329 register_t *reg = m_reg.get();
1330 if(reg == 0)
1331 return 0;
1332 for(size_t i = 0; i < reg->variant.size(); i++)
1333 if(reg->variant[i].id == m_id)
1334 return &reg->variant[i];
1335 return 0;
1336}
1337
1338register_ref_t variant_ref_t::reg() const
1339{
1340 return m_reg;
1341}
1342
1343std::string variant_ref_t::type() const
1344{
1345 variant_t *v = get();
1346 return v ? v->type : std::string();
1347}
1348
1349soc_word_t variant_ref_t::offset() const
1350{
1351 variant_t *v = get();
1352 return v ? v->offset : 0;
1353}
1354
957/** 1355/**
958 * node_inst_t 1356 * node_inst_t
959 */ 1357 */
@@ -965,8 +1363,8 @@ const size_t INST_NO_INDEX = std::numeric_limits<std::size_t>::max();
965 1363
966bool get_inst_addr(range_t& range, size_t index, soc_addr_t& addr) 1364bool get_inst_addr(range_t& range, size_t index, soc_addr_t& addr)
967{ 1365{
968 if(index < range.first || index >= range.first + range.count) 1366 if(index < range.first || index >= range.first + range.size())
969 return false; 1367 return false;
970 switch(range.type) 1368 switch(range.type)
971 { 1369 {
972 case range_t::STRIDE: 1370 case range_t::STRIDE:
@@ -983,6 +1381,9 @@ bool get_inst_addr(range_t& range, size_t index, soc_addr_t& addr)
983 addr += res; 1381 addr += res;
984 return true; 1382 return true;
985 } 1383 }
1384 case range_t::LIST:
1385 addr += range.list[index - range.first];
1386 return true;
986 default: 1387 default:
987 return false; 1388 return false;
988 } 1389 }
@@ -1030,6 +1431,11 @@ bool node_inst_t::valid() const
1030 return is_root() || get() != 0; 1431 return is_root() || get() != 0;
1031} 1432}
1032 1433
1434void node_inst_t::reset()
1435{
1436 m_node.reset();
1437}
1438
1033node_ref_t node_inst_t::node() const 1439node_ref_t node_inst_t::node() const
1034{ 1440{
1035 return m_node; 1441 return m_node;
@@ -1045,15 +1451,20 @@ bool node_inst_t::is_root() const
1045 return m_node.is_root(); 1451 return m_node.is_root();
1046} 1452}
1047 1453
1048node_inst_t node_inst_t::parent() const 1454node_inst_t node_inst_t::parent(unsigned level) const
1049{ 1455{
1456 if(level > depth())
1457 return node_inst_t();
1050 std::vector< soc_id_t > ids = m_id_path; 1458 std::vector< soc_id_t > ids = m_id_path;
1051 std::vector< size_t > indexes = m_index_path; 1459 std::vector< size_t > indexes = m_index_path;
1052 if(!ids.empty()) 1460 ids.resize(depth() - level);
1053 ids.pop_back(); 1461 indexes.resize(depth() - level);
1054 if(!indexes.empty()) 1462 return node_inst_t(m_node.parent(level), ids, indexes);
1055 indexes.pop_back(); 1463}
1056 return node_inst_t(m_node.parent(), ids, indexes); 1464
1465unsigned node_inst_t::depth() const
1466{
1467 return m_id_path.size();
1057} 1468}
1058 1469
1059instance_t *node_inst_t::get() const 1470instance_t *node_inst_t::get() const
@@ -1069,7 +1480,7 @@ instance_t *node_inst_t::get() const
1069 1480
1070soc_addr_t node_inst_t::addr() const 1481soc_addr_t node_inst_t::addr() const
1071{ 1482{
1072 if(is_root()) 1483 if(!valid() || is_root())
1073 return 0; 1484 return 0;
1074 soc_addr_t addr = parent().addr(); 1485 soc_addr_t addr = parent().addr();
1075 if(!get_inst_addr(get(), m_index_path.back(), addr)) 1486 if(!get_inst_addr(get(), m_index_path.back(), addr))
@@ -1100,7 +1511,7 @@ node_inst_t node_inst_t::child(const std::string& name, size_t index) const
1100 std::vector< soc_id_t > ids = m_id_path; 1511 std::vector< soc_id_t > ids = m_id_path;
1101 std::vector< size_t > indexes = m_index_path; 1512 std::vector< size_t > indexes = m_index_path;
1102 ids.push_back(node.instance[j].id); 1513 ids.push_back(node.instance[j].id);
1103 ids.push_back(index); 1514 indexes.push_back(index);
1104 return node_inst_t(child_node, ids, indexes); 1515 return node_inst_t(child_node, ids, indexes);
1105 } 1516 }
1106 child_node.m_path.pop_back(); 1517 child_node.m_path.pop_back();
@@ -1133,7 +1544,7 @@ std::vector< node_inst_t > node_inst_t::children() const
1133 i_path.pop_back(); 1544 i_path.pop_back();
1134 break; 1545 break;
1135 case instance_t::RANGE: 1546 case instance_t::RANGE:
1136 for(size_t i = 0; i < inst.range.count; i++) 1547 for(size_t i = 0; i < inst.range.size(); i++)
1137 { 1548 {
1138 i_path.push_back(inst.range.first + i); 1549 i_path.push_back(inst.range.first + i);
1139 list.push_back(node_inst_t(child_node, n_path, i_path)); 1550 list.push_back(node_inst_t(child_node, n_path, i_path));
diff --git a/utils/regtools/swiss_knife.cpp b/utils/regtools/swiss_knife.cpp
index eaa2519a27..fb65b5ca24 100644
--- a/utils/regtools/swiss_knife.cpp
+++ b/utils/regtools/swiss_knife.cpp
@@ -20,11 +20,14 @@
20 ****************************************************************************/ 20 ****************************************************************************/
21#include "soc_desc.hpp" 21#include "soc_desc.hpp"
22#include "soc_desc_v1.hpp" 22#include "soc_desc_v1.hpp"
23#include <stdio.h> 23#include <cstdio>
24#include <stdlib.h> 24#include <cstdlib>
25#include <map> 25#include <map>
26#include <set> 26#include <set>
27#include <cstring> 27#include <cstring>
28#include <fstream>
29#include <sstream>
30#include <cstring>
28 31
29using namespace soc_desc; 32using namespace soc_desc;
30 33
@@ -88,7 +91,6 @@ bool convert_v1_to_v2(const soc_desc_v1::soc_reg_t& in, node_t& out, error_conte
88{ 91{
89 std::string loc = _loc + "." + in.name; 92 std::string loc = _loc + "." + in.name;
90 out.name = in.name; 93 out.name = in.name;
91 out.desc = in.desc;
92 if(in.formula.type == soc_desc_v1::REG_FORMULA_NONE) 94 if(in.formula.type == soc_desc_v1::REG_FORMULA_NONE)
93 { 95 {
94 out.instance.resize(in.addr.size()); 96 out.instance.resize(in.addr.size());
@@ -133,6 +135,7 @@ bool convert_v1_to_v2(const soc_desc_v1::soc_reg_t& in, node_t& out, error_conte
133 } 135 }
134 out.register_.resize(1); 136 out.register_.resize(1);
135 out.register_[0].width = 32; 137 out.register_[0].width = 32;
138 out.register_[0].desc = in.desc;
136 out.register_[0].field.resize(in.field.size()); 139 out.register_[0].field.resize(in.field.size());
137 for(size_t i = 0; i < in.field.size(); i++) 140 for(size_t i = 0; i < in.field.size(); i++)
138 if(!convert_v1_to_v2(in.field[i], out.register_[0].field[i], ctx)) 141 if(!convert_v1_to_v2(in.field[i], out.register_[0].field[i], ctx))
@@ -140,15 +143,12 @@ bool convert_v1_to_v2(const soc_desc_v1::soc_reg_t& in, node_t& out, error_conte
140 /* sct */ 143 /* sct */
141 if(in.flags & soc_desc_v1::REG_HAS_SCT) 144 if(in.flags & soc_desc_v1::REG_HAS_SCT)
142 { 145 {
143 out.node.resize(1); 146 out.register_[0].variant.resize(3);
144 out.node[0].name = "SCT"; 147 const char *names[3] = {"set", "clr", "tog"};
145 out.node[0].instance.resize(3);
146 const char *names[3] = {"SET", "CLR", "TOG"};
147 for(size_t i = 0; i < 3; i++) 148 for(size_t i = 0; i < 3; i++)
148 { 149 {
149 out.node[0].instance[i].name = names[i]; 150 out.register_[0].variant[i].type = names[i];
150 out.node[0].instance[i].type = instance_t::SINGLE; 151 out.register_[0].variant[i].offset = 4 + i *4;
151 out.node[0].instance[i].addr = 4 + i *4;
152 } 152 }
153 } 153 }
154 return true; 154 return true;
@@ -171,10 +171,23 @@ bool convert_v1_to_v2(const soc_desc_v1::soc_dev_t& in, node_t& out, error_conte
171 out.name = in.name; 171 out.name = in.name;
172 out.title = in.long_name; 172 out.title = in.long_name;
173 out.desc = in.desc; 173 out.desc = in.desc;
174 out.instance.resize(in.addr.size()); 174 out.instance.resize(1);
175 for(size_t i = 0; i < in.addr.size(); i++) 175 if(in.addr.size() == 1)
176 if(!convert_v1_to_v2(in.addr[i], out.instance[i], ctx)) 176 {
177 return false; 177 out.instance[0].type = instance_t::SINGLE;
178 out.instance[0].name = in.addr[0].name;
179 out.instance[0].addr = in.addr[0].addr;
180 }
181 else
182 {
183 out.instance[0].type = instance_t::RANGE;
184 out.instance[0].name = in.name;
185 out.instance[0].range.type = range_t::LIST;
186 out.instance[0].range.first = 1;
187 out.instance[0].range.list.resize(in.addr.size());
188 for(size_t i = 0; i < in.addr.size(); i++)
189 out.instance[0].range.list[i] = in.addr[i].addr;
190 }
178 out.node.resize(in.reg.size()); 191 out.node.resize(in.reg.size());
179 for(size_t i = 0; i < in.reg.size(); i++) 192 for(size_t i = 0; i < in.reg.size(); i++)
180 if(!convert_v1_to_v2(in.reg[i], out.node[i], ctx, loc)) 193 if(!convert_v1_to_v2(in.reg[i], out.node[i], ctx, loc))
@@ -195,8 +208,21 @@ bool convert_v1_to_v2(const soc_desc_v1::soc_t& in, soc_t& out, error_context_t&
195 208
196int do_convert(int argc, char **argv) 209int do_convert(int argc, char **argv)
197{ 210{
198 if(argc != 2) 211 std::vector< std::string > authors;
199 return printf("convert mode expects two arguments\n"); 212 std::string version;
213 while(argc >= 2)
214 {
215 if(strcmp(argv[0], "--author") == 0)
216 authors.push_back(argv[1]);
217 else if(strcmp(argv[0], "--version") == 0)
218 version = argv[1];
219 else
220 break;
221 argc -= 2;
222 argv += 2;
223 }
224 if(argc < 2)
225 return printf("convert mode expects at least one description file and an output file\n");
200 soc_desc_v1::soc_t soc; 226 soc_desc_v1::soc_t soc;
201 if(!soc_desc_v1::parse_xml(argv[0], soc)) 227 if(!soc_desc_v1::parse_xml(argv[0], soc))
202 return printf("cannot read file '%s'\n", argv[0]); 228 return printf("cannot read file '%s'\n", argv[0]);
@@ -207,6 +233,8 @@ int do_convert(int argc, char **argv)
207 print_context(ctx); 233 print_context(ctx);
208 return printf("cannot convert from v1 to v2\n"); 234 return printf("cannot convert from v1 to v2\n");
209 } 235 }
236 new_soc.author = authors;
237 new_soc.version = version;
210 if(!produce_xml(argv[1], new_soc, ctx)) 238 if(!produce_xml(argv[1], new_soc, ctx))
211 { 239 {
212 print_context(ctx); 240 print_context(ctx);
@@ -392,7 +420,7 @@ void check_node(const std::string& _path, const node_t& node, error_context_t& c
392 std::string path = _path + "." + node.name; 420 std::string path = _path + "." + node.name;
393 check_name(_path, node.name, ctx); 421 check_name(_path, node.name, ctx);
394 if(node.instance.empty()) 422 if(node.instance.empty())
395 ctx.add(error_t(error_t::FATAL, path, "subnode with no instances")); 423 ctx.add(error_t(error_t::WARNING, path, "subnode with no instances"));
396 for(size_t j = 0; j < node.instance.size(); j++) 424 for(size_t j = 0; j < node.instance.size(); j++)
397 check_instance(path, node.instance[j], ctx); 425 check_instance(path, node.instance[j], ctx);
398 for(size_t i = 0; i < node.register_.size(); i++) 426 for(size_t i = 0; i < node.register_.size(); i++)
@@ -506,6 +534,12 @@ void print_reg(register_ref_t reg, unsigned flags)
506 printf(":[%u-%u]=", (unsigned)(f->pos + f->width - 1), (unsigned)f->pos); 534 printf(":[%u-%u]=", (unsigned)(f->pos + f->width - 1), (unsigned)f->pos);
507 printf("%s\n", f->name.c_str()); 535 printf("%s\n", f->name.c_str());
508 } 536 }
537 std::vector< variant_ref_t > variants = reg.variants();
538 for(size_t i = 0; i < variants.size(); i++)
539 {
540 print_path(node, false);
541 printf(":%s@+0x%x\n", variants[i].type().c_str(), variants[i].offset());
542 }
509} 543}
510 544
511void do_dump(node_ref_t node, unsigned flags) 545void do_dump(node_ref_t node, unsigned flags)
@@ -576,6 +610,178 @@ int do_dump(int argc, char **argv)
576 return 0; 610 return 0;
577} 611}
578 612
613std::string trim(const std::string& s)
614{
615 std::string ss = s.substr(s.find_first_not_of(" \t"));
616 return ss.substr(0, ss.find_last_not_of(" \t") + 1);
617}
618
619bool parse_key(const std::string& key, std::string& dev, std::string& reg)
620{
621 if(key.substr(0, 3) != "HW.")
622 return false;
623 std::string s = key.substr(3);
624 size_t idx = s.find('.');
625 if(idx == std::string::npos)
626 return false;
627 dev = s.substr(0, idx);
628 reg = s.substr(idx + 1);
629 return true;
630}
631
632bool find_addr(const soc_desc_v1::soc_dev_t& dev,
633 const std::string& reg, soc_desc_v1::soc_addr_t& addr)
634{
635 for(size_t i = 0; i < dev.reg.size(); i++)
636 for(size_t j = 0; j < dev.reg[i].addr.size(); j++)
637 if(dev.reg[i].addr[j].name == reg)
638 {
639 addr += dev.reg[i].addr[j].addr;
640 return true;
641 }
642 return false;
643}
644
645bool find_addr(const soc_desc_v1::soc_t& soc, const std::string& dev,
646 const std::string& reg, soc_desc_v1::soc_addr_t& addr)
647{
648 addr = 0;
649 for(size_t i = 0; i < soc.dev.size(); i++)
650 for(size_t j = 0; j < soc.dev[i].addr.size(); j++)
651 if(soc.dev[i].addr[j].name == dev)
652 {
653 addr += soc.dev[i].addr[j].addr;
654 return find_addr(soc.dev[i], reg, addr);
655 }
656 return false;
657}
658
659int convert_dump(const std::map< std::string, std::string >& entries,
660 const soc_desc_v1::soc_t& soc, std::ofstream& fout)
661{
662 std::map< std::string, std::string >::const_iterator it = entries.begin();
663 for(; it != entries.end(); ++it)
664 {
665 char *end;
666 soc_desc_v1::soc_word_t v = strtoul(it->second.c_str(), &end, 0);
667 if(*end != 0)
668 {
669 printf("because of invalid value '%s': ignore key '%s'\n",
670 it->second.c_str(), it->first.c_str());
671 continue;
672 }
673 std::string dev, reg;
674 if(!parse_key(it->first, dev, reg))
675 {
676 printf("invalid key format, ignore key '%s'\n", it->first.c_str());
677 continue;
678 }
679 soc_desc_v1::soc_addr_t addr;
680 if(!find_addr(soc, dev, reg, addr))
681 {
682 printf("cannot find register in description, ignore key '%s'\n",
683 it->first.c_str());
684 continue;
685 }
686 fout << "0x" << std::hex << addr << " = 0x" << std::hex << v << "\n";
687 }
688 return 0;
689}
690
691int do_convertdump(int argc, char **argv)
692{
693 if(argc < 3)
694 {
695 printf("you must specify at least one description file, one input file and one output file\n");
696 return 1;
697 }
698 std::vector< soc_desc_v1::soc_t > socs;
699 for(int i = 0; i < argc - 2; i++)
700 {
701 socs.resize(socs.size() + 1);
702 if(!parse_xml(argv[i], socs.back()))
703 {
704 socs.pop_back();
705 printf("cannot parse description file '%s'\n", argv[i]);
706 }
707 }
708 std::ifstream fin(argv[argc - 2]);
709 if(!fin)
710 {
711 printf("cannot open input file\n");
712 return 1;
713 }
714 std::map< std::string, std::string > entries;
715 std::string line;
716 while(std::getline(fin, line))
717 {
718 size_t idx = line.find('=');
719 if(idx == std::string::npos)
720 {
721 printf("ignore invalid line '%s'\n", line.c_str());
722 continue;
723 }
724 std::string key = trim(line.substr(0, idx));
725 std::string value = trim(line.substr(idx + 1));
726 entries[key] = value;
727 }
728 if(entries.find("HW") == entries.end())
729 {
730 printf("invalid dump file: missing HW key\n");
731 return 1;
732 }
733 std::string soc = entries["HW"];
734 soc_desc_v1::soc_t *psoc = 0;
735 for(size_t i = 0; i < socs.size(); i++)
736 if(socs[i].name == soc)
737 psoc = &socs[i];
738 if(psoc == 0)
739 {
740 printf("cannot convert dump: please provide the description file for the soc '%s'\n", soc.c_str());
741 return 1;
742 }
743 entries.erase(entries.find("HW"));
744 std::ofstream fout(argv[argc - 1]);
745 if(!fout)
746 {
747 printf("cannot open output file\n");
748 return 1;
749 }
750 fout << "soc = " << soc << "\n";
751 return convert_dump(entries, *psoc, fout);
752}
753
754int do_normalize(int argc, char **argv)
755{
756 if(argc != 2)
757 {
758 printf("normalize takes two arguments\n");
759 return 1;
760 }
761 error_context_t ctx;
762 soc_t soc;
763 bool ret = parse_xml(argv[0], soc, ctx);
764 if(ctx.count() != 0)
765 printf("In file %s:\n", argv[0]);
766 print_context(ctx);
767 if(!ret)
768 {
769 printf("cannot parse file '%s'\n", argv[1]);
770 return 2;
771 }
772 normalize(soc);
773 ret = produce_xml(argv[1], soc, ctx);
774 if(ctx.count() != 0)
775 printf("In file %s:\n", argv[1]);
776 print_context(ctx);
777 if(!ret)
778 {
779 printf("cannot write file '%s'\n", argv[1]);
780 return 3;
781 }
782 return 0;
783}
784
579void usage() 785void usage()
580{ 786{
581 printf("usage: swiss_knife <mode> [options]\n"); 787 printf("usage: swiss_knife <mode> [options]\n");
@@ -583,9 +789,22 @@ void usage()
583 printf(" read <files...>\n"); 789 printf(" read <files...>\n");
584 printf(" write <read file> <write file>\n"); 790 printf(" write <read file> <write file>\n");
585 printf(" eval [<formula>|--var <name>=<val>]...\n"); 791 printf(" eval [<formula>|--var <name>=<val>]...\n");
586 printf(" convert <input file> <output file>\n"); 792 printf(" convert [--author <auth>] [--version <ver>] <input file> <output file>\n");
587 printf(" check <files...>\n"); 793 printf(" check <files...>\n");
588 printf(" dump [--nodes] [--instances] [--registers] [--verbose] <files...>\n"); 794 printf(" dump [--nodes] [--instances] [--registers] [--verbose] <files...>\n");
795 printf(" convertdump <desc file> ... <desc file> <input dump file> <output dump file>\n");
796 printf(" normalize <desc file> <output desc file>\n");
797 printf("\n");
798 printf("The following operations are performed in each mode:\n");
799 printf("* read: open and parse the files, reports any obvious errors\n");
800 printf("* write: open, parse a file and write it back, checks the parser/generator match\n");
801 printf("* eval: evaluate a formula with the formula parser\n");
802 printf("* convert: convert a description file from version 1 to version 2\n");
803 printf("* check: performs deep checks on description files\n");
804 printf("* dump: debug tool to dump internal structures\n");
805 printf("* convertdump: convert a register dump from version 1 to version 2\n");
806 printf(" NOTE: description file must be a v1 file\n");
807 printf("* normalize: normalise a description file\n");
589 exit(1); 808 exit(1);
590} 809}
591 810
@@ -606,6 +825,10 @@ int main(int argc, char **argv)
606 return do_check(argc - 2, argv + 2); 825 return do_check(argc - 2, argv + 2);
607 else if(mode == "dump") 826 else if(mode == "dump")
608 return do_dump(argc - 2, argv + 2); 827 return do_dump(argc - 2, argv + 2);
828 else if(mode == "convertdump")
829 return do_convertdump(argc - 2, argv + 2);
830 else if(mode == "normalize")
831 return do_normalize(argc - 2, argv + 2);
609 else 832 else
610 usage(); 833 usage();
611 return 0; 834 return 0;