send address to memory only for one cycle and acknowledge LD immediately
[soc.git] / src / soc / minerva / units / debug / wbmaster.py
1 from functools import reduce
2 from operator import or_
3
4 from nmigen import Elaboratable, Module, Signal, Record
5
6 from ...wishbone import wishbone_layout
7 from .dmi import DebugReg
8
9
10 __all__ = ["BusError", "AccessSize", "DebugWishboneMaster"]
11
12
13 class BusError:
14 NONE = 0
15 TIMEOUT = 1
16 BAD_ADDRESS = 2
17 MISALIGNED = 3
18 BAD_SIZE = 4
19 OTHER = 7
20
21
22 class AccessSize:
23 BYTE = 0
24 HALF = 1
25 WORD = 2
26
27
28 class DebugWishboneMaster(Elaboratable):
29 def __init__(self, debugrf):
30 self.bus = Record(wishbone_layout)
31
32 self.dbus_busy = Signal()
33
34 self.sbcs = debugrf.reg_port(DebugReg.SBCS)
35 self.sbaddress0 = debugrf.reg_port(DebugReg.SBADDRESS0)
36 self.sbdata0 = debugrf.reg_port(DebugReg.SBDATA0)
37
38 def elaborate(self, platform):
39 m = Module()
40
41 addr = self.sbaddress0.w.value
42 size = self.sbcs.r.sbaccess
43
44 width = Signal(6)
45 m.d.comb += width.eq((1<<size)*8)
46
47 sbbusyerror = self.sbcs.w.sbbusyerror
48 sberror = self.sbcs.w.sberror
49 m.d.comb += self.dbus_busy.eq(self.sbcs.w.sbbusy)
50
51 m.d.comb += [
52 self.sbcs.w.sbaccess8.eq(1),
53 self.sbcs.w.sbaccess16.eq(1),
54 self.sbcs.w.sbaccess32.eq(1),
55 self.sbcs.w.sbasize.eq(32),
56 self.sbcs.w.sbversion.eq(1)
57 ]
58
59 with m.If(self.sbcs.update):
60 m.d.sync += [
61 self.sbcs.w.sbbusyerror.eq(self.sbcs.r.sbbusyerror),
62 self.sbcs.w.sberror.eq(self.sbcs.r.sberror)
63 ]
64
65 we = Signal()
66 re = Signal()
67
68 with m.If(self.sbdata0.update):
69 with m.If(self.sbcs.w.sbbusy):
70 m.d.sync += self.sbcs.w.sbbusyerror.eq(1)
71 with m.Else():
72 m.d.sync += we.eq(~sberror.bool())
73
74 with m.If(self.sbdata0.capture):
75 with m.If(self.sbcs.w.sbbusy):
76 m.d.sync += self.sbcs.w.sbbusyerror.eq(1)
77 with m.Else():
78 m.d.sync += re.eq(self.sbcs.r.sbreadondata & ~sberror.bool())
79
80 with m.If(self.sbaddress0.update):
81 with m.If(self.sbcs.w.sbbusy):
82 m.d.sync += self.sbcs.w.sbbusyerror.eq(1)
83 with m.Else():
84 m.d.sync += [
85 re.eq(self.sbcs.r.sbreadonaddr & ~sberror.bool()),
86 self.sbaddress0.w.value.eq(self.sbaddress0.r.value)
87 ]
88
89 with m.FSM():
90 with m.State("IDLE"):
91 with m.If(we | re):
92 m.d.sync += we.eq(0), re.eq(0)
93 with m.If(size > AccessSize.WORD):
94 m.d.sync += sberror.eq(BusError.BAD_SIZE)
95 with m.Elif((addr & (1<<size)-1) != 0):
96 m.d.sync += sberror.eq(BusError.MISALIGNED)
97 with m.Else():
98 m.d.sync += [
99 self.bus.cyc.eq(1),
100 self.bus.stb.eq(1),
101 self.bus.adr.eq(addr[2:]),
102 self.bus.we.eq(we),
103 self.bus.sel.eq((1<<(1<<size))-1 << addr[:2]),
104 self.bus.dat_w.eq((self.sbdata0.r & (1<<width)-1) << addr[:2]*8)
105 ]
106 m.next = "BUSY"
107
108 with m.State("BUSY"):
109 m.d.comb += self.sbcs.w.sbbusy.eq(1)
110 with m.If(self.bus.ack | self.bus.err):
111 m.d.sync += [
112 self.bus.cyc.eq(0),
113 self.bus.stb.eq(0),
114 self.bus.we.eq(0),
115 ]
116 with m.If(self.bus.err):
117 m.d.sync += sberror.eq(BusError.OTHER)
118 with m.Else():
119 with m.If(~self.bus.we):
120 m.d.sync += self.sbdata0.w.eq((self.bus.dat_r >> addr[:2]*8) & (1<<width)-1)
121 with m.If(self.sbcs.r.sbautoincrement):
122 m.d.sync += addr.eq(addr + (1<<size))
123 m.next = "IDLE"
124
125 return m