from enum import Enum, unique
-from nmigen import (Module, Signal, Elaboratable, Mux, Cat, Repl,
- signed, ResetSignal)
+from nmigen import (Module, Signal, Elaboratable, Mux, Cat, Repl, signed,
+ ResetSignal)
from nmigen.cli import main
-# library ieee;
-# use ieee.std_logic_1164.all;
-# use ieee.numeric_std.all;
+# library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all;
-# library work;
-# use work.common.all;
+# library work; use work.common.all;
# -- Radix MMU
-# -- Supports 4-level trees as in arch 3.0B, but not the two-step translation for
-# -- guests under a hypervisor (i.e. there is no gRA -> hRA translation).
-
-# type state_t is (IDLE,
-# DO_TLBIE,
-# TLB_WAIT,
-# PROC_TBL_READ,
-# PROC_TBL_WAIT,
-# SEGMENT_CHECK,
-# RADIX_LOOKUP,
-# RADIX_READ_WAIT,
-# RADIX_LOAD_TLB,
-# RADIX_FINISH
-# );
+# -- Supports 4-level trees as in arch 3.0B, but not the two-step translation
+# -- for guests under a hypervisor (i.e. there is no gRA -> hRA translation).
+
+# type state_t is
+# (IDLE,
+# DO_TLBIE,
+# TLB_WAIT,
+# PROC_TBL_READ,
+# PROC_TBL_WAIT,
+# SEGMENT_CHECK,
+# RADIX_LOOKUP,
+# RADIX_READ_WAIT,
+# RADIX_LOAD_TLB,
+# RADIX_FINISH
+# );
@unique
class State(Enum):
RADIX_LOAD_TLB = 8
RADIX_FINIS = 9
-# type reg_stage_t is record
-# -- latched request from loadstore1
-# valid : std_ulogic;
-# iside : std_ulogic;
-# store : std_ulogic;
-# priv : std_ulogic;
-# addr : std_ulogic_vector(63 downto 0);
-# inval_all : std_ulogic;
-# -- config SPRs
-# prtbl : std_ulogic_vector(63 downto 0);
-# pid : std_ulogic_vector(31 downto 0);
-# -- internal state
-# state : state_t;
-# done : std_ulogic;
-# err : std_ulogic;
-# pgtbl0 : std_ulogic_vector(63 downto 0);
-# pt0_valid : std_ulogic;
-# pgtbl3 : std_ulogic_vector(63 downto 0);
-# pt3_valid : std_ulogic;
-# shift : unsigned(5 downto 0);
-# mask_size : unsigned(4 downto 0);
-# pgbase : std_ulogic_vector(55 downto 0);
-# pde : std_ulogic_vector(63 downto 0);
-# invalid : std_ulogic;
-# badtree : std_ulogic;
-# segerror : std_ulogic;
-# perm_err : std_ulogic;
-# rc_error : std_ulogic;
-# end record;
+# type reg_stage_t is record
+# -- latched request from loadstore1
+# valid : std_ulogic;
+# iside : std_ulogic;
+# store : std_ulogic;
+# priv : std_ulogic;
+# addr : std_ulogic_vector(63 downto 0);
+# inval_all : std_ulogic;
+# -- config SPRs
+# prtbl : std_ulogic_vector(63 downto 0);
+# pid : std_ulogic_vector(31 downto 0);
+# -- internal state
+# state : state_t;
+# done : std_ulogic;
+# err : std_ulogic;
+# pgtbl0 : std_ulogic_vector(63 downto 0);
+# pt0_valid : std_ulogic;
+# pgtbl3 : std_ulogic_vector(63 downto 0);
+# pt3_valid : std_ulogic;
+# shift : unsigned(5 downto 0);
+# mask_size : unsigned(4 downto 0);
+# pgbase : std_ulogic_vector(55 downto 0);
+# pde : std_ulogic_vector(63 downto 0);
+# invalid : std_ulogic;
+# badtree : std_ulogic;
+# segerror : std_ulogic;
+# perm_err : std_ulogic;
+# rc_error : std_ulogic;
+# end record;
class RegStage():
def __init__(self):
# latched request from loadstore1
- self.valid = Signal(0),
- self.iside = Signal(0),
- self.store = Signal(0),
- self.priv = Signal(0),
- self.addr = [
- Signal(1, reset_less=True, name=f"reg_stage_addr{i}") for i in range(64)],
- self.inval_all = Signal(0),
+ self.valid = Signal(1)
+ self.iside = Signal(1)
+ self.store = Signal(1)
+ self.priv = Signal(1)
+ self.addr = Signal(64)
+ self.inval_all = Signal(1)
# config SPRs
- self.prtbl = [
- Signal(1, reset_less=True, name=f"reg_stage_addr{i}") for i in range(64)],
- self.pid = [
- Signal(1, reset_less=True, name=f"reg_stage_addr{i}") for i in range(32)],
+ self.prtbl = Signal(64)
+ self.pid = Signal(32
# internal state
- self.state = State.IDLE,
- self.done = Signal(0),
- self.err = Signal(0),
- self.pgtbl0 = [
- Signal(1, reset_less=True, name=f"reg_stage_addr{i}") for i in range(64)],
- self.pt0_valid = Signal(0),
- self.pgtbl3 = [
- Signal(1, reset_less=True, name=f"reg_stage_addr{i}") for i in range(64)],
- self.pt3_valid = Signal(0),
- self.shift = Signal(5),
- self.mask_size = Signal(4),
- self.pgbase = [
- Signal(1, reset_less=True, name=f"reg_stage_addr{i}") for i in range(56)],
- self.pde = [
- Signal(1, reset_less=True, name=f"reg_stage_addr{i}") for i in range(64)],
- self.invalid = Signal(0),
- self.badtree = Signal(0),
- self.segerror = Signal(0),
- self.perm_err = Signal(0),
- self.rc_error = Signal(0),
+ self.state = State.IDLE
+ self.done = Signal(1)
+ self.err = Signal(1)
+ self.pgtbl0 = Signal(64)
+ self.pt0_valid = Signal(1)
+ self.pgtbl3 = Signal(64)
+ self.pt3_valid = Signal(1)
+ self.shift = Signal(5)
+ self.mask_size = Signal(4)
+ self.pgbase = Signal(56)
+ self.pde = Signal(64)
+ self.invalid = Signal(1)
+ self.badtree = Signal(1)
+ self.segerror = Signal(1)
+ self.perm_err = Signal(1)
+ self.rc_error = Signal(1)
# architecture behave of mmu is
class MMU(Elaboratable):
- # entity mmu is
- # port (
- # clk : in std_ulogic;
- # rst : in std_ulogic;
-
- # l_in : in Loadstore1ToMmuType;
- # l_out : out MmuToLoadstore1Type;
-
- # d_out : out MmuToDcacheType;
- # d_in : in DcacheToMmuType;
-
- # i_out : out MmuToIcacheType
- # );
- # end mmu;
+# entity mmu is
+# port (
+# clk : in std_ulogic;
+# rst : in std_ulogic;
+#
+# l_in : in Loadstore1ToMmuType;
+# l_out : out MmuToLoadstore1Type;
+#
+# d_out : out MmuToDcacheType;
+# d_in : in DcacheToMmuType;
+#
+# i_out : out MmuToIcacheType
+# );
+# end mmu;
def __init__(self, l_in, l_out, d_out, d_in, i_out):
self.l_in = l_in
self.l_out = l_out
# begin
def elaborate(self, platform):
- # -- Multiplex internal SPR values back to loadstore1, selected
- # -- by l_in.sprn.
- # l_out.sprval <= r.prtbl when l_in.sprn(9) = '1' else x"00000000" & r.pid;
+# -- Multiplex internal SPR values back to loadstore1, selected
+# -- by l_in.sprn.
- # Multiplex internal SPR values back to loadstore1, selected by l_in.sprn.
+ # Multiplex internal SPR values back to loadstore1, selected by
+ # l_in.sprn.
m = Module()
comb = m.d.comb
d_in = self.d_in
i_out = self.i_out
- # non-existant variable, to be removed when I understand how to do VHDL rising_edge(clk) in nmigen
+ # non-existant variable, to be removed when I understand how to do VHDL
+ # rising_edge(clk) in nmigen
rising_edge = False
- # signal r, rin : reg_stage_t;
+# signal r, rin : reg_stage_t;
r = RegStage()
rin = RegStage()
- # signal addrsh : std_ulogic_vector(15 downto 0);
- # signal mask : std_ulogic_vector(15 downto 0);
- # signal finalmask : std_ulogic_vector(43 downto 0);
-
- addrsh = [
- Signal(1, reset_less=True, name=f"reg_stage_addr{i}") for i in range(16)]
- mask = [Signal(1, reset_less=True,
- name=f"reg_stage_addr{i}") for i in range(15)]
- finalmask = [
- Signal(1, reset_less=True, name=f"reg_stage_addr{i}") for i in range(44)]
+# signal addrsh : std_ulogic_vector(15 downto 0);
+# signal mask : std_ulogic_vector(15 downto 0);
+# signal finalmask : std_ulogic_vector(43 downto 0);
+ addrsh = Signal(16)
+ mask = Signal(15)
+ finalmask = Signal(44)
+# l_out.sprval <= r.prtbl when l_in.sprn(9) = '1'
with m.If(l_in.sprn[9] == 1):
m.d.comb += l_out.sprval.eq(r.prtbl)
+# else x"00000000" & r.pid;
with m.Else():
m.d.comb += l_out.sprval.eq(0x00000000 & r)
-
- # mmu_0: process(clk)
- # begin
- # if rising_edge(clk) then
- # if rst = '1' then
- # r.state <= IDLE;
- # r.valid <= '0';
- # r.pt0_valid <= '0';
- # r.pt3_valid <= '0';
- # r.prtbl <= (others => '0');
+# mmu_0: process(clk)
+# begin
+# if rising_edge(clk) then
with m.If(rising_edge):
+# if rst = '1' then
with m.If(rst == 1):
+# r.state <= IDLE;
+# r.valid <= '0';
+# r.pt0_valid <= '0';
+# r.pt3_valid <= '0';
+# r.prtbl <= (others => '0');
r.state = State.IDLE
r.valid = 0
r.pt0_valid = 0
r.pt3_valid = 0
# value should be vhdl (others => '0') in nmigen
r.prtbl = 0
- # else
+# else
with m.Else():
- # if rin.valid = '1' then
- # report "MMU got tlb miss for " & to_hstring(rin.addr);
- # end if;
+# if rin.valid = '1' then
+# report "MMU got tlb miss for " & to_hstring(rin.addr);
+# end if;
with m.If(rin.valid == 1):
print(f"MMU got tlb miss for {rin.addr}")
- # if l_out.done = '1' then
- # report "MMU completing op without error";
- # end if;
+# if l_out.done = '1' then
+# report "MMU completing op without error";
+# end if;
with m.If(l_out.done == 1):
print("MMU completing op without error")
- # if l_out.err = '1' then
- # report "MMU completing op with err invalid=" & std_ulogic'image(l_out.invalid) &
- # " badtree=" & std_ulogic'image(l_out.badtree);
- # end if;
+# if l_out.err = '1' then
+# report "MMU completing op with err invalid=" &
+# std_ulogic'image(l_out.invalid) & " badtree=" &
+# std_ulogic'image(l_out.badtree);
+# end if;
with m.If(l_out.err == 1):
- print(
- f"MMU completing op with err invalid={l_out.invalid} badtree={l_out.badtree}")
- # if rin.state = RADIX_LOOKUP then
- # report "radix lookup shift=" & integer'image(to_integer(rin.shift)) &
- # " msize=" & integer'image(to_integer(rin.mask_size));
- # end if;
+ print(f"MMU completing op with err invalid={l_out.invalid}
+ badtree={l_out.badtree}")
+
+# if rin.state = RADIX_LOOKUP then
+# report "radix lookup shift=" & integer'image(to_integer(
+# rin.shift)) & " msize=" & integer'image(to_integer(rin.
+# mask_size));
+# end if;
with m.If(rin.state == State.RADIX_LOOKUP):
- print(
- f"radix lookup shift={rin.shift} msize={rin.mask_size}")
- # if r.state = RADIX_LOOKUP then
- # report "send load addr=" & to_hstring(d_out.addr) &
- # " addrsh=" & to_hstring(addrsh) & " mask=" & to_hstring(mask);
- # end if;
+ print(f"radix lookup shift={rin.shift}
+ msize={rin.mask_size}")
+
+# if r.state = RADIX_LOOKUP then
+# report "send load addr=" & to_hstring(d_out.addr) &
+# " addrsh=" & to_hstring(addrsh) & " mask=" &
+# to_hstring(mask);
+# end if;
with m.If(r.state == State.RADIX_LOOKUP):
- print(
- f"send load addr={d_out.addr} addrsh={addrsh} mask={mask}")
- # r <= rin;
- comb += r.eq(rin)
- # end if;
- # end if;
- # end process;
-
- # -- Shift address bits 61--12 right by 0--47 bits and
- # -- supply the least significant 16 bits of the result.
- # addrshifter: process(all)
- # variable sh1 : std_ulogic_vector(30 downto 0);
- # variable sh2 : std_ulogic_vector(18 downto 0);
- # variable result : std_ulogic_vector(15 downto 0);
- # begin
- # case r.shift(5 downto 4) is
- # when "00" =>
- # sh1 := r.addr(42 downto 12);
- # when "01" =>
- # sh1 := r.addr(58 downto 28);
- # when others =>
- # sh1 := "0000000000000" & r.addr(61 downto 44);
- # end case;
- # case r.shift(3 downto 2) is
- # when "00" =>
- # sh2 := sh1(18 downto 0);
- # when "01" =>
- # sh2 := sh1(22 downto 4);
- # when "10" =>
- # sh2 := sh1(26 downto 8);
- # when others =>
- # sh2 := sh1(30 downto 12);
- # end case;
- # case r.shift(1 downto 0) is
- # when "00" =>
- # result := sh2(15 downto 0);
- # when "01" =>
- # result := sh2(16 downto 1);
- # when "10" =>
- # result := sh2(17 downto 2);
- # when others =>
- # result := sh2(18 downto 3);
- # end case;
- # addrsh <= result;
- # end process;
-
- # -- generate mask for extracting address fields for PTE address generation
- # addrmaskgen: process(all)
- # variable m : std_ulogic_vector(15 downto 0);
- # begin
- # -- mask_count has to be >= 5
- # m := x"001f";
- # for i in 5 to 15 loop
- # if i < to_integer(r.mask_size) then
- # m(i) := '1';
- # end if;
- # end loop;
- # mask <= m;
- # end process;
-
- # -- generate mask for extracting address bits to go in TLB entry
- # -- in order to support pages > 4kB
- # finalmaskgen: process(all)
- # variable m : std_ulogic_vector(43 downto 0);
- # begin
- # m := (others => '0');
- # for i in 0 to 43 loop
- # if i < to_integer(r.shift) then
- # m(i) := '1';
- # end if;
- # end loop;
- # finalmask <= m;
- # end process;
-
- # mmu_1: process(all)
- # variable v : reg_stage_t;
- # variable dcreq : std_ulogic;
- # variable tlb_load : std_ulogic;
- # variable itlb_load : std_ulogic;
- # variable tlbie_req : std_ulogic;
- # variable prtbl_rd : std_ulogic;
- # variable pt_valid : std_ulogic;
- # variable effpid : std_ulogic_vector(31 downto 0);
- # variable prtable_addr : std_ulogic_vector(63 downto 0);
- # variable rts : unsigned(5 downto 0);
- # variable mbits : unsigned(5 downto 0);
- # variable pgtable_addr : std_ulogic_vector(63 downto 0);
- # variable pte : std_ulogic_vector(63 downto 0);
- # variable tlb_data : std_ulogic_vector(63 downto 0);
- # variable nonzero : std_ulogic;
- # variable pgtbl : std_ulogic_vector(63 downto 0);
- # variable perm_ok : std_ulogic;
- # variable rc_ok : std_ulogic;
- # variable addr : std_ulogic_vector(63 downto 0);
- # variable data : std_ulogic_vector(63 downto 0);
- # begin
- # v := r;
- # v.valid := '0';
- # dcreq := '0';
- # v.done := '0';
- # v.err := '0';
- # v.invalid := '0';
- # v.badtree := '0';
- # v.segerror := '0';
- # v.perm_err := '0';
- # v.rc_error := '0';
- # tlb_load := '0';
- # itlb_load := '0';
- # tlbie_req := '0';
- # v.inval_all := '0';
- # prtbl_rd := '0';
-
- # -- Radix tree data structures in memory are big-endian,
- # -- so we need to byte-swap them
- # for i in 0 to 7 loop
- # data(i * 8 + 7 downto i * 8) := d_in.data((7 - i) * 8 + 7 downto (7 - i) * 8);
- # end loop;
-
- # case r.state is
- # when IDLE =>
- # if l_in.addr(63) = '0' then
- # pgtbl := r.pgtbl0;
- # pt_valid := r.pt0_valid;
- # else
- # pgtbl := r.pgtbl3;
- # pt_valid := r.pt3_valid;
- # end if;
- # -- rts == radix tree size, # address bits being translated
- # rts := unsigned('0' & pgtbl(62 downto 61) & pgtbl(7 downto 5));
- # -- mbits == # address bits to index top level of tree
- # mbits := unsigned('0' & pgtbl(4 downto 0));
- # -- set v.shift to rts so that we can use finalmask for the segment check
- # v.shift := rts;
- # v.mask_size := mbits(4 downto 0);
- # v.pgbase := pgtbl(55 downto 8) & x"00";
-
- # if l_in.valid = '1' then
- # v.addr := l_in.addr;
- # v.iside := l_in.iside;
- # v.store := not (l_in.load or l_in.iside);
- # v.priv := l_in.priv;
- # if l_in.tlbie = '1' then
- # -- Invalidate all iTLB/dTLB entries for tlbie with
- # -- RB[IS] != 0 or RB[AP] != 0, or for slbia
- # v.inval_all := l_in.slbia or l_in.addr(11) or l_in.addr(10) or
- # l_in.addr(7) or l_in.addr(6) or l_in.addr(5);
- # -- The RIC field of the tlbie instruction comes across on the
- # -- sprn bus as bits 2--3. RIC=2 flushes process table caches.
- # if l_in.sprn(3) = '1' then
- # v.pt0_valid := '0';
- # v.pt3_valid := '0';
- # end if;
- # v.state := DO_TLBIE;
- # else
- # v.valid := '1';
- # if pt_valid = '0' then
- # -- need to fetch process table entry
- # -- set v.shift so we can use finalmask for generating
- # -- the process table entry address
- # v.shift := unsigned('0' & r.prtbl(4 downto 0));
- # v.state := PROC_TBL_READ;
- # elsif mbits = 0 then
- # -- Use RPDS = 0 to disable radix tree walks
- # v.state := RADIX_FINISH;
- # v.invalid := '1';
- # else
- # v.state := SEGMENT_CHECK;
- # end if;
- # end if;
- # end if;
- # if l_in.mtspr = '1' then
- # -- Move to PID needs to invalidate L1 TLBs and cached
- # -- pgtbl0 value. Move to PRTBL does that plus
- # -- invalidating the cached pgtbl3 value as well.
- # if l_in.sprn(9) = '0' then
- # v.pid := l_in.rs(31 downto 0);
- # else
- # v.prtbl := l_in.rs;
- # v.pt3_valid := '0';
- # end if;
- # v.pt0_valid := '0';
- # v.inval_all := '1';
- # v.state := DO_TLBIE;
- # end if;
-
- # when DO_TLBIE =>
- # dcreq := '1';
- # tlbie_req := '1';
- # v.state := TLB_WAIT;
-
- # when TLB_WAIT =>
- # if d_in.done = '1' then
- # v.state := RADIX_FINISH;
- # end if;
-
- # when PROC_TBL_READ =>
- # dcreq := '1';
- # prtbl_rd := '1';
- # v.state := PROC_TBL_WAIT;
+ print(f"send load addr={d_out.addr}
+ addrsh={addrsh} mask={mask}")
- # when PROC_TBL_WAIT =>
- # if d_in.done = '1' then
- # if r.addr(63) = '1' then
- # v.pgtbl3 := data;
- # v.pt3_valid := '1';
- # else
- # v.pgtbl0 := data;
- # v.pt0_valid := '1';
- # end if;
- # -- rts == radix tree size, # address bits being translated
- # rts := unsigned('0' & data(62 downto 61) & data(7 downto 5));
- # -- mbits == # address bits to index top level of tree
- # mbits := unsigned('0' & data(4 downto 0));
- # -- set v.shift to rts so that we can use finalmask for the segment check
- # v.shift := rts;
- # v.mask_size := mbits(4 downto 0);
- # v.pgbase := data(55 downto 8) & x"00";
- # if mbits = 0 then
- # v.state := RADIX_FINISH;
- # v.invalid := '1';
- # else
- # v.state := SEGMENT_CHECK;
- # end if;
- # end if;
- # if d_in.err = '1' then
- # v.state := RADIX_FINISH;
- # v.badtree := '1';
- # end if;
-
- # when SEGMENT_CHECK =>
- # mbits := '0' & r.mask_size;
- # v.shift := r.shift + (31 - 12) - mbits;
- # nonzero := or(r.addr(61 downto 31) and not finalmask(30 downto 0));
- # if r.addr(63) /= r.addr(62) or nonzero = '1' then
- # v.state := RADIX_FINISH;
- # v.segerror := '1';
- # elsif mbits < 5 or mbits > 16 or mbits > (r.shift + (31 - 12)) then
- # v.state := RADIX_FINISH;
- # v.badtree := '1';
- # else
- # v.state := RADIX_LOOKUP;
- # end if;
-
- # when RADIX_LOOKUP =>
- # dcreq := '1';
- # v.state := RADIX_READ_WAIT;
-
- # when RADIX_READ_WAIT =>
- # if d_in.done = '1' then
- # v.pde := data;
- # -- test valid bit
- # if data(63) = '1' then
- # -- test leaf bit
- # if data(62) = '1' then
- # -- check permissions and RC bits
- # perm_ok := '0';
- # if r.priv = '1' or data(3) = '0' then
- # if r.iside = '0' then
- # perm_ok := data(1) or (data(2) and not r.store);
- # else
- # -- no IAMR, so no KUEP support for now
- # -- deny execute permission if cache inhibited
- # perm_ok := data(0) and not data(5);
- # end if;
- # end if;
- # rc_ok := data(8) and (data(7) or not r.store);
- # if perm_ok = '1' and rc_ok = '1' then
- # v.state := RADIX_LOAD_TLB;
- # else
- # v.state := RADIX_FINISH;
- # v.perm_err := not perm_ok;
- # -- permission error takes precedence over RC error
- # v.rc_error := perm_ok;
- # end if;
- # else
- # mbits := unsigned('0' & data(4 downto 0));
- # if mbits < 5 or mbits > 16 or mbits > r.shift then
- # v.state := RADIX_FINISH;
- # v.badtree := '1';
- # else
- # v.shift := v.shift - mbits;
- # v.mask_size := mbits(4 downto 0);
- # v.pgbase := data(55 downto 8) & x"00";
- # v.state := RADIX_LOOKUP;
- # end if;
- # end if;
- # else
- # -- non-present PTE, generate a DSI
- # v.state := RADIX_FINISH;
- # v.invalid := '1';
- # end if;
- # end if;
- # if d_in.err = '1' then
- # v.state := RADIX_FINISH;
- # v.badtree := '1';
- # end if;
-
- # when RADIX_LOAD_TLB =>
- # tlb_load := '1';
- # if r.iside = '0' then
- # dcreq := '1';
- # v.state := TLB_WAIT;
- # else
- # itlb_load := '1';
- # v.state := IDLE;
- # end if;
-
- # when RADIX_FINISH =>
- # v.state := IDLE;
-
- # end case;
-
- # if v.state = RADIX_FINISH or (v.state = RADIX_LOAD_TLB and r.iside = '1') then
- # v.err := v.invalid or v.badtree or v.segerror or v.perm_err or v.rc_error;
- # v.done := not v.err;
- # end if;
-
- # if r.addr(63) = '1' then
- # effpid := x"00000000";
- # else
- # effpid := r.pid;
- # end if;
- # prtable_addr := x"00" & r.prtbl(55 downto 36) &
- # ((r.prtbl(35 downto 12) and not finalmask(23 downto 0)) or
- # (effpid(31 downto 8) and finalmask(23 downto 0))) &
- # effpid(7 downto 0) & "0000";
-
- # pgtable_addr := x"00" & r.pgbase(55 downto 19) &
- # ((r.pgbase(18 downto 3) and not mask) or (addrsh and mask)) &
- # "000";
- # pte := x"00" &
- # ((r.pde(55 downto 12) and not finalmask) or (r.addr(55 downto 12) and finalmask))
- # & r.pde(11 downto 0);
-
- # -- update registers
- # rin <= v;
-
- # -- drive outputs
- # if tlbie_req = '1' then
- # addr := r.addr;
- # tlb_data := (others => '0');
- # elsif tlb_load = '1' then
- # addr := r.addr(63 downto 12) & x"000";
- # tlb_data := pte;
- # elsif prtbl_rd = '1' then
- # addr := prtable_addr;
- # tlb_data := (others => '0');
- # else
- # addr := pgtable_addr;
- # tlb_data := (others => '0');
- # end if;
-
- # l_out.done <= r.done;
- # l_out.err <= r.err;
- # l_out.invalid <= r.invalid;
- # l_out.badtree <= r.badtree;
- # l_out.segerr <= r.segerror;
- # l_out.perm_error <= r.perm_err;
- # l_out.rc_error <= r.rc_error;
-
- # d_out.valid <= dcreq;
- # d_out.tlbie <= tlbie_req;
- # d_out.doall <= r.inval_all;
- # d_out.tlbld <= tlb_load;
- # d_out.addr <= addr;
- # d_out.pte <= tlb_data;
-
- # i_out.tlbld <= itlb_load;
- # i_out.tlbie <= tlbie_req;
- # i_out.doall <= r.inval_all;
- # i_out.addr <= addr;
- # i_out.pte <= tlb_data;
-
- # end process;
- # end;
+# r <= rin;
+ comb += r.eq(rin)
+# end if;
+# end if;
+# end process;
+
+# -- Shift address bits 61--12 right by 0--47 bits and
+# -- supply the least significant 16 bits of the result.
+# addrshifter: process(all)
+# variable sh1 : std_ulogic_vector(30 downto 0);
+# variable sh2 : std_ulogic_vector(18 downto 0);
+# variable result : std_ulogic_vector(15 downto 0);
+# begin
+# case r.shift(5 downto 4) is
+# when "00" =>
+# sh1 := r.addr(42 downto 12);
+# when "01" =>
+# sh1 := r.addr(58 downto 28);
+# when others =>
+# sh1 := "0000000000000" & r.addr(61 downto 44);
+# end case;
+# case r.shift(3 downto 2) is
+# when "00" =>
+# sh2 := sh1(18 downto 0);
+# when "01" =>
+# sh2 := sh1(22 downto 4);
+# when "10" =>
+# sh2 := sh1(26 downto 8);
+# when others =>
+# sh2 := sh1(30 downto 12);
+# end case;
+# case r.shift(1 downto 0) is
+# when "00" =>
+# result := sh2(15 downto 0);
+# when "01" =>
+# result := sh2(16 downto 1);
+# when "10" =>
+# result := sh2(17 downto 2);
+# when others =>
+# result := sh2(18 downto 3);
+# end case;
+# addrsh <= result;
+# end process;
+#
+# -- generate mask for extracting address fields for PTE address generation
+# addrmaskgen: process(all)
+# variable m : std_ulogic_vector(15 downto 0);
+# begin
+# -- mask_count has to be >= 5
+# m := x"001f";
+# for i in 5 to 15 loop
+# if i < to_integer(r.mask_size) then
+# m(i) := '1';
+# end if;
+# end loop;
+# mask <= m;
+# end process;
+#
+# -- generate mask for extracting address bits to go in TLB entry
+# -- in order to support pages > 4kB
+# finalmaskgen: process(all)
+# variable m : std_ulogic_vector(43 downto 0);
+# begin
+# m := (others => '0');
+# for i in 0 to 43 loop
+# if i < to_integer(r.shift) then
+# m(i) := '1';
+# end if;
+# end loop;
+# finalmask <= m;
+# end process;
+#
+# mmu_1: process(all)
+# variable v : reg_stage_t;
+# variable dcreq : std_ulogic;
+# variable tlb_load : std_ulogic;
+# variable itlb_load : std_ulogic;
+# variable tlbie_req : std_ulogic;
+# variable prtbl_rd : std_ulogic;
+# variable pt_valid : std_ulogic;
+# variable effpid : std_ulogic_vector(31 downto 0);
+# variable prtable_addr : std_ulogic_vector(63 downto 0);
+# variable rts : unsigned(5 downto 0);
+# variable mbits : unsigned(5 downto 0);
+# variable pgtable_addr : std_ulogic_vector(63 downto 0);
+# variable pte : std_ulogic_vector(63 downto 0);
+# variable tlb_data : std_ulogic_vector(63 downto 0);
+# variable nonzero : std_ulogic;
+# variable pgtbl : std_ulogic_vector(63 downto 0);
+# variable perm_ok : std_ulogic;
+# variable rc_ok : std_ulogic;
+# variable addr : std_ulogic_vector(63 downto 0);
+# variable data : std_ulogic_vector(63 downto 0);
+# begin
+# v := r;
+# v.valid := '0';
+# dcreq := '0';
+# v.done := '0';
+# v.err := '0';
+# v.invalid := '0';
+# v.badtree := '0';
+# v.segerror := '0';
+# v.perm_err := '0';
+# v.rc_error := '0';
+# tlb_load := '0';
+# itlb_load := '0';
+# tlbie_req := '0';
+# v.inval_all := '0';
+# prtbl_rd := '0';
+#
+# -- Radix tree data structures in memory are big-endian,
+# -- so we need to byte-swap them
+# for i in 0 to 7 loop
+# data(i * 8 + 7 downto i * 8) := d_in.data((7 - i) * 8 + 7 downto
+# (7 - i) * 8);
+# end loop;
+#
+# case r.state is
+# when IDLE =>
+# if l_in.addr(63) = '0' then
+# pgtbl := r.pgtbl0;
+# pt_valid := r.pt0_valid;
+# else
+# pgtbl := r.pgtbl3;
+# pt_valid := r.pt3_valid;
+# end if;
+# -- rts == radix tree size, # address bits being translated
+# rts := unsigned('0' & pgtbl(62 downto 61) & pgtbl(7 downto 5));
+# -- mbits == # address bits to index top level of tree
+# mbits := unsigned('0' & pgtbl(4 downto 0));
+# -- set v.shift to rts so that we can use finalmask for the
+# segment check
+# v.shift := rts;
+# v.mask_size := mbits(4 downto 0);
+# v.pgbase := pgtbl(55 downto 8) & x"00";
+#
+# if l_in.valid = '1' then
+# v.addr := l_in.addr;
+# v.iside := l_in.iside;
+# v.store := not (l_in.load or l_in.iside);
+# v.priv := l_in.priv;
+# if l_in.tlbie = '1' then
+# -- Invalidate all iTLB/dTLB entries for tlbie with
+# -- RB[IS] != 0 or RB[AP] != 0, or for slbia
+# v.inval_all := l_in.slbia or l_in.addr(11) or l_in.
+# addr(10) or l_in.addr(7) or l_in.addr(6)
+# or l_in.addr(5);
+# -- The RIC field of the tlbie instruction comes across
+# -- on the sprn bus as bits 2--3. RIC=2 flushes process
+# -- table caches.
+# if l_in.sprn(3) = '1' then
+# v.pt0_valid := '0';
+# v.pt3_valid := '0';
+# end if;
+# v.state := DO_TLBIE;
+# else
+# v.valid := '1';
+# if pt_valid = '0' then
+# -- need to fetch process table entry
+# -- set v.shift so we can use finalmask for generating
+# -- the process table entry address
+# v.shift := unsigned('0' & r.prtbl(4 downto 0));
+# v.state := PROC_TBL_READ;
+# elsif mbits = 0 then
+# -- Use RPDS = 0 to disable radix tree walks
+# v.state := RADIX_FINISH;
+# v.invalid := '1';
+# else
+# v.state := SEGMENT_CHECK;
+# end if;
+# end if;
+# end if;
+# if l_in.mtspr = '1' then
+# -- Move to PID needs to invalidate L1 TLBs and cached
+# -- pgtbl0 value. Move to PRTBL does that plus
+# -- invalidating the cached pgtbl3 value as well.
+# if l_in.sprn(9) = '0' then
+# v.pid := l_in.rs(31 downto 0);
+# else
+# v.prtbl := l_in.rs;
+# v.pt3_valid := '0';
+# end if;
+# v.pt0_valid := '0';
+# v.inval_all := '1';
+# v.state := DO_TLBIE;
+# end if;
+#
+# when DO_TLBIE =>
+# dcreq := '1';
+# tlbie_req := '1';
+# v.state := TLB_WAIT;
+#
+# when TLB_WAIT =>
+# if d_in.done = '1' then
+# v.state := RADIX_FINISH;
+# end if;
+#
+# when PROC_TBL_READ =>
+# dcreq := '1';
+# prtbl_rd := '1';
+# v.state := PROC_TBL_WAIT;
+#
+# when PROC_TBL_WAIT =>
+# if d_in.done = '1' then
+# if r.addr(63) = '1' then
+# v.pgtbl3 := data;
+# v.pt3_valid := '1';
+# else
+# v.pgtbl0 := data;
+# v.pt0_valid := '1';
+# end if;
+# -- rts == radix tree size, # address bits being translated
+# rts := unsigned('0' & data(62 downto 61) & data(7 downto 5));
+# -- mbits == # address bits to index top level of tree
+# mbits := unsigned('0' & data(4 downto 0));
+# -- set v.shift to rts so that we can use finalmask for the
+# -- segment check
+# v.shift := rts;
+# v.mask_size := mbits(4 downto 0);
+# v.pgbase := data(55 downto 8) & x"00";
+# if mbits = 0 then
+# v.state := RADIX_FINISH;
+# v.invalid := '1';
+# else
+# v.state := SEGMENT_CHECK;
+# end if;
+# end if;
+# if d_in.err = '1' then
+# v.state := RADIX_FINISH;
+# v.badtree := '1';
+# end if;
+#
+# when SEGMENT_CHECK =>
+# mbits := '0' & r.mask_size;
+# v.shift := r.shift + (31 - 12) - mbits;
+# nonzero := or(r.addr(61 downto 31) and not finalmask(
+# 30 downto 0));
+# if r.addr(63) /= r.addr(62) or nonzero = '1' then
+# v.state := RADIX_FINISH;
+# v.segerror := '1';
+# elsif mbits < 5 or mbits > 16 or mbits >
+# (r.shift + (31 - 12)) then
+# v.state := RADIX_FINISH;
+# v.badtree := '1';
+# else
+# v.state := RADIX_LOOKUP;
+# end if;
+#
+# when RADIX_LOOKUP =>
+# dcreq := '1';
+# v.state := RADIX_READ_WAIT;
+#
+# when RADIX_READ_WAIT =>
+# if d_in.done = '1' then
+# v.pde := data;
+# -- test valid bit
+# if data(63) = '1' then
+# -- test leaf bit
+# if data(62) = '1' then
+# -- check permissions and RC bits
+# perm_ok := '0';
+# if r.priv = '1' or data(3) = '0' then
+# if r.iside = '0' then
+# perm_ok := data(1) or (data(2) and not
+# r.store);
+# else
+# -- no IAMR, so no KUEP support for now
+# -- deny execute permission if cache inhibited
+# perm_ok := data(0) and not data(5);
+# end if;
+# end if;
+# rc_ok := data(8) and (data(7) or not r.store);
+# if perm_ok = '1' and rc_ok = '1' then
+# v.state := RADIX_LOAD_TLB;
+# else
+# v.state := RADIX_FINISH;
+# v.perm_err := not perm_ok;
+# -- permission error takes precedence over
+# -- RC error
+# v.rc_error := perm_ok;
+# end if;
+# else
+# mbits := unsigned('0' & data(4 downto 0));
+# if mbits < 5 or mbits > 16 or mbits > r.shift then
+# v.state := RADIX_FINISH;
+# v.badtree := '1';
+# else
+# v.shift := v.shift - mbits;
+# v.mask_size := mbits(4 downto 0);
+# v.pgbase := data(55 downto 8) & x"00";
+# v.state := RADIX_LOOKUP;
+# end if;
+# end if;
+# else
+# -- non-present PTE, generate a DSI
+# v.state := RADIX_FINISH;
+# v.invalid := '1';
+# end if;
+# end if;
+# if d_in.err = '1' then
+# v.state := RADIX_FINISH;
+# v.badtree := '1';
+# end if;
+#
+# when RADIX_LOAD_TLB =>
+# tlb_load := '1';
+# if r.iside = '0' then
+# dcreq := '1';
+# v.state := TLB_WAIT;
+# else
+# itlb_load := '1';
+# v.state := IDLE;
+# end if;
+#
+# when RADIX_FINISH =>
+# v.state := IDLE;
+#
+# end case;
+#
+# if v.state = RADIX_FINISH or (v.state = RADIX_LOAD_TLB
+# and r.iside = '1') then
+# v.err := v.invalid or v.badtree or v.segerror or v.perm_err
+# or v.rc_error;
+# v.done := not v.err;
+# end if;
+#
+# if r.addr(63) = '1' then
+# effpid := x"00000000";
+# else
+# effpid := r.pid;
+# end if;
+# prtable_addr := x"00" & r.prtbl(55 downto 36) &
+# ((r.prtbl(35 downto 12) and not finalmask(
+# 23 downto 0)) or (effpid(31 downto 8) and
+# finalmask(23 downto 0))) & effpid(7 downto 0)
+# & "0000";
+#
+# pgtable_addr := x"00" & r.pgbase(55 downto 19) &
+# ((r.pgbase(18 downto 3) and not mask) or
+# (addrsh and mask)) & "000";
+#
+# pte := x"00" & ((r.pde(55 downto 12) and not finalmask) or
+# (r.addr(55 downto 12) and finalmask)) & r.pde(11 downto 0);
+#
+# -- update registers
+# rin <= v;
+#
+# -- drive outputs
+# if tlbie_req = '1' then
+# addr := r.addr;
+# tlb_data := (others => '0');
+# elsif tlb_load = '1' then
+# addr := r.addr(63 downto 12) & x"000";
+# tlb_data := pte;
+# elsif prtbl_rd = '1' then
+# addr := prtable_addr;
+# tlb_data := (others => '0');
+# else
+# addr := pgtable_addr;
+# tlb_data := (others => '0');
+# end if;
+#
+# l_out.done <= r.done;
+# l_out.err <= r.err;
+# l_out.invalid <= r.invalid;
+# l_out.badtree <= r.badtree;
+# l_out.segerr <= r.segerror;
+# l_out.perm_error <= r.perm_err;
+# l_out.rc_error <= r.rc_error;
+#
+# d_out.valid <= dcreq;
+# d_out.tlbie <= tlbie_req;
+# d_out.doall <= r.inval_all;
+# d_out.tlbld <= tlb_load;
+# d_out.addr <= addr;
+# d_out.pte <= tlb_data;
+#
+# i_out.tlbld <= itlb_load;
+# i_out.tlbie <= tlbie_req;
+# i_out.doall <= r.inval_all;
+# i_out.addr <= addr;
+# i_out.pte <= tlb_data;
+#
+# end process;
+# end;