@ -47,7 +47,6 @@ architecture behave of loadstore1 is
);
type reg_stage_t is record
busy : std_ulogic;
-- latch most of the input request
load : std_ulogic;
tlbie : std_ulogic;
@ -126,7 +125,6 @@ begin
if rising_edge(clk) then
if rst = '1' then
r.state <= IDLE;
r.busy <= '0';
else
r <= rin;
end if;
@ -143,7 +141,7 @@ begin
variable long_sel : std_ulogic_vector(15 downto 0);
variable byte_sel : std_ulogic_vector(7 downto 0);
variable req : std_ulogic;
variable stall : std_ulogic;
variable busy : std_ulogic;
variable addr : std_ulogic_vector(63 downto 0);
variable wdata : std_ulogic_vector(63 downto 0);
variable write_enable : std_ulogic;
@ -165,15 +163,12 @@ begin
begin
v := r;
req := '0';
stall := '0';
done := '0';
byte_sel := (others => '0');
addr := lsu_sum;
v.mfspr := '0';
mmu_mtspr := '0';
itlb_fault := '0';
sprn := std_ulogic_vector(to_unsigned(decode_spr_num(l_in.insn), 10));
exception := '0';
dsisr := (others => '0');
mmureq := '0';
@ -232,130 +227,18 @@ begin
-- compute (addr + 8) & ~7 for the second doubleword when unaligned
next_addr := std_ulogic_vector(unsigned(r.addr(63 downto 3)) + 1) & "000";
done := '0';
exception := '0';
case r.state is
when IDLE =>
if l_in.valid = '1' then
v.addr := lsu_sum;
v.load := '0';
v.dcbz := '0';
v.tlbie := '0';
v.instr_fault := '0';
v.dwords_done := '0';
case l_in.op is
when OP_STORE =>
req := '1';
when OP_LOAD =>
req := '1';
v.load := '1';
when OP_DCBZ =>
req := '1';
v.dcbz := '1';
when OP_TLBIE =>
mmureq := '1';
stall := '1';
v.tlbie := '1';
v.state := TLBIE_WAIT;
when OP_MFSPR =>
v.mfspr := '1';
-- partial decode on SPR number should be adequate given
-- the restricted set that get sent down this path
if sprn(9) = '0' and sprn(5) = '0' then
if sprn(0) = '0' then
v.sprval := x"00000000" & r.dsisr;
else
v.sprval := r.dar;
end if;
else
-- reading one of the SPRs in the MMU
v.sprval := m_in.sprval;
end if;
v.state := SPR_CMPLT;
when OP_MTSPR =>
if sprn(9) = '0' and sprn(5) = '0' then
if sprn(0) = '0' then
v.dsisr := l_in.data(31 downto 0);
else
v.dar := l_in.data;
end if;
v.state := SPR_CMPLT;
else
-- writing one of the SPRs in the MMU
mmu_mtspr := '1';
stall := '1';
v.state := TLBIE_WAIT;
end if;
when OP_FETCH_FAILED =>
-- send it to the MMU to do the radix walk
addr := l_in.nia;
v.addr := l_in.nia;
v.instr_fault := '1';
mmureq := '1';
stall := '1';
v.state := MMU_LOOKUP;
when others =>
assert false report "unknown op sent to loadstore1";
end case;
v.write_reg := l_in.write_reg;
v.length := l_in.length;
v.byte_reverse := l_in.byte_reverse;
v.sign_extend := l_in.sign_extend;
v.update := l_in.update;
v.update_reg := l_in.update_reg;
v.xerc := l_in.xerc;
v.reserve := l_in.reserve;
v.rc := l_in.rc;
v.nc := l_in.ci;
v.virt_mode := l_in.virt_mode;
v.priv_mode := l_in.priv_mode;
-- XXX Temporary hack. Mark the op as non-cachable if the address
-- is the form 0xc------- for a real-mode access.
--
-- This will have to be replaced by a combination of implementing the
-- proper HV CI load/store instructions and having an MMU to get the I
-- bit otherwise.
if lsu_sum(31 downto 28) = "1100" and l_in.virt_mode = '0' then
v.nc := '1';
end if;
-- Do length_to_sel and work out if we are doing 2 dwords
long_sel := xfer_data_sel(l_in.length, v.addr(2 downto 0));
byte_sel := long_sel(7 downto 0);
v.first_bytes := byte_sel;
v.second_bytes := long_sel(15 downto 8);
-- Do byte reversing and rotating for stores in the first cycle
byte_offset := unsigned(lsu_sum(2 downto 0));
brev_lenm1 := "000";
if l_in.byte_reverse = '1' then
brev_lenm1 := unsigned(l_in.length(2 downto 0)) - 1;
end if;
for i in 0 to 7 loop
k := (to_unsigned(i, 3) xor brev_lenm1) + byte_offset;
j := to_integer(k) * 8;
v.store_data(j + 7 downto j) := l_in.data(i * 8 + 7 downto i * 8);
end loop;
if req = '1' then
stall := '1';
if long_sel(15 downto 8) = "00000000" then
v.state := ACK_WAIT;
else
v.state := SECOND_REQ;
end if;
end if;
end if;
when SECOND_REQ =>
addr := next_addr;
byte_sel := r.second_bytes;
req := '1';
stall := '1';
v.state := ACK_WAIT;
when ACK_WAIT =>
stall := '1';
if d_in.valid = '1' then
if d_in.error = '1' then
-- dcache will discard the second request if it
@ -393,7 +276,6 @@ begin
else
-- stores write back rA update in this cycle
do_update := r.update;
stall := '0';
done := '1';
v.state := IDLE;
end if;
@ -402,7 +284,6 @@ begin
end if;
when MMU_LOOKUP =>
stall := '1';
if r.dwords_done = '1' then
addr := next_addr;
byte_sel := r.second_bytes;
@ -423,7 +304,6 @@ begin
end if;
else
-- nothing to do, the icache retries automatically
stall := '0';
done := '1';
v.state := IDLE;
end if;
@ -439,10 +319,8 @@ begin
end if;
when TLBIE_WAIT =>
stall := '1';
if m_in.done = '1' then
-- tlbie is finished
stall := '0';
done := '1';
v.state := IDLE;
end if;
@ -458,6 +336,117 @@ begin
end case;
busy := '1';
if r.state = IDLE or done = '1' then
busy := '0';
end if;
-- Note that l_in.valid is gated with busy inside execute1
if l_in.valid = '1' then
v.addr := lsu_sum;
v.load := '0';
v.dcbz := '0';
v.tlbie := '0';
v.instr_fault := '0';
v.dwords_done := '0';
v.write_reg := l_in.write_reg;
v.length := l_in.length;
v.byte_reverse := l_in.byte_reverse;
v.sign_extend := l_in.sign_extend;
v.update := l_in.update;
v.update_reg := l_in.update_reg;
v.xerc := l_in.xerc;
v.reserve := l_in.reserve;
v.rc := l_in.rc;
v.nc := l_in.ci;
v.virt_mode := l_in.virt_mode;
v.priv_mode := l_in.priv_mode;
-- XXX Temporary hack. Mark the op as non-cachable if the address
-- is the form 0xc------- for a real-mode access.
if lsu_sum(31 downto 28) = "1100" and l_in.virt_mode = '0' then
v.nc := '1';
end if;
-- Do length_to_sel and work out if we are doing 2 dwords
long_sel := xfer_data_sel(l_in.length, v.addr(2 downto 0));
byte_sel := long_sel(7 downto 0);
v.first_bytes := byte_sel;
v.second_bytes := long_sel(15 downto 8);
-- Do byte reversing and rotating for stores in the first cycle
byte_offset := unsigned(lsu_sum(2 downto 0));
brev_lenm1 := "000";
if l_in.byte_reverse = '1' then
brev_lenm1 := unsigned(l_in.length(2 downto 0)) - 1;
end if;
for i in 0 to 7 loop
k := (to_unsigned(i, 3) xor brev_lenm1) + byte_offset;
j := to_integer(k) * 8;
v.store_data(j + 7 downto j) := l_in.data(i * 8 + 7 downto i * 8);
end loop;
case l_in.op is
when OP_STORE =>
req := '1';
when OP_LOAD =>
req := '1';
v.load := '1';
when OP_DCBZ =>
req := '1';
v.dcbz := '1';
when OP_TLBIE =>
mmureq := '1';
v.tlbie := '1';
v.state := TLBIE_WAIT;
when OP_MFSPR =>
v.mfspr := '1';
-- partial decode on SPR number should be adequate given
-- the restricted set that get sent down this path
if sprn(9) = '0' and sprn(5) = '0' then
if sprn(0) = '0' then
v.sprval := x"00000000" & r.dsisr;
else
v.sprval := r.dar;
end if;
else
-- reading one of the SPRs in the MMU
v.sprval := m_in.sprval;
end if;
v.state := SPR_CMPLT;
when OP_MTSPR =>
if sprn(9) = '0' and sprn(5) = '0' then
if sprn(0) = '0' then
v.dsisr := l_in.data(31 downto 0);
else
v.dar := l_in.data;
end if;
v.state := SPR_CMPLT;
else
-- writing one of the SPRs in the MMU
mmu_mtspr := '1';
v.state := TLBIE_WAIT;
end if;
when OP_FETCH_FAILED =>
-- send it to the MMU to do the radix walk
addr := l_in.nia;
v.addr := l_in.nia;
v.instr_fault := '1';
mmureq := '1';
v.state := MMU_LOOKUP;
when others =>
assert false report "unknown op sent to loadstore1";
end case;
if req = '1' then
if long_sel(15 downto 8) = "00000000" then
v.state := ACK_WAIT;
else
v.state := SECOND_REQ;
end if;
end if;
end if;
-- Update outputs to dcache
d_out.valid <= req;
d_out.load <= v.load;
@ -504,7 +493,7 @@ begin
l_out.store_done <= d_in.store_done;
-- update exception info back to execute1
e_out.busy <= r.busy;
e_out.busy <= busy;
e_out.exception <= exception;
e_out.instr_fault <= r.instr_fault;
e_out.invalid <= m_in.invalid;
@ -519,8 +508,6 @@ begin
end if;
end if;
v.busy := stall;
-- Update registers
rin <= v;
@ -529,7 +516,7 @@ begin
ls1_log: process(clk)
begin
if rising_edge(clk) then
log_data <= r.busy &
log_data <= e_out.busy &
e_out.exception &
l_out.valid &
m_out.valid &