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