commit
						7c4dab7eb0
					
				@ -0,0 +1,473 @@
 | 
			
		||||
library ieee;
 | 
			
		||||
use ieee.std_logic_1164.all;
 | 
			
		||||
use ieee.numeric_std.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).
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
architecture behave of mmu is
 | 
			
		||||
 | 
			
		||||
    type state_t is (IDLE,
 | 
			
		||||
                     TLB_WAIT,
 | 
			
		||||
                     PROC_TBL_READ,
 | 
			
		||||
                     PROC_TBL_WAIT,
 | 
			
		||||
                     SEGMENT_CHECK,
 | 
			
		||||
                     RADIX_LOOKUP,
 | 
			
		||||
                     RADIX_READ_WAIT,
 | 
			
		||||
                     RADIX_LOAD_TLB,
 | 
			
		||||
                     RADIX_ERROR
 | 
			
		||||
                     );
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
        -- config SPRs
 | 
			
		||||
        prtbl     : std_ulogic_vector(63 downto 0);
 | 
			
		||||
        pid       : std_ulogic_vector(31 downto 0);
 | 
			
		||||
        -- internal state
 | 
			
		||||
        state     : state_t;
 | 
			
		||||
        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;
 | 
			
		||||
 | 
			
		||||
    signal r, rin : reg_stage_t;
 | 
			
		||||
 | 
			
		||||
    signal addrsh  : std_ulogic_vector(15 downto 0);
 | 
			
		||||
    signal mask    : std_ulogic_vector(15 downto 0);
 | 
			
		||||
    signal finalmask : std_ulogic_vector(43 downto 0);
 | 
			
		||||
 | 
			
		||||
begin
 | 
			
		||||
    -- 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;
 | 
			
		||||
 | 
			
		||||
    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');
 | 
			
		||||
            else
 | 
			
		||||
                if rin.valid = '1' then
 | 
			
		||||
                    report "MMU got tlb miss for " & to_hstring(rin.addr);
 | 
			
		||||
                end if;
 | 
			
		||||
                if l_out.done = '1' then
 | 
			
		||||
                    report "MMU completing op with invalid=" & std_ulogic'image(l_out.invalid) &
 | 
			
		||||
                        " badtree=" & std_ulogic'image(l_out.badtree);
 | 
			
		||||
                end if;
 | 
			
		||||
                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;
 | 
			
		||||
                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;
 | 
			
		||||
                r <= 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 done : std_ulogic;
 | 
			
		||||
        variable tlb_load : std_ulogic;
 | 
			
		||||
        variable itlb_load : std_ulogic;
 | 
			
		||||
        variable tlbie_req : std_ulogic;
 | 
			
		||||
        variable inval_all : 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';
 | 
			
		||||
        done := '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';
 | 
			
		||||
        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
 | 
			
		||||
                    dcreq := '1';
 | 
			
		||||
                    tlbie_req := '1';
 | 
			
		||||
                    -- Invalidate all iTLB/dTLB entries for tlbie with
 | 
			
		||||
                    -- RB[IS] != 0 or RB[AP] != 0, or for slbia
 | 
			
		||||
                    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 := TLB_WAIT;
 | 
			
		||||
                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_ERROR;
 | 
			
		||||
                        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';
 | 
			
		||||
                dcreq := '1';
 | 
			
		||||
                tlbie_req := '1';
 | 
			
		||||
                inval_all := '1';
 | 
			
		||||
                v.state := TLB_WAIT;
 | 
			
		||||
            end if;
 | 
			
		||||
 | 
			
		||||
        when TLB_WAIT =>
 | 
			
		||||
            if d_in.done = '1' then
 | 
			
		||||
                done := '1';
 | 
			
		||||
                v.state := IDLE;
 | 
			
		||||
            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 d_in.err = '0' 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_ERROR;
 | 
			
		||||
                        v.invalid := '1';
 | 
			
		||||
                    else
 | 
			
		||||
                        v.state := SEGMENT_CHECK;
 | 
			
		||||
                    end if;
 | 
			
		||||
                else
 | 
			
		||||
                    v.state := RADIX_ERROR;
 | 
			
		||||
                    v.badtree := '1';
 | 
			
		||||
                end if;
 | 
			
		||||
            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_ERROR;
 | 
			
		||||
                v.segerror := '1';
 | 
			
		||||
            elsif mbits < 5 or mbits > 16 or mbits > (r.shift + (31 - 12)) then
 | 
			
		||||
                v.state := RADIX_ERROR;
 | 
			
		||||
                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
 | 
			
		||||
                if d_in.err = '0' 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_ERROR;
 | 
			
		||||
                                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_ERROR;
 | 
			
		||||
                                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_ERROR;
 | 
			
		||||
                        v.invalid := '1';
 | 
			
		||||
                    end if;
 | 
			
		||||
                else
 | 
			
		||||
                    v.state := RADIX_ERROR;
 | 
			
		||||
                    v.badtree := '1';
 | 
			
		||||
                end if;
 | 
			
		||||
            end if;
 | 
			
		||||
 | 
			
		||||
        when RADIX_LOAD_TLB =>
 | 
			
		||||
            tlb_load := '1';
 | 
			
		||||
            if r.iside = '0' then
 | 
			
		||||
                dcreq := '1';
 | 
			
		||||
                v.state := TLB_WAIT;
 | 
			
		||||
            else
 | 
			
		||||
                itlb_load := '1';
 | 
			
		||||
                done := '1';
 | 
			
		||||
                v.state := IDLE;
 | 
			
		||||
            end if;
 | 
			
		||||
 | 
			
		||||
        when RADIX_ERROR =>
 | 
			
		||||
            done := '1';
 | 
			
		||||
            v.state := IDLE;
 | 
			
		||||
 | 
			
		||||
        end case;
 | 
			
		||||
 | 
			
		||||
        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 := l_in.addr;
 | 
			
		||||
            tlb_data := l_in.rs;
 | 
			
		||||
        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 <= done;
 | 
			
		||||
        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 <= 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 <= inval_all;
 | 
			
		||||
        i_out.addr <= addr;
 | 
			
		||||
        i_out.pte <= tlb_data;
 | 
			
		||||
 | 
			
		||||
    end process;
 | 
			
		||||
end;
 | 
			
		||||
@ -0,0 +1,3 @@
 | 
			
		||||
TEST=mmu
 | 
			
		||||
 | 
			
		||||
include ../Makefile.test
 | 
			
		||||
@ -0,0 +1,179 @@
 | 
			
		||||
/* Copyright 2013-2014 IBM Corp.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 * 	http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 | 
			
		||||
 * implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Load an immediate 64-bit value into a register */
 | 
			
		||||
#define LOAD_IMM64(r, e)			\
 | 
			
		||||
	lis     r,(e)@highest;			\
 | 
			
		||||
	ori     r,r,(e)@higher;			\
 | 
			
		||||
	rldicr  r,r, 32, 31;			\
 | 
			
		||||
	oris    r,r, (e)@h;			\
 | 
			
		||||
	ori     r,r, (e)@l;
 | 
			
		||||
 | 
			
		||||
	.section ".head","ax"
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Microwatt currently enters in LE mode at 0x0, so we don't need to
 | 
			
		||||
	 * do any endian fix ups
 | 
			
		||||
	 */
 | 
			
		||||
	. = 0
 | 
			
		||||
.global _start
 | 
			
		||||
_start:
 | 
			
		||||
	LOAD_IMM64(%r10,__bss_start)
 | 
			
		||||
	LOAD_IMM64(%r11,__bss_end)
 | 
			
		||||
	subf	%r11,%r10,%r11
 | 
			
		||||
	addi	%r11,%r11,63
 | 
			
		||||
	srdi.	%r11,%r11,6
 | 
			
		||||
	beq	2f
 | 
			
		||||
	mtctr	%r11
 | 
			
		||||
1:	dcbz	0,%r10
 | 
			
		||||
	addi	%r10,%r10,64
 | 
			
		||||
	bdnz	1b
 | 
			
		||||
 | 
			
		||||
2:	LOAD_IMM64(%r1,__stack_top)
 | 
			
		||||
	li	%r0,0
 | 
			
		||||
	stdu	%r0,-16(%r1)
 | 
			
		||||
	LOAD_IMM64(%r12, main)
 | 
			
		||||
	mtctr	%r12
 | 
			
		||||
	bctrl
 | 
			
		||||
	attn // terminate on exit
 | 
			
		||||
	b .
 | 
			
		||||
 | 
			
		||||
	/* Read a location with translation on */
 | 
			
		||||
	.globl	test_read
 | 
			
		||||
test_read:
 | 
			
		||||
	mfmsr	%r9
 | 
			
		||||
	ori	%r8,%r9,0x10	/* set MSR_DR */
 | 
			
		||||
	mtmsrd	%r8,0
 | 
			
		||||
	mr	%r6,%r3
 | 
			
		||||
	li	%r3,0
 | 
			
		||||
	ld	%r5,0(%r6)
 | 
			
		||||
	li	%r3,1
 | 
			
		||||
	/* land here if DSI occurred */
 | 
			
		||||
	mtmsrd	%r9,0
 | 
			
		||||
	std	%r5,0(%r4)
 | 
			
		||||
	blr
 | 
			
		||||
 | 
			
		||||
	/* Write a location with translation on */
 | 
			
		||||
	.globl	test_write
 | 
			
		||||
test_write:
 | 
			
		||||
	mfmsr	%r9
 | 
			
		||||
	ori	%r8,%r9,0x10	/* set MSR_DR */
 | 
			
		||||
	mtmsrd	%r8,0
 | 
			
		||||
	mr	%r6,%r3
 | 
			
		||||
	li	%r3,0
 | 
			
		||||
	std	%r4,0(%r6)
 | 
			
		||||
	li	%r3,1
 | 
			
		||||
	/* land here if DSI occurred */
 | 
			
		||||
	mtmsrd	%r9,0
 | 
			
		||||
	blr
 | 
			
		||||
 | 
			
		||||
	/* Do a dcbz with translation on */
 | 
			
		||||
	.globl	test_dcbz
 | 
			
		||||
test_dcbz:
 | 
			
		||||
	mfmsr	%r9
 | 
			
		||||
	ori	%r8,%r9,0x10	/* set MSR_DR */
 | 
			
		||||
	mtmsrd	%r8,0
 | 
			
		||||
	mr	%r6,%r3
 | 
			
		||||
	li	%r3,0
 | 
			
		||||
	dcbz	0,%r6
 | 
			
		||||
	li	%r3,1
 | 
			
		||||
	/* land here if DSI occurred */
 | 
			
		||||
	mtmsrd	%r9,0
 | 
			
		||||
	blr
 | 
			
		||||
 | 
			
		||||
	.globl	test_exec
 | 
			
		||||
test_exec:
 | 
			
		||||
	mtsrr0	%r4
 | 
			
		||||
	mtsrr1	%r5
 | 
			
		||||
	rfid
 | 
			
		||||
 | 
			
		||||
#define EXCEPTION(nr)		\
 | 
			
		||||
	.= nr			;\
 | 
			
		||||
	attn
 | 
			
		||||
 | 
			
		||||
	/* DSI vector - skip the failing instruction + the next one */
 | 
			
		||||
	. = 0x300
 | 
			
		||||
	mtsprg0	%r10
 | 
			
		||||
	mfsrr0	%r10
 | 
			
		||||
	addi	%r10,%r10,8
 | 
			
		||||
	mtsrr0	%r10
 | 
			
		||||
	rfid
 | 
			
		||||
 | 
			
		||||
	EXCEPTION(0x380)
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * ISI vector - jump to LR to return from the test,
 | 
			
		||||
	 * with r3 cleared
 | 
			
		||||
	 */
 | 
			
		||||
	. = 0x400
 | 
			
		||||
	li	%r3,0
 | 
			
		||||
	blr
 | 
			
		||||
 | 
			
		||||
	/* More exception stubs */
 | 
			
		||||
	EXCEPTION(0x480)
 | 
			
		||||
	EXCEPTION(0x500)
 | 
			
		||||
	EXCEPTION(0x600)
 | 
			
		||||
	EXCEPTION(0x700)
 | 
			
		||||
	EXCEPTION(0x800)
 | 
			
		||||
	EXCEPTION(0x900)
 | 
			
		||||
	EXCEPTION(0x980)
 | 
			
		||||
	EXCEPTION(0xa00)
 | 
			
		||||
	EXCEPTION(0xb00)
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * System call - used to exit from tests where MSR[PR]
 | 
			
		||||
	 * may have been set.
 | 
			
		||||
	 */
 | 
			
		||||
	. = 0xc00
 | 
			
		||||
	blr
 | 
			
		||||
 | 
			
		||||
	EXCEPTION(0xd00)
 | 
			
		||||
	EXCEPTION(0xe00)
 | 
			
		||||
	EXCEPTION(0xe20)
 | 
			
		||||
	EXCEPTION(0xe40)
 | 
			
		||||
	EXCEPTION(0xe60)
 | 
			
		||||
	EXCEPTION(0xe80)
 | 
			
		||||
	EXCEPTION(0xf00)
 | 
			
		||||
	EXCEPTION(0xf20)
 | 
			
		||||
	EXCEPTION(0xf40)
 | 
			
		||||
	EXCEPTION(0xf60)
 | 
			
		||||
	EXCEPTION(0xf80)
 | 
			
		||||
 | 
			
		||||
	. = 0x1000
 | 
			
		||||
	/*
 | 
			
		||||
	 * This page gets mapped at various locations and
 | 
			
		||||
	 * the tests try to execute from it.
 | 
			
		||||
	 * r3 contains the test number.
 | 
			
		||||
	 */
 | 
			
		||||
	.globl	test_start
 | 
			
		||||
test_start:
 | 
			
		||||
	nop
 | 
			
		||||
	nop
 | 
			
		||||
	cmpdi	%r3,1
 | 
			
		||||
	beq	test_1
 | 
			
		||||
	cmpdi	%r3,2
 | 
			
		||||
	beq	test_2
 | 
			
		||||
test_return:
 | 
			
		||||
	li	%r3,1
 | 
			
		||||
	sc
 | 
			
		||||
 | 
			
		||||
	. = 0x1ff8
 | 
			
		||||
	/* test a branch near the end of a page */
 | 
			
		||||
test_1:	b	test_return
 | 
			
		||||
 | 
			
		||||
	/* test flowing from one page to the next */
 | 
			
		||||
test_2:	nop
 | 
			
		||||
	b	test_return
 | 
			
		||||
@ -0,0 +1,688 @@
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
#include "console.h"
 | 
			
		||||
 | 
			
		||||
#define MSR_DR	0x10
 | 
			
		||||
#define MSR_IR	0x20
 | 
			
		||||
 | 
			
		||||
extern int test_read(long *addr, long *ret, long init);
 | 
			
		||||
extern int test_write(long *addr, long val);
 | 
			
		||||
extern int test_dcbz(long *addr);
 | 
			
		||||
extern int test_exec(int testno, unsigned long pc, unsigned long msr);
 | 
			
		||||
 | 
			
		||||
static inline void do_tlbie(unsigned long rb, unsigned long rs)
 | 
			
		||||
{
 | 
			
		||||
	__asm__ volatile("tlbie %0,%1" : : "r" (rb), "r" (rs) : "memory");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define DSISR	18
 | 
			
		||||
#define DAR	19
 | 
			
		||||
#define SRR0	26
 | 
			
		||||
#define SRR1	27
 | 
			
		||||
#define PID	48
 | 
			
		||||
#define PRTBL	720
 | 
			
		||||
 | 
			
		||||
static inline unsigned long mfspr(int sprnum)
 | 
			
		||||
{
 | 
			
		||||
	long val;
 | 
			
		||||
 | 
			
		||||
	__asm__ volatile("mfspr %0,%1" : "=r" (val) : "i" (sprnum));
 | 
			
		||||
	return val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void mtspr(int sprnum, unsigned long val)
 | 
			
		||||
{
 | 
			
		||||
	__asm__ volatile("mtspr %0,%1" : : "i" (sprnum), "r" (val));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void store_pte(unsigned long *p, unsigned long pte)
 | 
			
		||||
{
 | 
			
		||||
	__asm__ volatile("stdbrx %1,0,%0" : : "r" (p), "r" (pte) : "memory");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void print_string(const char *str)
 | 
			
		||||
{
 | 
			
		||||
	for (; *str; ++str)
 | 
			
		||||
		putchar(*str);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void print_hex(unsigned long val)
 | 
			
		||||
{
 | 
			
		||||
	int i, x;
 | 
			
		||||
 | 
			
		||||
	for (i = 60; i >= 0; i -= 4) {
 | 
			
		||||
		x = (val >> i) & 0xf;
 | 
			
		||||
		if (x >= 10)
 | 
			
		||||
			putchar(x + 'a' - 10);
 | 
			
		||||
		else
 | 
			
		||||
			putchar(x + '0');
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// i < 100
 | 
			
		||||
void print_test_number(int i)
 | 
			
		||||
{
 | 
			
		||||
	print_string("test ");
 | 
			
		||||
	putchar(48 + i/10);
 | 
			
		||||
	putchar(48 + i%10);
 | 
			
		||||
	putchar(':');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define CACHE_LINE_SIZE	64
 | 
			
		||||
 | 
			
		||||
void zero_memory(void *ptr, unsigned long nbytes)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long nb, i, nl;
 | 
			
		||||
	void *p;
 | 
			
		||||
 | 
			
		||||
	for (; nbytes != 0; nbytes -= nb, ptr += nb) {
 | 
			
		||||
		nb = -((unsigned long)ptr) & (CACHE_LINE_SIZE - 1);
 | 
			
		||||
		if (nb == 0 && nbytes >= CACHE_LINE_SIZE) {
 | 
			
		||||
			nl = nbytes / CACHE_LINE_SIZE;
 | 
			
		||||
			p = ptr;
 | 
			
		||||
			for (i = 0; i < nl; ++i) {
 | 
			
		||||
				__asm__ volatile("dcbz 0,%0" : : "r" (p) : "memory");
 | 
			
		||||
				p += CACHE_LINE_SIZE;
 | 
			
		||||
			}
 | 
			
		||||
			nb = nl * CACHE_LINE_SIZE;
 | 
			
		||||
		} else {
 | 
			
		||||
			if (nb > nbytes)
 | 
			
		||||
				nb = nbytes;
 | 
			
		||||
			for (i = 0; i < nb; ++i)
 | 
			
		||||
				((unsigned char *)ptr)[i] = 0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define PERM_EX		0x001
 | 
			
		||||
#define PERM_WR		0x002
 | 
			
		||||
#define PERM_RD		0x004
 | 
			
		||||
#define PERM_PRIV	0x008
 | 
			
		||||
#define ATTR_NC		0x020
 | 
			
		||||
#define CHG		0x080
 | 
			
		||||
#define REF		0x100
 | 
			
		||||
 | 
			
		||||
#define DFLT_PERM	(PERM_WR | PERM_RD | REF | CHG)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Set up an MMU translation tree using memory starting at the 64k point.
 | 
			
		||||
 * We use 2 levels, mapping 2GB (the minimum size possible), with a
 | 
			
		||||
 * 8kB PGD level pointing to 4kB PTE pages.
 | 
			
		||||
 */
 | 
			
		||||
unsigned long *pgdir = (unsigned long *) 0x10000;
 | 
			
		||||
unsigned long *proc_tbl = (unsigned long *) 0x12000;
 | 
			
		||||
unsigned long free_ptr = 0x13000;
 | 
			
		||||
void *eas_mapped[4];
 | 
			
		||||
int neas_mapped;
 | 
			
		||||
 | 
			
		||||
void init_mmu(void)
 | 
			
		||||
{
 | 
			
		||||
	/* set up process table */
 | 
			
		||||
	zero_memory(proc_tbl, 512 * sizeof(unsigned long));
 | 
			
		||||
	mtspr(PRTBL, (unsigned long)proc_tbl);
 | 
			
		||||
	mtspr(PID, 1);
 | 
			
		||||
	zero_memory(pgdir, 1024 * sizeof(unsigned long));
 | 
			
		||||
	/* RTS = 0 (2GB address space), RPDS = 10 (1024-entry top level) */
 | 
			
		||||
	store_pte(&proc_tbl[2 * 1], (unsigned long) pgdir | 10);
 | 
			
		||||
	do_tlbie(0xc00, 0);	/* invalidate all TLB entries */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static unsigned long *read_pgd(unsigned long i)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long ret;
 | 
			
		||||
 | 
			
		||||
	__asm__ volatile("ldbrx %0,%1,%2" : "=r" (ret) : "b" (pgdir),
 | 
			
		||||
			 "r" (i * sizeof(unsigned long)));
 | 
			
		||||
	return (unsigned long *) (ret & 0x00ffffffffffff00);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void map(void *ea, void *pa, unsigned long perm_attr)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long epn = (unsigned long) ea >> 12;
 | 
			
		||||
	unsigned long i, j;
 | 
			
		||||
	unsigned long *ptep;
 | 
			
		||||
 | 
			
		||||
	i = (epn >> 9) & 0x3ff;
 | 
			
		||||
	j = epn & 0x1ff;
 | 
			
		||||
	if (pgdir[i] == 0) {
 | 
			
		||||
		zero_memory((void *)free_ptr, 512 * sizeof(unsigned long));
 | 
			
		||||
		store_pte(&pgdir[i], 0x8000000000000000 | free_ptr | 9);
 | 
			
		||||
		free_ptr += 512 * sizeof(unsigned long);
 | 
			
		||||
	}
 | 
			
		||||
	ptep = read_pgd(i);
 | 
			
		||||
	store_pte(&ptep[j], 0xc000000000000000 | ((unsigned long)pa & 0x00fffffffffff000) | perm_attr);
 | 
			
		||||
	eas_mapped[neas_mapped++] = ea;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void unmap(void *ea)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long epn = (unsigned long) ea >> 12;
 | 
			
		||||
	unsigned long i, j;
 | 
			
		||||
	unsigned long *ptep;
 | 
			
		||||
 | 
			
		||||
	i = (epn >> 9) & 0x3ff;
 | 
			
		||||
	j = epn & 0x1ff;
 | 
			
		||||
	if (pgdir[i] == 0)
 | 
			
		||||
		return;
 | 
			
		||||
	ptep = read_pgd(i);
 | 
			
		||||
	ptep[j] = 0;
 | 
			
		||||
	do_tlbie(((unsigned long)ea & ~0xfff), 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void unmap_all(void)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < neas_mapped; ++i)
 | 
			
		||||
		unmap(eas_mapped[i]);
 | 
			
		||||
	neas_mapped = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mmu_test_1(void)
 | 
			
		||||
{
 | 
			
		||||
	long *ptr = (long *) 0x123000;
 | 
			
		||||
	long val;
 | 
			
		||||
 | 
			
		||||
	/* this should fail */
 | 
			
		||||
	if (test_read(ptr, &val, 0xdeadbeefd00d))
 | 
			
		||||
		return 1;
 | 
			
		||||
	/* dest reg of load should be unchanged */
 | 
			
		||||
	if (val != 0xdeadbeefd00d)
 | 
			
		||||
		return 2;
 | 
			
		||||
	/* DAR and DSISR should be set correctly */
 | 
			
		||||
	if (mfspr(DAR) != (long) ptr || mfspr(DSISR) != 0x40000000)
 | 
			
		||||
		return 3;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mmu_test_2(void)
 | 
			
		||||
{
 | 
			
		||||
	long *mem = (long *) 0x8000;
 | 
			
		||||
	long *ptr = (long *) 0x124000;
 | 
			
		||||
	long *ptr2 = (long *) 0x1124000;
 | 
			
		||||
	long val;
 | 
			
		||||
 | 
			
		||||
	/* create PTE */
 | 
			
		||||
	map(ptr, mem, DFLT_PERM);
 | 
			
		||||
	/* initialize the memory content */
 | 
			
		||||
	mem[33] = 0xbadc0ffee;
 | 
			
		||||
	/* this should succeed and be a cache miss */
 | 
			
		||||
	if (!test_read(&ptr[33], &val, 0xdeadbeefd00d))
 | 
			
		||||
		return 1;
 | 
			
		||||
	/* dest reg of load should have the value written */
 | 
			
		||||
	if (val != 0xbadc0ffee)
 | 
			
		||||
		return 2;
 | 
			
		||||
	/* load a second TLB entry in the same set as the first */
 | 
			
		||||
	map(ptr2, mem, DFLT_PERM);
 | 
			
		||||
	/* this should succeed and be a cache hit */
 | 
			
		||||
	if (!test_read(&ptr2[33], &val, 0xdeadbeefd00d))
 | 
			
		||||
		return 3;
 | 
			
		||||
	/* dest reg of load should have the value written */
 | 
			
		||||
	if (val != 0xbadc0ffee)
 | 
			
		||||
		return 4;
 | 
			
		||||
	/* check that the first entry still works */
 | 
			
		||||
	if (!test_read(&ptr[33], &val, 0xdeadbeefd00d))
 | 
			
		||||
		return 5;
 | 
			
		||||
	if (val != 0xbadc0ffee)
 | 
			
		||||
		return 6;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mmu_test_3(void)
 | 
			
		||||
{
 | 
			
		||||
	long *mem = (long *) 0x9000;
 | 
			
		||||
	long *ptr = (long *) 0x14a000;
 | 
			
		||||
	long val;
 | 
			
		||||
 | 
			
		||||
	/* create PTE */
 | 
			
		||||
	map(ptr, mem, DFLT_PERM);
 | 
			
		||||
	/* initialize the memory content */
 | 
			
		||||
	mem[45] = 0xfee1800d4ea;
 | 
			
		||||
	/* this should succeed and be a cache miss */
 | 
			
		||||
	if (!test_read(&ptr[45], &val, 0xdeadbeefd0d0))
 | 
			
		||||
		return 1;
 | 
			
		||||
	/* dest reg of load should have the value written */
 | 
			
		||||
	if (val != 0xfee1800d4ea)
 | 
			
		||||
		return 2;
 | 
			
		||||
	/* remove the PTE */
 | 
			
		||||
	unmap(ptr);
 | 
			
		||||
	/* this should fail */
 | 
			
		||||
	if (test_read(&ptr[45], &val, 0xdeadbeefd0d0))
 | 
			
		||||
		return 3;
 | 
			
		||||
	/* dest reg of load should be unchanged */
 | 
			
		||||
	if (val != 0xdeadbeefd0d0)
 | 
			
		||||
		return 4;
 | 
			
		||||
	/* DAR and DSISR should be set correctly */
 | 
			
		||||
	if (mfspr(DAR) != (long) &ptr[45] || mfspr(DSISR) != 0x40000000)
 | 
			
		||||
		return 5;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mmu_test_4(void)
 | 
			
		||||
{
 | 
			
		||||
	long *mem = (long *) 0xa000;
 | 
			
		||||
	long *ptr = (long *) 0x10b000;
 | 
			
		||||
	long *ptr2 = (long *) 0x110b000;
 | 
			
		||||
	long val;
 | 
			
		||||
 | 
			
		||||
	/* create PTE */
 | 
			
		||||
	map(ptr, mem, DFLT_PERM);
 | 
			
		||||
	/* initialize the memory content */
 | 
			
		||||
	mem[27] = 0xf00f00f00f00;
 | 
			
		||||
	/* this should succeed and be a cache miss */
 | 
			
		||||
	if (!test_write(&ptr[27], 0xe44badc0ffee))
 | 
			
		||||
		return 1;
 | 
			
		||||
	/* memory should now have the value written */
 | 
			
		||||
	if (mem[27] != 0xe44badc0ffee)
 | 
			
		||||
		return 2;
 | 
			
		||||
	/* load a second TLB entry in the same set as the first */
 | 
			
		||||
	map(ptr2, mem, DFLT_PERM);
 | 
			
		||||
	/* this should succeed and be a cache hit */
 | 
			
		||||
	if (!test_write(&ptr2[27], 0x6e11ae))
 | 
			
		||||
		return 3;
 | 
			
		||||
	/* memory should have the value written */
 | 
			
		||||
	if (mem[27] != 0x6e11ae)
 | 
			
		||||
		return 4;
 | 
			
		||||
	/* check that the first entry still exists */
 | 
			
		||||
	/* (assumes TLB is 2-way associative or more) */
 | 
			
		||||
	if (!test_read(&ptr[27], &val, 0xdeadbeefd00d))
 | 
			
		||||
		return 5;
 | 
			
		||||
	if (val != 0x6e11ae)
 | 
			
		||||
		return 6;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mmu_test_5(void)
 | 
			
		||||
{
 | 
			
		||||
	long *mem = (long *) 0xbffd;
 | 
			
		||||
	long *ptr = (long *) 0x39fffd;
 | 
			
		||||
	long val;
 | 
			
		||||
 | 
			
		||||
	/* create PTE */
 | 
			
		||||
	map(ptr, mem, DFLT_PERM);
 | 
			
		||||
	/* this should fail */
 | 
			
		||||
	if (test_read(ptr, &val, 0xdeadbeef0dd0))
 | 
			
		||||
		return 1;
 | 
			
		||||
	/* dest reg of load should be unchanged */
 | 
			
		||||
	if (val != 0xdeadbeef0dd0)
 | 
			
		||||
		return 2;
 | 
			
		||||
	/* DAR and DSISR should be set correctly */
 | 
			
		||||
	if (mfspr(DAR) != ((long)ptr & ~0xfff) + 0x1000 || mfspr(DSISR) != 0x40000000)
 | 
			
		||||
		return 3;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mmu_test_6(void)
 | 
			
		||||
{
 | 
			
		||||
	long *mem = (long *) 0xbffd;
 | 
			
		||||
	long *ptr = (long *) 0x39fffd;
 | 
			
		||||
 | 
			
		||||
	/* create PTE */
 | 
			
		||||
	map(ptr, mem, DFLT_PERM);
 | 
			
		||||
	/* initialize memory */
 | 
			
		||||
	*mem = 0x123456789abcdef0;
 | 
			
		||||
	/* this should fail */
 | 
			
		||||
	if (test_write(ptr, 0xdeadbeef0dd0))
 | 
			
		||||
		return 1;
 | 
			
		||||
	/* DAR and DSISR should be set correctly */
 | 
			
		||||
	if (mfspr(DAR) != ((long)ptr & ~0xfff) + 0x1000 || mfspr(DSISR) != 0x42000000)
 | 
			
		||||
		return 2;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mmu_test_7(void)
 | 
			
		||||
{
 | 
			
		||||
	long *mem = (long *) 0x8000;
 | 
			
		||||
	long *ptr = (long *) 0x124000;
 | 
			
		||||
	long val;
 | 
			
		||||
 | 
			
		||||
	*mem = 0x123456789abcdef0;
 | 
			
		||||
	/* create PTE without R or C */
 | 
			
		||||
	map(ptr, mem, PERM_RD | PERM_WR);
 | 
			
		||||
	/* this should fail */
 | 
			
		||||
	if (test_read(ptr, &val, 0xdeadd00dbeef))
 | 
			
		||||
		return 1;
 | 
			
		||||
	/* dest reg of load should be unchanged */
 | 
			
		||||
	if (val != 0xdeadd00dbeef)
 | 
			
		||||
		return 2;
 | 
			
		||||
	/* DAR and DSISR should be set correctly */
 | 
			
		||||
	if (mfspr(DAR) != (long) ptr || mfspr(DSISR) != 0x00040000)
 | 
			
		||||
		return 3;
 | 
			
		||||
	/* this should fail */
 | 
			
		||||
	if (test_write(ptr, 0xdeadbeef0dd0))
 | 
			
		||||
		return 4;
 | 
			
		||||
	/* DAR and DSISR should be set correctly */
 | 
			
		||||
	if (mfspr(DAR) != (long)ptr || mfspr(DSISR) != 0x02040000)
 | 
			
		||||
		return 5;
 | 
			
		||||
	/* memory should be unchanged */
 | 
			
		||||
	if (*mem != 0x123456789abcdef0)
 | 
			
		||||
		return 6;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mmu_test_8(void)
 | 
			
		||||
{
 | 
			
		||||
	long *mem = (long *) 0x8000;
 | 
			
		||||
	long *ptr = (long *) 0x124000;
 | 
			
		||||
	long val;
 | 
			
		||||
 | 
			
		||||
	*mem = 0x123456789abcdef0;
 | 
			
		||||
	/* create PTE with R but not C */
 | 
			
		||||
	map(ptr, mem, REF | PERM_RD | PERM_WR);
 | 
			
		||||
	/* this should succeed */
 | 
			
		||||
	if (!test_read(ptr, &val, 0xdeadd00dbeef))
 | 
			
		||||
		return 1;
 | 
			
		||||
	/* this should fail */
 | 
			
		||||
	if (test_write(ptr, 0xdeadbeef0dd1))
 | 
			
		||||
		return 2;
 | 
			
		||||
	/* DAR and DSISR should be set correctly */
 | 
			
		||||
	if (mfspr(DAR) != (long)ptr || mfspr(DSISR) != 0x02040000)
 | 
			
		||||
		return 3;
 | 
			
		||||
	/* memory should be unchanged */
 | 
			
		||||
	if (*mem != 0x123456789abcdef0)
 | 
			
		||||
		return 4;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mmu_test_9(void)
 | 
			
		||||
{
 | 
			
		||||
	long *mem = (long *) 0x8000;
 | 
			
		||||
	long *ptr = (long *) 0x124000;
 | 
			
		||||
	long val;
 | 
			
		||||
 | 
			
		||||
	*mem = 0x123456789abcdef0;
 | 
			
		||||
	/* create PTE without read or write permission */
 | 
			
		||||
	map(ptr, mem, REF);
 | 
			
		||||
	/* this should fail */
 | 
			
		||||
	if (test_read(ptr, &val, 0xdeadd00dbeef))
 | 
			
		||||
		return 1;
 | 
			
		||||
	/* dest reg of load should be unchanged */
 | 
			
		||||
	if (val != 0xdeadd00dbeef)
 | 
			
		||||
		return 2;
 | 
			
		||||
	/* DAR and DSISR should be set correctly */
 | 
			
		||||
	if (mfspr(DAR) != (long) ptr || mfspr(DSISR) != 0x08000000)
 | 
			
		||||
		return 3;
 | 
			
		||||
	/* this should fail */
 | 
			
		||||
	if (test_write(ptr, 0xdeadbeef0dd1))
 | 
			
		||||
		return 4;
 | 
			
		||||
	/* DAR and DSISR should be set correctly */
 | 
			
		||||
	if (mfspr(DAR) != (long)ptr || mfspr(DSISR) != 0x0a000000)
 | 
			
		||||
		return 5;
 | 
			
		||||
	/* memory should be unchanged */
 | 
			
		||||
	if (*mem != 0x123456789abcdef0)
 | 
			
		||||
		return 6;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mmu_test_10(void)
 | 
			
		||||
{
 | 
			
		||||
	long *mem = (long *) 0x8000;
 | 
			
		||||
	long *ptr = (long *) 0x124000;
 | 
			
		||||
	long val;
 | 
			
		||||
 | 
			
		||||
	*mem = 0x123456789abcdef0;
 | 
			
		||||
	/* create PTE with read but not write permission */
 | 
			
		||||
	map(ptr, mem, REF | PERM_RD);
 | 
			
		||||
	/* this should succeed */
 | 
			
		||||
	if (!test_read(ptr, &val, 0xdeadd00dbeef))
 | 
			
		||||
		return 1;
 | 
			
		||||
	/* this should fail */
 | 
			
		||||
	if (test_write(ptr, 0xdeadbeef0dd1))
 | 
			
		||||
		return 2;
 | 
			
		||||
	/* DAR and DSISR should be set correctly */
 | 
			
		||||
	if (mfspr(DAR) != (long)ptr || mfspr(DSISR) != 0x0a000000)
 | 
			
		||||
		return 3;
 | 
			
		||||
	/* memory should be unchanged */
 | 
			
		||||
	if (*mem != 0x123456789abcdef0)
 | 
			
		||||
		return 4;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mmu_test_11(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long ptr = 0x523000;
 | 
			
		||||
 | 
			
		||||
	/* this should fail */
 | 
			
		||||
	if (test_exec(0, ptr, MSR_IR))
 | 
			
		||||
		return 1;
 | 
			
		||||
	/* SRR0 and SRR1 should be set correctly */
 | 
			
		||||
	if (mfspr(SRR0) != (long) ptr || mfspr(SRR1) != 0x40000020)
 | 
			
		||||
		return 2;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mmu_test_12(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long mem = 0x1000;
 | 
			
		||||
	unsigned long ptr = 0x324000;
 | 
			
		||||
	unsigned long ptr2 = 0x1324000;
 | 
			
		||||
 | 
			
		||||
	/* create PTE */
 | 
			
		||||
	map((void *)ptr, (void *)mem, PERM_EX | REF);
 | 
			
		||||
	/* this should succeed and be a cache miss */
 | 
			
		||||
	if (!test_exec(0, ptr, MSR_IR))
 | 
			
		||||
		return 1;
 | 
			
		||||
	/* create a second PTE */
 | 
			
		||||
	map((void *)ptr2, (void *)mem, PERM_EX | REF);
 | 
			
		||||
	/* this should succeed and be a cache hit */
 | 
			
		||||
	if (!test_exec(0, ptr2, MSR_IR))
 | 
			
		||||
		return 2;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mmu_test_13(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long mem = 0x1000;
 | 
			
		||||
	unsigned long ptr = 0x349000;
 | 
			
		||||
	unsigned long ptr2 = 0x34a000;
 | 
			
		||||
 | 
			
		||||
	/* create a PTE */
 | 
			
		||||
	map((void *)ptr, (void *)mem, PERM_EX | REF);
 | 
			
		||||
	/* this should succeed */
 | 
			
		||||
	if (!test_exec(1, ptr, MSR_IR))
 | 
			
		||||
		return 1;
 | 
			
		||||
	/* invalidate the PTE */
 | 
			
		||||
	unmap((void *)ptr);
 | 
			
		||||
	/* install a second PTE */
 | 
			
		||||
	map((void *)ptr2, (void *)mem, PERM_EX | REF);
 | 
			
		||||
	/* this should fail */
 | 
			
		||||
	if (test_exec(1, ptr, MSR_IR))
 | 
			
		||||
		return 2;
 | 
			
		||||
	/* SRR0 and SRR1 should be set correctly */
 | 
			
		||||
	if (mfspr(SRR0) != (long) ptr || mfspr(SRR1) != 0x40000020)
 | 
			
		||||
		return 3;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mmu_test_14(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long mem = 0x1000;
 | 
			
		||||
	unsigned long mem2 = 0x2000;
 | 
			
		||||
	unsigned long ptr = 0x30a000;
 | 
			
		||||
	unsigned long ptr2 = 0x30b000;
 | 
			
		||||
 | 
			
		||||
	/* create a PTE */
 | 
			
		||||
	map((void *)ptr, (void *)mem, PERM_EX | REF);
 | 
			
		||||
	/* this should fail due to second page not being mapped */
 | 
			
		||||
	if (test_exec(2, ptr, MSR_IR))
 | 
			
		||||
		return 1;
 | 
			
		||||
	/* SRR0 and SRR1 should be set correctly */
 | 
			
		||||
	if (mfspr(SRR0) != ptr2 || mfspr(SRR1) != 0x40000020)
 | 
			
		||||
		return 2;
 | 
			
		||||
	/* create a PTE for the second page */
 | 
			
		||||
	map((void *)ptr2, (void *)mem2, PERM_EX | REF);
 | 
			
		||||
	/* this should succeed */
 | 
			
		||||
	if (!test_exec(2, ptr, MSR_IR))
 | 
			
		||||
		return 3;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mmu_test_15(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long mem = 0x1000;
 | 
			
		||||
	unsigned long ptr = 0x324000;
 | 
			
		||||
 | 
			
		||||
	/* create a PTE without execute permission */
 | 
			
		||||
	map((void *)ptr, (void *)mem, DFLT_PERM);
 | 
			
		||||
	/* this should fail */
 | 
			
		||||
	if (test_exec(0, ptr, MSR_IR))
 | 
			
		||||
		return 1;
 | 
			
		||||
	/* SRR0 and SRR1 should be set correctly */
 | 
			
		||||
	if (mfspr(SRR0) != ptr || mfspr(SRR1) != 0x10000020)
 | 
			
		||||
		return 2;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mmu_test_16(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long mem = 0x1000;
 | 
			
		||||
	unsigned long mem2 = 0x2000;
 | 
			
		||||
	unsigned long ptr = 0x30a000;
 | 
			
		||||
	unsigned long ptr2 = 0x30b000;
 | 
			
		||||
 | 
			
		||||
	/* create a PTE */
 | 
			
		||||
	map((void *)ptr, (void *)mem, PERM_EX | REF);
 | 
			
		||||
	/* create a PTE for the second page without execute permission */
 | 
			
		||||
	map((void *)ptr2, (void *)mem2, PERM_RD | REF);
 | 
			
		||||
	/* this should fail due to second page being no-execute */
 | 
			
		||||
	if (test_exec(2, ptr, MSR_IR))
 | 
			
		||||
		return 1;
 | 
			
		||||
	/* SRR0 and SRR1 should be set correctly */
 | 
			
		||||
	if (mfspr(SRR0) != ptr2 || mfspr(SRR1) != 0x10000020)
 | 
			
		||||
		return 2;
 | 
			
		||||
	/* create a PTE for the second page with execute permission */
 | 
			
		||||
	map((void *)ptr2, (void *)mem2, PERM_RD | PERM_EX | REF);
 | 
			
		||||
	/* this should succeed */
 | 
			
		||||
	if (!test_exec(2, ptr, MSR_IR))
 | 
			
		||||
		return 3;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mmu_test_17(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long mem = 0x1000;
 | 
			
		||||
	unsigned long ptr = 0x349000;
 | 
			
		||||
 | 
			
		||||
	/* create a PTE without the ref bit set */
 | 
			
		||||
	map((void *)ptr, (void *)mem, PERM_EX);
 | 
			
		||||
	/* this should fail */
 | 
			
		||||
	if (test_exec(2, ptr, MSR_IR))
 | 
			
		||||
		return 1;
 | 
			
		||||
	/* SRR0 and SRR1 should be set correctly */
 | 
			
		||||
	if (mfspr(SRR0) != (long) ptr || mfspr(SRR1) != 0x00040020)
 | 
			
		||||
		return 2;
 | 
			
		||||
	/* create a PTE without ref or execute permission */
 | 
			
		||||
	unmap((void *)ptr);
 | 
			
		||||
	map((void *)ptr, (void *)mem, 0);
 | 
			
		||||
	/* this should fail */
 | 
			
		||||
	if (test_exec(2, ptr, MSR_IR))
 | 
			
		||||
		return 1;
 | 
			
		||||
	/* SRR0 and SRR1 should be set correctly */
 | 
			
		||||
	/* RC update fail bit should not be set */
 | 
			
		||||
	if (mfspr(SRR0) != (long) ptr || mfspr(SRR1) != 0x10000020)
 | 
			
		||||
		return 2;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mmu_test_18(void)
 | 
			
		||||
{
 | 
			
		||||
	long *mem = (long *) 0x8000;
 | 
			
		||||
	long *ptr = (long *) 0x124000;
 | 
			
		||||
	long *ptr2 = (long *) 0x1124000;
 | 
			
		||||
 | 
			
		||||
	/* create PTE */
 | 
			
		||||
	map(ptr, mem, DFLT_PERM);
 | 
			
		||||
	/* this should succeed and be a cache miss */
 | 
			
		||||
	if (!test_dcbz(&ptr[129]))
 | 
			
		||||
		return 1;
 | 
			
		||||
	/* create a second PTE */
 | 
			
		||||
	map(ptr2, mem, DFLT_PERM);
 | 
			
		||||
	/* this should succeed and be a cache hit */
 | 
			
		||||
	if (!test_dcbz(&ptr2[130]))
 | 
			
		||||
		return 2;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int mmu_test_19(void)
 | 
			
		||||
{
 | 
			
		||||
	long *mem = (long *) 0x8000;
 | 
			
		||||
	long *ptr = (long *) 0x124000;
 | 
			
		||||
 | 
			
		||||
	*mem = 0x123456789abcdef0;
 | 
			
		||||
	/* create PTE with read but not write permission */
 | 
			
		||||
	map(ptr, mem, REF | PERM_RD);
 | 
			
		||||
	/* this should fail and create a TLB entry */
 | 
			
		||||
	if (test_write(ptr, 0xdeadbeef0dd1))
 | 
			
		||||
		return 1;
 | 
			
		||||
	/* DAR and DSISR should be set correctly */
 | 
			
		||||
	if (mfspr(DAR) != (long)ptr || mfspr(DSISR) != 0x0a000000)
 | 
			
		||||
		return 2;
 | 
			
		||||
	/* Update the PTE to have write permission */
 | 
			
		||||
	map(ptr, mem, REF | CHG | PERM_RD | PERM_WR);
 | 
			
		||||
	/* this should succeed */
 | 
			
		||||
	if (!test_write(ptr, 0xdeadbeef0dd1))
 | 
			
		||||
		return 3;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int fail = 0;
 | 
			
		||||
 | 
			
		||||
void do_test(int num, int (*test)(void))
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	mtspr(DSISR, 0);
 | 
			
		||||
	mtspr(DAR, 0);
 | 
			
		||||
	unmap_all();
 | 
			
		||||
	print_test_number(num);
 | 
			
		||||
	ret = test();
 | 
			
		||||
	if (ret == 0) {
 | 
			
		||||
		print_string("PASS\r\n");
 | 
			
		||||
	} else {
 | 
			
		||||
		fail = 1;
 | 
			
		||||
		print_string("FAIL ");
 | 
			
		||||
		putchar(ret + '0');
 | 
			
		||||
		if (num <= 10 || num == 19) {
 | 
			
		||||
			print_string(" DAR=");
 | 
			
		||||
			print_hex(mfspr(DAR));
 | 
			
		||||
			print_string(" DSISR=");
 | 
			
		||||
			print_hex(mfspr(DSISR));
 | 
			
		||||
		} else {
 | 
			
		||||
			print_string(" SRR0=");
 | 
			
		||||
			print_hex(mfspr(SRR0));
 | 
			
		||||
			print_string(" SRR1=");
 | 
			
		||||
			print_hex(mfspr(SRR1));
 | 
			
		||||
		}
 | 
			
		||||
		print_string("\r\n");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(void)
 | 
			
		||||
{
 | 
			
		||||
	potato_uart_init();
 | 
			
		||||
	init_mmu();
 | 
			
		||||
 | 
			
		||||
	do_test(1, mmu_test_1);
 | 
			
		||||
	do_test(2, mmu_test_2);
 | 
			
		||||
	do_test(3, mmu_test_3);
 | 
			
		||||
	do_test(4, mmu_test_4);
 | 
			
		||||
	do_test(5, mmu_test_5);
 | 
			
		||||
	do_test(6, mmu_test_6);
 | 
			
		||||
	do_test(7, mmu_test_7);
 | 
			
		||||
	do_test(8, mmu_test_8);
 | 
			
		||||
	do_test(9, mmu_test_9);
 | 
			
		||||
	do_test(10, mmu_test_10);
 | 
			
		||||
	do_test(11, mmu_test_11);
 | 
			
		||||
	do_test(12, mmu_test_12);
 | 
			
		||||
	do_test(13, mmu_test_13);
 | 
			
		||||
	do_test(14, mmu_test_14);
 | 
			
		||||
	do_test(15, mmu_test_15);
 | 
			
		||||
	do_test(16, mmu_test_16);
 | 
			
		||||
	do_test(17, mmu_test_17);
 | 
			
		||||
	do_test(18, mmu_test_18);
 | 
			
		||||
	do_test(19, mmu_test_19);
 | 
			
		||||
 | 
			
		||||
	return fail;
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,27 @@
 | 
			
		||||
SECTIONS
 | 
			
		||||
{
 | 
			
		||||
	. = 0;
 | 
			
		||||
	_start = .;
 | 
			
		||||
	.head : {
 | 
			
		||||
		KEEP(*(.head))
 | 
			
		||||
	}
 | 
			
		||||
	. = ALIGN(0x1000);
 | 
			
		||||
	.text : { *(.text) *(.text.*) *(.rodata) *(.rodata.*) }
 | 
			
		||||
	. = ALIGN(0x1000);
 | 
			
		||||
	.data : { *(.data) *(.data.*) *(.got) *(.toc) }
 | 
			
		||||
	. = ALIGN(0x80);
 | 
			
		||||
	__bss_start = .;
 | 
			
		||||
	.bss : {
 | 
			
		||||
		*(.dynsbss)
 | 
			
		||||
		*(.sbss)
 | 
			
		||||
		*(.scommon)
 | 
			
		||||
		*(.dynbss)
 | 
			
		||||
		*(.bss)
 | 
			
		||||
		*(.common)
 | 
			
		||||
		*(.bss.*)
 | 
			
		||||
	}
 | 
			
		||||
	. = ALIGN(0x80);
 | 
			
		||||
	__bss_end = .;
 | 
			
		||||
	. = . + 0x4000;
 | 
			
		||||
	__stack_top = .;
 | 
			
		||||
}
 | 
			
		||||
											
												Binary file not shown.
											
										
									
								@ -0,0 +1,19 @@
 | 
			
		||||
test 01:PASS
 | 
			
		||||
test 02:PASS
 | 
			
		||||
test 03:PASS
 | 
			
		||||
test 04:PASS
 | 
			
		||||
test 05:PASS
 | 
			
		||||
test 06:PASS
 | 
			
		||||
test 07:PASS
 | 
			
		||||
test 08:PASS
 | 
			
		||||
test 09:PASS
 | 
			
		||||
test 10:PASS
 | 
			
		||||
test 11:PASS
 | 
			
		||||
test 12:PASS
 | 
			
		||||
test 13:PASS
 | 
			
		||||
test 14:PASS
 | 
			
		||||
test 15:PASS
 | 
			
		||||
test 16:PASS
 | 
			
		||||
test 17:PASS
 | 
			
		||||
test 18:PASS
 | 
			
		||||
test 19:PASS
 | 
			
		||||
											
												Binary file not shown.
											
										
									
								
					Loading…
					
					
				
		Reference in New Issue