iu.vhd
来自「sparc org, vhdl rtl code」· VHDL 代码 · 共 1,813 行 · 第 1/5 页
VHD
1,813 行
ctrl.annul := ctrl.annul or wr.annul_all;
read := not op3(2);
dcache_write := '0'; enaddr := '0'; wpi := 0;
ld_size := LDWORD; signed := '0'; addr_misal := '0'; lock := '0';
write_reg := ex.write_reg;
write_icc := ex.write_icc;
write_y := ex.write_y;
fpmein.fpop := fpu_reg.ex.fpop;
fpmein.dsz := fpu_reg.ex.dsz;
fpmein.ldfsr := fpu_reg.ex.ldfsr;
fpmein.cexc := fpuo.excep(4 downto 0);
fpmein.fcc := fpuo.ConditionCodes;
muli.mac <= op3(5);
dsu_cache := '0';
-- load/store size decoding
case op is
when LDST =>
case op3 is
when LDUB | LDUBA => ld_size := LDBYTE;
when LDSTUB | LDSTUBA => ld_size := LDBYTE; lock := '1';
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 | LDF | LDC => ld_size := LDWORD;
when SWAP | SWAPA => ld_size := LDWORD; lock := '1';
when LDD | LDDA | LDDF | LDDC => ld_size := LDDBL;
when STB | STBA => ld_size := LDBYTE;
when STH | STHA => ld_size := LDHALF;
when ST | STA | STF => ld_size := LDWORD;
when ISTD | STDA => ld_size := LDDBL;
when STDF | STDFQ => if FPEN then ld_size := LDDBL; end if;
when STDC | STDCQ => if CPEN then ld_size := LDDBL; end if;
when others => null;
end case;
when others => null;
end case;
link_pc := '0'; jump:= '0'; inull :='0'; force_a2 := '0';
-- load/store control decoding
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 := me.ctrl.annul or not me.jmpl_rett;
when RETT =>
jump := '1'; inull := me.ctrl.annul or not me.jmpl_rett;
when others => null;
end case;
when LDST =>
if (ctrl.trap or (wrin.ctrl.trap and not wrin.ctrl.annul)) = '0' then
case ex.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/STD
dcache_write := '1';
end if;
if op3(3 downto 2) = "11" then -- 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;
-- supervisor bit generation
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') and ((op3(5) = '0') or not CPEN) 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;
-- bypassed operands to multiplier
muli.signed <= op3(0); divi.signed <= op3(0);
mulop1 := (aluin1(31) and op3(0)) & aluin1;
mulop2 := (aluin2(31) and op3(0)) & aluin2;
if (ex.mulinsn = '0') and not INFER_MULT then -- try to minimise power
mulop1 := (others => '0'); mulop2 := (others => '0');
end if;
muli.op1 <= mulop1; muli.op2 <= mulop2;
divi.op1 <= (aluin1(31) and op3(0)) & aluin1;
divi.op2 <= (aluin2(31) and op3(0)) & aluin2;
-- ALU add/sub
icc := "0000";
-- pragma translate_off
if not (is_x(aluin1) or is_x(aluin2)) then
-- pragma translate_on
cin := ex.alu_cin; addin2 := aluin2;
if ex.aluadd = '0' then
addin2 := not aluin2; cin := not cin;
end if;
-- addout := aluin1 + addin2 + cin;
if FASTADD then addout := sum32;
else
if ex.aluadd = '0' then addout := aluin1 - aluin2 - ex.alu_cin;
else addout := aluin1 + aluin2 + ex.alu_cin; end if;
end if;
-- pragma translate_off
end if;
-- pragma translate_on
add32in1 <= aluin1;
add32in2 <= addin2;
add32cin <= cin;
-- 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 ALU_DIV =>
if DIVIDER /= none then logicout := aluin2;
else logicout := (others => '-'); end if;
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
-- select Y
if (me.write_y and not (me.ctrl.annul or me.ctrl.trap)) = '1'
then y := me.my; else y := wr.y; end if;
-- alu ops which dont set icc
miscout := (others => '-'); edata := (others => '-');
case ex.aluop is
when ALU_STB => edata := aluin1(7 downto 0) & aluin1(7 downto 0) &
aluin1(7 downto 0) & aluin1(7 downto 0);
miscout := edata;
when ALU_STH => edata := aluin1(15 downto 0) & aluin1(15 downto 0);
miscout := edata;
when ALU_PASS1 => miscout := aluin1; edata := aluin1;
when ALU_PASS2 => miscout := aluin2;
when ALU_ONES => miscout := (others => '1'); edata := (others => '1');
when ALU_RDY =>
miscout := y;
if (WATCHPOINTS > 0) and (rs1(4 downto 3) = "11") then
wpi := conv_integer(unsigned(rs1(2 downto 1)));
if rs1(0) = '0' then miscout := tr(wpi).addr & '0' & tr(wpi).exec;
else miscout := tr(wpi).mask & tr(wpi).load & tr(wpi).store; end if;
end if;
when ALU_FSR =>
if ((FPIFTYPE = serial) and FPEN) then
edata := fpu_reg.fsr.rd & "00" & fpu_reg.fsr.tem & "000" &
std_logic_vector(FPUVER) & fpu_reg.fsr.ftt & "00" & fpu_reg.fsr.fcc &
fpu_reg.fsr.aexc & fpu_reg.fsr.cexc;
miscout := edata;
end if;
when ALU_FOP =>
if ((FPIFTYPE = serial) and FPEN) then
miscout := aluin2;
case opf(3 downto 2) is
when "01" => miscout(31) := not miscout(31);
when "10" => miscout(31) := '0';
when others => null;
end case;
end if;
when others => null;
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.icc <= icc;
-- FPU interface
if ((FPIFTYPE = serial) and FPEN) then
-- pragma translate_off
if is_x(aluin1) then aluin1 := (others => '0'); end if;
if is_x(aluin2) then aluin2 := (others => '0'); end if;
if is_x(de.inst(19) & de.inst(13 downto 5)) then
fpui.FpInst <= (others => '0');
else
-- pragma translate_on
fpui.FpInst <= de.inst(19) & de.inst(13 downto 5);
-- pragma translate_off
end if;
if is_x(fpu_reg.fsr.rd) then fpui.RoundingMode <= (others => '0');
else
-- pragma translate_on
fpui.RoundingMode <= fpu_reg.fsr.rd;
-- pragma translate_off
end if;
-- pragma translate_on
if (ex.ctrl.cnt = "00") or (opf(1) = '0') then
fpui.fprf_dout1 <= aluin1 & aluin1;
fpui.fprf_dout2 <= aluin2 & aluin2;
else
fpui.fprf_dout1 <= fpu_reg.op1h & aluin1;
fpui.fprf_dout2 <= me.result & aluin2;
end if;
fpu_regin.op1h <= aluin1;
if fpu_reg.ex.fpop = "01" and (ex.write_reg = '1') then
if fpu_reg.ex.dsz = '1' then
if (ex.ctrl.cnt /= "00") then
aluresult := fpuo.FracResult(34 downto 3);
end if;
else
aluresult := fpuo.SignResult & fpuo.ExpResult(7 downto 0) &
fpuo.FracResult(54 downto 32);
end if;
end if;
fpu_regin.me <= fpmein;
end if;
if (MULTIPLIER = m32x32) and (ex.mulinsn = '1') then
aluresult := mulo.result(31 downto 0);
end if;
if MACEN then
if ex.aluop = ALU_RDY then
if rs1 = "10010" then
if ((me.mul
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?