1 from migen
.fhdl
.std
import *
2 from migen
.genlib
.roundrobin
import *
3 from migen
.genlib
.misc
import optree
4 from migen
.genlib
.fsm
import FSM
, NextState
5 from migen
.bank
.description
import AutoCSR
7 from misoclib
.sdram
.lasmicon
.perf
import Bandwidth
10 def __init__(self
, a
, ba
):
13 self
.cas_n
= Signal(reset
=1)
14 self
.ras_n
= Signal(reset
=1)
15 self
.we_n
= Signal(reset
=1)
17 class CommandRequestRW(CommandRequest
):
18 def __init__(self
, a
, ba
):
19 CommandRequest
.__init
__(self
, a
, ba
)
22 self
.is_cmd
= Signal()
23 self
.is_read
= Signal()
24 self
.is_write
= Signal()
26 class _CommandChooser(Module
):
27 def __init__(self
, requests
):
28 self
.want_reads
= Signal()
29 self
.want_writes
= Signal()
30 self
.want_cmds
= Signal()
31 # NB: cas_n/ras_n/we_n are 1 when stb is inactive
32 self
.cmd
= CommandRequestRW(flen(requests
[0].a
), flen(requests
[0].ba
))
36 rr
= RoundRobin(len(requests
), SP_CE
)
39 self
.comb
+= [rr
.request
[i
].eq(req
.stb
& ((req
.is_cmd
& self
.want_cmds
) |
((req
.is_read
== self
.want_reads
) |
(req
.is_write
== self
.want_writes
))))
40 for i
, req
in enumerate(requests
)]
43 self
.comb
+= stb
.eq(Array(req
.stb
for req
in requests
)[rr
.grant
])
44 for name
in ["a", "ba", "is_read", "is_write", "is_cmd"]:
45 choices
= Array(getattr(req
, name
) for req
in requests
)
46 self
.comb
+= getattr(self
.cmd
, name
).eq(choices
[rr
.grant
])
47 for name
in ["cas_n", "ras_n", "we_n"]:
48 # we should only assert those signals when stb is 1
49 choices
= Array(getattr(req
, name
) for req
in requests
)
50 self
.comb
+= If(self
.cmd
.stb
, getattr(self
.cmd
, name
).eq(choices
[rr
.grant
]))
51 self
.comb
+= self
.cmd
.stb
.eq(stb \
52 & ((self
.cmd
.is_cmd
& self
.want_cmds
) |
((self
.cmd
.is_read
== self
.want_reads
) \
53 & (self
.cmd
.is_write
== self
.want_writes
))))
55 self
.comb
+= [If(self
.cmd
.stb
& self
.cmd
.ack
& (rr
.grant
== i
), req
.ack
.eq(1))
56 for i
, req
in enumerate(requests
)]
57 self
.comb
+= rr
.ce
.eq(self
.cmd
.ack
)
59 class _Steerer(Module
):
60 def __init__(self
, commands
, dfi
):
63 self
.sel
= [Signal(max=ncmd
) for i
in range(nph
)]
67 def stb_and(cmd
, attr
):
68 if not hasattr(cmd
, "stb"):
71 return cmd
.stb
& getattr(cmd
, attr
)
72 for phase
, sel
in zip(dfi
.phases
, self
.sel
):
77 if hasattr(phase
, "odt"):
78 self
.comb
+= phase
.odt
.eq(1)
79 if hasattr(phase
, "reset_n"):
80 self
.comb
+= phase
.reset_n
.eq(1)
82 phase
.address
.eq(Array(cmd
.a
for cmd
in commands
)[sel
]),
83 phase
.bank
.eq(Array(cmd
.ba
for cmd
in commands
)[sel
]),
84 phase
.cas_n
.eq(Array(cmd
.cas_n
for cmd
in commands
)[sel
]),
85 phase
.ras_n
.eq(Array(cmd
.ras_n
for cmd
in commands
)[sel
]),
86 phase
.we_n
.eq(Array(cmd
.we_n
for cmd
in commands
)[sel
]),
87 phase
.rddata_en
.eq(Array(stb_and(cmd
, "is_read") for cmd
in commands
)[sel
]),
88 phase
.wrdata_en
.eq(Array(stb_and(cmd
, "is_write") for cmd
in commands
)[sel
])
91 class Multiplexer(Module
, AutoCSR
):
92 def __init__(self
, phy_settings
, geom_settings
, timing_settings
, bank_machines
, refresher
, dfi
, lasmic
):
93 assert(phy_settings
.nphases
== len(dfi
.phases
))
96 requests
= [bm
.cmd
for bm
in bank_machines
]
97 choose_cmd
= _CommandChooser(requests
)
98 choose_req
= _CommandChooser(requests
)
100 choose_cmd
.want_reads
.eq(0),
101 choose_cmd
.want_writes
.eq(0)
103 if phy_settings
.nphases
== 1:
105 choose_cmd
.want_cmds
.eq(1),
106 choose_req
.want_cmds
.eq(1)
108 self
.submodules
+= choose_cmd
, choose_req
111 nop
= CommandRequest(geom_settings
.mux_a
, geom_settings
.bank_a
)
112 commands
= [nop
, choose_cmd
.cmd
, choose_req
.cmd
, refresher
.cmd
] # nop must be 1st
113 (STEER_NOP
, STEER_CMD
, STEER_REQ
, STEER_REFRESH
) = range(4)
114 steerer
= _Steerer(commands
, dfi
)
115 self
.submodules
+= steerer
117 # Read/write turnaround
118 read_available
= Signal()
119 write_available
= Signal()
121 read_available
.eq(optree("|", [req
.stb
& req
.is_read
for req
in requests
])),
122 write_available
.eq(optree("|", [req
.stb
& req
.is_write
for req
in requests
]))
125 def anti_starvation(timeout
):
130 time
= Signal(max=t
+1)
131 self
.comb
+= max_time
.eq(time
== 0)
138 self
.comb
+= max_time
.eq(0)
140 read_time_en
, max_read_time
= anti_starvation(timing_settings
.read_time
)
141 write_time_en
, max_write_time
= anti_starvation(timing_settings
.write_time
)
144 self
.comb
+= [bm
.refresh_req
.eq(refresher
.req
) for bm
in bank_machines
]
145 go_to_refresh
= Signal()
146 self
.comb
+= go_to_refresh
.eq(optree("&", [bm
.refresh_gnt
for bm
in bank_machines
]))
149 all_rddata
= [p
.rddata
for p
in dfi
.phases
]
150 all_wrdata
= [p
.wrdata
for p
in dfi
.phases
]
151 all_wrdata_mask
= [p
.wrdata_mask
for p
in dfi
.phases
]
153 lasmic
.dat_r
.eq(Cat(*all_rddata
)),
154 Cat(*all_wrdata
).eq(lasmic
.dat_w
),
155 Cat(*all_wrdata_mask
).eq(~lasmic
.dat_we
)
160 self
.submodules
+= fsm
162 def steerer_sel(steerer
, phy_settings
, r_w_n
):
164 for i
in range(phy_settings
.nphases
):
165 s
= steerer
.sel
[i
].eq(STEER_NOP
)
167 if i
== phy_settings
.rdphase
:
168 s
= steerer
.sel
[i
].eq(STEER_REQ
)
169 elif i
== phy_settings
.rdcmdphase
:
170 s
= steerer
.sel
[i
].eq(STEER_CMD
)
171 elif r_w_n
== "write":
172 if i
== phy_settings
.wrphase
:
173 s
= steerer
.sel
[i
].eq(STEER_REQ
)
174 elif i
== phy_settings
.wrcmdphase
:
175 s
= steerer
.sel
[i
].eq(STEER_CMD
)
183 choose_req
.want_reads
.eq(1),
184 choose_cmd
.cmd
.ack
.eq(1),
185 choose_req
.cmd
.ack
.eq(1),
186 steerer_sel(steerer
, phy_settings
, "read"),
188 # TODO: switch only after several cycles of ~read_available?
189 If(~read_available | max_read_time
, NextState("RTW"))
191 If(go_to_refresh
, NextState("REFRESH"))
195 choose_req
.want_writes
.eq(1),
196 choose_cmd
.cmd
.ack
.eq(1),
197 choose_req
.cmd
.ack
.eq(1),
198 steerer_sel(steerer
, phy_settings
, "write"),
200 If(~write_available | max_write_time
, NextState("WTR"))
202 If(go_to_refresh
, NextState("REFRESH"))
205 steerer
.sel
[0].eq(STEER_REFRESH
),
206 If(~refresher
.req
, NextState("READ"))
208 fsm
.delayed_enter("RTW", "WRITE", phy_settings
.read_latency
-1) # FIXME: reduce this, actual limit is around (cl+1)/nphases
209 fsm
.delayed_enter("WTR", "READ", timing_settings
.tWTR
-1)
210 # FIXME: workaround for zero-delay loop simulation problem with Icarus Verilog
212 self
.comb
+= refresher
.ack
.eq(fsm
.state
== fsm
.encoding
["REFRESH"])
214 self
.submodules
.bandwidth
= Bandwidth(choose_req
.cmd
)