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