📄 iu.vhd
字号:
end if;
when "01" =>
if (op3(2 downto 0) = "111") or --STD/SWAP
(op3(3 downto 0) = "1101") then -- LDST
cnt := "10"; pv := '0'; hold_pc := '1';
else
cnt := "00";
end if;
when "10" =>
cnt := "00";
when others => null;
end case;
when others => null;
end case;
end if;
-- prioritise traps
ctrl.trap := de.mexc or privileged_inst or illegal_inst or fp_disabled or
cp_disabled or fp_exception or ticc_exception or winunf_exception or
winovf_exception;
if de.mexc = '1' then ctrl.tt := IAEX_TT;
elsif privileged_inst = '1' then ctrl.tt := PRIV_TT;
elsif illegal_inst = '1' then ctrl.tt := IINST_TT;
elsif fp_disabled = '1' then ctrl.tt := FPDIS_TT;
elsif cp_disabled = '1' then ctrl.tt := CPDIS_TT;
elsif winovf_exception = '1' then ctrl.tt := WINOF_TT;
elsif winunf_exception = '1' then ctrl.tt := WINUF_TT;
elsif fp_exception = '1' then ctrl.tt := FPEXC_TT;
elsif ticc_exception = '1' then ctrl.tt := TICC_TT;
end if;
hold_pc := (hold_pc or ldlock) and not wr.annul_all;
if hold_pc = '1' then
dein.pc <= de.pc;
else
dein.pc <= fe.pc;
end if;
annul_current := annul_current or ldlock or wr.annul_all;
ctrl.annul := de.annul or wr.annul_all or annul_current;
annul_next := (mein.inull and not hold_pc) or annul_next or wr.annul_all;
if annul_next = '1' then
cnt := (others => '0'); mulcnt := (others => '0');
end if;
fecomb.hold_pc <= hold_pc;
fecomb.branch <= branch;
dein.annul <= annul_next;
dein.cnt <= cnt;
dein.mulcnt <= mulcnt;
dein.pv <= pv;
inull := inull or mein.inull or hold_pc or wr.annul_all;
ici.nullify <= inull;
ici.su <= su;
exin.ctrl <= ctrl;
exin.write_reg <= write_reg;
-- latch next cwp
if (write_cwp and not ctrl.annul) = '1' then
dein.cwp <= cwp_new;
elsif (ex.write_cwp and not ex.ctrl.annul) = '1' then
dein.cwp <= ex.cwp;
elsif (me.write_cwp and not me.ctrl.annul) = '1' then
dein.cwp <= me.cwp;
elsif (wr.write_cwp and not wr.ctrl.annul) = '1' then
dein.cwp <= wr.cwp;
else
dein.cwp <= sregs.cwp;
end if;
-- y-register write select and forwarding
rst_mey := '0';
case op is
when FMT3 =>
case op3 is
when MULSCC | WRY =>
write_y := '1';
when UMUL | SMUL | UMULCC | SMULCC =>
if MULTIPLIER = iterative then
if de.cnt = "00" then rst_mey := '1'; end if;
if de.cnt = "11" then write_y := '1'; end if;
end if;
when others => null;
end case;
when others => null;
end case;
exin.write_y <= write_y;
exin.rst_mey <= rst_mey;
end process;
-------------------------------------------------------------------------------
-- execute stage
-------------------------------------------------------------------------------
execute_stage : process(ex, me, wr, wrin, sregs)
variable op : std_logic_vector(1 downto 0);
variable op3 : std_logic_vector(5 downto 0);
variable inull, jump, link_pc : std_logic;
variable dcache_write : std_logic; -- Load or store cycle
variable memory_load : std_logic;
variable signed : std_logic;
variable enaddr : std_logic;
variable force_a2 : std_logic; -- force A(2) in second LDD cycle
variable addr_misal : std_logic; -- misaligned address (JMPL/RETT)
variable ld_size : std_logic_vector(1 downto 0); -- Load size
variable read : std_logic;
variable su : std_logic; -- Local supervisor bit
variable asi : std_logic_vector(7 downto 0); -- Local ASI
variable ctrl : pipeline_control_type;
variable res, y : std_logic_vector(31 downto 0);
variable icc, licc, micc : std_logic_vector(3 downto 0);
variable addout : std_logic_vector(31 downto 0);
variable shiftout : std_logic_vector(31 downto 0);
variable logicout : std_logic_vector(31 downto 0);
variable miscout : std_logic_vector(31 downto 0);
variable aluresult : std_logic_vector(31 downto 0);
variable nexty : std_logic_vector(31 downto 0);
variable aluin1, aluin2 : std_logic_vector(31 downto 0);
variable shiftin : std_logic_vector(63 downto 0);
variable shiftcnt : std_logic_vector(4 downto 0);
variable ymsb : std_logic; -- next msb of Y during MUL
begin
op := ex.ctrl.inst(31 downto 30);
op3 := ex.ctrl.inst(24 downto 19);
ctrl := ex.ctrl; memory_load := '0';
ctrl.annul := ctrl.annul or wr.annul_all;
read := not op3(2);
dcache_write := '0'; enaddr := '0';
ld_size := LDWORD; signed := '0'; addr_misal := '0';
case op is
when LDST =>
case op3 is
when LDUB | LDUBA | LDSTUB | LDSTUBA => ld_size := LDBYTE;
when LDUH | LDUHA => ld_size := LDHALF;
when LDSB | LDSBA => ld_size := LDBYTE; signed := '1';
when LDSH | LDSHA => ld_size := LDHALF; signed := '1';
when LD | LDA => ld_size := LDWORD;
when SWAP | SWAPA => ld_size := LDWORD;
when LDD | LDDA => ld_size := LDDBL;
when STB | STBA => ld_size := LDBYTE;
when STH | STHA => ld_size := LDHALF;
when ST | STA => ld_size := LDWORD;
when ISTD | STDA => ld_size := LDDBL;
when others => null;
end case;
when others => null;
end case;
link_pc := '0'; jump:= '0'; inull :='0'; force_a2 := '0';
if (ctrl.annul = '0') then
case op is
when CALL =>
link_pc := '1';
when FMT3 =>
case op3 is
when JMPL =>
jump := '1'; link_pc := '1'; inull := '1';
when RETT =>
jump := '1';
when others => null;
end case;
when LDST =>
if (ctrl.trap or (wrin.ctrl.trap and not wrin.ctrl.annul)) = '0' then
case ctrl.cnt is
when "00" =>
memory_load := op3(3) or not op3(2); -- LD/LDST/SWAP
read := memory_load; enaddr := '1';
when "01" =>
memory_load := not op3(2); -- LDD
enaddr := memory_load; force_a2 := memory_load;
if op3(3 downto 2) = "01" then -- ST
dcache_write := '1';
end if;
if op3(3 downto 2) = "11" then -- STD/LDST/SWAP
enaddr := '1';
end if;
when "10" => -- STD/LDST/SWAP
dcache_write := '1';
when others => null;
end case;
end if;
when others => null;
end case;
end if;
if ((wr.ctrl.rett and not wr.ctrl.annul) = '1') then
su := sregs.ps;
else
su := sregs.s;
end if;
if su = '1' then asi := "00001011"; else asi := "00001010"; end if;
if op3(4) = '1' then asi := ex.ctrl.inst(12 downto 5); end if;
-- load data bypass in case (LDDELAY = 1)
aluin1 := ex.rs1data;
aluin2 := ex.rs2data;
ymsb := ex.ymsb;
if LDDELAY = 1 then
if ex.ldbp1 = '1' then
aluin1 := wr.result;
ymsb := wr.result(0);
end if;
if ex.ldbp2 = '1' then
aluin2 := wr.result;
end if;
end if;
-- ALU add/sub
icc := "0000";
-- pragma translate_off
if not (is_x(aluin1) or is_x(aluin2)) then
-- pragma translate_on
-- if ido.dp.aluadd = '0' then
-- aluin2 := not aluin2; cin := not cin;
-- end if;
-- addout := aluin1 + aluin2 + cin;
if ex.aluadd = '0' then
addout := aluin1 - aluin2 - ex.alu_cin;
else
addout := aluin1 + aluin2 + ex.alu_cin;
end if;
-- pragma translate_off
end if;
-- pragma translate_on
addout(2) := addout(2) or force_a2;
-- fast address adders if enabled
if FASTJUMP then
-- pragma translate_off
if not (is_x(aluin1) or is_x(aluin2)) then
-- pragma translate_on
fecomb.jump_address <= aluin1(31 downto PCLOW) + aluin2(31 downto PCLOW);
if (aluin1(1 downto 0) + aluin2(1 downto 0)) = "00" then
addr_misal := '0';
else
addr_misal := '1';
end if;
-- pragma translate_off
else
fecomb.jump_address <= (others => 'X');
end if;
-- pragma translate_on
else
fecomb.jump_address(31 downto PCLOW) <= addout(31 downto PCLOW);
if addout(1 downto 0) = "00" then
addr_misal := '0';
else
addr_misal := '1';
end if;
end if;
res := (others => '-');
-- alu ops which set icc
case ex.aluop is
when ALU_OR => logicout := aluin1 or aluin2;
when ALU_ORN => logicout := aluin1 or not aluin2;
when ALU_AND => logicout := aluin1 and aluin2;
when ALU_ANDN => logicout := aluin1 and not aluin2;
when ALU_XOR => logicout := aluin1 xor aluin2;
when ALU_XNOR => logicout := aluin1 xor not aluin2;
when others => logicout := (others => '-');
end case;
-- generate condition codes
if (ex.alusel(1) = '0') then
res := addout;
if ex.aluadd = '0' then
icc(0) := ((not aluin1(31)) and aluin2(31)) or -- Carry
(addout(31) and ((not aluin1(31)) or aluin2(31)));
icc(1) := (aluin1(31) and (not aluin2(31)) and not addout(31)) or -- Overflow
(addout(31) and (not aluin1(31)) and aluin2(31));
else
icc(0) := (aluin1(31) and aluin2(31)) or -- Carry
((not addout(31)) and (aluin1(31) or aluin2(31)));
icc(1) := (aluin1(31) and aluin2(31) and not addout(31)) or -- Overflow
(addout(31) and (not aluin1(31)) and (not aluin2(31)));
end if;
else
res := logicout;
icc(1 downto 0) := "00";
end if;
if res = zero32 then -- Zero
icc(2) := '1';
else
icc(2) := '0';
end if;
icc(3) := res(31); -- Negative
-- alu ops which don't set icc
case ex.aluop is
when ALU_STB => miscout := aluin1(7 downto 0) & aluin1(7 downto 0) &
aluin1(7 downto 0) & aluin1(7 downto 0);
when ALU_STH => miscout := aluin1(15 downto 0) & aluin1(15 downto 0);
when ALU_PASS1 => miscout := aluin1;
when ALU_PASS2 => miscout := aluin2;
when ALU_ONES => miscout := (others => '1');
when ALU_RDY => miscout := me.y;
when others => miscout := (others => '-');
end case;
-- shifter
shiftin := zero32 & aluin1;
shiftcnt := aluin2(4 downto 0);
if ex.aluop = ALU_SLL then
shiftin(31 downto 0) := zero32;
shiftin(63 downto 31) := '0' & aluin1;
shiftcnt := not shiftcnt;
elsif ex.aluop = ALU_SRA then
if aluin1(31) = '1' then
shiftin(63 downto 32) := (others => '1');
else
shiftin(63 downto 32) := zero32;
end if;
end if;
if shiftcnt (4) = '1' then
shiftin(47 downto 0) := shiftin(63 downto 16);
end if;
if shiftcnt (3) = '1' then
shiftin(39 downto 0) := shiftin(47 downto 8);
end if;
if shiftcnt (2) = '1' then
shiftin(35 downto 0) := shiftin(39 downto 4);
end if;
if shiftcnt (1) = '1' then
shiftin(33 downto 0) := shiftin(35 downto 2);
end if;
if shiftcnt (0) = '1' then
shiftin(31 downto 0) := shiftin(32 downto 1);
end if;
shiftout := shiftin(31 downto 0);
-- generate overflow for tagged add/sub
case op is
when FMT3 =>
case op3 is
when TADDCC | TADDCCTV | TSUBCC | TSUBCCTV =>
icc(1) := aluin1(0) or aluin1(1) or aluin2(0) or aluin2(1) or icc(1);
when others => null;
end case;
when others => null;
end case;
-- select alu output
aluresult := (others => '0');
if link_pc = '1' then
aluresult := ex.ctrl.pc(31 downto 2) & "00"; -- save PC during jmpl
else
case ex.alusel is
when ALU_RES_ADD => aluresult := addout;
when ALU_RES_SHIFT => aluresult := shiftout;
when ALU_RES_LOGIC => aluresult := logicout;
when others => aluresult := miscout;
end case;
end if;
ex.result <= aluresult;
ex.icc <= icc;
-- select Y
if (me.write_y and not me.ctrl.annul) = '1' then y := me.y;
else y := wr.y; end if;
-- generate Y
micc := icc;
licc := icc;
nexty := y;
if ex.mulstep = '1' then
nexty := ymsb & me.y(31 downto 1);
elsif ex.mulinsn = '1' then
if MULTIPLIER = iterative then
case ex.ctrl.cnt is
when "00" =>
nexty := y;
when "01" =>
nexty := ymsb & me.y(31 downto 1);
when "10" =>
aluresult := ymsb & me.y(31 downto 1);
licc(3) := ymsb; licc(1 downto 0) := "00";
if aluresult = zero32 then licc(2) := '1'; else licc(2) := '0'; end if;
nexty := me.y;
when others => null;
end case;
end if;
elsif (ex.rst_mey or ex.write_y) = '1' then
if ex.ctrl.cnt = "11" then
nexty := addout;
else
nexty := logicout;
end if;
end if;
micc(3) := icc(3) and not ex.rst_mey;
micc(1) := icc(1) and not ex.rst_mey;
if ex.alusel = ALU_RES_ADD then
dci.eaddress <= addout;
else
dci.eaddress <= miscout;
end if;
mein.y <= nexty;
mein.result <= aluresult;
dciin.enaddr <= enaddr;
dciin.read <= read;
dciin.write <= dcache_write;
dciin.asi <= asi;
dciin.lock <= '0';
fecomb.jump <= jump;
ex.micc <= micc;
mein.inull <= inull;
mein.icc <= licc;
mein.memory_load <= memory_load;
mein.ld_size <= ld_size;
mein.signed <= signed;
mein.addr_misal <= addr_misal;
mein.ctrl <= ctrl;
end process;
-------------------------------------------------------------------------------
-- memory stage
-------------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -