add hack to get at XER through DMI interface
[soc.git] / src / soc / debug / dmi.py
1 """Converted from microwatt core_debug.vhdl to nmigen
2
3 Provides a DMI (Debug Module Interface) for accessing a Libre-SOC core,
4 compatible with microwatt's same interface.
5
6 See constants below for addresses and register formats
7 """
8
9 from nmigen import Elaboratable, Module, Signal, Cat, Const, Record, Array, Mux
10 from nmutil.iocontrol import RecordObject
11 from nmigen.utils import log2_int
12 from nmigen.cli import rtlil
13 from soc.config.state import CoreState
14
15
16 # DMI register addresses
17 class DBGCore:
18 CTRL = 0b0000
19 STAT = 0b0001
20 NIA = 0b0010 # NIA register (read only for now)
21 MSR = 0b0011 # MSR (read only)
22 GSPR_IDX = 0b0100 # GSPR register index
23 GSPR_DATA = 0b0101 # GSPR register data
24 LOG_ADDR = 0b0110 # Log buffer address register
25 LOG_DATA = 0b0111 # Log buffer data register
26 CR = 0b1000 # CR (read only)
27 XER = 0b1001 # XER (read only) - note this is a TEMPORARY hack
28
29
30 # CTRL register (direct actions, write 1 to act, read back 0)
31 # bit 0 : Core stop
32 # bit 1 : Core reset (doesn't clear stop)
33 # bit 2 : Icache reset
34 # bit 3 : Single step
35 # bit 4 : Core start
36 class DBGCtrl:
37 STOP = 0
38 RESET = 1
39 ICRESET = 2
40 STEP = 3
41 START = 4
42
43
44 # STAT register (read only)
45 # bit 0 : Core stopping (wait til bit 1 set)
46 # bit 1 : Core stopped
47 # bit 2 : Core terminated (clears with start or reset)
48 class DBGStat:
49 STOPPING = 0
50 STOPPED = 1
51 TERM = 2
52
53
54 class DMIInterface(RecordObject):
55 def __init__(self, name):
56 super().__init__(name=name)
57 self.addr_i = Signal(4) # DMI register address
58 self.din = Signal(64) # DMI data in (if we=1)
59 self.dout = Signal(64) # DMI data out (if we=0)
60 self.req_i = Signal() # DMI request valid (stb)
61 self.we_i = Signal() # DMI write-enable
62 self.ack_o = Signal() # DMI ack request
63
64
65 class DbgReg(RecordObject):
66 def __init__(self, name):
67 super().__init__(name=name)
68 self.req = Signal()
69 self.ack = Signal()
70 self.addr = Signal(7) # includes fast SPRs, others?
71 self.data = Signal(64)
72
73
74 class DbgCRReg(RecordObject):
75 def __init__(self, name):
76 super().__init__(name=name)
77 self.req = Signal()
78 self.ack = Signal()
79 self.data = Signal(32)
80
81
82 class CoreDebug(Elaboratable):
83 def __init__(self, LOG_LENGTH=0): # TODO - debug log 512):
84 # Length of log buffer
85 self.LOG_LENGTH = LOG_LENGTH
86 self.dmi = DMIInterface("dmi")
87
88 # Debug actions
89 self.core_stop_o = Signal()
90 self.core_rst_o = Signal()
91 self.icache_rst_o = Signal()
92
93 # Core status inputs
94 self.terminate_i = Signal()
95 self.core_stopped_i = Signal()
96 self.state = CoreState("core_dbg")
97
98 # GSPR register read port
99 self.d_gpr = DbgReg("d_gpr")
100
101 # CR register read port
102 self.d_cr = DbgReg("d_cr")
103
104 # XER register read port
105 self.d_xer = DbgReg("d_xer")
106
107 # Core logging data
108 self.log_data_i = Signal(256)
109 self.log_read_addr_i = Signal(32)
110 self.log_read_data_o = Signal(64)
111 self.log_write_addr_o = Signal(32)
112
113 # Misc
114 self.terminated_o = Signal()
115
116 def elaborate(self, platform):
117
118 m = Module()
119 comb, sync = m.d.comb, m.d.sync
120 dmi, d_gpr, d_cr, d_xer, = self.dmi, self.d_gpr, self.d_cr, self.d_xer
121
122 # DMI needs fixing... make a one clock pulse
123 dmi_req_i_1 = Signal()
124
125 # Some internal wires
126 stat_reg = Signal(64)
127
128 # Some internal latches
129 stopping = Signal()
130 do_step = Signal()
131 do_reset = Signal()
132 do_icreset = Signal()
133 terminated = Signal()
134 do_gspr_rd = Signal()
135 gspr_index = Signal.like(d_gpr.addr)
136
137 log_dmi_addr = Signal(32)
138 log_dmi_data = Signal(64)
139 do_dmi_log_rd = Signal()
140 dmi_read_log_data = Signal()
141 dmi_read_log_data_1 = Signal()
142
143 LOG_INDEX_BITS = log2_int(self.LOG_LENGTH)
144
145 # Single cycle register accesses on DMI except for GSPR data
146 with m.Switch(dmi.addr_i):
147 with m.Case(DBGCore.GSPR_DATA):
148 comb += dmi.ack_o.eq(d_gpr.ack)
149 comb += d_gpr.req.eq(dmi.req_i)
150 with m.Case(DBGCore.CR):
151 comb += dmi.ack_o.eq(d_cr.ack)
152 comb += d_cr.req.eq(dmi.req_i)
153 with m.Case(DBGCore.XER):
154 comb += dmi.ack_o.eq(d_xer.ack)
155 comb += d_xer.req.eq(dmi.req_i)
156 with m.Default():
157 comb += dmi.ack_o.eq(dmi.req_i)
158
159 # Status register read composition (DBUG_CORE_STAT_xxx)
160 comb += stat_reg.eq(Cat(stopping, # bit 0
161 self.core_stopped_i, # bit 1
162 terminated)) # bit 2
163
164 # DMI read data mux
165 with m.Switch(dmi.addr_i):
166 with m.Case( DBGCore.STAT):
167 comb += dmi.dout.eq(stat_reg)
168 with m.Case( DBGCore.NIA):
169 comb += dmi.dout.eq(self.state.pc)
170 with m.Case( DBGCore.MSR):
171 comb += dmi.dout.eq(self.state.msr)
172 with m.Case( DBGCore.GSPR_DATA):
173 comb += dmi.dout.eq(d_gpr.data)
174 with m.Case( DBGCore.LOG_ADDR):
175 comb += dmi.dout.eq(Cat(log_dmi_addr, self.log_write_addr_o))
176 with m.Case( DBGCore.LOG_DATA):
177 comb += dmi.dout.eq(log_dmi_data)
178 with m.Case(DBGCore.CR):
179 comb += dmi.dout.eq(d_cr.data)
180 with m.Case(DBGCore.XER):
181 comb += dmi.dout.eq(d_xer.data)
182
183 # DMI writes
184 # Reset the 1-cycle "do" signals
185 sync += do_step.eq(0)
186 sync += do_reset.eq(0)
187 sync += do_icreset.eq(0)
188 sync += do_dmi_log_rd.eq(0)
189
190 # Edge detect on dmi_req_i for 1-shot pulses
191 sync += dmi_req_i_1.eq(dmi.req_i)
192 with m.If(dmi.req_i & ~dmi_req_i_1):
193 with m.If(dmi.we_i):
194 #sync += Display("DMI write to " & to_hstring(dmi_addr))
195
196 # Control register actions
197
198 # Core control
199 with m.If(dmi.addr_i == DBGCore.CTRL):
200 with m.If(dmi.din[DBGCtrl.RESET]):
201 sync += do_reset.eq(1)
202 sync += terminated.eq(0)
203 with m.If(dmi.din[DBGCtrl.STOP]):
204 sync += stopping.eq(1)
205 with m.If(dmi.din[DBGCtrl.STEP]):
206 sync += do_step.eq(1)
207 sync += terminated.eq(0)
208 with m.If(dmi.din[DBGCtrl.ICRESET]):
209 sync += do_icreset.eq(1)
210 with m.If(dmi.din[DBGCtrl.START]):
211 sync += stopping.eq(0)
212 sync += terminated.eq(0)
213
214 # GSPR address
215 with m.Elif(dmi.addr_i == DBGCore.GSPR_IDX):
216 sync += gspr_index.eq(dmi.din)
217
218 # Log address
219 with m.Elif(dmi.addr_i == DBGCore.LOG_ADDR):
220 sync += log_dmi_addr.eq(dmi.din)
221 sync += do_dmi_log_rd.eq(1)
222 with m.Else():
223 # sync += Display("DMI read from " & to_string(dmi_addr))
224 pass
225
226 with m.Elif(dmi_read_log_data_1 & ~dmi_read_log_data):
227 # Increment log_dmi_addr after end of read from DBGCore.LOG_DATA
228 lds = log_dmi_addr[:LOG_INDEX_BITS+2]
229 sync += lds.eq(lds + 1)
230 sync += do_dmi_log_rd.eq(1)
231
232 sync += dmi_read_log_data_1.eq(dmi_read_log_data)
233 sync += dmi_read_log_data.eq(dmi.req_i &
234 (dmi.addr_i == DBGCore.LOG_DATA))
235
236 # Set core stop on terminate. We'll be stopping some time *after*
237 # the offending instruction, at least until we can do back flushes
238 # that preserve NIA which we can't just yet.
239 with m.If(self.terminate_i):
240 sync += stopping.eq(1)
241 sync += terminated.eq(1)
242
243 comb += d_gpr.addr.eq(gspr_index)
244
245 # Core control signals generated by the debug module
246 comb += self.core_stop_o.eq(stopping & ~do_step)
247 comb += self.core_rst_o.eq(do_reset)
248 comb += self.icache_rst_o.eq(do_icreset)
249 comb += self.terminated_o.eq(terminated)
250
251 # Logging RAM (none)
252
253 if self.LOG_LENGTH == 0:
254 self.log_read_data_o.eq(0)
255 self.log_write_addr_o.eq(0x00000001)
256
257 return m
258
259 # TODO: debug logging
260 """
261 maybe_log: with m.If(LOG_LENGTH > 0 generate
262 subtype log_ptr_t is unsigned(LOG_INDEX_BITS - 1 downto 0)
263 type log_array_t is array(0 to LOG_LENGTH - 1) of std_ulogic_vector(255 downto 0)
264 signal log_array : log_array_t
265 signal log_rd_ptr : log_ptr_t
266 signal log_wr_ptr : log_ptr_t
267 signal log_toggle = Signal()
268 signal log_wr_enable = Signal()
269 signal log_rd_ptr_latched : log_ptr_t
270 signal log_rd = Signal()_vector(255 downto 0)
271 signal log_dmi_reading = Signal()
272 signal log_dmi_read_done = Signal()
273
274 function select_dword(data = Signal()_vector(255 downto 0)
275 addr = Signal()_vector(31 downto 0)) return std_ulogic_vector is
276 variable firstbit : integer
277 begin
278 firstbit := to_integer(unsigned(addr(1 downto 0))) * 64
279 return data(firstbit + 63 downto firstbit)
280 end
281
282 attribute ram_style : string
283 attribute ram_style of log_array : signal is "block"
284 attribute ram_decomp : string
285 attribute ram_decomp of log_array : signal is "power"
286
287 begin
288 # Use MSB of read addresses to stop the logging
289 log_wr_enable.eq(not (self.log_read_addr(31) or log_dmi_addr(31))
290
291 log_ram: process(clk)
292 begin
293 with m.If(rising_edge(clk)):
294 with m.If(log_wr_enable = '1'):
295 log_array(to_integer(log_wr_ptr)).eq(self.log_data
296 end if
297 log_rd.eq(log_array(to_integer(log_rd_ptr_latched))
298 end if
299 end process
300
301
302 log_buffer: process(clk)
303 variable b : integer
304 variable data = Signal()_vector(255 downto 0)
305 begin
306 with m.If(rising_edge(clk)):
307 with m.If(rst = '1'):
308 log_wr_ptr.eq((others => '0')
309 log_toggle.eq('0'
310 with m.Elif(log_wr_enable = '1'):
311 with m.If(log_wr_ptr = to_unsigned(LOG_LENGTH - 1, LOG_INDEX_BITS)):
312 log_toggle.eq(not log_toggle
313 end if
314 log_wr_ptr.eq(log_wr_ptr + 1
315 end if
316 with m.If(do_dmi_log_rd = '1'):
317 log_rd_ptr_latched.eq(unsigned(log_dmi_addr(LOG_INDEX_BITS + 1 downto 2))
318 else
319 log_rd_ptr_latched.eq(unsigned(self.log_read_addr(LOG_INDEX_BITS + 1 downto 2))
320 end if
321 with m.If(log_dmi_read_done = '1'):
322 log_dmi_data.eq(select_dword(log_rd, log_dmi_addr)
323 else
324 self.log_read_data.eq(select_dword(log_rd, self.log_read_addr)
325 end if
326 log_dmi_read_done.eq(log_dmi_reading
327 log_dmi_reading.eq(do_dmi_log_rd
328 end if
329 end process
330 self.log_write_addr(LOG_INDEX_BITS - 1 downto 0).eq(std_ulogic_vector(log_wr_ptr)
331 self.log_write_addr(LOG_INDEX_BITS).eq('1'
332 self.log_write_addr(31 downto LOG_INDEX_BITS + 1).eq((others => '0')
333 end generate
334
335 """
336
337 def __iter__(self):
338 yield from self.dmi
339 yield self.core_stop_o
340 yield self.core_rst_o
341 yield self.icache_rst_o
342 yield self.terminate_i
343 yield self.core_stopped_i
344 yield from self.state
345 yield from self.d_gpr
346 yield from self.d_cr
347 yield from self.d_xer
348 yield self.log_data_i
349 yield self.log_read_addr_i
350 yield self.log_read_data_o
351 yield self.log_write_addr_o
352 yield self.terminated_o
353
354 def ports(self):
355 return list(self)
356
357
358 def test_debug():
359
360 dut = CoreDebug()
361 vl = rtlil.convert(dut, ports=dut.ports())
362 with open("test_core_debug.il", "w") as f:
363 f.write(vl)
364
365 if __name__ == '__main__':
366 test_debug()
367