853e7d9aa42b751aefb5c90e11bd688e7fa28abc
[litex.git] / litex / soc / misoc / cores / lasmicon / bankmachine.py
1 from migen import *
2 from migen.genlib.roundrobin import *
3 from migen.genlib.fsm import FSM, NextState
4 from migen.genlib.fifo import SyncFIFO
5
6 from misoc.cores.lasmicon.multiplexer import *
7
8
9 class _AddressSlicer:
10 def __init__(self, colbits, address_align):
11 self.colbits = colbits
12 self.address_align = address_align
13
14 def row(self, address):
15 split = self.colbits - self.address_align
16 if isinstance(address, int):
17 return address >> split
18 else:
19 return address[split:]
20
21 def col(self, address):
22 split = self.colbits - self.address_align
23 if isinstance(address, int):
24 return (address & (2**split - 1)) << self.address_align
25 else:
26 return Cat(Replicate(0, self.address_align), address[:split])
27
28
29 class BankMachine(Module):
30 def __init__(self, geom_settings, timing_settings, controller_settings, address_align, bankn, req):
31 self.refresh_req = Signal()
32 self.refresh_gnt = Signal()
33 self.cmd = CommandRequestRW(geom_settings.addressbits, geom_settings.bankbits)
34
35 ###
36
37 # Request FIFO
38 layout = [("we", 1), ("adr", len(req.adr))]
39 req_in = Record(layout)
40 reqf = Record(layout)
41 self.submodules.req_fifo = SyncFIFO(layout_len(layout),
42 controller_settings.req_queue_size)
43 self.comb += [
44 self.req_fifo.din.eq(req_in.raw_bits()),
45 reqf.raw_bits().eq(self.req_fifo.dout)
46 ]
47 self.comb += [
48 req_in.we.eq(req.we),
49 req_in.adr.eq(req.adr),
50 self.req_fifo.we.eq(req.stb),
51 req.req_ack.eq(self.req_fifo.writable),
52
53 self.req_fifo.re.eq(req.dat_w_ack | req.dat_r_ack),
54 req.lock.eq(self.req_fifo.readable)
55 ]
56
57 slicer = _AddressSlicer(geom_settings.colbits, address_align)
58
59 # Row tracking
60 has_openrow = Signal()
61 openrow = Signal(geom_settings.rowbits)
62 hit = Signal()
63 self.comb += hit.eq(openrow == slicer.row(reqf.adr))
64 track_open = Signal()
65 track_close = Signal()
66 self.sync += [
67 If(track_open,
68 has_openrow.eq(1),
69 openrow.eq(slicer.row(reqf.adr))
70 ),
71 If(track_close,
72 has_openrow.eq(0)
73 )
74 ]
75
76 # Address generation
77 s_row_adr = Signal()
78 self.comb += [
79 self.cmd.ba.eq(bankn),
80 If(s_row_adr,
81 self.cmd.a.eq(slicer.row(reqf.adr))
82 ).Else(
83 self.cmd.a.eq(slicer.col(reqf.adr))
84 )
85 ]
86
87 # Respect write-to-precharge specification
88 precharge_ok = Signal()
89 t_unsafe_precharge = 2 + timing_settings.tWR - 1
90 unsafe_precharge_count = Signal(max=t_unsafe_precharge+1)
91 self.comb += precharge_ok.eq(unsafe_precharge_count == 0)
92 self.sync += [
93 If(self.cmd.stb & self.cmd.ack & self.cmd.is_write,
94 unsafe_precharge_count.eq(t_unsafe_precharge)
95 ).Elif(~precharge_ok,
96 unsafe_precharge_count.eq(unsafe_precharge_count-1)
97 )
98 ]
99
100 # Control and command generation FSM
101 fsm = FSM()
102 self.submodules += fsm
103 fsm.act("REGULAR",
104 If(self.refresh_req,
105 NextState("REFRESH")
106 ).Elif(self.req_fifo.readable,
107 If(has_openrow,
108 If(hit,
109 # NB: write-to-read specification is enforced by multiplexer
110 self.cmd.stb.eq(1),
111 req.dat_w_ack.eq(self.cmd.ack & reqf.we),
112 req.dat_r_ack.eq(self.cmd.ack & ~reqf.we),
113 self.cmd.is_read.eq(~reqf.we),
114 self.cmd.is_write.eq(reqf.we),
115 self.cmd.cas_n.eq(0),
116 self.cmd.we_n.eq(~reqf.we)
117 ).Else(
118 NextState("PRECHARGE")
119 )
120 ).Else(
121 NextState("ACTIVATE")
122 )
123 )
124 )
125 fsm.act("PRECHARGE",
126 # Notes:
127 # 1. we are presenting the column address, A10 is always low
128 # 2. since we always go to the ACTIVATE state, we do not need
129 # to assert track_close.
130 If(precharge_ok,
131 self.cmd.stb.eq(1),
132 If(self.cmd.ack, NextState("TRP")),
133 self.cmd.ras_n.eq(0),
134 self.cmd.we_n.eq(0),
135 self.cmd.is_cmd.eq(1)
136 )
137 )
138 fsm.act("ACTIVATE",
139 s_row_adr.eq(1),
140 track_open.eq(1),
141 self.cmd.stb.eq(1),
142 self.cmd.is_cmd.eq(1),
143 If(self.cmd.ack, NextState("TRCD")),
144 self.cmd.ras_n.eq(0)
145 )
146 fsm.act("REFRESH",
147 self.refresh_gnt.eq(precharge_ok),
148 track_close.eq(1),
149 self.cmd.is_cmd.eq(1),
150 If(~self.refresh_req, NextState("REGULAR"))
151 )
152 fsm.delayed_enter("TRP", "ACTIVATE", timing_settings.tRP-1)
153 fsm.delayed_enter("TRCD", "REGULAR", timing_settings.tRCD-1)