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
15 # DMI register addresses
19 NIA
= 0b0010 # NIA register (read only for now)
20 MSR
= 0b0011 # MSR (read only)
21 GSPR_INDEX
= 0b0100 # GSPR register index
22 GSPR_DATA
= 0b0101 # GSPR register data
23 LOG_ADDR
= 0b0110 # Log buffer address register
24 LOG_DATA
= 0b0111 # Log buffer data register
27 # CTRL register (direct actions, write 1 to act, read back 0)
29 # bit 1 : Core reset (doesn't clear stop)
30 # bit 2 : Icache reset
41 # STAT register (read only)
42 # bit 0 : Core stopping (wait til bit 1 set)
43 # bit 1 : Core stopped
44 # bit 2 : Core terminated (clears with start or reset)
51 class DMIInterface(RecordObject
):
52 def __init__(self
, name
):
53 super().__init
__(name
=name
)
54 self
.addr_i
= Signal(4) # DMI register address
55 self
.din
= Signal(64) # DMI data in (if we=1)
56 self
.dout
= Signal(64) # DMI data out (if we=0)
57 self
.req_i
= Signal() # DMI request valid (stb)
58 self
.we_i
= Signal() # DMI write-enable
59 self
.ack_o
= Signal() # DMI ack request
62 class CoreDebug(Elaboratable
):
63 def __init__(self
, LOG_LENGTH
=0): # TODO - debug log 512):
64 # Length of log buffer
65 self
.LOG_LENGTH
= LOG_LENGTH
66 self
.dmi
= DMIInterface("dmi")
69 self
.core_stop_o
= Signal()
70 self
.core_rst_o
= Signal()
71 self
.icache_rst_o
= Signal()
74 self
.terminate_i
= Signal()
75 self
.core_stopped_i
= Signal()
79 # GSPR register read port
80 self
.dbg_gpr_req_o
= Signal()
81 self
.dbg_gpr_ack_i
= Signal()
82 self
.dbg_gpr_addr_o
= Signal(7) # includes fast SPRs, others?
83 self
.dbg_gpr_data_i
= Signal(64)
86 self
.log_data_i
= Signal(256)
87 self
.log_read_addr_i
= Signal(32)
88 self
.log_read_data_o
= Signal(64)
89 self
.log_write_addr_o
= Signal(32)
92 self
.terminated_o
= Signal()
94 def elaborate(self
, platform
):
97 comb
, sync
= m
.d
.comb
, m
.d
.sync
99 # DMI needs fixing... make a one clock pulse
100 dmi_req_i_1
= Signal()
102 # Some internal wires
103 stat_reg
= Signal(64)
105 # Some internal latches
109 do_icreset
= Signal()
110 terminated
= Signal()
111 do_gspr_rd
= Signal()
112 gspr_index
= Signal
.like(self
.dbg_gpr_addr_o
)
114 log_dmi_addr
= Signal(32)
115 log_dmi_data
= Signal(64)
116 do_dmi_log_rd
= Signal()
117 dmi_read_log_data
= Signal()
118 dmi_read_log_data_1
= Signal()
120 LOG_INDEX_BITS
= log2_int(self
.LOG_LENGTH
)
122 # Single cycle register accesses on DMI except for GSPR data
123 comb
+= self
.dmi
.ack_o
.eq(Mux(self
.dmi
.addr_i
== DBGCore
.GSPR_DATA
,
124 self
.dbg_gpr_ack_i
, self
.dmi
.req_i
))
125 comb
+= self
.dbg_gpr_req_o
.eq(Mux(self
.dmi
.addr_i
== DBGCore
.GSPR_DATA
,
128 # Status register read composition (DBUG_CORE_STAT_xxx)
129 comb
+= stat_reg
.eq(Cat(stopping
, # bit 0
130 self
.core_stopped_i
, # bit 1
134 with m
.Switch(self
.dmi
.addr_i
):
135 with m
.Case( DBGCore
.STAT
):
136 comb
+= self
.dmi
.dout
.eq(stat_reg
)
137 with m
.Case( DBGCore
.NIA
):
138 comb
+= self
.dmi
.dout
.eq(self
.nia
)
139 with m
.Case( DBGCore
.MSR
):
140 comb
+= self
.dmi
.dout
.eq(self
.msr
)
141 with m
.Case( DBGCore
.GSPR_DATA
):
142 comb
+= self
.dmi
.dout
.eq(self
.dbg_gpr_data_i
)
143 with m
.Case( DBGCore
.LOG_ADDR
):
144 comb
+= self
.dmi
.dout
.eq(Cat(log_dmi_addr
,
145 self
.log_write_addr_o
))
146 with m
.Case( DBGCore
.LOG_DATA
):
147 comb
+= self
.dmi
.dout
.eq(log_dmi_data
)
150 # Reset the 1-cycle "do" signals
151 sync
+= do_step
.eq(0)
152 sync
+= do_reset
.eq(0)
153 sync
+= do_icreset
.eq(0)
154 sync
+= do_dmi_log_rd
.eq(0)
156 # Edge detect on dmi_req_i for 1-shot pulses
157 sync
+= dmi_req_i_1
.eq(self
.dmi
.req_i
)
158 with m
.If(self
.dmi
.req_i
& ~dmi_req_i_1
):
159 with m
.If(self
.dmi
.we_i
):
160 #sync += Display("DMI write to " & to_hstring(dmi_addr))
162 # Control register actions
165 with m
.If(self
.dmi
.addr_i
== DBGCore
.CTRL
):
166 with m
.If(self
.dmi
.din
[DBGCtrl
.RESET
]):
167 sync
+= do_reset
.eq(1)
168 sync
+= terminated
.eq(0)
169 with m
.If(self
.dmi
.din
[DBGCtrl
.STOP
]):
170 sync
+= stopping
.eq(1)
171 with m
.If(self
.dmi
.din
[DBGCtrl
.STEP
]):
172 sync
+= do_step
.eq(1)
173 sync
+= terminated
.eq(0)
174 with m
.If(self
.dmi
.din
[DBGCtrl
.ICRESET
]):
175 sync
+= do_icreset
.eq(1)
176 with m
.If(self
.dmi
.din
[DBGCtrl
.START
]):
177 sync
+= stopping
.eq(0)
178 sync
+= terminated
.eq(0)
181 with m
.Elif(self
.dmi
.addr_i
== DBGCore
.GSPR_INDEX
):
182 sync
+= gspr_index
.eq(self
.dmi
.din
)
185 with m
.Elif(self
.dmi
.addr_i
== DBGCore
.LOG_ADDR
):
186 sync
+= log_dmi_addr
.eq(self
.dmi
.din
)
187 sync
+= do_dmi_log_rd
.eq(1)
189 # sync += Display("DMI read from " & to_string(dmi_addr))
192 with m
.Elif(dmi_read_log_data_1
& ~dmi_read_log_data
):
193 # Increment log_dmi_addr after end of read from DBGCore.LOG_DATA
194 lds
= log_dmi_addr
[:LOG_INDEX_BITS
+2]
195 sync
+= lds
.eq(lds
+ 1)
196 sync
+= do_dmi_log_rd
.eq(1)
198 sync
+= dmi_read_log_data_1
.eq(dmi_read_log_data
)
199 sync
+= dmi_read_log_data
.eq(self
.dmi
.req_i
&
200 (self
.dmi
.addr_i
== DBGCore
.LOG_DATA
))
202 # Set core stop on terminate. We'll be stopping some time *after*
203 # the offending instruction, at least until we can do back flushes
204 # that preserve NIA which we can't just yet.
205 with m
.If(self
.terminate_i
):
206 sync
+= stopping
.eq(1)
207 sync
+= terminated
.eq(1)
209 comb
+= self
.dbg_gpr_addr_o
.eq(gspr_index
)
211 # Core control signals generated by the debug module
212 comb
+= self
.core_stop_o
.eq(stopping
& ~do_step
)
213 comb
+= self
.core_rst_o
.eq(do_reset
)
214 comb
+= self
.icache_rst_o
.eq(do_icreset
)
215 comb
+= self
.terminated_o
.eq(terminated
)
219 if self
.LOG_LENGTH
== 0:
220 self
.log_read_data_o
.eq(0)
221 self
.log_write_addr_o
.eq(0x00000001)
225 # TODO: debug logging
227 maybe_log: with m.If(LOG_LENGTH > 0 generate
228 subtype log_ptr_t is unsigned(LOG_INDEX_BITS - 1 downto 0)
229 type log_array_t is array(0 to LOG_LENGTH - 1) of std_ulogic_vector(255 downto 0)
230 signal log_array : log_array_t
231 signal log_rd_ptr : log_ptr_t
232 signal log_wr_ptr : log_ptr_t
233 signal log_toggle = Signal()
234 signal log_wr_enable = Signal()
235 signal log_rd_ptr_latched : log_ptr_t
236 signal log_rd = Signal()_vector(255 downto 0)
237 signal log_dmi_reading = Signal()
238 signal log_dmi_read_done = Signal()
240 function select_dword(data = Signal()_vector(255 downto 0)
241 addr = Signal()_vector(31 downto 0)) return std_ulogic_vector is
242 variable firstbit : integer
244 firstbit := to_integer(unsigned(addr(1 downto 0))) * 64
245 return data(firstbit + 63 downto firstbit)
248 attribute ram_style : string
249 attribute ram_style of log_array : signal is "block"
250 attribute ram_decomp : string
251 attribute ram_decomp of log_array : signal is "power"
254 # Use MSB of read addresses to stop the logging
255 log_wr_enable.eq(not (self.log_read_addr(31) or log_dmi_addr(31))
257 log_ram: process(clk)
259 with m.If(rising_edge(clk)):
260 with m.If(log_wr_enable = '1'):
261 log_array(to_integer(log_wr_ptr)).eq(self.log_data
263 log_rd.eq(log_array(to_integer(log_rd_ptr_latched))
268 log_buffer: process(clk)
270 variable data = Signal()_vector(255 downto 0)
272 with m.If(rising_edge(clk)):
273 with m.If(rst = '1'):
274 log_wr_ptr.eq((others => '0')
276 with m.Elif(log_wr_enable = '1'):
277 with m.If(log_wr_ptr = to_unsigned(LOG_LENGTH - 1, LOG_INDEX_BITS)):
278 log_toggle.eq(not log_toggle
280 log_wr_ptr.eq(log_wr_ptr + 1
282 with m.If(do_dmi_log_rd = '1'):
283 log_rd_ptr_latched.eq(unsigned(log_dmi_addr(LOG_INDEX_BITS + 1 downto 2))
285 log_rd_ptr_latched.eq(unsigned(self.log_read_addr(LOG_INDEX_BITS + 1 downto 2))
287 with m.If(log_dmi_read_done = '1'):
288 log_dmi_data.eq(select_dword(log_rd, log_dmi_addr)
290 self.log_read_data.eq(select_dword(log_rd, self.log_read_addr)
292 log_dmi_read_done.eq(log_dmi_reading
293 log_dmi_reading.eq(do_dmi_log_rd
296 self.log_write_addr(LOG_INDEX_BITS - 1 downto 0).eq(std_ulogic_vector(log_wr_ptr)
297 self.log_write_addr(LOG_INDEX_BITS).eq('1'
298 self.log_write_addr(31 downto LOG_INDEX_BITS + 1).eq((others => '0')
305 yield self
.core_stop_o
306 yield self
.core_rst_o
307 yield self
.icache_rst_o
308 yield self
.terminate_i
309 yield self
.core_stopped_i
312 yield self
.dbg_gpr_req_o
313 yield self
.dbg_gpr_ack_i
314 yield self
.dbg_gpr_addr_o
315 yield self
.dbg_gpr_data_i
316 yield self
.log_data_i
317 yield self
.log_read_addr_i
318 yield self
.log_read_data_o
319 yield self
.log_write_addr_o
320 yield self
.terminated_o
329 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
330 with
open("test_core_debug.il", "w") as f
:
333 if __name__
== '__main__':