From: Cole Poirier Date: Thu, 6 Aug 2020 19:21:09 +0000 (-0700) Subject: Fix mmu.py formatting X-Git-Tag: semi_working_ecp5~426 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=b2cf719b76d381bf5d582315fd222690bcffb3fa;p=soc.git Fix mmu.py formatting --- diff --git a/src/soc/experiment/mmu.py b/src/soc/experiment/mmu.py index 801b0df3..603ac12a 100644 --- a/src/soc/experiment/mmu.py +++ b/src/soc/experiment/mmu.py @@ -1,32 +1,30 @@ 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): @@ -41,92 +39,85 @@ 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 @@ -136,11 +127,11 @@ class MMU(Elaboratable): # 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 @@ -153,452 +144,468 @@ class MMU(Elaboratable): 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;