1 """Converted from microwatt core_debug.vhdl to nmigen
3 Provides a DMI (Debug Module Interface) for accessing a Libre-SOC core,
4 compatible with microwatt's same interface.
6 See constants below for addresses and register formats
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
16 # DMI register addresses
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
30 # CTRL register (direct actions, write 1 to act, read back 0)
32 # bit 1 : Core reset (doesn't clear stop)
33 # bit 2 : Icache reset
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)
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
65 class DbgReg(RecordObject
):
66 def __init__(self
, name
):
67 super().__init
__(name
=name
)
70 self
.addr
= Signal(7) # includes fast SPRs, others?
71 self
.data
= Signal(64)
74 class DbgCRReg(RecordObject
):
75 def __init__(self
, name
):
76 super().__init
__(name
=name
)
79 self
.data
= Signal(32)
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")
89 self
.core_stop_o
= Signal()
90 self
.core_rst_o
= Signal()
91 self
.icache_rst_o
= Signal()
94 self
.terminate_i
= Signal()
95 self
.core_stopped_i
= Signal()
96 self
.state
= CoreState("core_dbg")
98 # GSPR register read port
99 self
.d_gpr
= DbgReg("d_gpr")
101 # CR register read port
102 self
.d_cr
= DbgReg("d_cr")
104 # XER register read port
105 self
.d_xer
= DbgReg("d_xer")
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)
114 self
.terminated_o
= Signal()
116 def elaborate(self
, platform
):
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
122 # DMI needs fixing... make a one clock pulse
123 dmi_req_i_1
= Signal()
125 # Some internal wires
126 stat_reg
= Signal(64)
128 # Some internal latches
132 do_icreset
= Signal()
133 terminated
= Signal()
134 do_gspr_rd
= Signal()
135 gspr_index
= Signal
.like(d_gpr
.addr
)
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()
143 LOG_INDEX_BITS
= log2_int(self
.LOG_LENGTH
)
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
)
157 comb
+= dmi
.ack_o
.eq(dmi
.req_i
)
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
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
)
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)
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
):
194 #sync += Display("DMI write to " & to_hstring(dmi_addr))
196 # Control register actions
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)
215 with m
.Elif(dmi
.addr_i
== DBGCore
.GSPR_IDX
):
216 sync
+= gspr_index
.eq(dmi
.din
)
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)
223 # sync += Display("DMI read from " & to_string(dmi_addr))
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)
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
))
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)
243 comb
+= d_gpr
.addr
.eq(gspr_index
)
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
)
253 if self
.LOG_LENGTH
== 0:
254 self
.log_read_data_o
.eq(0)
255 self
.log_write_addr_o
.eq(0x00000001)
259 # TODO: debug logging
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()
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
278 firstbit := to_integer(unsigned(addr(1 downto 0))) * 64
279 return data(firstbit + 63 downto firstbit)
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"
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))
291 log_ram: process(clk)
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
297 log_rd.eq(log_array(to_integer(log_rd_ptr_latched))
302 log_buffer: process(clk)
304 variable data = Signal()_vector(255 downto 0)
306 with m.If(rising_edge(clk)):
307 with m.If(rst = '1'):
308 log_wr_ptr.eq((others => '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
314 log_wr_ptr.eq(log_wr_ptr + 1
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))
319 log_rd_ptr_latched.eq(unsigned(self.log_read_addr(LOG_INDEX_BITS + 1 downto 2))
321 with m.If(log_dmi_read_done = '1'):
322 log_dmi_data.eq(select_dword(log_rd, log_dmi_addr)
324 self.log_read_data.eq(select_dword(log_rd, self.log_read_addr)
326 log_dmi_read_done.eq(log_dmi_reading
327 log_dmi_reading.eq(do_dmi_log_rd
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')
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
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
361 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
362 with
open("test_core_debug.il", "w") as f
:
365 if __name__
== '__main__':