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