iu.vhd

来自「sparc org, vhdl rtl code」· VHDL 代码 · 共 1,813 行 · 第 1/5 页

VHD
1,813
字号
  variable hold_pc : std_logic;		-- Hold PC during multi-cycle ops
  variable pv : std_logic;		-- PC valid
  variable ldlock, ldcheck1, ldcheck2, ldcheck3 : std_logic; -- load interlock
  variable ldchkex, ldchkme : std_logic;  	-- load interlock for ex and me
  variable illegal_inst : std_logic;  	-- illegal instruction
  variable privileged_inst : std_logic;  	-- privileged instruction trap
  variable cp_disabled  : std_logic;  	-- CP disable trap
  variable fp_disabled  : std_logic;  	-- FP disable trap
  variable watchpoint_exc  : std_logic;  	-- watchpoint trap
  variable winovf_exception : std_logic;  	-- window overflow trap
  variable winunf_exception : std_logic;  	-- window underflow trap
  variable ticc_exception : std_logic;  	-- TICC trap
  variable fp_exception : std_logic;  	-- STDFQ trap 
  variable ctrl : pipeline_control_type;
  variable ldbp1, ldbp2 : std_logic;		-- load bypass enable
  variable mulcnt  : std_logic_vector(4 downto 0);   -- multiply cycle number
  variable ymsb : std_logic;		-- next msb of Y during MUL
  variable rst_mey : std_logic;		-- reset me stage Y register
  variable fpld, fpst, fpop : std_logic;	-- FPU instructions
  variable fpmov  : std_logic;		-- FPU instructions
  variable fbres, fbranch_true : std_logic;	-- FBCC branch result
  variable cbres, cbranch_true : std_logic;	-- CBCC branch result
  variable fcc : std_logic_vector(1 downto 0);   -- FPU condition codes
  variable ccc : std_logic_vector(1 downto 0);   -- CP condition codes
  variable cwpmax : std_logic_vector(4 downto 0); 
  variable bicc_hold, icc_check : std_logic;
  variable fsr_ld, fsr_ld_check, fsr_check, fsr_lock : std_logic;
  variable fpexin : fpu_ctrl1_type;
  variable rs1mod : std_logic;
  variable step : std_logic;
  variable divstart,mulstart : std_logic;	-- start multiply or divide
  variable cpldlock, fpldlock, annul_current_cp : std_logic;
  constant RDOPT : boolean := FASTDECODE;-- optimise dest reg address generation
  constant RS1OPT : boolean := FASTDECODE;-- optimise src1 reg address generation

  function regdec(cwp, regin : std_logic_vector; fp : std_logic) 
  	return std_logic_vector is
  variable reg : std_logic_vector(4 downto 0);
  variable ra : std_logic_vector(RABITS -1 downto 0);
  begin
    reg := regin; ra(4 downto 0) := reg;
    if (FPIFTYPE = serial) and (fp = '1') then
      ra(RABITS -1 downto 5) := F0ADDR(RABITS-5 downto 1);
    elsif reg(4 downto 3) = "00" then ra(RABITS -1 downto 4) := R0ADDR;
    else
-- pragma translate_off
      if not (is_x(cwp & ra(4))) then
-- pragma translate_on
        ra(NWINLOG2+3 downto 4) := (cwp + ra(4));
	if CWPOPT then ra(RABITS-1) := '0';
	elsif ra(RABITS-1 downto 4) = R0ADDR then
	  ra(RABITS-1 downto 4) := (others => '0');
	end if;
-- pragma translate_off
      end if;
-- pragma translate_on
    end if;
    return(ra);
  end;

begin

-- instruction bit-field decoding

    op    := de.inst(31 downto 30);
    op2   := de.inst(24 downto 22);
    op3   := de.inst(24 downto 19);
    opf   := de.inst(13 downto 5);
    cond  := de.inst(28 downto 25);
    annul := de.inst(29);
    rs1   := de.inst(18 downto 14);
    rs2   := de.inst(4 downto 0);
    rd    := de.inst(29 downto 25);
    i     := de.inst(13);

-- common initialisation

    ctrl.annul := de.annul; ctrl.cnt := de.cnt; ctrl.pv := de.pv; pv := '1';
    cnt := "00"; ctrl.tt := "000000"; ctrl.ld := '0'; ctrl.rett := '0';
    ctrl.pc := de.pc; ctrl.inst := de.inst; mulcnt := de.mulcnt;
    write_y := '0'; fpld := '0'; fpst := '0'; fpop := '0';
    fp_exception := '0'; fpmov := '0'; step := '0';
    fpexin.fpop := "00"; fpexin.dsz := '0'; fpexin.ldfsr := '0';

    winovf_exception := '0'; winunf_exception := '0';
    write_cwp := '0'; cwp_new := de.cwp; rs1mod := '0';
    rfenable1 := '0'; rfenable2 := '0'; 

-- detect RETT instruction in the pipeline and set the local psr.su and psr.et

    if ((ex.ctrl.rett and not ex.ctrl.annul) or (me.ctrl.rett and not me.ctrl.annul) or 
        (wr.ctrl.rett and not wr.ctrl.annul)) = '1' 
    then 
      su := sregs.ps; et := '1';
    else 
      su := sregs.s; et := sregs.et;
    end if;

-- Check for illegal and privileged instructions

    illegal_inst := '0'; privileged_inst := '0'; cp_disabled := '0'; 
    fp_disabled := '0';
    case op is
    when CALL => null;
    when FMT2 =>
      case op2 is
      when SETHI | BICC => null;
      when FBFCC => 
	if FPEN then fp_disabled := not sregs.ef;
	else fp_disabled := '1'; end if;
      when CBCCC =>
	if (not CPEN) or (sregs.ec = '0') then cp_disabled := '1'; end if;
      when others => illegal_inst := '1';
      end case;
    when FMT3 =>
      case op3 is
      when IAND | ANDCC | ANDN | ANDNCC | IOR | ORCC | ORN | ORNCC | IXOR |
        XORCC | IXNOR | XNORCC | ISLL | ISRL | ISRA | MULSCC | IADD | ADDX |
	ADDCC | ADDXCC | TADDCC | TADDCCTV | ISUB | SUBX | SUBCC | SUBXCC |
	TSUBCC | TSUBCCTV  | FLUSH | JMPL | TICC | SAVE | RESTORE | RDY => null;
      when UMAC | SMAC => 
	if not MACEN then illegal_inst := '1'; end if;
      when UMUL | SMUL | UMULCC | SMULCC => 
	if MULTIPLIER = none then illegal_inst := '1'; end if;
      when UDIV | SDIV | UDIVCC | SDIVCC => 
	if DIVIDER = none then illegal_inst := '1'; end if;
      when RETT => illegal_inst := et; privileged_inst := not su;
      when RDPSR | RDTBR | RDWIM => privileged_inst := not su;
      when WRY  => 

	if not ((rd = "00000") or ((rd = "10010") and MACEN) or 
               ((rd(4 downto 3) = "11") and (WATCHPOINTS > 0))) 
	then 

	  illegal_inst := '1';
	end if;
      when WRPSR => 
	privileged_inst := not su; 
      when WRWIM | WRTBR  => privileged_inst := not su;
      when FPOP1 | FPOP2 => 
	if FPEN then fp_disabled := not sregs.ef; fpop := '1';
	else fp_disabled := '1'; fpop := '0'; end if;
      when CPOP1 | CPOP2 =>
	if (not CPEN) or (sregs.ec = '0') then cp_disabled := '1'; end if;
      when others => illegal_inst := '1';
      end case;
    when others =>	-- LDST
      case op3 is
      when LDD | ISTD => illegal_inst := rd(0);	-- trap if odd destination register
      when LD | LDUB | LDSTUB | LDUH | LDSB | LDSH | ST | STB | STH | SWAP =>
	null;
      when LDDA | STDA =>
	illegal_inst := i or rd(0); privileged_inst := not su;
      when LDA | LDUBA| LDSTUBA | LDUHA | LDSBA | LDSHA | STA | STBA | STHA |
	   SWAPA => 
	illegal_inst := i; privileged_inst := not su;
      when LDDF | STDF | LDF | LDFSR | STF | STFSR => 
	if FPEN then fp_disabled := not sregs.ef;
	else fp_disabled := '1'; end if;
      when STDFQ => 
	privileged_inst := not su; 
	if (not FPEN) or (sregs.ef = '0') then fp_disabled := '1'; end if;
      when STDCQ => 
	privileged_inst := not su;
	if (not CPEN) or (sregs.ec = '0') then cp_disabled := '1'; end if;
      when LDC | LDCSR | LDDC | STC | STCSR | STDC => 
	if (not CPEN) or (sregs.ec = '0') then cp_disabled := '1'; end if;
      when others => illegal_inst := '1';
      end case;
    end case;

-- branch address adder

    branch_address := (others => '0');
    if op = CALL then branch_address(31 downto 2) := de.inst(29 downto 0);
    else branch_address(31 downto 2) := de.inst(21) & de.inst(21) & de.inst(21) & 
            de.inst(21) & de.inst(21) & de.inst(21) & de.inst(21) & 
            de.inst(21) & de.inst(21 downto 0);
    end if;

-- pragma translate_off
    if not (is_x(branch_address) or is_x(de.pc)) then
-- pragma translate_on
      branch_address := branch_address + de.pc;	-- address adder (branch)
-- pragma translate_off
    else
      branch_address := (others => 'X');
    end if;
-- pragma translate_on

    fecomb.branch_address <= branch_address;

-- ICC pipeline and forwarding

    if (me.write_icc and not me.ctrl.annul) = '1' then icc := wrin.icc;
    elsif (wr.write_icc and not wr.ctrl.annul) = '1' then icc := wr.icc;
    else icc := sregs.icc; end if;

    br_icc := icc;

    if ((ex.write_icc and not ex.ctrl.annul) = '1') then
      icc := ex.icc;
      if not ICC_HOLD then br_icc := icc; end if;
    end if;

    write_icc := '0'; alu_cin := '0';

    case op is
    when FMT3 =>
      case op3 is
      when SUBCC | TSUBCC | TSUBCCTV => 
	write_icc := '1';
      when ADDCC | ANDCC | ORCC | XORCC | ANDNCC | ORNCC | XNORCC | MULSCC |
           TADDCC | TADDCCTV => 
	write_icc := '1';
      when UMULCC | SMULCC =>
	if MULTIPLIER = iterative then
	  if de.cnt /= "11" then write_icc := '1'; end if;
	end if;
	if MULTIPLIER = m32x32 then write_icc := '1'; end if;
      when ADDX | SUBX => 
	alu_cin := icc(0);
      when  ADDXCC | SUBXCC => 
	write_icc := '1'; alu_cin := icc(0);
      when others => null;
      end case;
    when others => null;
    end case;

    exin.write_icc <= write_icc; exin.alu_cin <= alu_cin;

-- BICC/TICC evaluation

    n := br_icc(3); z := br_icc(2); v := br_icc(1); c := br_icc(0);
    case cond(2 downto 0) is
    when "000" => bres := '0';				-- bn, ba
    when "001" => bres := z;      			-- be, bne
    when "010" => bres := z or (n xor v);             	-- ble, bg
    when "011" => bres := n xor v; 	            	-- bl, bge
    when "100" => bres := c or z;   	           	-- blue, bgu
    when "101" => bres := c;		              	-- bcs, bcc 
    when "110" => bres := n;		              	-- bneg, bpos
    when others => bres := v;		              	-- bvs. bvc   
    end case;
    branch_true := cond(3) xor bres;

-- FBFCC evaluation

    if FPEN then
      if FPIFTYPE = serial then
        if (fpu_reg.me.fpop = "10") and (me.ctrl.annul = '0') then 
	  fcc := fpu_reg.me.fcc;
        elsif (fpu_reg.wr.fpop = "10") and (wr.ctrl.annul = '0') then 
	  fcc := fpu_reg.wr.fcc;
        else fcc := fpu_reg.fsr.fcc; end if;
      else fcc := fpo.cc; end if;
      case cond(2 downto 0) is
      when "000" => fbres := '0';			-- fba, fbn
      when "001" => fbres := fcc(1) or fcc(0);
      when "010" => fbres := fcc(1) xor fcc(0);
      when "011" => fbres := fcc(0);
      when "100" => fbres := (not fcc(1)) and fcc(0);
      when "101" => fbres := fcc(1);
      when "110" => fbres := fcc(1) and not fcc(0);
      when others => fbres := fcc(1) and fcc(0);
      end case;
      fbranch_true := cond(3) xor fbres;

-- decode some FPU instruction types
      case opf is
      when FMOVS | FABSS | FNEGS => fpmov := '1';
      when FITOD | FSTOD | FSQRTD | FADDD | FSUBD | FMULD | FDIVD => 
	fpexin.dsz := '1';
      when others => null;
      end case;
    end if;

-- CBCCC evaluation

    if CPEN then
      ccc := cpo.cc;
      case cond(2 downto 0) is
      when "000" => cbres := '0';
      when "001" => cbres := ccc(1) or ccc(0);
      when "010" => cbres := ccc(1) xor ccc(0);
      when "011" => cbres := ccc(0);
      when "100" => cbres := (not ccc(1)) and ccc(0);
      when "101" => cbres := ccc(1);
      when "110" => cbres := ccc(1) and not ccc(0);
      when others => cbres := ccc(1) and ccc(0);
      end case;
      cbranch_true := cond(3) xor cbres;
    end if;

-- Alu operation generation

    aluop := ALU_NOP; alusel := ALU_RES_MISC; aluadd := '1'; 
    mulstep := '0'; mulinsn := '0';
    case op is
    when FMT2 =>
      case op2 is
      when SETHI => aluop := ALU_PASS2;
      when others =>
      end case;
    when FMT3 =>
      case op3 is
      when IADD | ADDX | ADDCC | ADDXCC | TADDCC | TADDCCTV | SAVE | RESTORE |
	   TICC | JMPL | RETT  => alusel := ALU_RES_ADD;
      when ISUB | SUBX | SUBCC | SUBXCC | TSUBCC | TSUBCCTV  => 
	alusel := ALU_RES_ADD; aluadd := '0';
      when MULSCC => alusel := ALU_RES_ADD; mulstep := '1';
      when UMUL | UMULCC => 
	if MULTIPLIER = iterative then
          case de.cnt is
	  when "00" => aluop := ALU_XOR; alusel := ALU_RES_MISC;
	  when "01" | "10" => alusel := ALU_RES_ADD; mulinsn := '1';
	  when others => alusel := ALU_RES_ADD;
	  end case;
	end if;
	if MULTIPLIER > iterative then mulinsn := '1'; end if;
      when SMUL | SMULCC => 
	if MULTIPLIER = iterative then
          case de.cnt is
	  when "00" => aluop := ALU_XOR; alusel := ALU_RES_MISC;
	  when "01" | "10" => alusel := ALU_RES_ADD; mulinsn := '1';
	  when others => alusel := ALU_RES_ADD; aluadd := '0';
	  end case;
	end if;
	if MULTIPLIER > iterative then mulinsn := '1'; end if;
      when UMAC | SMAC => 
	if MACEN then mulinsn := '1'; end if;
      when UDIV | UDIVCC | SDIV | SDIVCC => 
	if DIVIDER /= none then aluop := ALU_DIV; alusel := ALU_RES_LOGIC; end if;
      when IAND | ANDCC => aluop := ALU_AND; alusel := ALU_RES_LOGIC;
      when ANDN | ANDNCC => aluop := ALU_ANDN; alusel := ALU_RES_LOGIC;
      when IOR | ORCC  => aluop := ALU_OR; alusel := ALU_RES_LOGIC;
      when ORN | ORNCC  => aluop := ALU_ORN; alusel := ALU_RES_LOGIC;
      when IXNOR | XNORCC  => aluop := ALU_XNOR; alusel := ALU_RES_LOGIC;
      when XORCC | IXOR | WRPSR | WRWIM | WRTBR | WRY  => 
	aluop := ALU_XOR; alusel := ALU_RES_LOGIC;
      when RDPSR | RDTBR | RDWIM => aluop := ALU_PASS2;
      when RDY => aluop := ALU_RDY;
      when ISLL => aluop := ALU_SLL; alusel := ALU_RES_SHIFT;
      when ISRL => aluop := ALU_SRL; alusel := ALU_RES_SHIFT;
      when ISRA => aluop := ALU_SRA; alusel := ALU_RES_SHIFT;
      when FPOP1 | FPOP2 =>
	if ((FPIFTYPE = serial) and FPEN) then
          if de.cnt /= "00" then 
	    if opf(1) = '1' then rs1(0) := '1'; rs2(0) := '1'; end if;
	    if fpexin.dsz = '1' then rd(0) := '1'; end if;
	  end if;
	  if op3 = FPOP1 then fpexin.fpop := "01"; else fpexin.fpop := "10"; end if;
	  if fpmov = '1' then aluop := ALU_FOP; fpexin.fpop := "11";
	  else aluop := ALU_PASS2; end if;
	end if;
      when others =>
      end case;
    when others =>	-- LDST
      case de.cnt is
      when "00" =>
        alusel := ALU_RES_ADD;
	if FPEN then fpld := (op3(5) and not op3(2));
	else fpld := '0'; end if;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?