From 3edc95eea50ef5520b6e399b1b9409555204933d Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 20 Aug 2020 18:14:16 +1000 Subject: [PATCH 1/6] tests/mmu: Update to use correct MSR values The tests were using MSR values that did not have MSR_SF or MSR_LE set. Fix this so that the test still works when 32-bit and BE modes are implemented. Signed-off-by: Paul Mackerras --- tests/mmu/mmu.c | 47 +++++++++++++++++++++++++++------------------ tests/test_mmu.bin | Bin 20504 -> 24600 bytes 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/tests/mmu/mmu.c b/tests/mmu/mmu.c index b91a852..ef00824 100644 --- a/tests/mmu/mmu.c +++ b/tests/mmu/mmu.c @@ -4,8 +4,10 @@ #include "console.h" +#define MSR_LE 0x1 #define MSR_DR 0x10 #define MSR_IR 0x20 +#define MSR_SF 0x8000000000000000ul extern int test_read(long *addr, long *ret, long init); extern int test_write(long *addr, long val); @@ -445,10 +447,11 @@ int mmu_test_11(void) unsigned long ptr = 0x523000; /* this should fail */ - if (test_exec(0, ptr, MSR_IR)) + if (test_exec(0, ptr, MSR_SF | MSR_IR | MSR_LE)) return 1; /* SRR0 and SRR1 should be set correctly */ - if (mfspr(SRR0) != (long) ptr || mfspr(SRR1) != 0x40000020) + if (mfspr(SRR0) != (long) ptr || + mfspr(SRR1) != (MSR_SF | 0x40000000 | MSR_IR | MSR_LE)) return 2; return 0; } @@ -462,12 +465,12 @@ int mmu_test_12(void) /* 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)) + if (!test_exec(0, ptr, MSR_SF | MSR_IR | MSR_LE)) 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)) + if (!test_exec(0, ptr2, MSR_SF | MSR_IR | MSR_LE)) return 2; return 0; } @@ -481,17 +484,18 @@ int mmu_test_13(void) /* create a PTE */ map((void *)ptr, (void *)mem, PERM_EX | REF); /* this should succeed */ - if (!test_exec(1, ptr, MSR_IR)) + if (!test_exec(1, ptr, MSR_SF | MSR_IR | MSR_LE)) 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)) + if (test_exec(1, ptr, MSR_SF | MSR_IR | MSR_LE)) return 2; /* SRR0 and SRR1 should be set correctly */ - if (mfspr(SRR0) != (long) ptr || mfspr(SRR1) != 0x40000020) + if (mfspr(SRR0) != (long) ptr || + mfspr(SRR1) != (MSR_SF | 0x40000000 | MSR_IR | MSR_LE)) return 3; return 0; } @@ -506,15 +510,16 @@ int mmu_test_14(void) /* 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)) + if (test_exec(2, ptr, MSR_SF | MSR_IR | MSR_LE)) return 1; /* SRR0 and SRR1 should be set correctly */ - if (mfspr(SRR0) != ptr2 || mfspr(SRR1) != 0x40000020) + if (mfspr(SRR0) != ptr2 || + mfspr(SRR1) != (MSR_SF | 0x40000000 | MSR_IR | MSR_LE)) 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)) + if (!test_exec(2, ptr, MSR_SF | MSR_IR | MSR_LE)) return 3; return 0; } @@ -527,10 +532,11 @@ int mmu_test_15(void) /* create a PTE without execute permission */ map((void *)ptr, (void *)mem, DFLT_PERM); /* this should fail */ - if (test_exec(0, ptr, MSR_IR)) + if (test_exec(0, ptr, MSR_SF | MSR_IR | MSR_LE)) return 1; /* SRR0 and SRR1 should be set correctly */ - if (mfspr(SRR0) != ptr || mfspr(SRR1) != 0x10000020) + if (mfspr(SRR0) != ptr || + mfspr(SRR1) != (MSR_SF | 0x10000000 | MSR_IR | MSR_LE)) return 2; return 0; } @@ -547,15 +553,16 @@ int mmu_test_16(void) /* 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)) + if (test_exec(2, ptr, MSR_SF | MSR_IR | MSR_LE)) return 1; /* SRR0 and SRR1 should be set correctly */ - if (mfspr(SRR0) != ptr2 || mfspr(SRR1) != 0x10000020) + if (mfspr(SRR0) != ptr2 || + mfspr(SRR1) != (MSR_SF | 0x10000000 | MSR_IR | MSR_LE)) 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)) + if (!test_exec(2, ptr, MSR_SF | MSR_IR | MSR_LE)) return 3; return 0; } @@ -568,20 +575,22 @@ int mmu_test_17(void) /* 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)) + if (test_exec(2, ptr, MSR_SF | MSR_IR | MSR_LE)) return 1; /* SRR0 and SRR1 should be set correctly */ - if (mfspr(SRR0) != (long) ptr || mfspr(SRR1) != 0x00040020) + if (mfspr(SRR0) != (long) ptr || + mfspr(SRR1) != (MSR_SF | 0x00040000 | MSR_IR | MSR_LE)) 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)) + if (test_exec(2, ptr, MSR_SF | MSR_IR | MSR_LE)) 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) + if (mfspr(SRR0) != (long) ptr || + mfspr(SRR1) != (MSR_SF | 0x10000000 | MSR_IR | MSR_LE)) return 2; return 0; } diff --git a/tests/test_mmu.bin b/tests/test_mmu.bin index 5526c40992adc360f9d2b5d7c08a4bab3013a182..7f87578a8479b4001d9aec97edf42bde0e9eabd7 100755 GIT binary patch literal 24600 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 literal 20504 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 Qz*m7lfy>&(dP?T=e{6|~O8@`> From 2e7b371305243f181807654bc6e82e223a567013 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Wed, 12 Aug 2020 21:59:28 +1000 Subject: [PATCH 2/6] core: Implement big-endian mode Big-endian mode affects both instruction fetches and data accesses. For instruction fetches, we byte-swap each word read from memory when writing it into the icache data RAM, and use a tag bit to indicate whether each cache line contains instructions in BE or LE form. For data accesses, we simply need to invert the existing byte_reverse signal in BE mode. The only thing to be careful of is to get the sign bit from the correct place when doing a sign-extending load that crosses two doublewords of memory. For now, interrupts unconditionally set MSR[LE]. We will need some sort of interrupt-little-endian bit somewhere, perhaps in LPCR. This also fixes a debug report statement in fetch1.vhdl. Signed-off-by: Paul Mackerras --- common.vhdl | 5 ++++- execute1.vhdl | 8 ++++++-- fetch1.vhdl | 7 +++++-- icache.vhdl | 27 ++++++++++++++++++++------- loadstore1.vhdl | 22 ++++++++++++++-------- 5 files changed, 49 insertions(+), 20 deletions(-) diff --git a/common.vhdl b/common.vhdl index bd9210b..9ed07b3 100644 --- a/common.vhdl +++ b/common.vhdl @@ -108,6 +108,7 @@ package common is req: std_ulogic; virt_mode : std_ulogic; priv_mode : std_ulogic; + big_endian : std_ulogic; stop_mark: std_ulogic; sequential: std_ulogic; nia: std_ulogic_vector(63 downto 0); @@ -245,10 +246,12 @@ package common is redirect: std_ulogic; virt_mode: std_ulogic; priv_mode: std_ulogic; + big_endian: std_ulogic; redirect_nia: std_ulogic_vector(63 downto 0); end record; constant Execute1ToFetch1Init : Execute1ToFetch1Type := (redirect => '0', virt_mode => '0', - priv_mode => '0', others => (others => '0')); + priv_mode => '0', big_endian => '0', + others => (others => '0')); type Execute1ToLoadstore1Type is record valid : std_ulogic; diff --git a/execute1.vhdl b/execute1.vhdl index 1b83997..99553cc 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -496,9 +496,10 @@ begin v.terminate := '0'; icache_inval <= '0'; v.busy := '0'; - -- send MSR[IR] and ~MSR[PR] up to fetch1 + -- send MSR[IR], ~MSR[PR] and ~MSR[LE] up to fetch1 v.f.virt_mode := ctrl.msr(MSR_IR); v.f.priv_mode := not ctrl.msr(MSR_PR); + v.f.big_endian := not ctrl.msr(MSR_LE); -- Next insn adder used in a couple of places next_nia := std_ulogic_vector(unsigned(e_in.nia) + 4); @@ -740,6 +741,7 @@ begin when OP_RFID => v.f.virt_mode := a_in(MSR_IR) or a_in(MSR_PR); v.f.priv_mode := not a_in(MSR_PR); + v.f.big_endian := not a_in(MSR_LE); -- Can't use msr_copy here because the partial function MSR -- bits should be left unchanged, not zeroed. ctrl_tmp.msr(63 downto 31) <= a_in(63 downto 31); @@ -1161,6 +1163,8 @@ begin v.f.redirect := '1'; v.f.virt_mode := '0'; v.f.priv_mode := '1'; + -- XXX need an interrupt LE bit here, e.g. from LPCR + v.f.big_endian := '0'; end if; if v.f.redirect = '1' then @@ -1176,7 +1180,7 @@ begin lv.data := c_in; lv.write_reg := gspr_to_gpr(e_in.write_reg); lv.length := e_in.data_len; - lv.byte_reverse := e_in.byte_reverse; + lv.byte_reverse := e_in.byte_reverse xnor ctrl.msr(MSR_LE); lv.sign_extend := e_in.sign_extend; lv.update := e_in.update; lv.update_reg := gspr_to_gpr(e_in.read_reg1); diff --git a/fetch1.vhdl b/fetch1.vhdl index a56f33d..63672cb 100644 --- a/fetch1.vhdl +++ b/fetch1.vhdl @@ -50,8 +50,9 @@ begin log_nia <= r.nia(63) & r.nia(43 downto 2); if r /= r_next then report "fetch1 rst:" & std_ulogic'image(rst) & - " IR:" & std_ulogic'image(e_in.virt_mode) & - " P:" & std_ulogic'image(e_in.priv_mode) & + " IR:" & std_ulogic'image(r_next.virt_mode) & + " P:" & std_ulogic'image(r_next.priv_mode) & + " E:" & std_ulogic'image(r_next.big_endian) & " R:" & std_ulogic'image(e_in.redirect) & std_ulogic'image(d_in.redirect) & " S:" & std_ulogic'image(stall_in) & " T:" & std_ulogic'image(stop_in) & @@ -81,11 +82,13 @@ begin end if; v.virt_mode := '0'; v.priv_mode := '1'; + v.big_endian := '0'; v_int.stop_state := RUNNING; elsif e_in.redirect = '1' then v.nia := e_in.redirect_nia(63 downto 2) & "00"; v.virt_mode := e_in.virt_mode; v.priv_mode := e_in.priv_mode; + v.big_endian := e_in.big_endian; elsif d_in.redirect = '1' then v.nia := d_in.redirect_nia(63 downto 2) & "00"; elsif stall_in = '0' then diff --git a/icache.vhdl b/icache.vhdl index 3f1c15f..d24a146 100644 --- a/icache.vhdl +++ b/icache.vhdl @@ -98,7 +98,8 @@ architecture rtl of icache is -- SET_SIZE_BITS is the log base 2 of the set size constant SET_SIZE_BITS : natural := LINE_OFF_BITS + INDEX_BITS; -- TAG_BITS is the number of bits of the tag part of the address - constant TAG_BITS : natural := REAL_ADDR_BITS - SET_SIZE_BITS; + -- the +1 is to allow the endianness to be stored in the tag + constant TAG_BITS : natural := REAL_ADDR_BITS - SET_SIZE_BITS + 1; -- WAY_BITS is the number of bits to select a way constant WAY_BITS : natural := log2(NUM_WAYS); @@ -289,9 +290,10 @@ architecture rtl of icache is end; -- Get the tag value from the address - function get_tag(addr: std_ulogic_vector(REAL_ADDR_BITS - 1 downto 0)) return cache_tag_t is + function get_tag(addr: std_ulogic_vector(REAL_ADDR_BITS - 1 downto 0); + endian: std_ulogic) return cache_tag_t is begin - return addr(REAL_ADDR_BITS - 1 downto SET_SIZE_BITS); + return endian & addr(REAL_ADDR_BITS - 1 downto SET_SIZE_BITS); end; -- Read a tag from a tag memory row @@ -327,9 +329,9 @@ begin report "geometry bits don't add up" severity FAILURE; assert (LINE_OFF_BITS = ROW_OFF_BITS + ROW_LINEBITS) report "geometry bits don't add up" severity FAILURE; - assert (REAL_ADDR_BITS = TAG_BITS + INDEX_BITS + LINE_OFF_BITS) + assert (REAL_ADDR_BITS + 1 = TAG_BITS + INDEX_BITS + LINE_OFF_BITS) report "geometry bits don't add up" severity FAILURE; - assert (REAL_ADDR_BITS = TAG_BITS + ROW_BITS + ROW_OFF_BITS) + assert (REAL_ADDR_BITS + 1 = TAG_BITS + ROW_BITS + ROW_OFF_BITS) report "geometry bits don't add up" severity FAILURE; sim_debug: if SIM generate @@ -359,6 +361,7 @@ begin signal wr_addr : std_ulogic_vector(ROW_BITS-1 downto 0); signal dout : cache_row_t; signal wr_sel : std_ulogic_vector(ROW_SIZE-1 downto 0); + signal wr_dat : std_ulogic_vector(wishbone_in.dat'left downto 0); begin way: entity work.cache_ram generic map ( @@ -372,10 +375,20 @@ begin rd_data => dout, wr_sel => wr_sel, wr_addr => wr_addr, - wr_data => wishbone_in.dat + wr_data => wr_dat ); process(all) + variable j: integer; begin + -- byte-swap read data if big endian + if r.store_tag(TAG_BITS - 1) = '0' then + wr_dat <= wishbone_in.dat; + else + for i in 0 to (wishbone_in.dat'length / 8) - 1 loop + j := ((i / 4) * 4) + (3 - (i mod 4)); + wr_dat(i * 8 + 7 downto i * 8) <= wishbone_in.dat(j * 8 + 7 downto j * 8); + end loop; + end if; do_read <= not (stall_in or use_previous); do_write <= '0'; if wishbone_in.ack = '1' and replace_way = i then @@ -494,7 +507,7 @@ begin -- Extract line, row and tag from request req_index <= get_index(i_in.nia); req_row <= get_row(i_in.nia); - req_tag <= get_tag(real_addr); + req_tag <= get_tag(real_addr, i_in.big_endian); -- Calculate address of beginning of cache row, will be -- used for cache miss processing if needed diff --git a/loadstore1.vhdl b/loadstore1.vhdl index 62914c0..123c8ad 100644 --- a/loadstore1.vhdl +++ b/loadstore1.vhdl @@ -201,14 +201,20 @@ begin end loop; -- Work out the sign bit for sign extension. - -- Assumes we are not doing both sign extension and byte reversal, - -- in that for unaligned loads crossing two dwords we end up - -- using a bit from the second dword, whereas for a byte-reversed - -- (i.e. big-endian) load the sign bit would be in the first dword. - negative := (r.length(3) and data_permuted(63)) or - (r.length(2) and data_permuted(31)) or - (r.length(1) and data_permuted(15)) or - (r.length(0) and data_permuted(7)); + -- For unaligned loads crossing two dwords, the sign bit is in the + -- first dword for big-endian (byte_reverse = 1), or the second dword + -- for little-endian. + if r.dwords_done = '1' and r.byte_reverse = '1' then + negative := (r.length(3) and r.load_data(63)) or + (r.length(2) and r.load_data(31)) or + (r.length(1) and r.load_data(15)) or + (r.length(0) and r.load_data(7)); + else + negative := (r.length(3) and data_permuted(63)) or + (r.length(2) and data_permuted(31)) or + (r.length(1) and data_permuted(15)) or + (r.length(0) and data_permuted(7)); + end if; -- trim and sign-extend for i in 0 to 7 loop From 033ee909fdecc252d117863b111fbe7fa910d2a4 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Mon, 17 Aug 2020 09:38:13 +1000 Subject: [PATCH 3/6] core: Implement 32-bit mode In 32-bit mode, effective addresses are truncated to 32 bits, both for instruction fetches and data accesses, and CR0 is set for Rc=1 (record form) instructions based on the lower 32 bits of the result rather than all 64 bits. Signed-off-by: Paul Mackerras --- common.vhdl | 9 ++++++--- execute1.vhdl | 8 +++++++- fetch1.vhdl | 16 +++++++++++++++- loadstore1.vhdl | 14 +++++++++++--- writeback.vhdl | 9 +++++++-- 5 files changed, 46 insertions(+), 10 deletions(-) diff --git a/common.vhdl b/common.vhdl index 9ed07b3..ec63323 100644 --- a/common.vhdl +++ b/common.vhdl @@ -247,11 +247,12 @@ package common is virt_mode: std_ulogic; priv_mode: std_ulogic; big_endian: std_ulogic; + mode_32bit: std_ulogic; redirect_nia: std_ulogic_vector(63 downto 0); end record; constant Execute1ToFetch1Init : Execute1ToFetch1Type := (redirect => '0', virt_mode => '0', priv_mode => '0', big_endian => '0', - others => (others => '0')); + mode_32bit => '0', others => (others => '0')); type Execute1ToLoadstore1Type is record valid : std_ulogic; @@ -273,13 +274,14 @@ package common is rc : std_ulogic; -- set for stcx. virt_mode : std_ulogic; -- do translation through TLB priv_mode : std_ulogic; -- privileged mode (MSR[PR] = 0) + mode_32bit : std_ulogic; -- trim addresses to 32 bits end record; constant Execute1ToLoadstore1Init : Execute1ToLoadstore1Type := (valid => '0', op => OP_ILLEGAL, ci => '0', byte_reverse => '0', sign_extend => '0', update => '0', xerc => xerc_init, reserve => '0', rc => '0', virt_mode => '0', priv_mode => '0', nia => (others => '0'), insn => (others => '0'), addr1 => (others => '0'), addr2 => (others => '0'), data => (others => '0'), length => (others => '0'), - others => (others => '0')); + mode_32bit => '0', others => (others => '0')); type Loadstore1ToExecute1Type is record busy : std_ulogic; @@ -376,6 +378,7 @@ package common is type Execute1ToWritebackType is record valid: std_ulogic; rc : std_ulogic; + mode_32bit : std_ulogic; write_enable : std_ulogic; write_reg: gspr_index_t; write_data: std_ulogic_vector(63 downto 0); @@ -388,7 +391,7 @@ package common is exc_write_reg : gspr_index_t; exc_write_data : std_ulogic_vector(63 downto 0); end record; - constant Execute1ToWritebackInit : Execute1ToWritebackType := (valid => '0', rc => '0', write_enable => '0', + constant Execute1ToWritebackInit : Execute1ToWritebackType := (valid => '0', rc => '0', mode_32bit => '0', write_enable => '0', write_cr_enable => '0', exc_write_enable => '0', write_xerc_enable => '0', xerc => xerc_init, write_data => (others => '0'), write_cr_mask => (others => '0'), diff --git a/execute1.vhdl b/execute1.vhdl index 99553cc..b9411c1 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -496,10 +496,11 @@ begin v.terminate := '0'; icache_inval <= '0'; v.busy := '0'; - -- send MSR[IR], ~MSR[PR] and ~MSR[LE] up to fetch1 + -- send MSR[IR], ~MSR[PR], ~MSR[LE] and ~MSR[SF] up to fetch1 v.f.virt_mode := ctrl.msr(MSR_IR); v.f.priv_mode := not ctrl.msr(MSR_PR); v.f.big_endian := not ctrl.msr(MSR_LE); + v.f.mode_32bit := not ctrl.msr(MSR_SF); -- Next insn adder used in a couple of places next_nia := std_ulogic_vector(unsigned(e_in.nia) + 4); @@ -522,6 +523,8 @@ begin v.last_nia := e_in.nia; end if; + v.e.mode_32bit := not ctrl.msr(MSR_SF); + if ctrl.irq_state = WRITE_SRR1 then v.e.exc_write_reg := fast_spr_num(SPR_SRR1); v.e.exc_write_data := ctrl.srr1; @@ -742,6 +745,7 @@ begin v.f.virt_mode := a_in(MSR_IR) or a_in(MSR_PR); v.f.priv_mode := not a_in(MSR_PR); v.f.big_endian := not a_in(MSR_LE); + v.f.mode_32bit := not a_in(MSR_SF); -- Can't use msr_copy here because the partial function MSR -- bits should be left unchanged, not zeroed. ctrl_tmp.msr(63 downto 31) <= a_in(63 downto 31); @@ -1165,6 +1169,7 @@ begin v.f.priv_mode := '1'; -- XXX need an interrupt LE bit here, e.g. from LPCR v.f.big_endian := '0'; + v.f.mode_32bit := '0'; end if; if v.f.redirect = '1' then @@ -1195,6 +1200,7 @@ begin end if; lv.virt_mode := ctrl.msr(MSR_DR); lv.priv_mode := not ctrl.msr(MSR_PR); + lv.mode_32bit := not ctrl.msr(MSR_SF); -- Update registers rin <= v; diff --git a/fetch1.vhdl b/fetch1.vhdl index 63672cb..b100fb9 100644 --- a/fetch1.vhdl +++ b/fetch1.vhdl @@ -38,6 +38,7 @@ architecture behaviour of fetch1 is type stop_state_t is (RUNNING, STOPPED, RESTARTING); type reg_internal_t is record stop_state: stop_state_t; + mode_32bit: std_ulogic; end record; signal r, r_next : Fetch1ToIcacheType; signal r_int, r_next_int : reg_internal_t; @@ -53,6 +54,7 @@ begin " IR:" & std_ulogic'image(r_next.virt_mode) & " P:" & std_ulogic'image(r_next.priv_mode) & " E:" & std_ulogic'image(r_next.big_endian) & + " 32:" & std_ulogic'image(r_next_int.mode_32bit) & " R:" & std_ulogic'image(e_in.redirect) & std_ulogic'image(d_in.redirect) & " S:" & std_ulogic'image(stall_in) & " T:" & std_ulogic'image(stop_in) & @@ -84,13 +86,21 @@ begin v.priv_mode := '1'; v.big_endian := '0'; v_int.stop_state := RUNNING; + v_int.mode_32bit := '0'; elsif e_in.redirect = '1' then v.nia := e_in.redirect_nia(63 downto 2) & "00"; + if e_in.mode_32bit = '1' then + v.nia(63 downto 32) := (others => '0'); + end if; v.virt_mode := e_in.virt_mode; v.priv_mode := e_in.priv_mode; v.big_endian := e_in.big_endian; + v_int.mode_32bit := e_in.mode_32bit; elsif d_in.redirect = '1' then v.nia := d_in.redirect_nia(63 downto 2) & "00"; + if r_int.mode_32bit = '1' then + v.nia(63 downto 32) := (others => '0'); + end if; elsif stall_in = '0' then -- For debug stop/step to work properly we need a little bit of @@ -136,7 +146,11 @@ begin end case; if increment then - v.nia := std_logic_vector(unsigned(v.nia) + 4); + if r_int.mode_32bit = '0' then + v.nia := std_ulogic_vector(unsigned(r.nia) + 4); + else + v.nia := x"00000000" & std_ulogic_vector(unsigned(r.nia(31 downto 0)) + 4); + end if; v.sequential := '1'; end if; end if; diff --git a/loadstore1.vhdl b/loadstore1.vhdl index 123c8ad..6eb6804 100644 --- a/loadstore1.vhdl +++ b/loadstore1.vhdl @@ -84,6 +84,7 @@ architecture behave of loadstore1 is wait_mmu : std_ulogic; do_update : std_ulogic; extra_cycle : std_ulogic; + mode_32bit : std_ulogic; end record; type byte_sel_t is array(0 to 7) of std_ulogic; @@ -272,13 +273,16 @@ begin exception := '0'; if r.dwords_done = '1' or r.state = SECOND_REQ then - maddr := next_addr; + addr := next_addr; byte_sel := r.second_bytes; else - maddr := r.addr; + addr := r.addr; byte_sel := r.first_bytes; end if; - addr := maddr; + if r.mode_32bit = '1' then + addr(63 downto 32) := (others => '0'); + end if; + maddr := addr; case r.state is when IDLE => @@ -365,6 +369,7 @@ begin -- Note that l_in.valid is gated with busy inside execute1 if l_in.valid = '1' then v.addr := lsu_sum; + v.mode_32bit := l_in.mode_32bit; v.load := '0'; v.dcbz := '0'; v.tlbie := '0'; @@ -389,6 +394,9 @@ begin v.extra_cycle := '0'; addr := lsu_sum; + if l_in.mode_32bit = '1' then + addr(63 downto 32) := (others => '0'); + end if; maddr := l_in.addr2; -- address from RB for tlbie -- XXX Temporary hack. Mark the op as non-cachable if the address diff --git a/writeback.vhdl b/writeback.vhdl index d02a0b1..053a8ba 100644 --- a/writeback.vhdl +++ b/writeback.vhdl @@ -99,8 +99,13 @@ begin -- Perform CR0 update for RC forms -- Note that loads never have a form with an RC bit, therefore this can test e_in.write_data if e_in.rc = '1' and e_in.write_enable = '1' then - sign := e_in.write_data(63); - zero := not (or e_in.write_data); + zero := not (or e_in.write_data(31 downto 0)); + if e_in.mode_32bit = '0' then + sign := e_in.write_data(63); + zero := zero and not (or e_in.write_data(63 downto 32)); + else + sign := e_in.write_data(31); + end if; c_out.write_cr_enable <= '1'; c_out.write_cr_mask <= num_to_fxm(0); cf(3) := sign; From 371fd4cc20862738b8eefc05c64abee493e0a26b Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 20 Aug 2020 18:03:14 +1000 Subject: [PATCH 4/6] tests: Add tests for 32-bit and big-endian modes Signed-off-by: Paul Mackerras --- tests/modes/Makefile | 3 + tests/modes/head.S | 232 ++++++++++++++++++++++++ tests/modes/modes.c | 339 +++++++++++++++++++++++++++++++++++ tests/modes/powerpc.lds | 27 +++ tests/test_modes.bin | Bin 0 -> 20512 bytes tests/test_modes.console_out | 6 + tests/update_console_tests | 2 +- 7 files changed, 608 insertions(+), 1 deletion(-) create mode 100644 tests/modes/Makefile create mode 100644 tests/modes/head.S create mode 100644 tests/modes/modes.c create mode 100644 tests/modes/powerpc.lds create mode 100755 tests/test_modes.bin create mode 100644 tests/test_modes.console_out diff --git a/tests/modes/Makefile b/tests/modes/Makefile new file mode 100644 index 0000000..8f40880 --- /dev/null +++ b/tests/modes/Makefile @@ -0,0 +1,3 @@ +TEST=modes + +include ../Makefile.test diff --git a/tests/modes/head.S b/tests/modes/head.S new file mode 100644 index 0000000..d9e69dc --- /dev/null +++ b/tests/modes/head.S @@ -0,0 +1,232 @@ +/* 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) + mtsprg2 %r0 + LOAD_IMM64(%r12, main) + mtctr %r12 + bctrl + attn // terminate on exit + b . + +exception: + mfsprg2 %r0 + cmpdi %r0,0 + bne call_ret + attn + +#define EXCEPTION(nr) \ + .= nr ;\ + li %r3,nr ;\ + b exception + + EXCEPTION(0x300) + EXCEPTION(0x380) + EXCEPTION(0x400) + EXCEPTION(0x480) + EXCEPTION(0x500) + EXCEPTION(0x600) + EXCEPTION(0x700) + EXCEPTION(0x800) + EXCEPTION(0x900) + EXCEPTION(0x980) + EXCEPTION(0xa00) + EXCEPTION(0xb00) + 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_code +test_code: + nop + nop + mflr %r9 + cmpdi %r3,1 + beq test_1 + cmpdi %r3,2 + beq test_2 + cmpdi %r3,3 + beq test_3 + li %r3,0 + blr + + /* test a doubleword load from memory */ +test_1: ld %r3,0(%r4) + blr + + /* test a branch from the page at fffff000 */ +test_2: + b test_2a + 0x1000 +test_2a: + b test_2b - 0x1000 +test_2b: + beq test_2c + 0x1000 +test_2c: + beq test_2d - 0x1000 +test_2d: + li %r3,0 + blr + +test_return: + mflr %r3 + mtlr %r9 + blr + . = 0x1ffc + /* test a branch with link from the 4G-4 address */ +test_3: bl test_return + + .globl test_code_end +test_code_end: + + . = 0x2000 + /* + * Call a function in a context with a given MSR value. + * r3, r4 = args; r5 = function; r6 = MSR + */ + .globl callit +callit: + mflr %r0 + std %r0,16(%r1) + stdu %r1,-256(%r1) + mfcr %r8 + stw %r8,100(%r1) + std %r13,104(%r1) + std %r14,112(%r1) + std %r15,120(%r1) + std %r16,128(%r1) + std %r17,136(%r1) + std %r18,144(%r1) + std %r19,152(%r1) + std %r20,160(%r1) + std %r21,168(%r1) + std %r22,176(%r1) + std %r23,184(%r1) + std %r24,192(%r1) + std %r25,200(%r1) + std %r26,208(%r1) + std %r27,216(%r1) + std %r28,224(%r1) + std %r29,232(%r1) + std %r30,240(%r1) + std %r31,248(%r1) + li %r0,restore@l + mtsprg0 %r0 + mtsprg1 %r1 + mtsprg2 %r2 + mfmsr %r9 + mtsprg3 %r9 + li %r10,call_ret@l + mtlr %r10 + mtsrr0 %r5 + mtsrr1 %r6 + mr %r12,%r5 + rfid +call_ret: + tdi 0,%r0,0x48 /* b .+8 if wrong endian */ + b 2f /* if endian OK */ + /* reverse-endian version of instructions from 2: on */ + .long 0xa642107c + .long 0xa642937c + .long 0xa602ba7c + .long 0xa602db7c + .long 0xa643b07c + .long 0xa643d37c + .long 0xa6031a7c + .long 0xa6039b7c + .long 0x2400004c +2: mfsprg0 %r0 + mfsprg3 %r4 + mfsrr0 %r5 + mfsrr1 %r6 + mtsprg0 %r5 + mtsprg3 %r6 + mtsrr0 %r0 + mtsrr1 %r4 + rfid +restore: + mfsprg1 %r1 + mfsprg2 %r2 + li %r7,0 + mtsprg2 %r7 + lwz %r8,100(%r1) + mtcr %r8 + ld %r13,104(%r1) + ld %r14,112(%r1) + ld %r15,120(%r1) + ld %r16,128(%r1) + ld %r17,136(%r1) + ld %r18,144(%r1) + ld %r19,152(%r1) + ld %r20,160(%r1) + ld %r21,168(%r1) + ld %r22,176(%r1) + ld %r23,184(%r1) + ld %r24,192(%r1) + ld %r25,200(%r1) + ld %r26,208(%r1) + ld %r27,216(%r1) + ld %r28,224(%r1) + ld %r29,232(%r1) + ld %r30,240(%r1) + ld %r31,248(%r1) + addi %r1,%r1,256 + ld %r0,16(%r1) + mtlr %r0 + blr diff --git a/tests/modes/modes.c b/tests/modes/modes.c new file mode 100644 index 0000000..5d0c870 --- /dev/null +++ b/tests/modes/modes.c @@ -0,0 +1,339 @@ +#include +#include +#include + +#include "console.h" + +#define MSR_LE 0x1 +#define MSR_DR 0x10 +#define MSR_IR 0x20 +#define MSR_SF 0x8000000000000000ul + +extern unsigned long callit(unsigned long arg1, unsigned long arg2, + unsigned long fn, 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 SPRG0 272 +#define SPRG1 273 +#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 ndigit) +{ + int i, x; + + for (i = (ndigit - 1) * 4; 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_EX | PERM_WR | PERM_RD | REF | CHG) + +/* + * Set up an MMU translation tree using memory starting at the 64k point. + * We use 3 levels, mapping 512GB, with 4kB PGD/PMD/PTE pages. + */ +unsigned long *proc_tbl = (unsigned long *) 0x10000; +unsigned long *pgdir = (unsigned long *) 0x11000; +unsigned long free_ptr = 0x12000; + +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, 512 * sizeof(unsigned long)); + /* RTS = 8 (512GB address space), RPDS = 9 (512-entry top level) */ + store_pte(&proc_tbl[2 * 1], (unsigned long) pgdir | 0x2000000000000009); + do_tlbie(0xc00, 0); /* invalidate all TLB entries */ +} + +static unsigned long *read_pd(unsigned long *pdp, unsigned long i) +{ + unsigned long ret; + + __asm__ volatile("ldbrx %0,%1,%2" : "=r" (ret) : "b" (pdp), + "r" (i * sizeof(unsigned long))); + return (unsigned long *) (ret & 0x00ffffffffffff00); +} + +void map(unsigned long ea, unsigned long pa, unsigned long perm_attr) +{ + unsigned long epn = ea >> 12; + unsigned long h, i, j; + unsigned long *ptep; + unsigned long *pmdp; + + h = (epn >> 18) & 0x1ff; + i = (epn >> 9) & 0x1ff; + j = epn & 0x1ff; + if (pgdir[h] == 0) { + zero_memory((void *)free_ptr, 512 * sizeof(unsigned long)); + store_pte(&pgdir[h], 0x8000000000000000 | free_ptr | 9); + free_ptr += 512 * sizeof(unsigned long); + } + pmdp = read_pd(pgdir, h); + if (pmdp[i] == 0) { + zero_memory((void *)free_ptr, 512 * sizeof(unsigned long)); + store_pte(&pmdp[i], 0x8000000000000000 | free_ptr | 9); + free_ptr += 512 * sizeof(unsigned long); + } + ptep = read_pd(pmdp, i); + if (ptep[j]) { + ptep[j] = 0; + do_tlbie(ea & ~0xfff, 0); + } + store_pte(&ptep[j], 0xc000000000000000 | (pa & 0x00fffffffffff000) | + perm_attr); +} + +void unmap(void *ea) +{ + unsigned long epn = (unsigned long) ea >> 12; + unsigned long h, i, j; + unsigned long *ptep, *pmdp; + + h = (epn >> 18) & 0x1ff; + i = (epn >> 9) & 0x1ff; + j = epn & 0x1ff; + if (pgdir[h] == 0) + return; + pmdp = read_pd(pgdir, h); + if (pmdp[i] == 0) + return; + ptep = read_pd(pmdp, i); + ptep[j] = 0; + do_tlbie(((unsigned long)ea & ~0xfff), 0); +} + +extern unsigned long test_code(unsigned long sel, unsigned long addr); + +static unsigned long bits = 0x0102030405060708ul; + +int mode_test_1(void) +{ + unsigned long ret, msr; + + msr = MSR_SF | MSR_IR | MSR_DR | MSR_LE; + ret = callit(1, (unsigned long)&bits, (unsigned long)&test_code, msr); + if (ret != bits) + return ret? ret: 1; + return 0; +} + +unsigned long be_test_code; + +int mode_test_2(void) +{ + unsigned long i; + unsigned int *src, *dst; + unsigned long ret, msr; + + /* copy and byte-swap the page containing test_code */ + be_test_code = free_ptr; + free_ptr += 0x1000; + src = (unsigned int *) &test_code; + dst = (unsigned int *) be_test_code; + for (i = 0; i < 0x1000 / sizeof(unsigned int); ++i) + dst[i] = __builtin_bswap32(src[i]); + __asm__ volatile("isync; icbi 0,%0" : : "r" (be_test_code)); + map(be_test_code, be_test_code, DFLT_PERM); + + msr = MSR_SF | MSR_IR | MSR_DR; + ret = callit(1, (unsigned long)&bits, be_test_code, msr); + if (ret != __builtin_bswap64(bits)) + return ret? ret: 1; + return 0; +} + +int mode_test_3(void) +{ + unsigned long ret, msr; + unsigned long addr = (unsigned long) &bits; + unsigned long code = (unsigned long) &test_code; + + msr = MSR_IR | MSR_DR | MSR_LE; + ret = callit(1, addr, code, msr); + if (ret != bits) + return ret? ret: 1; + ret = callit(1, addr + 0x5555555500000000ul, + code + 0x9999999900000000ul, msr); + if (ret != bits) + return ret? ret: 2; + return 0; +} + +int mode_test_4(void) +{ + unsigned long ret, msr; + unsigned long addr = (unsigned long) &bits; + + msr = MSR_IR | MSR_DR; + ret = callit(1, addr, be_test_code, msr); + if (ret != __builtin_bswap64(bits)) + return ret? ret: 1; + ret = callit(1, addr + 0x5555555500000000ul, + be_test_code + 0x9999999900000000ul, msr); + if (ret != __builtin_bswap64(bits)) + return ret? ret: 2; + return 0; +} + +int mode_test_5(void) +{ + unsigned long ret, msr; + + /* + * Try branching from the page at fffff000 + * to the page at 0 in 32-bit mode. + */ + map(0xfffff000, (unsigned long) &test_code, DFLT_PERM); + map(0, (unsigned long) &test_code, DFLT_PERM); + msr = MSR_IR | MSR_DR | MSR_LE; + ret = callit(2, 0, 0xfffff000, msr); + return ret; +} + +int mode_test_6(void) +{ + unsigned long ret, msr; + + /* + * Try a bl from address fffffffc in 32-bit mode. + * We expect LR to be set to 100000000, though the + * arch says the value is undefined. + */ + msr = MSR_IR | MSR_DR | MSR_LE; + ret = callit(3, 0, 0xfffff000, msr); + if (ret != 0x100000000ul) + return 1; + return 0; +} + +int fail = 0; + +void do_test(int num, int (*test)(void)) +{ + int ret; + + print_test_number(num); + ret = test(); + if (ret == 0) { + print_string("PASS\r\n"); + } else { + fail = 1; + print_string("FAIL "); + print_hex(ret, 16); + if (ret != 0 && (ret & ~0xfe0ul) == 0) { + print_string(" SRR0="); + print_hex(mfspr(SPRG0), 16); + print_string(" SRR1="); + print_hex(mfspr(SPRG1), 16); + } + print_string("\r\n"); + } +} + +int main(void) +{ + unsigned long addr; + extern unsigned char __stack_top[]; + + console_init(); + init_mmu(); + + /* + * Map test code and stack 1-1 + */ + for (addr = 0; addr < (unsigned long)&__stack_top; addr += 0x1000) + map(addr, addr, DFLT_PERM); + + do_test(1, mode_test_1); + do_test(2, mode_test_2); + do_test(3, mode_test_3); + do_test(4, mode_test_4); + do_test(5, mode_test_5); + do_test(6, mode_test_6); + + return fail; +} diff --git a/tests/modes/powerpc.lds b/tests/modes/powerpc.lds new file mode 100644 index 0000000..99611ab --- /dev/null +++ b/tests/modes/powerpc.lds @@ -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 = .; +} diff --git a/tests/test_modes.bin b/tests/test_modes.bin new file mode 100755 index 0000000000000000000000000000000000000000..0c526280d1c1380597eec3e19573d3891b14a1b4 GIT binary patch literal 20512 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 literal 0 HcmV?d00001 diff --git a/tests/test_modes.console_out b/tests/test_modes.console_out new file mode 100644 index 0000000..a49bb9b --- /dev/null +++ b/tests/test_modes.console_out @@ -0,0 +1,6 @@ +test 01:PASS +test 02:PASS +test 03:PASS +test 04:PASS +test 05:PASS +test 06:PASS diff --git a/tests/update_console_tests b/tests/update_console_tests index 57ac0b0..2101c6b 100755 --- a/tests/update_console_tests +++ b/tests/update_console_tests @@ -3,7 +3,7 @@ # Script to update console related tests from source # -for i in sc illegal decrementer xics privileged mmu misc ; do +for i in sc illegal decrementer xics privileged mmu misc modes ; do cd $i make cd - From eee90a081516c3bbac9625e78be15652b79caa68 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 21 Aug 2020 12:16:27 +1000 Subject: [PATCH 5/6] loadstore1: Generate alignment interrupts for unaligned larx/stcx Load-and-reserve and store-conditional instructions are required to generate an alignment interrupt (0x600 vector) if their EA is not aligned. Implement this. Signed-off-by: Paul Mackerras --- common.vhdl | 1 + execute1.vhdl | 4 +++- loadstore1.vhdl | 18 +++++++++++++++--- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/common.vhdl b/common.vhdl index ec63323..03211ce 100644 --- a/common.vhdl +++ b/common.vhdl @@ -286,6 +286,7 @@ package common is type Loadstore1ToExecute1Type is record busy : std_ulogic; exception : std_ulogic; + alignment : std_ulogic; invalid : std_ulogic; perm_error : std_ulogic; rc_error : std_ulogic; diff --git a/execute1.vhdl b/execute1.vhdl index b9411c1..51ea5b0 100644 --- a/execute1.vhdl +++ b/execute1.vhdl @@ -1139,7 +1139,9 @@ begin -- generate DSI or DSegI for load/store exceptions -- or ISI or ISegI for instruction fetch exceptions if l_in.exception = '1' then - if l_in.instr_fault = '0' then + if l_in.alignment = '1' then + v.f.redirect_nia := std_logic_vector(to_unsigned(16#600#, 64)); + elsif l_in.instr_fault = '0' then if l_in.segment_fault = '0' then v.f.redirect_nia := std_logic_vector(to_unsigned(16#300#, 64)); else diff --git a/loadstore1.vhdl b/loadstore1.vhdl index 6eb6804..e36025c 100644 --- a/loadstore1.vhdl +++ b/loadstore1.vhdl @@ -78,6 +78,7 @@ architecture behave of loadstore1 is dar : std_ulogic_vector(63 downto 0); dsisr : std_ulogic_vector(31 downto 0); instr_fault : std_ulogic; + align_intr : std_ulogic; sprval : std_ulogic_vector(63 downto 0); busy : std_ulogic; wait_dcache : std_ulogic; @@ -171,6 +172,7 @@ begin variable dsisr : std_ulogic_vector(31 downto 0); variable mmu_mtspr : std_ulogic; variable itlb_fault : std_ulogic; + variable misaligned : std_ulogic; begin v := r; req := '0'; @@ -358,6 +360,7 @@ begin when TLBIE_WAIT => when COMPLETE => + exception := r.align_intr; end case; @@ -374,6 +377,7 @@ begin v.dcbz := '0'; v.tlbie := '0'; v.instr_fault := '0'; + v.align_intr := '0'; v.dwords_done := '0'; v.last_dword := '1'; v.write_reg := l_in.write_reg; @@ -411,6 +415,10 @@ begin v.first_bytes := byte_sel; v.second_bytes := long_sel(15 downto 8); + -- check alignment for larx/stcx + misaligned := or (std_ulogic_vector(unsigned(l_in.length(2 downto 0)) - 1) and addr(2 downto 0)); + v.align_intr := l_in.reserve and misaligned; + case l_in.op is when OP_STORE => req := '1'; @@ -420,6 +428,7 @@ begin -- Allow an extra cycle for RA update on loads v.extra_cycle := l_in.update; when OP_DCBZ => + v.align_intr := v.nc; req := '1'; v.dcbz := '1'; when OP_TLBIE => @@ -468,7 +477,9 @@ begin end case; if req = '1' then - if long_sel(15 downto 8) = "00000000" then + if v.align_intr = '1' then + v.state := COMPLETE; + elsif long_sel(15 downto 8) = "00000000" then v.state := ACK_WAIT; else v.state := SECOND_REQ; @@ -479,7 +490,7 @@ begin end if; -- Update outputs to dcache - d_out.valid <= req; + d_out.valid <= req and not v.align_intr; d_out.load <= v.load; d_out.dcbz <= v.dcbz; d_out.nc <= v.nc; @@ -526,6 +537,7 @@ begin -- update exception info back to execute1 e_out.busy <= busy; e_out.exception <= exception; + e_out.alignment <= r.align_intr; e_out.instr_fault <= r.instr_fault; e_out.invalid <= m_in.invalid; e_out.badtree <= m_in.badtree; @@ -534,7 +546,7 @@ begin e_out.segment_fault <= m_in.segerr; if exception = '1' and r.instr_fault = '0' then v.dar := addr; - if m_in.segerr = '0' then + if m_in.segerr = '0' and r.align_intr = '0' then v.dsisr := dsisr; end if; end if; From e7a08f33ebdec6c3825f60c0834734455301160e Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Sat, 22 Aug 2020 19:53:59 +1000 Subject: [PATCH 6/6] tests: Add a test for the load-reserve and store-conditional instructions This checks that the instructions seem to update memory as expected, and also that they generate alignment interrupts when necessary. We don't check whether the memory update is atomic as we don't have SMP yet. Signed-off-by: Paul Mackerras --- tests/reservation/Makefile | 3 + tests/reservation/head.S | 157 +++++++++++++++++++++ tests/reservation/powerpc.lds | 27 ++++ tests/reservation/reservation.c | 210 +++++++++++++++++++++++++++++ tests/test_reservation.bin | Bin 0 -> 10896 bytes tests/test_reservation.console_out | 2 + tests/update_console_tests | 2 +- 7 files changed, 400 insertions(+), 1 deletion(-) create mode 100644 tests/reservation/Makefile create mode 100644 tests/reservation/head.S create mode 100644 tests/reservation/powerpc.lds create mode 100644 tests/reservation/reservation.c create mode 100755 tests/test_reservation.bin create mode 100644 tests/test_reservation.console_out diff --git a/tests/reservation/Makefile b/tests/reservation/Makefile new file mode 100644 index 0000000..42aa52a --- /dev/null +++ b/tests/reservation/Makefile @@ -0,0 +1,3 @@ +TEST=reservation + +include ../Makefile.test diff --git a/tests/reservation/head.S b/tests/reservation/head.S new file mode 100644 index 0000000..ce258b5 --- /dev/null +++ b/tests/reservation/head.S @@ -0,0 +1,157 @@ +/* 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) + mtsprg2 %r0 + LOAD_IMM64(%r12, main) + mtctr %r12 + bctrl + attn // terminate on exit + b . + +exception: + mfsprg2 %r0 + cmpdi %r0,0 + bne call_ret + attn + +#define EXCEPTION(nr) \ + .= nr ;\ + li %r3,nr ;\ + b exception + + EXCEPTION(0x300) + EXCEPTION(0x380) + EXCEPTION(0x400) + EXCEPTION(0x480) + EXCEPTION(0x500) + EXCEPTION(0x600) + EXCEPTION(0x700) + EXCEPTION(0x800) + EXCEPTION(0x900) + EXCEPTION(0x980) + EXCEPTION(0xa00) + EXCEPTION(0xb00) + EXCEPTION(0xc00) + EXCEPTION(0xd00) + EXCEPTION(0xe00) + EXCEPTION(0xe20) + EXCEPTION(0xe40) + EXCEPTION(0xe60) + EXCEPTION(0xe80) + EXCEPTION(0xf00) + EXCEPTION(0xf20) + EXCEPTION(0xf40) + EXCEPTION(0xf60) + EXCEPTION(0xf80) + + . = 0x1000 + /* + * Call a function in a context with a given MSR value. + * r3, r4 = args; r5 = function + */ + .globl callit +callit: + mflr %r0 + std %r0,16(%r1) + stdu %r1,-256(%r1) + mfcr %r8 + stw %r8,100(%r1) + std %r13,104(%r1) + std %r14,112(%r1) + std %r15,120(%r1) + std %r16,128(%r1) + std %r17,136(%r1) + std %r18,144(%r1) + std %r19,152(%r1) + std %r20,160(%r1) + std %r21,168(%r1) + std %r22,176(%r1) + std %r23,184(%r1) + std %r24,192(%r1) + std %r25,200(%r1) + std %r26,208(%r1) + std %r27,216(%r1) + std %r28,224(%r1) + std %r29,232(%r1) + std %r30,240(%r1) + std %r31,248(%r1) + mtsprg0 %r0 + mtsprg1 %r1 + mtsprg2 %r2 + mtctr %r5 + mr %r12,%r5 + bctrl +call_ret: + mfsprg0 %r0 /* restore regs in case of trap */ + mfsprg1 %r1 + mfsprg2 %r2 + li %r7,0 + mtsprg2 %r7 + mtlr %r0 + lwz %r8,100(%r1) + mtcr %r8 + ld %r13,104(%r1) + ld %r14,112(%r1) + ld %r15,120(%r1) + ld %r16,128(%r1) + ld %r17,136(%r1) + ld %r18,144(%r1) + ld %r19,152(%r1) + ld %r20,160(%r1) + ld %r21,168(%r1) + ld %r22,176(%r1) + ld %r23,184(%r1) + ld %r24,192(%r1) + ld %r25,200(%r1) + ld %r26,208(%r1) + ld %r27,216(%r1) + ld %r28,224(%r1) + ld %r29,232(%r1) + ld %r30,240(%r1) + ld %r31,248(%r1) + addi %r1,%r1,256 + blr diff --git a/tests/reservation/powerpc.lds b/tests/reservation/powerpc.lds new file mode 100644 index 0000000..99611ab --- /dev/null +++ b/tests/reservation/powerpc.lds @@ -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 = .; +} diff --git a/tests/reservation/reservation.c b/tests/reservation/reservation.c new file mode 100644 index 0000000..280d76f --- /dev/null +++ b/tests/reservation/reservation.c @@ -0,0 +1,210 @@ +#include +#include +#include + +#include "console.h" + +extern unsigned long callit(unsigned long arg1, unsigned long arg2, + unsigned long (*fn)(unsigned long, unsigned long)); + +#define DSISR 18 +#define DAR 19 +#define SRR0 26 +#define SRR1 27 +#define PID 48 +#define SPRG0 272 +#define SPRG1 273 +#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 ndigits) +{ + int i, x; + + for (i = (ndigits - 1) * 4; 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 DO_LARX(instr, addr, val) __asm__ volatile(instr " %0,0,%1" : "=r" (val) : "r" (addr)) +#define DO_STCX(instr, addr, val, cc) __asm__ volatile(instr " %2,0,%1; mfcr %0" : "=r" (cc) \ + : "r" (addr), "r" (val) : "cr0", "memory"); + +int resv_test_1(void) +{ + unsigned long x, val, cc = 0; + int count; + + x = 1234; + for (count = 0; count < 1000; ++count) { + DO_LARX("ldarx", &x, val); + DO_STCX("stdcx.", &x, 5678, cc); + if (cc & 0x20000000) + break; + } + /* ldarx/stdcx. should succeed eventually */ + if (count == 1000) + return 1; + if (x != 5678) + return 2; + for (count = 0; count < 1000; ++count) { + DO_LARX("lwarx", &x, val); + DO_STCX("stwcx.", &x, 9876, cc); + if (cc & 0x20000000) + break; + } + /* lwarx/stwcx. should succeed eventually */ + if (count == 1000) + return 3; + if (x != 9876) + return 4; + for (count = 0; count < 1000; ++count) { + DO_LARX("lharx", &x, val); + DO_STCX("sthcx.", &x, 3210, cc); + if (cc & 0x20000000) + break; + } + /* lharx/sthcx. should succeed eventually */ + if (count == 1000) + return 5; + if (x != 3210) + return 6; + return 0; +} + +unsigned long do_larx(unsigned long size, unsigned long addr) +{ + unsigned long val; + + switch (size) { + case 1: + DO_LARX("lbarx", addr, val); + break; + case 2: + DO_LARX("lharx", addr, val); + break; + case 4: + DO_LARX("lwarx", addr, val); + break; + case 8: + DO_LARX("ldarx", addr, val); + break; + } + return 0; +} + +unsigned long do_stcx(unsigned long size, unsigned long addr) +{ + unsigned long val = 0, cc; + + switch (size) { + case 1: + DO_STCX("stbcx.", addr, val, cc); + break; + case 2: + DO_STCX("sthcx.", addr, val, cc); + break; + case 4: + DO_STCX("stwcx.", addr, val, cc); + break; + case 8: + DO_STCX("stdcx.", addr, val, cc); + break; + } + return 0; +} + +int resv_test_2(void) +{ + unsigned long x[3]; + unsigned long offset, j, size, ret; + + x[0] = 1234; + x[1] = x[2] = 0; + for (j = 0; j <= 3; ++j) { + size = 1 << j; + for (offset = 0; offset < 16; ++offset) { + ret = callit(size, (unsigned long)&x[0] + offset, do_larx); + if (0 && ret == 0 && (offset & (size - 1)) != 0) + return j + 1; + if (ret == 0x600) { + if ((offset & (size - 1)) == 0) + return j + 0x10; + } else if (ret) + return ret; + ret = callit(size, (unsigned long)&x[0] + offset, do_stcx); + if (ret == 0 && (offset & (size - 1)) != 0) + return j + 0x20; + if (ret == 0x600) { + if ((offset & (size - 1)) == 0) + return j + 0x30; + } else if (ret) + return ret; + } + } + return 0; +} + +int fail = 0; + +void do_test(int num, int (*test)(void)) +{ + int ret; + + print_test_number(num); + ret = test(); + if (ret == 0) { + print_string("PASS\r\n"); + } else { + fail = 1; + print_string("FAIL "); + print_hex(ret, 4); + print_string("\r\n"); + } +} + +int main(void) +{ + console_init(); + + do_test(1, resv_test_1); + do_test(2, resv_test_2); + + return fail; +} diff --git a/tests/test_reservation.bin b/tests/test_reservation.bin new file mode 100755 index 0000000000000000000000000000000000000000..31d3c8cac00d9ca0e705463d9c4175951796d156 GIT binary patch literal 10896 zcmeHNU2GKB6+W}O-W?ocwiSvjL6ccb=-S<+TPdn$v&PKWK#hTbAQe2c)ocus!KsAR zR9d&Q*|Ez5M3xE_56~t!sMU%_Q1Rf0R7xegR8gwFB$ZXAZ3=e7!~VFEAxX2|CAt01 z%q+XM%K9Nfe(;WTxp&Sv_nhzh?wwirGDO;TqW;7?f&LNn$0^#MATnSZf^7)4q2pF` zC~@%U$Q1T_F`S zy-blAdcVAT1Nh&q!yo>^I(`lQzB+yb{%{??1;1R! z|K$nR&yexRW{{+!Btpe)M5$vWogbtti>GLMF-dca7D=Tu6e^t~y>yWhr8j7_bd|1@ zZqRh;Et)G$kyL({Lgn{JFMmLZ@+^&(vvj4rK-1+S&6P8~K{M0)Ewn>s#`{|{`HgEP z|IMH2fxQRzoo)qJTT;eArB0BV8{bQ z9vBM1PymJkFcg5H01O3SC;&r&q>!o*&KVk4LxF|@4FwtsG!$qk&`_YEKtq9s0u2Qk z3N#d0qY7lbTI{brC6@8-Nj>v8#TG z3)`HzVa$EH2G2!zuGgJgyL>)s4{P{FVKa^D62@CG_P9M`=Cc49_n#ogRmC#rh1ffY z{to&q`VY~E(a)e?p7&@?-iVv`S@g^E;yZ@e^^gMnoV62kColZ&{h#bQO6+Mj zesWn|iL@@d(WCNN4X@RxpZbPzUL(Yo9YT0^;MgBG-$e52HnA zzn@lU;-`~=KctDK;zFc2CYJomQ|XQO&YH=>uhSZh7C-%u&DX#H*OSO;**U+5oZr6x=X7_V z6bQ`*EctT8?X*fiwDye#Gy_^dAZ1+S|TLlJ{x!iXVj%lQQC$?`{O zA6e?_7_%=5-&Cz0%hrMM%mGi%NUX0;+KAE*` zPZ(ymf8YftcV{l>#^$TB8pq05501|x{=F(slwKJJzek9c;!qyo=*-zT4j3-Kr5I!< zPV4rccmdyU*|GT}N~%VSB^dY}!t2lbZ|U=M`{zX6k)ZqhKr;0u?B`~BBFxX!dfe;a zmHhZ-I)=W6qhw)!B{!YKIj*7puB|i0+VXFL1Wgtmro|L(S4d8vjo7;FrW8#n+sQAF zfD`N;jvYF)7HzB%{Ms@fP4V|@WN-^w|5ou^g}MDBSm(vf{B0ZVe{on&`HGz*H#hW; zSjc1VS&MT z05Ra=-fYg1}?BJac2%;CoScWZ>~y?geXY-5~Jx~x0DZyNmV5!vR~ zpQz$>>jKLx)`I;W8Ze-#jVu3PUm;`lGG0FZqn8!jAJh*YUf)c#Ti>&f?|D2WaON*? z<}YyOFL35BaON*?=I_2s`B`Qzh$|qjfVcwU3WzK4vx->z{ek!bze_ll$Ly=TTi6yv zJ-(!$93o#*mo~LX#I`oHzR!f1VJ9xOK^T(pi+Gd`xY(wl?Sn0ep06%6JS21jHd(@8 z=Q^GAi}IzwFa5u2dd>H`_p)a~`ilOF-g-{@L31nVw{QLH!+-wc?;rT}#}K|1?E+eI zQ3(EFvFA@ny{%Eq*=fhyfnm7bM!SeOyY?>B;ncfoB5zf5W)XV_u_k(|#O}6Z585F7 zIw^1kfmtmH!5CEA2!EM-w*xKRstK z=L|b>RrKt`8{)KMBIcx_y#1xgpw literal 0 HcmV?d00001 diff --git a/tests/test_reservation.console_out b/tests/test_reservation.console_out new file mode 100644 index 0000000..0c39ae3 --- /dev/null +++ b/tests/test_reservation.console_out @@ -0,0 +1,2 @@ +test 01:PASS +test 02:PASS diff --git a/tests/update_console_tests b/tests/update_console_tests index 2101c6b..ffb30c7 100755 --- a/tests/update_console_tests +++ b/tests/update_console_tests @@ -3,7 +3,7 @@ # Script to update console related tests from source # -for i in sc illegal decrementer xics privileged mmu misc modes ; do +for i in sc illegal decrementer xics privileged mmu misc modes reservation ; do cd $i make cd -