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 + -
显示快捷键?