2 from nmigen
.lib
.coding
import PriorityEncoder
6 from ...wishbone
import wishbone_layout
7 from .dmi
import DebugReg
, Command
, Error
, Version
, cmd_access_reg_layout
10 __all__
= ["DebugController"]
21 cause_map
= [2, 1, 5, 3, 4]
24 class DebugController(Elaboratable
, AutoCSR
):
25 def __init__(self
, debugrf
):
26 self
.dcsr
= CSR(0x7b0, dcsr_layout
, name
="dcsr")
27 self
.dpc
= CSR(0x7b1, flat_layout
, name
="dpc")
29 self
.dmstatus
= debugrf
.reg_port(DebugReg
.DMSTATUS
)
30 self
.dmcontrol
= debugrf
.reg_port(DebugReg
.DMCONTROL
)
31 self
.hartinfo
= debugrf
.reg_port(DebugReg
.HARTINFO
)
32 self
.abstractcs
= debugrf
.reg_port(DebugReg
.ABSTRACTCS
)
33 self
.command
= debugrf
.reg_port(DebugReg
.COMMAND
)
34 self
.data0
= debugrf
.reg_port(DebugReg
.DATA0
)
36 self
.trigger_haltreq
= Signal()
38 self
.x_pc
= Signal(32)
39 self
.x_ebreak
= Signal()
40 self
.x_stall
= Signal()
42 self
.m_branch_taken
= Signal()
43 self
.m_branch_target
= Signal(32)
44 self
.m_mret
= Signal()
45 self
.m_exception
= Signal()
46 self
.m_pc
= Signal(32)
47 self
.m_valid
= Signal()
48 self
.mepc_r_base
= Signal(30)
49 self
.mtvec_r_base
= Signal(30)
52 self
.halted
= Signal()
53 self
.killall
= Signal()
54 self
.resumereq
= Signal()
55 self
.resumeack
= Signal()
57 self
.gprf_addr
= Signal(5)
58 self
.gprf_re
= Signal()
59 self
.gprf_dat_r
= Signal(32)
60 self
.gprf_we
= Signal()
61 self
.gprf_dat_w
= Signal(32)
63 self
.csrf_addr
= Signal(12)
64 self
.csrf_re
= Signal()
65 self
.csrf_dat_r
= Signal(32)
66 self
.csrf_we
= Signal()
67 self
.csrf_dat_w
= Signal(32)
69 def elaborate(self
, platform
):
72 for csr
in self
.dcsr
, self
.dpc
:
74 m
.d
.sync
+= csr
.r
.eq(csr
.w
)
76 with m
.If(self
.dmcontrol
.update
):
78 self
.dmcontrol
.w
.dmactive
.eq(self
.dmcontrol
.r
.dmactive
),
79 self
.dmcontrol
.w
.ndmreset
.eq(self
.dmcontrol
.r
.ndmreset
),
80 self
.dmcontrol
.w
.hartselhi
.eq(self
.dmcontrol
.r
.hartselhi
),
81 self
.dmcontrol
.w
.hartsello
.eq(self
.dmcontrol
.r
.hartsello
),
82 self
.dmcontrol
.w
.hasel
.eq(self
.dmcontrol
.r
.hasel
),
83 self
.dmcontrol
.w
.hartreset
.eq(self
.dmcontrol
.r
.hartreset
),
84 self
.dmcontrol
.w
.resumereq
.eq(self
.dmcontrol
.r
.resumereq
)
87 with m
.If(self
.abstractcs
.update
):
88 m
.d
.sync
+= self
.abstractcs
.w
.cmderr
.eq(self
.abstractcs
.r
.cmderr
)
91 self
.dmstatus
.w
.version
.eq(Version
.V013
),
92 self
.dmstatus
.w
.authenticated
.eq(1),
93 self
.resumereq
.eq(self
.dmcontrol
.w
.resumereq
)
96 m_breakpoint
= Signal()
97 with m
.If(~self
.x_stall
):
98 m
.d
.comb
+= m_breakpoint
.eq(self
.x_ebreak
& self
.dcsr
.r
.ebreakm
)
100 halt_pe
= m
.submodules
.halt_pe
= PriorityEncoder(5)
102 halt_pe
.i
[HaltCause
.EBREAK
].eq(m_breakpoint
& self
.m_valid
),
103 halt_pe
.i
[HaltCause
.TRIGGER
].eq(self
.trigger_haltreq
),
104 halt_pe
.i
[HaltCause
.HALTREQ
].eq(self
.dmcontrol
.r
.haltreq
),
105 halt_pe
.i
[HaltCause
.STEP
].eq(self
.dcsr
.r
.step
& self
.m_valid
),
110 m
.d
.comb
+= self
.dmstatus
.w
.allrunning
.eq(1)
111 with m
.If(~halt_pe
.n
):
114 self
.dcsr
.r
.cause
.eq(Array(cause_map
)[halt_pe
.o
]),
115 self
.dcsr
.r
.stepie
.eq(1)
117 with m
.If(halt_pe
.o
== HaltCause
.EBREAK
):
118 m
.d
.sync
+= self
.dpc
.r
.eq(self
.m_pc
)
119 with m
.Elif(self
.m_exception
& self
.m_valid
):
120 m
.d
.sync
+= self
.dpc
.r
.eq(self
.mtvec_r_base
<< 30)
121 with m
.Elif(self
.m_mret
& self
.m_valid
):
122 m
.d
.sync
+= self
.dpc
.r
.eq(self
.mepc_r_base
<< 30)
123 with m
.Elif(self
.m_branch_taken
& self
.m_valid
):
124 m
.d
.sync
+= self
.dpc
.r
.eq(self
.m_branch_target
)
126 m
.d
.sync
+= self
.dpc
.r
.eq(self
.x_pc
)
129 with m
.State("HALTING"):
130 with m
.If(self
.halted
):
131 m
.d
.comb
+= self
.killall
.eq(1)
132 m
.d
.sync
+= self
.dmstatus
.w
.allhalted
.eq(1)
135 with m
.State("WAIT"):
136 with m
.If(self
.dmcontrol
.w
.resumereq
):
138 with m
.Elif(self
.command
.update
):
139 m
.d
.sync
+= self
.abstractcs
.w
.busy
.eq(1)
140 m
.next
= "COMMAND:START"
142 with m
.State("RESUME"):
143 with m
.If(self
.resumeack
):
145 self
.dmcontrol
.w
.resumereq
.eq(0),
146 self
.dmstatus
.w
.allresumeack
.eq(1),
148 self
.dmstatus
.w
.allhalted
.eq(0)
152 with m
.State("COMMAND:START"):
153 with m
.Switch(self
.command
.r
.cmdtype
):
154 with m
.Case(Command
.ACCESS_REG
):
155 control
= Record(cmd_access_reg_layout
)
156 m
.d
.comb
+= control
.eq(self
.command
.r
.control
)
157 m
.d
.comb
+= self
.gprf_addr
.eq(control
.regno
)
158 m
.next
= "COMMAND:ACCESS-REG"
160 m
.d
.sync
+= self
.abstractcs
.w
.cmderr
.eq(Error
.UNSUPPORTED
)
161 m
.next
= "COMMAND:DONE"
163 with m
.State("COMMAND:ACCESS-REG"):
164 control
= Record(cmd_access_reg_layout
)
165 m
.d
.comb
+= control
.eq(self
.command
.r
.control
)
166 with m
.If(control
.postexec |
(control
.aarsize
!= 2) | control
.aarpostincrement
):
167 # Unsupported parameters.
168 m
.d
.sync
+= self
.abstractcs
.w
.cmderr
.eq(Error
.EXCEPTION
)
169 with m
.Elif((control
.regno
>= 0x0000) & (control
.regno
< 0x1000)):
170 with m
.If(control
.transfer
):
171 m
.d
.comb
+= self
.csrf_addr
.eq(control
.regno
)
172 with m
.If(control
.write
):
175 self
.csrf_dat_w
.eq(self
.data0
.r
)
178 m
.d
.comb
+= self
.csrf_re
.eq(1)
179 m
.d
.sync
+= self
.data0
.w
.eq(self
.csrf_dat_r
)
180 m
.d
.sync
+= self
.abstractcs
.w
.cmderr
.eq(Error
.NONE
)
181 with m
.Elif((control
.regno
>= 0x1000) & (control
.regno
< 0x1020)):
182 with m
.If(control
.transfer
):
183 m
.d
.comb
+= self
.gprf_addr
.eq(control
.regno
)
184 with m
.If(control
.write
):
187 self
.gprf_dat_w
.eq(self
.data0
.r
)
190 m
.d
.sync
+= self
.data0
.w
.eq(self
.gprf_dat_r
)
191 m
.d
.sync
+= self
.abstractcs
.w
.cmderr
.eq(Error
.NONE
)
193 # Unknown register number.
194 m
.d
.sync
+= self
.abstractcs
.w
.cmderr
.eq(Error
.EXCEPTION
)
195 m
.next
= "COMMAND:DONE"
197 with m
.State("COMMAND:DONE"):
198 m
.d
.sync
+= self
.abstractcs
.w
.busy
.eq(0)