add minerva source from https://github.com/lambdaconcept/minerva
[soc.git] / src / soc / minerva / units / debug / controller.py
1 from nmigen import *
2 from nmigen.lib.coding import PriorityEncoder
3
4 from ...csr import *
5 from ...isa import *
6 from ...wishbone import wishbone_layout
7 from .dmi import DebugReg, Command, Error, Version, cmd_access_reg_layout
8
9
10 __all__ = ["DebugController"]
11
12
13 class HaltCause:
14 EBREAK = 1
15 TRIGGER = 0
16 HALTREQ = 3
17 STEP = 4
18 RESET_HALTREQ = 2
19
20
21 cause_map = [2, 1, 5, 3, 4]
22
23
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")
28
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)
35
36 self.trigger_haltreq = Signal()
37
38 self.x_pc = Signal(32)
39 self.x_ebreak = Signal()
40 self.x_stall = Signal()
41
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)
50
51 self.halt = Signal()
52 self.halted = Signal()
53 self.killall = Signal()
54 self.resumereq = Signal()
55 self.resumeack = Signal()
56
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)
62
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)
68
69 def elaborate(self, platform):
70 m = Module()
71
72 for csr in self.dcsr, self.dpc:
73 with m.If(csr.we):
74 m.d.sync += csr.r.eq(csr.w)
75
76 with m.If(self.dmcontrol.update):
77 m.d.sync += [
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)
85 ]
86
87 with m.If(self.abstractcs.update):
88 m.d.sync += self.abstractcs.w.cmderr.eq(self.abstractcs.r.cmderr)
89
90 m.d.comb += [
91 self.dmstatus.w.version.eq(Version.V013),
92 self.dmstatus.w.authenticated.eq(1),
93 self.resumereq.eq(self.dmcontrol.w.resumereq)
94 ]
95
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)
99
100 halt_pe = m.submodules.halt_pe = PriorityEncoder(5)
101 m.d.comb += [
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),
106 ]
107
108 with m.FSM():
109 with m.State("RUN"):
110 m.d.comb += self.dmstatus.w.allrunning.eq(1)
111 with m.If(~halt_pe.n):
112 m.d.sync += [
113 self.halt.eq(1),
114 self.dcsr.r.cause.eq(Array(cause_map)[halt_pe.o]),
115 self.dcsr.r.stepie.eq(1)
116 ]
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)
125 with m.Else():
126 m.d.sync += self.dpc.r.eq(self.x_pc)
127 m.next = "HALTING"
128
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)
133 m.next = "WAIT"
134
135 with m.State("WAIT"):
136 with m.If(self.dmcontrol.w.resumereq):
137 m.next = "RESUME"
138 with m.Elif(self.command.update):
139 m.d.sync += self.abstractcs.w.busy.eq(1)
140 m.next = "COMMAND:START"
141
142 with m.State("RESUME"):
143 with m.If(self.resumeack):
144 m.d.sync += [
145 self.dmcontrol.w.resumereq.eq(0),
146 self.dmstatus.w.allresumeack.eq(1),
147 self.halt.eq(0),
148 self.dmstatus.w.allhalted.eq(0)
149 ]
150 m.next = "RUN"
151
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"
159 with m.Case():
160 m.d.sync += self.abstractcs.w.cmderr.eq(Error.UNSUPPORTED)
161 m.next = "COMMAND:DONE"
162
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):
173 m.d.comb += [
174 self.csrf_we.eq(1),
175 self.csrf_dat_w.eq(self.data0.r)
176 ]
177 with m.Else():
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):
185 m.d.comb += [
186 self.gprf_we.eq(1),
187 self.gprf_dat_w.eq(self.data0.r)
188 ]
189 with m.Else():
190 m.d.sync += self.data0.w.eq(self.gprf_dat_r)
191 m.d.sync += self.abstractcs.w.cmderr.eq(Error.NONE)
192 with m.Else():
193 # Unknown register number.
194 m.d.sync += self.abstractcs.w.cmderr.eq(Error.EXCEPTION)
195 m.next = "COMMAND:DONE"
196
197 with m.State("COMMAND:DONE"):
198 m.d.sync += self.abstractcs.w.busy.eq(0)
199 m.next = "WAIT"
200
201 return m