1 from migen
.fhdl
.std
import *
2 from migen
.genlib
.roundrobin
import *
3 from migen
.genlib
.fsm
import FSM
, NextState
4 from migen
.genlib
.misc
import optree
5 from migen
.genlib
.fifo
import SyncFIFO
7 from misoclib
.lasmicon
.multiplexer
import *
10 def __init__(self
, col_a
, address_align
):
12 self
.address_align
= address_align
14 def row(self
, address
):
15 split
= self
.col_a
- self
.address_align
16 if isinstance(address
, int):
17 return address
>> split
19 return address
[split
:]
21 def col(self
, address
):
22 split
= self
.col_a
- self
.address_align
23 if isinstance(address
, int):
24 return (address
& (2**split
- 1)) << self
.address_align
26 return Cat(Replicate(0, self
.address_align
), address
[:split
])
28 class BankMachine(Module
):
29 def __init__(self
, geom_settings
, timing_settings
, address_align
, bankn
, req
):
30 self
.refresh_req
= Signal()
31 self
.refresh_gnt
= Signal()
32 self
.cmd
= CommandRequestRW(geom_settings
.mux_a
, geom_settings
.bank_a
)
37 self
.submodules
.req_fifo
= SyncFIFO([("we", 1), ("adr", flen(req
.adr
))], timing_settings
.req_queue_size
)
39 self
.req_fifo
.din
.we
.eq(req
.we
),
40 self
.req_fifo
.din
.adr
.eq(req
.adr
),
41 self
.req_fifo
.we
.eq(req
.stb
),
42 req
.req_ack
.eq(self
.req_fifo
.writable
),
44 self
.req_fifo
.re
.eq(req
.dat_ack
),
45 req
.lock
.eq(self
.req_fifo
.readable
)
47 reqf
= self
.req_fifo
.dout
49 slicer
= _AddressSlicer(geom_settings
.col_a
, address_align
)
52 has_openrow
= Signal()
53 openrow
= Signal(geom_settings
.row_a
)
55 self
.comb
+= hit
.eq(openrow
== slicer
.row(reqf
.adr
))
57 track_close
= Signal()
61 openrow
.eq(slicer
.row(reqf
.adr
))
71 self
.cmd
.ba
.eq(bankn
),
73 self
.cmd
.a
.eq(slicer
.row(reqf
.adr
))
75 self
.cmd
.a
.eq(slicer
.col(reqf
.adr
))
79 # Respect write-to-precharge specification
80 precharge_ok
= Signal()
81 t_unsafe_precharge
= 2 + timing_settings
.tWR
- 1
82 unsafe_precharge_count
= Signal(max=t_unsafe_precharge
+1)
83 self
.comb
+= precharge_ok
.eq(unsafe_precharge_count
== 0)
85 If(self
.cmd
.stb
& self
.cmd
.ack
& self
.cmd
.is_write
,
86 unsafe_precharge_count
.eq(t_unsafe_precharge
)
88 unsafe_precharge_count
.eq(unsafe_precharge_count
-1)
92 # Control and command generation FSM
94 self
.submodules
+= fsm
98 ).Elif(self
.req_fifo
.readable
,
101 # NB: write-to-read specification is enforced by multiplexer
103 req
.dat_ack
.eq(self
.cmd
.ack
),
104 self
.cmd
.is_read
.eq(~reqf
.we
),
105 self
.cmd
.is_write
.eq(reqf
.we
),
106 self
.cmd
.cas_n
.eq(0),
107 self
.cmd
.we_n
.eq(~reqf
.we
)
109 NextState("PRECHARGE")
112 NextState("ACTIVATE")
118 # 1. we are presenting the column address, A10 is always low
119 # 2. since we always go to the ACTIVATE state, we do not need
120 # to assert track_close.
123 If(self
.cmd
.ack
, NextState("TRP")),
124 self
.cmd
.ras_n
.eq(0),
126 self
.cmd
.is_cmd
.eq(1)
133 self
.cmd
.is_cmd
.eq(1),
134 If(self
.cmd
.ack
, NextState("TRCD")),
138 self
.refresh_gnt
.eq(precharge_ok
),
140 self
.cmd
.is_cmd
.eq(1),
141 If(~self
.refresh_req
, NextState("REGULAR"))
143 fsm
.delayed_enter("TRP", "ACTIVATE", timing_settings
.tRP
-1)
144 fsm
.delayed_enter("TRCD", "REGULAR", timing_settings
.tRCD
-1)