1 from migen
.fhdl
.structure
import *
2 from migen
.corelogic
.roundrobin
import *
3 from migen
.corelogic
.misc
import optree
4 from migen
.corelogic
.fsm
import FSM
7 def __init__(self
, a
, ba
):
10 self
.cas_n
= Signal(reset
=1)
11 self
.ras_n
= Signal(reset
=1)
12 self
.we_n
= Signal(reset
=1)
14 class CommandRequestRW(CommandRequest
):
15 def __init__(self
, a
, ba
, tagbits
):
16 CommandRequest
.__init
__(self
, a
, ba
)
19 self
.is_read
= Signal()
20 self
.is_write
= Signal()
21 self
.tag
= Signal(tagbits
)
23 class _CommandChooser
:
24 def __init__(self
, requests
, tagbits
):
25 self
.requests
= requests
27 self
.want_reads
= Signal()
28 self
.want_writes
= Signal()
29 # NB: cas_n/ras_n/we_n are 1 when stb is inactive
30 self
.cmd
= CommandRequestRW(len(self
.requests
[0].a
), len(self
.requests
[0].ba
), tagbits
)
32 def get_fragment(self
):
36 rr
= RoundRobin(len(self
.requests
), SP_CE
)
38 comb
+= [rr
.request
[i
].eq(req
.stb
& ((req
.is_read
== self
.want_reads
) |
(req
.is_write
== self
.want_writes
)))
39 for i
, req
in enumerate(self
.requests
)]
42 comb
.append(stb
.eq(Array(req
.stb
for req
in self
.requests
)[rr
.grant
]))
43 for name
in ["a", "ba", "is_read", "is_write", "tag"]:
44 choices
= Array(getattr(req
, name
) for req
in self
.requests
)
45 comb
.append(getattr(self
.cmd
, name
).eq(choices
[rr
.grant
]))
46 for name
in ["cas_n", "ras_n", "we_n"]:
47 # we should only assert those signals when stb is 1
48 choices
= Array(getattr(req
, name
) for req
in self
.requests
)
49 comb
.append(If(self
.cmd
.stb
, getattr(self
.cmd
, name
).eq(choices
[rr
.grant
])))
50 comb
.append(self
.cmd
.stb
.eq(stb \
51 & (self
.cmd
.is_read
== self
.want_reads
) \
52 & (self
.cmd
.is_write
== self
.want_writes
)))
54 comb
+= [If(self
.cmd
.stb
& self
.cmd
.ack
& (rr
.grant
== i
), req
.ack
.eq(1))
55 for i
, req
in enumerate(self
.requests
)]
56 comb
.append(rr
.ce
.eq(self
.cmd
.ack
))
58 return Fragment(comb
, sync
) + rr
.get_fragment()
61 def __init__(self
, commands
, dfi
):
62 self
.commands
= commands
65 ncmd
= len(self
.commands
)
66 nph
= len(self
.dfi
.phases
)
67 self
.sel
= [Signal(bits_for(ncmd
-1)) for i
in range(nph
)]
69 def get_fragment(self
):
72 def stb_and(cmd
, attr
):
73 if not hasattr(cmd
, "stb"):
76 return cmd
.stb
& getattr(cmd
, attr
)
77 for phase
, sel
in zip(self
.dfi
.phases
, self
.sel
):
83 phase
.address
.eq(Array(cmd
.a
for cmd
in self
.commands
)[sel
]),
84 phase
.bank
.eq(Array(cmd
.ba
for cmd
in self
.commands
)[sel
]),
85 phase
.cas_n
.eq(Array(cmd
.cas_n
for cmd
in self
.commands
)[sel
]),
86 phase
.ras_n
.eq(Array(cmd
.ras_n
for cmd
in self
.commands
)[sel
]),
87 phase
.we_n
.eq(Array(cmd
.we_n
for cmd
in self
.commands
)[sel
]),
88 phase
.rddata_en
.eq(Array(stb_and(cmd
, "is_read") for cmd
in self
.commands
)[sel
]),
89 phase
.wrdata_en
.eq(Array(stb_and(cmd
, "is_write") for cmd
in self
.commands
)[sel
])
91 return Fragment(comb
, sync
)
94 def __init__(self
, timing_settings
, command
, dfi
, hub
):
95 self
.timing_settings
= timing_settings
96 self
.command
= command
100 def get_fragment(self
):
103 tagbits
= len(self
.hub
.tag_call
)
106 rd_tag
= Signal(tagbits
)
108 wr_tag
= Signal(tagbits
)
110 self
.hub
.call
.eq(rd_valid | wr_valid
),
112 self
.hub
.tag_call
.eq(wr_tag
)
114 self
.hub
.tag_call
.eq(rd_tag
)
118 rd_delay
= self
.timing_settings
.rd_delay
+ 1
119 rd_valid_d
= [Signal() for i
in range(rd_delay
)]
120 rd_tag_d
= [Signal(tagbits
) for i
in range(rd_delay
)]
121 for i
in range(rd_delay
):
124 rd_valid_d
[i
].eq(rd_valid_d
[i
-1]),
125 rd_tag_d
[i
].eq(rd_tag_d
[i
-1])
129 rd_valid_d
[i
].eq(self
.command
.stb
& self
.command
.ack
& self
.command
.is_read
),
130 rd_tag_d
[i
].eq(self
.command
.tag
)
133 rd_valid
.eq(rd_valid_d
[-1]),
134 rd_tag
.eq(rd_tag_d
[-1]),
135 wr_valid
.eq(self
.command
.stb
& self
.command
.ack
& self
.command
.is_write
),
136 wr_tag
.eq(self
.command
.tag
),
139 all_rddata
= [p
.rddata
for p
in self
.dfi
.phases
]
140 all_wrdata
= [p
.wrdata
for p
in self
.dfi
.phases
]
141 all_wrdata_mask
= [p
.wrdata_mask
for p
in self
.dfi
.phases
]
143 self
.hub
.dat_r
.eq(Cat(*all_rddata
)),
144 Cat(*all_wrdata
).eq(self
.hub
.dat_w
),
145 Cat(*all_wrdata_mask
).eq(self
.hub
.dat_wm
)
148 return Fragment(comb
, sync
)
151 def __init__(self
, phy_settings
, geom_settings
, timing_settings
, bank_machines
, refresher
, dfi
, hub
):
152 self
.phy_settings
= phy_settings
153 self
.geom_settings
= geom_settings
154 self
.timing_settings
= timing_settings
155 self
.bank_machines
= bank_machines
156 self
.refresher
= refresher
160 assert(self
.phy_settings
.nphases
== len(dfi
.phases
))
161 if self
.phy_settings
.nphases
!= 2:
162 raise NotImplementedError("TODO: multiplexer only supports 2 phases")
164 def get_fragment(self
):
169 requests
= [bm
.cmd
for bm
in self
.bank_machines
]
170 tagbits
= len(self
.hub
.tag_call
)
171 choose_cmd
= _CommandChooser(requests
, tagbits
)
172 choose_req
= _CommandChooser(requests
, tagbits
)
174 choose_cmd
.want_reads
.eq(0),
175 choose_cmd
.want_writes
.eq(0)
179 nop
= CommandRequest(self
.geom_settings
.mux_a
, self
.geom_settings
.bank_a
)
180 commands
= [nop
, choose_cmd
.cmd
, choose_req
.cmd
, self
.refresher
.cmd
] # nop must be 1st
181 (STEER_NOP
, STEER_CMD
, STEER_REQ
, STEER_REFRESH
) = range(4)
182 steerer
= _Steerer(commands
, self
.dfi
)
184 # Read/write turnaround
185 read_available
= Signal()
186 write_available
= Signal()
188 read_available
.eq(optree("|", [req
.stb
& req
.is_read
for req
in requests
])),
189 write_available
.eq(optree("|", [req
.stb
& req
.is_write
for req
in requests
]))
192 def anti_starvation(timeout
):
197 time
= Signal(bits_for(t
))
198 comb
.append(max_time
.eq(time
== 0))
207 comb
.append(max_time
.eq(0))
209 read_time_en
, max_read_time
= anti_starvation(self
.timing_settings
.read_time
)
210 write_time_en
, max_write_time
= anti_starvation(self
.timing_settings
.write_time
)
213 comb
+= [bm
.refresh_req
.eq(self
.refresher
.req
)
214 for bm
in self
.bank_machines
]
215 go_to_refresh
= Signal()
216 comb
.append(go_to_refresh
.eq(
217 optree("&", [bm
.refresh_gnt
for bm
in self
.bank_machines
])))
220 datapath
= _Datapath(self
.timing_settings
, choose_req
.cmd
, self
.dfi
, self
.hub
)
223 fsm
= FSM("READ", "WRITE", "REFRESH", delayed_enters
=[
224 ("RTW", "WRITE", self
.timing_settings
.rd_delay
),
225 ("WTR", "READ", self
.timing_settings
.tWR
)
229 choose_req
.want_reads
.eq(1),
230 choose_cmd
.cmd
.ack
.eq(1),
231 choose_req
.cmd
.ack
.eq(1),
232 steerer
.sel
[1-self
.phy_settings
.rdphase
].eq(STEER_CMD
),
233 steerer
.sel
[self
.phy_settings
.rdphase
].eq(STEER_REQ
),
235 # TODO: switch only after several cycles of ~read_available?
236 If(~read_available | max_read_time
, fsm
.next_state(fsm
.RTW
))
238 If(go_to_refresh
, fsm
.next_state(fsm
.REFRESH
))
242 choose_req
.want_writes
.eq(1),
243 choose_cmd
.cmd
.ack
.eq(1),
244 choose_req
.cmd
.ack
.eq(1),
245 steerer
.sel
[1-self
.phy_settings
.wrphase
].eq(STEER_CMD
),
246 steerer
.sel
[self
.phy_settings
.wrphase
].eq(STEER_REQ
),
248 If(~write_available | max_write_time
, fsm
.next_state(fsm
.WTR
))
250 If(go_to_refresh
, fsm
.next_state(fsm
.REFRESH
))
253 steerer
.sel
[0].eq(STEER_REFRESH
),
254 If(~self
.refresher
.req
, fsm
.next_state(fsm
.READ
))
256 # FIXME: workaround for zero-delay loop simulation problem with Icarus Verilog
257 comb
.append(self
.refresher
.ack
.eq(fsm
._state
== fsm
.REFRESH
))
259 return Fragment(comb
, sync
) + \
260 choose_cmd
.get_fragment() + \
261 choose_req
.get_fragment() + \
262 steerer
.get_fragment() + \
263 datapath
.get_fragment() + \