move memory related types from mmu.py into new file mem_types.py as they
[soc.git] / src / soc / experiment / mmu.py
1 """MMU
2
3 based on Anton Blanchard microwatt mmu.vhdl
4
5 """
6 from enum import Enum, unique
7 from nmigen import (Module, Signal, Elaboratable,
8 Mux, Cat, Repl, signed,
9 ResetSignal)
10 from nmigen.cli import main
11 from nmigen.iocontrol import RecordObject
12
13 from experiment.mem_types import LoadStore1ToMmuType,
14 MmuToLoadStore1Type,
15 MmuToDcacheType,
16 DcacheToMmuType,
17 MmuToIcacheType
18
19 # library ieee; use ieee.std_logic_1164.all;
20 # use ieee.numeric_std.all;
21
22 # library work; use work.common.all;
23
24
25 # -- Radix MMU
26 # -- Supports 4-level trees as in arch 3.0B, but not the
27 # -- two-step translation
28 # -- for guests under a hypervisor (i.e. there is no gRA -> hRA translation).
29
30 # type state_t is
31 # (IDLE,
32 # DO_TLBIE,
33 # TLB_WAIT,
34 # PROC_TBL_READ,
35 # PROC_TBL_WAIT,
36 # SEGMENT_CHECK,
37 # RADIX_LOOKUP,
38 # RADIX_READ_WAIT,
39 # RADIX_LOAD_TLB,
40 # RADIX_FINISH
41 # );
42
43 # architecture behave of mmu is
44
45 @unique
46 class State(Enum):
47 IDLE = 0
48 DO_TLBIE = 1
49 TLB_WAIT = 2
50 PROC_TBL_READ = 3
51 PROC_TBL_WAIT = 4
52 SEGMENT_CHECK = 5
53 RADIX_LOOKUP = 6
54 RADIX_READ_WAIT = 7
55 RADIX_LOAD_TLB = 8
56 RADIX_FINISH = 9
57
58 # type reg_stage_t is record
59 # -- latched request from loadstore1
60 # valid : std_ulogic;
61 # iside : std_ulogic;
62 # store : std_ulogic;
63 # priv : std_ulogic;
64 # addr : std_ulogic_vector(63 downto 0);
65 # inval_all : std_ulogic;
66 # -- config SPRs
67 # prtbl : std_ulogic_vector(63 downto 0);
68 # pid : std_ulogic_vector(31 downto 0);
69 # -- internal state
70 # state : state_t;
71 # done : std_ulogic;
72 # err : std_ulogic;
73 # pgtbl0 : std_ulogic_vector(63 downto 0);
74 # pt0_valid : std_ulogic;
75 # pgtbl3 : std_ulogic_vector(63 downto 0);
76 # pt3_valid : std_ulogic;
77 # shift : unsigned(5 downto 0);
78 # mask_size : unsigned(4 downto 0);
79 # pgbase : std_ulogic_vector(55 downto 0);
80 # pde : std_ulogic_vector(63 downto 0);
81 # invalid : std_ulogic;
82 # badtree : std_ulogic;
83 # segerror : std_ulogic;
84 # perm_err : std_ulogic;
85 # rc_error : std_ulogic;
86 # end record;
87
88
89 class RegStage(RecordObject):
90 def __init__(self, name=None):
91 super().__init__(self, name=name)
92 # latched request from loadstore1
93 self.valid = Signal(reset_less=True)
94 self.iside = Signal(reset_less=True)
95 self.store = Signal(reset_less=True)
96 self.priv = Signal(reset_less=True)
97 self.addr = Signal(64, reset_less=True)
98 self.inval_all = Signal(reset_less=True)
99 # config SPRs
100 self.prtbl = Signal(64, reset_less=True)
101 self.pid = Signal(32, reset_less=True)
102 # internal state
103 self.state = State.IDLE
104 self.done = Signal(reset_less=True)
105 self.err = Signal(reset_less=True)
106 self.pgtbl0 = Signal(64, reset_less=True)
107 self.pt0_valid = Signal(reset_less=True)
108 self.pgtbl3 = Signal(64, reset_less=True)
109 self.pt3_valid = Signal(reset_less=True)
110 self.shift = Signal(6, reset_less=True)
111 self.mask_size = Signal(5, reset_less=True)
112 self.pgbase = Signal(56, reset_less=True)
113 self.pde = Signal(64, reset_less=True)
114 self.invalid = Signal(reset_less=True)
115 self.badtree = Signal(reset_less=True)
116 self.segerror = Signal(reset_less=True)
117 self.perm_err = Signal(reset_less=True)
118 self.rc_error = Signal(reset_less=True)
119
120
121 # Radix MMU
122 # Supports 4-level trees as in arch 3.0B, but not the
123 # two-step translation for guests under a hypervisor
124 # (i.e. there is no gRA -> hRA translation).
125 class MMU(Elaboratable):
126 # entity mmu is
127 # port (
128 # clk : in std_ulogic;
129 # rst : in std_ulogic;
130 #
131 # l_in : in Loadstore1ToMmuType;
132 # l_out : out MmuToLoadstore1Type;
133 #
134 # d_out : out MmuToDcacheType;
135 # d_in : in DcacheToMmuType;
136 #
137 # i_out : out MmuToIcacheType
138 # );
139 # end mmu;
140 def __init__(self):
141 self.l_in = LoadStore1ToMmuType()
142 self.l_out = MmuToLoadStore1Type()
143 self.d_out = MmuToDcacheType()
144 self.d_in = DcacheToMmuType()
145 self.i_out = MmuToIcacheType()
146
147 # signal addrsh : std_ulogic_vector(15 downto 0);
148 # signal mask : std_ulogic_vector(15 downto 0);
149 # signal finalmask : std_ulogic_vector(43 downto 0);
150 self.addrsh = Signal(16)
151 self.mask = Signal(16)
152 self.finalmask = Signal(44)
153
154 # signal r, rin : reg_stage_t;
155 self.r = RegStage()
156 self.rin = RegStage()
157
158 # begin
159 def elaborate(self, platform):
160 # -- Multiplex internal SPR values back to loadstore1,
161 # -- selected by l_in.sprn.
162 # Multiplex internal SPR values back to loadstore1,
163 # selected by l_in.sprn.
164 m = Module()
165
166 comb = m.d.comb
167 sync = m.d.sync
168
169 l_in = self.l_in
170 l_out = self.l_out
171 d_out = self.d_out
172 d_in = self.d_in
173 i_out = self.i_out
174
175 addrsh = self.addrsh
176 mask = self.mask
177 finalmask = self.finalmask
178
179 r = self.r
180 rin = self.rin
181
182 # l_out.sprval <= r.prtbl when l_in.sprn(9) = '1'
183 with m.If(l_in.sprn[9]):
184 comb += l_out.sprval.eq(r.prtbl)
185
186 # else x"00000000" & r.pid;
187 with m.Else():
188 comb += l_out.sprval.eq(Cat(r.pid,
189 Const(0x00000000, 32))
190
191 # if rin.valid = '1' then
192 # report "MMU got tlb miss for "
193 # & to_hstring(rin.addr);
194 # end if;
195 with m.If(rin.valid):
196 print(f"MMU got tlb miss for {rin.addr}")
197
198 # if l_out.done = '1' then
199 # report "MMU completing op without error";
200 # end if;
201 with m.If(l_out.done):
202 print("MMU completing op without error")
203
204 # if l_out.err = '1' then
205 # report "MMU completing op with err invalid=" &
206 # std_ulogic'image(l_out.invalid) &
207 # " badtree=" & std_ulogic'image(
208 # l_out.badtree);
209 # end if;
210 with m.If(l_out.err):
211 print(f"MMU completing op with err invalid=
212 {l_out.invalid} badtree={l_out.badtree}")
213
214 # if rin.state = RADIX_LOOKUP then
215 # report "radix lookup shift=" & integer'image(
216 # to_integer(rin.shift)) & " msize=" &
217 # integer'image(to_integer(rin.mask_size));
218 # end if;
219 with m.If(rin.state == State.RADIX_LOOKUP):
220 print(f"radix lookup shift={rin.shift}
221 msize={rin.mask_size}")
222
223 # if r.state = RADIX_LOOKUP then
224 # report "send load addr=" & to_hstring(d_out.addr)
225 # & " addrsh=" & to_hstring(addrsh) &
226 # " mask=" & to_hstring(mask);
227 # end if;
228 with m.If(r.state == State.RADIX_LOOKUP):
229 print(f"send load addr={d_out.addr}
230 addrsh={addrsh} mask={mask}")
231
232 # r <= rin;
233 sync += r.eq(rin)
234 # end process;
235
236 # -- generate mask for extracting address fields for PTE address
237 # -- generation
238 # addrmaskgen: process(all)
239 # generate mask for extracting address fields for PTE address
240 # generation
241 class AddrMaskGen(Elaboratable, MMU):
242 def __init__(self):
243 # variable m : std_ulogic_vector(15 downto 0);
244 super().__init__()
245 self.msk = Signal(16)
246
247 # begin
248 def elaborate(self, platform):
249 m = Module()
250
251 comb = m.d.comb
252 sync = m.d.sync
253
254 rst = ResetSignal()
255
256 msk = self.msk
257
258 r = self.r
259 mask = self.mask
260
261 # -- mask_count has to be >= 5
262 # m := x"001f";
263 # mask_count has to be >= 5
264 comb += mask.eq(Const(0x001F, 16)
265
266 # for i in 5 to 15 loop
267 for i in range(5,16):
268 # if i < to_integer(r.mask_size) then
269 with m.If(i < r.mask_size):
270 # m(i) := '1';
271 comb += msk[i].eq(1)
272 # end if;
273 # end loop;
274 # mask <= m;
275 comb += mask.eq(msk)
276 # end process;
277
278 # -- generate mask for extracting address bits to go in
279 # -- TLB entry in order to support pages > 4kB
280 # finalmaskgen: process(all)
281 # generate mask for extracting address bits to go in
282 # TLB entry in order to support pages > 4kB
283 class FinalMaskGen(Elaboratable, MMU):
284 def __init__(self):
285 # variable m : std_ulogic_vector(43 downto 0);
286 super().__init__()
287 self.msk = Signal(44)
288
289 # begin
290 def elaborate(self, platform):
291 m = Module()
292
293 comb = m.d.comb
294 sync = m.d.sync
295
296 rst = ResetSignal()
297
298 mask = self.mask
299 r = self.r
300
301 msk = self.msk
302
303 # for i in 0 to 43 loop
304 for i in range(44):
305 # if i < to_integer(r.shift) then
306 with m.If(i < r.shift):
307 # m(i) := '1';
308 comb += msk.eq(1)
309 # end if;
310 # end loop;
311 # finalmask <= m;
312 comb += self.finalmask(mask)
313 # end process;
314
315 # mmu_1: process(all)
316 class MMU1(Elaboratable):
317 def __init__(self):
318 # variable v : reg_stage_t;
319 # variable dcreq : std_ulogic;
320 # variable tlb_load : std_ulogic;
321 # variable itlb_load : std_ulogic;
322 # variable tlbie_req : std_ulogic;
323 # variable prtbl_rd : std_ulogic;
324 # variable pt_valid : std_ulogic;
325 # variable effpid : std_ulogic_vector(31 downto 0);
326 # variable prtable_addr : std_ulogic_vector(63 downto 0);
327 # variable rts : unsigned(5 downto 0);
328 # variable mbits : unsigned(5 downto 0);
329 # variable pgtable_addr : std_ulogic_vector(63 downto 0);
330 # variable pte : std_ulogic_vector(63 downto 0);
331 # variable tlb_data : std_ulogic_vector(63 downto 0);
332 # variable nonzero : std_ulogic;
333 # variable pgtbl : std_ulogic_vector(63 downto 0);
334 # variable perm_ok : std_ulogic;
335 # variable rc_ok : std_ulogic;
336 # variable addr : std_ulogic_vector(63 downto 0);
337 # variable data : std_ulogic_vector(63 downto 0);
338 self.v = RegStage()
339 self.dcrq = Signal()
340 self.tlb_load = Signal()
341 self.itlb_load = Signal()
342 self.tlbie_req = Signal()
343 self.prtbl_rd = Signal()
344 self.pt_valid = Signal()
345 self.effpid = Signal(32)
346 self.prtable_addr = Signal(64)
347 self.rts = Signal(6)
348 self.mbits = Signal(6)
349 self.pgtable_addr = Signal(64)
350 self.pte = Signal(64)
351 self.tlb_data = Signal(64)
352 self.nonzero = Signal()
353 self.pgtbl = Signal(64)
354 self.perm_ok = Signal()
355 self.rc_ok = Signal()
356 self.addr = Signal(64)
357 self.data = Signal(64)
358
359 # begin
360 def elaborate(self, platform):
361
362 m = Module()
363
364 comb = m.d.comb
365 sync = m.d.sync
366
367 l_in = self.l_in
368 l_out = self.l_out
369 d_out = self.d_out
370 d_in = self.d_in
371 i_out = self.i_out
372
373 r = self.r
374
375 v = self.v
376 dcrq = self.dcrq
377 tlb_load = self.tlb_load
378 itlb_load = self.itlb_load
379 tlbie_req = self.tlbie_req
380 prtbl_rd = self.prtbl_rd
381 pt_valid = self.pt_valid
382 effpid = self.effpid
383 prtable_addr = self.prtable_addr
384 rts = self.rts
385 mbits = self.mbits
386 pgtable_addr = self.pgtable_addr
387 pte = self.pte
388 tlb_data = self.tlb_data
389 nonzero = self.nonzero
390 pgtbl = self.pgtbl
391 perm_ok = self.perm_ok
392 rc_ok = self.rc_ok
393 addr = self.addr
394 data = self.data
395
396 # v := r;
397 # v.valid := '0';
398 # dcreq := '0';
399 # v.done := '0';
400 # v.err := '0';
401 # v.invalid := '0';
402 # v.badtree := '0';
403 # v.segerror := '0';
404 # v.perm_err := '0';
405 # v.rc_error := '0';
406 # tlb_load := '0';
407 # itlb_load := '0';
408 # tlbie_req := '0';
409 # v.inval_all := '0';
410 # prtbl_rd := '0';
411
412 comb += v.eq(r)
413 comb += v.valid.eq(0)
414 comb += dcreq.eq(0)
415 comb += v.done.eq(0)
416 comb += v.err.eq(0)
417 comb += v.invalid.eq(0)
418 comb += v.badtree.eq(0)
419 comb += v.segerror.eq(0)
420 comb += v.perm_err.eq(0)
421 comb += v.rc_error.eq(0)
422 comb += tlb_load.eq(0)
423 comb += itlb_load.eq(0)
424 comb += tlbie_req.eq(0)
425 comb += v.inval_all.eq(0)
426 comb += prtbl_rd.eq(0)
427
428
429 # -- Radix tree data structures in memory are
430 # -- big-endian, so we need to byte-swap them
431 # for i in 0 to 7 loop
432 # Radix tree data structures in memory are
433 # big-endian, so we need to byte-swap them
434 for i in range(8):
435 # data(i * 8 + 7 downto i * 8) := d_in.data(
436 # (7 - i) * 8 + 7 downto (7 - i) * 8);
437 comb += data[i * 8:i * 8 + 7 + 1].eq(
438 d_in.data[
439 (7 - i) * 8:(7 - i) * 8 + 7 + 1
440 ])
441 # end loop;
442
443 # case r.state is
444 with m.Switch(r.state):
445 # when IDLE =>
446 with m.Case(State.IDLE):
447 # if l_in.addr(63) = '0' then
448 # pgtbl := r.pgtbl0;
449 # pt_valid := r.pt0_valid;
450 with m.If(~l_in.addr[63]):
451 comb += pgtbl.eq(r.pgtbl0)
452 comb += pt_valid.eq(r.pt0_valid)
453 # else
454 # pgtbl := r.pgtbl3;
455 # pt_valid := r.pt3_valid;
456 with m.Else():
457 comb += pgtbl.eq(r.pt3_valid)
458 comb += pt_valid.eq(r.pt3_valid)
459 # end if;
460
461 # -- rts == radix tree size, # address bits being
462 # -- translated
463 # rts := unsigned('0' & pgtbl(62 downto 61) &
464 # pgtbl(7 downto 5));
465 # rts == radix tree size, number of address bits
466 # being translated
467 comb += rts.eq((Cat(
468 Cat(
469 pgtbl[5:8],
470 pgtbl[61:63]
471 ),
472 Const(0b0,1)
473 )).as_unsigned())
474
475 # -- mbits == # address bits to index top level
476 # -- of tree
477 # mbits := unsigned('0' & pgtbl(4 downto 0));
478 # mbits == number of address bits to index top
479 # level of tree
480 comb += mbits.eq((
481 Cat(pgtbl[0:5], Const(0b0, 1))
482 ).as_unsigned())
483 # -- set v.shift to rts so that we can use finalmask
484 # -- for the segment check
485 # v.shift := rts;
486 # v.mask_size := mbits(4 downto 0);
487 # v.pgbase := pgtbl(55 downto 8) & x"00";
488 # set v.shift to rts so that we can use finalmask
489 # for the segment check
490 comb += v.shift.eq(rts)
491 comb += v.mask_size.eq(mbits[0:5])
492 comb += v.pgbase.eq(Cat(
493 Cont(0x00, 8),
494 pgtbl[8:56]
495 ))
496
497 # if l_in.valid = '1' then
498 with m.If(l_in.valid):
499 # v.addr := l_in.addr;
500 # v.iside := l_in.iside;
501 # v.store := not (l_in.load or l_in.iside);
502 # v.priv := l_in.priv;
503 comb += v.addr.eq(l_in.addr
504 comb += v.iside.eq(l_in.iside)
505 comb += v.store.eq(~(l_in.load | l_in.siside))
506 # if l_in.tlbie = '1' then
507 with m.If(l_in.tlbie):
508 # -- Invalidate all iTLB/dTLB entries for
509 # -- tlbie with RB[IS] != 0 or RB[AP] != 0,
510 # -- or for slbia
511 # v.inval_all := l_in.slbia or l_in.addr(11)
512 # or l_in.addr(10) or
513 # l_in.addr(7) or l_in.addr(6)
514 # or l_in.addr(5);
515 # Invalidate all iTLB/dTLB entries for
516 # tlbie with RB[IS] != 0 or RB[AP] != 0,
517 # or for slbia
518 comb += v.inval_all.eq(l_in.slbia
519 | l_in.addr[11]
520 | l_in.addr[10]
521 | l_in.addr[7]
522 | l_in.addr[6]
523 | l_in.addr[5]
524 )
525 # -- The RIC field of the tlbie instruction
526 # -- comes across on the sprn bus as bits 2--3.
527 # -- RIC=2 flushes process table caches.
528 # if l_in.sprn(3) = '1' then
529 # The RIC field of the tlbie instruction
530 # comes across on the sprn bus as bits 2--3.
531 # RIC=2 flushes process table caches.
532 with m.If(l_in.sprn[3]):
533 # v.pt0_valid := '0';
534 # v.pt3_valid := '0';
535 comb += v.pt0_valid.eq(0)
536 comb += v.pt3_valid.eq(0)
537 # end if;
538 # v.state := DO_TLBIE;
539 comb += v.state.eq(State.DO_TLBIE)
540 # else
541 with m.Else():
542 # v.valid := '1';
543 comb += v.valid.eq(1)
544 # if pt_valid = '0' then
545 with m.If(~pt_valid):
546 # -- need to fetch process table entry
547 # -- set v.shift so we can use finalmask
548 # -- for generating the process table
549 # -- entry address
550 # v.shift := unsigned('0' & r.prtbl(
551 # 4 downto 0));
552 # v.state := PROC_TBL_READ;
553 # need to fetch process table entry
554 # set v.shift so we can use finalmask
555 # for generating the process table
556 # entry address
557 comb += v.shift.eq((Cat(
558 r.prtble[0:5],
559 Const(0b0, 1)
560 )).as_unsigned())
561 comb += v.state.eq(State.PROC_TBL_READ)
562
563 # elsif mbits = 0 then
564 with m.If(~mbits):
565 # -- Use RPDS = 0 to disable radix
566 # -- tree walks
567 # v.state := RADIX_FINISH;
568 # v.invalid := '1';
569 # Use RPDS = 0 to disable radix
570 # tree walks
571 comb += v.state.eq(State.RADIX_FINISH)
572 comb += v.invalid.eq(1)
573 # else
574 with m.Else():
575 # v.state := SEGMENT_CHECK;
576 comb += v.state.eq(State.SEGMENT_CHECK)
577 # end if;
578 # end if;
579 # end if;
580
581 # if l_in.mtspr = '1' then
582 with m.If(l_in.mtspr):
583 # -- Move to PID needs to invalidate L1 TLBs
584 # -- and cached pgtbl0 value. Move to PRTBL
585 # -- does that plus invalidating the cached
586 # -- pgtbl3 value as well.
587 # if l_in.sprn(9) = '0' then
588 # Move to PID needs to invalidate L1 TLBs
589 # and cached pgtbl0 value. Move to PRTBL
590 # does that plus invalidating the cached
591 # pgtbl3 value as well.
592 with m.If(~l_in.sprn[9]):
593 # v.pid := l_in.rs(31 downto 0);
594 comb += v.pid.eq(l_in.rs[0:32])
595 # else
596 with m.Else():
597 # v.prtbl := l_in.rs;
598 # v.pt3_valid := '0';
599 comb += v.prtbl.eq(l_in.rs)
600 comb += v.pt3_valid.eq(0)
601 # end if;
602
603 # v.pt0_valid := '0';
604 # v.inval_all := '1';
605 # v.state := DO_TLBIE;
606 comb += v.pt0_valid.eq(0)
607 comb += v.inval_all.eq(1)
608 comb += v.state.eq(State.DO_TLBIE)
609 # end if;
610
611 # when DO_TLBIE =>
612 with m.Case(State.DO_TLBIE):
613 # dcreq := '1';
614 # tlbie_req := '1';
615 # v.state := TLB_WAIT;
616 comb += dcreq.eq(1)
617 comb += tlbie_req.eq(1)
618 comb += v.state.eq(State.TLB_WAIT)
619
620 # when TLB_WAIT =>
621 with m.Case(State.TLB_WAIT):
622 # if d_in.done = '1' then
623 with m.If(d_in.done):
624 # v.state := RADIX_FINISH;
625 comb += v.state.eq(State.RADIX_FINISH)
626 # end if;
627
628 # when PROC_TBL_READ =>
629 with m.Case(State.PROC_TBL_READ):
630 # dcreq := '1';
631 # prtbl_rd := '1';
632 # v.state := PROC_TBL_WAIT;
633 comb += dcreq.eq(1)
634 comb += prtbl_rd.eq(1)
635 comb += v.state.eq(State.PROC_TBL_WAIT)
636
637 # when PROC_TBL_WAIT =>
638 with m.Case(State.PROC_TBL_WAIT):
639 # if d_in.done = '1' then
640 with m.If(d_in.done):
641 # if r.addr(63) = '1' then
642 with m.If(r.addr[63]):
643 # v.pgtbl3 := data;
644 # v.pt3_valid := '1';
645 comb += v.pgtbl3.eq(data)
646 comb += v.pt3_valid.eq(1)
647 # else
648 with m.Else():
649 # v.pgtbl0 := data;
650 # v.pt0_valid := '1';
651 comb += v.pgtbl0.eq(data)
652 comb += v.pt0_valid.eq(1)
653 # end if;
654 # -- rts == radix tree size, # address bits
655 # -- being translated
656 # rts := unsigned('0' & data(62 downto 61) &
657 # data(7 downto 5));
658 # rts == radix tree size, # address bits
659 # being translated
660 comb += rts.eq((
661 Cat(
662 Cat(
663 data[5:8],
664 data[61:63]
665 ),
666 Const(0b0, 1)
667 )
668 ).as_unsigned())
669
670 # -- mbits == # address bits to index
671 # -- top level of tree
672 # mbits := unsigned('0' & data(4 downto 0));
673 # mbits == # address bits to index
674 # top level of tree
675 comb += mbits.eq((
676 Cat(
677 data[0:5],
678 Const(0b0, 1)
679 )
680 ).as_unsigned())
681 # -- set v.shift to rts so that we can use
682 # -- finalmask for the segment check
683 # v.shift := rts;
684 # v.mask_size := mbits(4 downto 0);
685 # v.pgbase := data(55 downto 8) & x"00";
686 # set v.shift to rts so that we can use
687 # finalmask for the segment check
688 comb += v.shift.eq(rts)
689 comb += v.mask_size.eq(mbits[0:5])
690 comb += v.pgbase.eq(
691 Cat(
692 Const(0x00, 8),
693 data[8:56]
694 )
695 )
696
697 # if mbits = 0 then
698 with m.If(~mbits):
699 # v.state := RADIX_FINISH;
700 # v.invalid := '1';
701 comb += v.state.eq(State.RADIX_FINISH)
702 comb += v.invalid.eq(1)
703 # else
704 # v.state := SEGMENT_CHECK;
705 comb += v.state.eq(State.SEGMENT_CHECK)
706 # end if;
707 # end if;
708
709 # if d_in.err = '1' then
710 with m.If(d_in.err):
711 # v.state := RADIX_FINISH;
712 # v.badtree := '1';
713 comb += v.state.eq(State.RADIX_FINISH)
714 comb += v.badtree.eq(1)
715 # end if;
716
717 # when SEGMENT_CHECK =>
718 with m.Case(State.SEGMENT_CHECK):
719 # mbits := '0' & r.mask_size;
720 # v.shift := r.shift + (31 - 12) - mbits;
721 # nonzero := or(r.addr(61 downto 31) and
722 # not finalmask(30 downto 0));
723 comb += mbits.eq(
724 Cat(
725 r.mask_size,
726 Const(0b0, 1)
727 )
728 )
729 comb += v.shift.eq(r.shift + (31 -12) - mbits)
730 comb += nonzero.eq((
731 r.addr[31:62] & ~finalmask[0:31]
732 ).bool())
733 # if r.addr(63) /= r.addr(62) or nonzero = '1' then
734 # v.state := RADIX_FINISH;
735 # v.segerror := '1';
736 with m.If((r.addr[63] != r.addr[62])
737 | nonzero):
738 comb += v.state.eq(State.RADIX_FINISH)
739 comb += v.segerror.eq(1)
740 # elsif mbits < 5 or mbits > 16 or mbits
741 # > (r.shift + (31 - 12)) then
742 # v.state := RADIX_FINISH;
743 # v.badtree := '1';
744 with m.If((mbits < 5) | (mbits > 16)
745 | (mbits > (r.shift + (31-12)))):
746 comb += v.state.eq(State.RADIX_FINISH)
747 comb += v.badtree.eq(1)
748 # else
749 # v.state := RADIX_LOOKUP;
750 with m.Else():
751 comb += v.state.eq(State.RADIX_LOOKUP)
752 # end if;
753 #
754 # when RADIX_LOOKUP =>
755 with m.Case(State.RADIX_LOOKUP):
756 # dcreq := '1';
757 # v.state := RADIX_READ_WAIT;
758 comb += dcreq.eq(1)
759 comb += v.state.eq(State.RADIX_READ_WAIT)
760
761 # when RADIX_READ_WAIT =>
762 with m.Case(State.RADIX_READ_WAIT):
763 # if d_in.done = '1' then
764 with m.If(d_in.done):
765 # v.pde := data;
766 comb += v.pde.eq(data)
767 # -- test valid bit
768 # if data(63) = '1' then
769 # test valid bit
770 with m.If(data[63]):
771 # -- test leaf bit
772 # if data(62) = '1' then
773 # test leaf bit
774 with m.If(data[62]):
775 # -- check permissions and RC bits
776 # perm_ok := '0';
777 comb += perm_ok.eq(0)
778 # if r.priv = '1' or data(3) = '0' then
779 with m.If(r.priv | ~data[3])):
780 # if r.iside = '0' then
781 # perm_ok := data(1) or (data(2)
782 # and not r.store);
783 with m.If(~r.iside):
784 comb += perm_ok.eq(
785 (data[1] | data[2])
786 & (~r.store)
787 )
788 # else
789 with m.Else():
790 # -- no IAMR, so no KUEP support
791 # -- for now deny execute
792 # -- permission if cache inhibited
793 # perm_ok :=
794 # data(0) and not data(5);
795 # no IAMR, so no KUEP support
796 # for now deny execute
797 # permission if cache inhibited
798 comb += perm_ok.eq(
799 data[0] & ~data[5]
800 )
801 # end if;
802 # end if;
803
804 # rc_ok := data(8) and (data(7) or
805 # not r.store);
806 comb += rc_ok.eq(
807 data[8] &
808 (data[7] | (~r.store))
809 )
810 # if perm_ok = '1' and rc_ok = '1' then
811 # v.state := RADIX_LOAD_TLB;
812 with m.If(perm_ok & rc_ok):
813 comb += v.state.eq(
814 State.RADIX_LOAD_TLB
815 )
816 # else
817 with m.Else():
818 # v.state := RADIX_FINISH;
819 # v.perm_err := not perm_ok;
820 # -- permission error takes precedence
821 # -- over RC error
822 # v.rc_error := perm_ok;
823 comb += vl.state.eq(
824 State.RADIX_FINISH
825 )
826 comb += v.perm_err.eq(~perm_ok)
827 # permission error takes precedence
828 # over RC error
829 comb += v.rc_error.eq(perm_ok)
830 # end if;
831 # else
832 with m.Else():
833 # mbits := unsigned('0' &
834 # data(4 downto 0));
835 comb += mbits.eq((
836 Cat(
837 data[0:5]
838 Cont(0b0,1)
839 )
840 ).as_unsigned())
841 # if mbits < 5 or mbits > 16 or
842 # mbits > r.shift then
843 # v.state := RADIX_FINISH;
844 # v.badtree := '1';
845 with m.If((mbits < 5) | (mbits > 16) |
846 (mbits > r.shift)):
847 comb += v.state.eq(
848 State.RADIX_FINISH
849 )
850 comb += v.badtree.eq(1)
851 # else
852 with m.Else():
853 # v.shift := v.shift - mbits;
854 # v.mask_size := mbits(4 downto 0);
855 # v.pgbase := data(55 downto 8)
856 # & x"00";
857 # v.state := RADIX_LOOKUP;
858 comb += v.shift.eq(v.shif - mbits)
859 comb += v.mask_size.eq(mbits[0:5])
860 comb += v.pgbase.eq(
861 Cat(
862 Const(0x00, 8),
863 mbits[8:56]
864 )
865 )
866 comb += v.state.eq(
867 State.RADIX_LOOKUP
868 )
869 # end if;
870 # end if;
871 # else
872 with m.Else():
873 # -- non-present PTE, generate a DSI
874 # v.state := RADIX_FINISH;
875 # v.invalid := '1';
876 # non-present PTE, generate a DSI
877 comb += v.state.eq(State.RADIX_FINISH)
878 comb += v.invalid.eq(1)
879 # end if;
880 # end if;
881
882 # if d_in.err = '1' then
883 with m.If(d_in.err):
884 # v.state := RADIX_FINISH;
885 # v.badtree := '1';
886 comb += v.state.eq(State.RADIX_FINISH)
887 comb += v.badtree.eq(1)
888 # end if;
889
890 # when RADIX_LOAD_TLB =>
891 with m.Case(State.RADIX_LOAD_TLB):
892 # tlb_load := '1';
893 comb += tlb_load.eq(1)
894 # if r.iside = '0' then
895 with m.If(~r.iside):
896 # dcreq := '1';
897 # v.state := TLB_WAIT;
898 comb += dcreq.eq(1)
899 comb += v.state.eq(State.TLB_WAIT)
900 # else
901 with m.Else():
902 # itlb_load := '1';
903 # v.state := IDLE;
904 comb += itlb_load.eq(1)
905 comb += v.state.eq(State.IDLE)
906 # end if;
907
908 # when RADIX_FINISH =>
909 # v.state := IDLE;
910 with m.Case(State.RADIX_FINISH):
911 # v.state := IDLE
912 comb += v.state.eq(State.IDLE)
913 # end case;
914 #
915 # if v.state = RADIX_FINISH or (v.state = RADIX_LOAD_TLB
916 # and r.iside = '1') then
917 with m.If(v.state == State.RADIX_FINISH
918 | (v.state == State.RADIX_LOAD_TLB & r.iside)
919 )
920 # v.err := v.invalid or v.badtree or v.segerror
921 # or v.perm_err or v.rc_error;
922 # v.done := not v.err;
923 comb += v.err.eq(v.invalid | v.badtree | v.segerror
924 | v.perm_err | v.rc_error)
925 comb += v.done.eq(~v.err)
926 # end if;
927
928 # if r.addr(63) = '1' then
929 with m.If(r.addr[63]):
930 # effpid := x"00000000";
931 comb += effpid.eq(Const(0x00000000, 32))
932 # else
933 with m.Else():
934 # effpid := r.pid;
935 comb += effpid.eq(r.pid)
936 # end if;
937 # prtable_addr := x"00" & r.prtbl(55 downto 36) &
938 # ((r.prtbl(35 downto 12) and not finalmask(
939 # 23 downto 0)) or (effpid(31 downto 8) and
940 # finalmask(23 downto 0))) & effpid(7 downto 0)
941 # & "0000";
942 comb += prtable_addr.eq(
943 Cat(
944 Cat(
945 Cat(
946 Cat(Const(0b0000, 4), effpid[0:8]),
947 (
948 (r.prtble[12:36] & ~finalmask[0:24])
949 | effpid[8:32] & finalmask[0:24]
950 )
951 ),
952 r.prtbl[36:56]
953 ),
954 Const(0x00, 8)
955 )
956 )
957
958 # pgtable_addr := x"00" & r.pgbase(55 downto 19) &
959 # ((r.pgbase(18 downto 3) and not mask) or
960 # (addrsh and mask)) & "000";
961 comb += pgtable_addr.eq(
962 Cat(
963 Cat(
964 Const(0b000, 3),
965 (
966 (r.pgbase[3:19] & ~mask)
967 | (addrsh & mask)
968 )
969 ),
970 Const(0x00, 8)
971 )
972 )
973
974 # pte := x"00" & ((r.pde(55 downto 12) and not finalmask) or
975 # (r.addr(55 downto 12) and finalmask)) & r.pde(11 downto 0);
976 comb += pte.eq(
977 Cat(
978 Cat(
979 r.pde[0:12],
980 (
981 (r.pde[12:56] & ~finalmask)
982 | (r.addr[12:56] & finalmask)
983 )
984 ),
985 Const(0x00, 8)
986 )
987 )
988
989 # -- update registers
990 # rin <= v;
991 # update registers
992 rin.eq(v)
993
994 # -- drive outputs
995 # if tlbie_req = '1' then
996 # drive outputs
997 with m.If(tlbie_req):
998 # addr := r.addr;
999 # tlb_data := (others => '0');
1000 comb += addr.eq(r.addr)
1001 # elsif tlb_load = '1' then
1002 with m.If(tlb_load):
1003 # addr := r.addr(63 downto 12) & x"000";
1004 # tlb_data := pte;
1005 comb += addr.eq(Cat(Const(0x000, 12), r.addr[12:64]))
1006 # elsif prtbl_rd = '1' then
1007 with m.If(prtbl_rd):
1008 # addr := prtable_addr;
1009 # tlb_data := (others => '0');
1010 comb += addr.eq(prtable_addr)
1011 # else
1012 with m.Else():
1013 # addr := pgtable_addr;
1014 # tlb_data := (others => '0');
1015 comb += addr.eq(pgtable_addr)
1016 # end if;
1017
1018 # l_out.done <= r.done;
1019 # l_out.err <= r.err;
1020 # l_out.invalid <= r.invalid;
1021 # l_out.badtree <= r.badtree;
1022 # l_out.segerr <= r.segerror;
1023 # l_out.perm_error <= r.perm_err;
1024 # l_out.rc_error <= r.rc_error;
1025 comb += l_out.done.eq(r.done)
1026 comb += l_out.err.eq(r.err)
1027 comb += l_out.invalid.eq(r.invalid)
1028 comb += l_out.badtree.eq(r.badtree)
1029 comb += l_out.segerr.eq(r.segerror)
1030 comb += l_out.perm_error.eq(r.perm_err)
1031 comb += l_out.rc_error.eq(r.rc_error)
1032
1033 # d_out.valid <= dcreq;
1034 # d_out.tlbie <= tlbie_req;
1035 # d_out.doall <= r.inval_all;
1036 # d_out.tlbld <= tlb_load;
1037 # d_out.addr <= addr;
1038 # d_out.pte <= tlb_data;
1039 comb += d_out.valid.eq(dcreq)
1040 comb += d_out.tlbie.eq(tlbie_req)
1041 comb += d_out.doall.eq(r.inval_all)
1042 comb += d_out.tlbld.eeq(tlb_load)
1043 comb += d_out.addr.eq(addr)
1044 comb += d_out.pte.eq(tlb_data)
1045
1046 # i_out.tlbld <= itlb_load;
1047 # i_out.tlbie <= tlbie_req;
1048 # i_out.doall <= r.inval_all;
1049 # i_out.addr <= addr;
1050 # i_out.pte <= tlb_data;
1051 comb += i_out.tlbld.eq(itlb_load)
1052 comb += i_out.tblie.eq(tlbie_req)
1053 comb += i_out.doall.eq(r.inval_all)
1054 comb += i_out.addr.eq(addr)
1055 comb += i_out.pte.eq(tlb_data)
1056
1057 # end process;
1058 # end;
1059
1060
1061 def mmu_sim():
1062 yield wp.waddr.eq(1)
1063 yield wp.data_i.eq(2)
1064 yield wp.wen.eq(1)
1065 yield
1066 yield wp.wen.eq(0)
1067 yield rp.ren.eq(1)
1068 yield rp.raddr.eq(1)
1069 yield Settle()
1070 data = yield rp.data_o
1071 print(data)
1072 assert data == 2
1073 yield
1074
1075 yield wp.waddr.eq(5)
1076 yield rp.raddr.eq(5)
1077 yield rp.ren.eq(1)
1078 yield wp.wen.eq(1)
1079 yield wp.data_i.eq(6)
1080 yield Settle()
1081 data = yield rp.data_o
1082 print(data)
1083 assert data == 6
1084 yield
1085 yield wp.wen.eq(0)
1086 yield rp.ren.eq(0)
1087 yield Settle()
1088 data = yield rp.data_o
1089 print(data)
1090 assert data == 0
1091 yield
1092 data = yield rp.data_o
1093 print(data)
1094
1095 def test_mmu():
1096 dut = MMU()
1097 rp = dut.read_port()
1098 wp = dut.write_port()
1099 vl = rtlil.convert(dut, ports=dut.ports())
1100 with open("test_mmu.il", "w") as f:
1101 f.write(vl)
1102
1103 run_simulation(dut, mmu_sim(), vcd_name='test_mmu.vcd')
1104
1105 if __name__ == '__main__':
1106 test_mmu()