1 from enum
import Enum
, unique
3 from nmigen
import (Module
, Signal
, Elaboratable
, Mux
, Cat
, Repl
,
5 from nmigen
.cli
import main
9 # use ieee.std_logic_1164.all;
10 # use ieee.numeric_std.all;
13 # use work.common.all;
16 # -- Supports 4-level trees as in arch 3.0B, but not the two-step translation for
17 # -- guests under a hypervisor (i.e. there is no gRA -> hRA translation).
19 # type state_t is (IDLE,
44 # type reg_stage_t is record
45 # -- latched request from loadstore1
50 # addr : std_ulogic_vector(63 downto 0);
51 # inval_all : std_ulogic;
53 # prtbl : std_ulogic_vector(63 downto 0);
54 # pid : std_ulogic_vector(31 downto 0);
59 # pgtbl0 : std_ulogic_vector(63 downto 0);
60 # pt0_valid : std_ulogic;
61 # pgtbl3 : std_ulogic_vector(63 downto 0);
62 # pt3_valid : std_ulogic;
63 # shift : unsigned(5 downto 0);
64 # mask_size : unsigned(4 downto 0);
65 # pgbase : std_ulogic_vector(55 downto 0);
66 # pde : std_ulogic_vector(63 downto 0);
67 # invalid : std_ulogic;
68 # badtree : std_ulogic;
69 # segerror : std_ulogic;
70 # perm_err : std_ulogic;
71 # rc_error : std_ulogic;
77 # latched request from loadstore1
78 self
.valid
= Signal(0),
79 self
.iside
= Signal(0),
80 self
.store
= Signal(0),
81 self
.priv
= Signal(0),
83 Signal(1, reset_less
=True, name
=f
"reg_stage_addr{i}") for i
in range(64)],
84 self
.inval_all
= Signal(0),
87 Signal(1, reset_less
=True, name
=f
"reg_stage_addr{i}") for i
in range(64)],
89 Signal(1, reset_less
=True, name
=f
"reg_stage_addr{i}") for i
in range(32)],
91 self
.state
= State
.IDLE
,
92 self
.done
= Signal(0),
95 Signal(1, reset_less
=True, name
=f
"reg_stage_addr{i}") for i
in range(64)],
96 self
.pt0_valid
= Signal(0),
98 Signal(1, reset_less
=True, name
=f
"reg_stage_addr{i}") for i
in range(64)],
99 self
.pt3_valid
= Signal(0),
100 self
.shift
= Signal(5),
101 self
.mask_size
= Signal(4),
103 Signal(1, reset_less
=True, name
=f
"reg_stage_addr{i}") for i
in range(56)],
105 Signal(1, reset_less
=True, name
=f
"reg_stage_addr{i}") for i
in range(64)],
106 self
.invalid
= Signal(0),
107 self
.badtree
= Signal(0),
108 self
.segerror
= Signal(0),
109 self
.perm_err
= Signal(0),
110 self
.rc_error
= Signal(0),
113 # architecture behave of mmu is
114 class MMU(Elaboratable
):
118 # clk : in std_ulogic;
119 # rst : in std_ulogic;
121 # l_in : in Loadstore1ToMmuType;
122 # l_out : out MmuToLoadstore1Type;
124 # d_out : out MmuToDcacheType;
125 # d_in : in DcacheToMmuType;
127 # i_out : out MmuToIcacheType
130 def __init__(self
, l_in
, l_out
, d_out
, d_in
, i_out
):
138 def elaborate(self
, platform
):
139 # -- Multiplex internal SPR values back to loadstore1, selected
141 # l_out.sprval <= r.prtbl when l_in.sprn(9) = '1' else x"00000000" & r.pid;
143 # Multiplex internal SPR values back to loadstore1, selected by l_in.sprn.
156 # non-existant variable, to be removed when I understand how to do VHDL rising_edge(clk) in nmigen
159 # signal r, rin : reg_stage_t;
163 # signal addrsh : std_ulogic_vector(15 downto 0);
164 # signal mask : std_ulogic_vector(15 downto 0);
165 # signal finalmask : std_ulogic_vector(43 downto 0);
168 Signal(1, reset_less
=True, name
=f
"reg_stage_addr{i}") for i
in range(16)]
169 mask
= [Signal(1, reset_less
=True,
170 name
=f
"reg_stage_addr{i}") for i
in range(15)]
172 Signal(1, reset_less
=True, name
=f
"reg_stage_addr{i}") for i
in range(44)]
174 with m
.If(l_in
.sprn
[9] == 1):
175 m
.d
.comb
+= l_out
.sprval
.eq(r
.prtbl
)
178 m
.d
.comb
+= l_out
.sprval
.eq(0x00000000 & r
)
180 # mmu_0: process(clk)
182 # if rising_edge(clk) then
186 # r.pt0_valid <= '0';
187 # r.pt3_valid <= '0';
188 # r.prtbl <= (others => '0');
189 with m
.If(rising_edge
):
195 # value should be vhdl (others => '0') in nmigen
199 # if rin.valid = '1' then
200 # report "MMU got tlb miss for " & to_hstring(rin.addr);
202 with m
.If(rin
.valid
== 1):
203 print(f
"MMU got tlb miss for {rin.addr}")
205 # if l_out.done = '1' then
206 # report "MMU completing op without error";
208 with m
.If(l_out
.done
== 1):
209 print("MMU completing op without error")
211 # if l_out.err = '1' then
212 # report "MMU completing op with err invalid=" & std_ulogic'image(l_out.invalid) &
213 # " badtree=" & std_ulogic'image(l_out.badtree);
215 with m
.If(l_out
.err
== 1):
217 f
"MMU completing op with err invalid={l_out.invalid} badtree={l_out.badtree}")
218 # if rin.state = RADIX_LOOKUP then
219 # report "radix lookup shift=" & integer'image(to_integer(rin.shift)) &
220 # " msize=" & integer'image(to_integer(rin.mask_size));
222 with m
.If(rin
.state
== State
.RADIX_LOOKUP
):
224 f
"radix lookup shift={rin.shift} msize={rin.mask_size}")
225 # if r.state = RADIX_LOOKUP then
226 # report "send load addr=" & to_hstring(d_out.addr) &
227 # " addrsh=" & to_hstring(addrsh) & " mask=" & to_hstring(mask);
229 with m
.If(r
.state
== State
.RADIX_LOOKUP
):
231 f
"send load addr={d_out.addr} addrsh={addrsh} mask={mask}")
238 # -- Shift address bits 61--12 right by 0--47 bits and
239 # -- supply the least significant 16 bits of the result.
240 # addrshifter: process(all)
241 # variable sh1 : std_ulogic_vector(30 downto 0);
242 # variable sh2 : std_ulogic_vector(18 downto 0);
243 # variable result : std_ulogic_vector(15 downto 0);
245 # case r.shift(5 downto 4) is
247 # sh1 := r.addr(42 downto 12);
249 # sh1 := r.addr(58 downto 28);
251 # sh1 := "0000000000000" & r.addr(61 downto 44);
253 # case r.shift(3 downto 2) is
255 # sh2 := sh1(18 downto 0);
257 # sh2 := sh1(22 downto 4);
259 # sh2 := sh1(26 downto 8);
261 # sh2 := sh1(30 downto 12);
263 # case r.shift(1 downto 0) is
265 # result := sh2(15 downto 0);
267 # result := sh2(16 downto 1);
269 # result := sh2(17 downto 2);
271 # result := sh2(18 downto 3);
276 # -- generate mask for extracting address fields for PTE address generation
277 # addrmaskgen: process(all)
278 # variable m : std_ulogic_vector(15 downto 0);
280 # -- mask_count has to be >= 5
282 # for i in 5 to 15 loop
283 # if i < to_integer(r.mask_size) then
290 # -- generate mask for extracting address bits to go in TLB entry
291 # -- in order to support pages > 4kB
292 # finalmaskgen: process(all)
293 # variable m : std_ulogic_vector(43 downto 0);
295 # m := (others => '0');
296 # for i in 0 to 43 loop
297 # if i < to_integer(r.shift) then
304 # mmu_1: process(all)
305 # variable v : reg_stage_t;
306 # variable dcreq : std_ulogic;
307 # variable tlb_load : std_ulogic;
308 # variable itlb_load : std_ulogic;
309 # variable tlbie_req : std_ulogic;
310 # variable prtbl_rd : std_ulogic;
311 # variable pt_valid : std_ulogic;
312 # variable effpid : std_ulogic_vector(31 downto 0);
313 # variable prtable_addr : std_ulogic_vector(63 downto 0);
314 # variable rts : unsigned(5 downto 0);
315 # variable mbits : unsigned(5 downto 0);
316 # variable pgtable_addr : std_ulogic_vector(63 downto 0);
317 # variable pte : std_ulogic_vector(63 downto 0);
318 # variable tlb_data : std_ulogic_vector(63 downto 0);
319 # variable nonzero : std_ulogic;
320 # variable pgtbl : std_ulogic_vector(63 downto 0);
321 # variable perm_ok : std_ulogic;
322 # variable rc_ok : std_ulogic;
323 # variable addr : std_ulogic_vector(63 downto 0);
324 # variable data : std_ulogic_vector(63 downto 0);
339 # v.inval_all := '0';
342 # -- Radix tree data structures in memory are big-endian,
343 # -- so we need to byte-swap them
344 # for i in 0 to 7 loop
345 # data(i * 8 + 7 downto i * 8) := d_in.data((7 - i) * 8 + 7 downto (7 - i) * 8);
350 # if l_in.addr(63) = '0' then
352 # pt_valid := r.pt0_valid;
355 # pt_valid := r.pt3_valid;
357 # -- rts == radix tree size, # address bits being translated
358 # rts := unsigned('0' & pgtbl(62 downto 61) & pgtbl(7 downto 5));
359 # -- mbits == # address bits to index top level of tree
360 # mbits := unsigned('0' & pgtbl(4 downto 0));
361 # -- set v.shift to rts so that we can use finalmask for the segment check
363 # v.mask_size := mbits(4 downto 0);
364 # v.pgbase := pgtbl(55 downto 8) & x"00";
366 # if l_in.valid = '1' then
367 # v.addr := l_in.addr;
368 # v.iside := l_in.iside;
369 # v.store := not (l_in.load or l_in.iside);
370 # v.priv := l_in.priv;
371 # if l_in.tlbie = '1' then
372 # -- Invalidate all iTLB/dTLB entries for tlbie with
373 # -- RB[IS] != 0 or RB[AP] != 0, or for slbia
374 # v.inval_all := l_in.slbia or l_in.addr(11) or l_in.addr(10) or
375 # l_in.addr(7) or l_in.addr(6) or l_in.addr(5);
376 # -- The RIC field of the tlbie instruction comes across on the
377 # -- sprn bus as bits 2--3. RIC=2 flushes process table caches.
378 # if l_in.sprn(3) = '1' then
379 # v.pt0_valid := '0';
380 # v.pt3_valid := '0';
382 # v.state := DO_TLBIE;
385 # if pt_valid = '0' then
386 # -- need to fetch process table entry
387 # -- set v.shift so we can use finalmask for generating
388 # -- the process table entry address
389 # v.shift := unsigned('0' & r.prtbl(4 downto 0));
390 # v.state := PROC_TBL_READ;
391 # elsif mbits = 0 then
392 # -- Use RPDS = 0 to disable radix tree walks
393 # v.state := RADIX_FINISH;
396 # v.state := SEGMENT_CHECK;
400 # if l_in.mtspr = '1' then
401 # -- Move to PID needs to invalidate L1 TLBs and cached
402 # -- pgtbl0 value. Move to PRTBL does that plus
403 # -- invalidating the cached pgtbl3 value as well.
404 # if l_in.sprn(9) = '0' then
405 # v.pid := l_in.rs(31 downto 0);
407 # v.prtbl := l_in.rs;
408 # v.pt3_valid := '0';
410 # v.pt0_valid := '0';
411 # v.inval_all := '1';
412 # v.state := DO_TLBIE;
418 # v.state := TLB_WAIT;
421 # if d_in.done = '1' then
422 # v.state := RADIX_FINISH;
425 # when PROC_TBL_READ =>
428 # v.state := PROC_TBL_WAIT;
430 # when PROC_TBL_WAIT =>
431 # if d_in.done = '1' then
432 # if r.addr(63) = '1' then
434 # v.pt3_valid := '1';
437 # v.pt0_valid := '1';
439 # -- rts == radix tree size, # address bits being translated
440 # rts := unsigned('0' & data(62 downto 61) & data(7 downto 5));
441 # -- mbits == # address bits to index top level of tree
442 # mbits := unsigned('0' & data(4 downto 0));
443 # -- set v.shift to rts so that we can use finalmask for the segment check
445 # v.mask_size := mbits(4 downto 0);
446 # v.pgbase := data(55 downto 8) & x"00";
448 # v.state := RADIX_FINISH;
451 # v.state := SEGMENT_CHECK;
454 # if d_in.err = '1' then
455 # v.state := RADIX_FINISH;
459 # when SEGMENT_CHECK =>
460 # mbits := '0' & r.mask_size;
461 # v.shift := r.shift + (31 - 12) - mbits;
462 # nonzero := or(r.addr(61 downto 31) and not finalmask(30 downto 0));
463 # if r.addr(63) /= r.addr(62) or nonzero = '1' then
464 # v.state := RADIX_FINISH;
466 # elsif mbits < 5 or mbits > 16 or mbits > (r.shift + (31 - 12)) then
467 # v.state := RADIX_FINISH;
470 # v.state := RADIX_LOOKUP;
473 # when RADIX_LOOKUP =>
475 # v.state := RADIX_READ_WAIT;
477 # when RADIX_READ_WAIT =>
478 # if d_in.done = '1' then
481 # if data(63) = '1' then
483 # if data(62) = '1' then
484 # -- check permissions and RC bits
486 # if r.priv = '1' or data(3) = '0' then
487 # if r.iside = '0' then
488 # perm_ok := data(1) or (data(2) and not r.store);
490 # -- no IAMR, so no KUEP support for now
491 # -- deny execute permission if cache inhibited
492 # perm_ok := data(0) and not data(5);
495 # rc_ok := data(8) and (data(7) or not r.store);
496 # if perm_ok = '1' and rc_ok = '1' then
497 # v.state := RADIX_LOAD_TLB;
499 # v.state := RADIX_FINISH;
500 # v.perm_err := not perm_ok;
501 # -- permission error takes precedence over RC error
502 # v.rc_error := perm_ok;
505 # mbits := unsigned('0' & data(4 downto 0));
506 # if mbits < 5 or mbits > 16 or mbits > r.shift then
507 # v.state := RADIX_FINISH;
510 # v.shift := v.shift - mbits;
511 # v.mask_size := mbits(4 downto 0);
512 # v.pgbase := data(55 downto 8) & x"00";
513 # v.state := RADIX_LOOKUP;
517 # -- non-present PTE, generate a DSI
518 # v.state := RADIX_FINISH;
522 # if d_in.err = '1' then
523 # v.state := RADIX_FINISH;
527 # when RADIX_LOAD_TLB =>
529 # if r.iside = '0' then
531 # v.state := TLB_WAIT;
537 # when RADIX_FINISH =>
542 # if v.state = RADIX_FINISH or (v.state = RADIX_LOAD_TLB and r.iside = '1') then
543 # v.err := v.invalid or v.badtree or v.segerror or v.perm_err or v.rc_error;
544 # v.done := not v.err;
547 # if r.addr(63) = '1' then
548 # effpid := x"00000000";
552 # prtable_addr := x"00" & r.prtbl(55 downto 36) &
553 # ((r.prtbl(35 downto 12) and not finalmask(23 downto 0)) or
554 # (effpid(31 downto 8) and finalmask(23 downto 0))) &
555 # effpid(7 downto 0) & "0000";
557 # pgtable_addr := x"00" & r.pgbase(55 downto 19) &
558 # ((r.pgbase(18 downto 3) and not mask) or (addrsh and mask)) &
561 # ((r.pde(55 downto 12) and not finalmask) or (r.addr(55 downto 12) and finalmask))
562 # & r.pde(11 downto 0);
564 # -- update registers
568 # if tlbie_req = '1' then
570 # tlb_data := (others => '0');
571 # elsif tlb_load = '1' then
572 # addr := r.addr(63 downto 12) & x"000";
574 # elsif prtbl_rd = '1' then
575 # addr := prtable_addr;
576 # tlb_data := (others => '0');
578 # addr := pgtable_addr;
579 # tlb_data := (others => '0');
582 # l_out.done <= r.done;
583 # l_out.err <= r.err;
584 # l_out.invalid <= r.invalid;
585 # l_out.badtree <= r.badtree;
586 # l_out.segerr <= r.segerror;
587 # l_out.perm_error <= r.perm_err;
588 # l_out.rc_error <= r.rc_error;
590 # d_out.valid <= dcreq;
591 # d_out.tlbie <= tlbie_req;
592 # d_out.doall <= r.inval_all;
593 # d_out.tlbld <= tlb_load;
594 # d_out.addr <= addr;
595 # d_out.pte <= tlb_data;
597 # i_out.tlbld <= itlb_load;
598 # i_out.tlbie <= tlbie_req;
599 # i_out.doall <= r.inval_all;
600 # i_out.addr <= addr;
601 # i_out.pte <= tlb_data;