--------------------------------------------------------------------------
-- Project: JIPS, a portable 32-bit RISC CPU written in VHDL
-- This file: Types, constants and functions for JCPU
--
-- Copyright (C) 2008 J. Ahrensfeld
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
--
-- For questions and ideas, please contact the author at jens@jayfield.org
--
--------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.ALL;

library work;
use work.mips_types.all;

--------------------------------------------------------------------------
package mips_instr is

	function extract_opc(instr : word_t) return opcode_t;
	function extract_rs(instr : word_t) return reg_ptr_t;
	function extract_rt(instr : word_t) return reg_ptr_t;
	function extract_rd(instr : word_t) return reg_ptr_t;
	function extract_shamt(instr : word_t) return shamt_t;
	function extract_func(instr : word_t) return func_t;
	function extract_simm32(instr : word_t) return word_t;
	function extract_uimm16(instr : word_t) return word_t;
	function extract_jimm32(instr, pc : word_t) return word_t;
	function extract_bimm18(instr, pc : word_t) return word_t;
	function decode_op(instr : word_t) return op_t;
	function ctrl_lines_default return ctrl_lines_t;
	function opcode_ctrl_lines(instr : word_t) return ctrl_lines_t;

end mips_instr;

--------------------------------------------------------------------------
library work;
use work.mips_types.all;

package body mips_instr is

	function extract_opc(instr : word_t) return opcode_t is
	variable result : opcode_t;
	begin
		result := instr(31 downto 26);
		
		return result;

	end extract_opc;
	
	function extract_rs(instr : word_t) return reg_ptr_t is
	variable result : reg_ptr_t;
	begin
		result := instr(25 downto 21);
		
		return result;

	end extract_rs;
	
	function extract_rt(instr : word_t) return reg_ptr_t is
	variable result : reg_ptr_t;
	begin
		result := instr(20 downto 16);
		
		return result;

	end extract_rt;

	function extract_rd(instr : word_t) return reg_ptr_t is
	variable result : reg_ptr_t;
	begin
		result := instr(15 downto 11);
		
		return result;

	end extract_rd;

	function extract_shamt(instr : word_t) return shamt_t is
	variable result : shamt_t;
	begin
		result := instr(10 downto 6);
		
		return result;

	end extract_shamt;

	function extract_func(instr : word_t) return func_t is
	variable result : func_t;
	begin
		result := instr(5 downto 0);
		
		return result;

	end extract_func;

	function extract_simm32(instr : word_t) return word_t is
	variable result : word_t;
	begin
		result := (31 downto 16 => instr(15)) & instr(15 downto 0);
		
		return result;

	end extract_simm32;

	function extract_uimm16(instr : word_t) return word_t is
	variable result : word_t;
	begin
		result := (31 downto 16 => '0') & instr(15 downto 0);
		
		return result;

	end extract_uimm16;

	function extract_jimm32(instr, pc : word_t) return word_t is
	variable result : word_t;
	begin
		result := pc(31 downto 28) & instr(25 downto 0) & "00";
		
		return result;

	end extract_jimm32;

	function extract_bimm18(instr, pc : word_t) return word_t is
	variable result : word_t;
	begin
		result := (31 downto 18 => instr(15)) & instr(15 downto 0) & "00";
		
		return result;

	end extract_bimm18;

	function decode_op(instr : word_t) return op_t is
	variable result : op_t;
	variable opc : natural range 0 to 63;
	variable func : natural range 0 to 63;
	variable rt : natural range 0 to 31;
	variable rs : natural range 0 to 31;
	
	begin
		
		opc		:= to_integer(extract_opc(instr));
		func	:= to_integer(extract_func(instr));
		rt		:= to_integer(extract_rt(instr));
		rs		:= to_integer(extract_rs(instr));
		
		result := op_illegal;
		
		case opc is

		when 0 =>
			case func is

			when 0 =>
				result := op_sll;
			
			when 2 =>
				result := op_srl;

			when 3 =>
				result := op_sra;

			when 4 =>
				result := op_sllv;

			when 6 =>
				result := op_srlv;

			when 7 =>
				result := op_srav;

			when 8 =>
				result := op_jr;

			when 9 =>
				result := op_jalr;

			when 12 =>
				result := op_syscall;

			when 13 =>
				result := op_break;

			when 16 =>
				result := op_mfhi;

			when 17 =>
				result := op_mthi;

			when 18 =>
				result := op_mflo;

			when 19 =>
				result := op_mtlo;

			when 24 =>
				result := op_mult;

			when 25 =>
				result := op_multu;

			when 26 =>
				result := op_div;

			when 27 =>
				result := op_divu;

			when 32 =>
				result := op_add;
			
			when 33 =>
				result := op_addu;
			
			when 34 =>
				result := op_sub;
			
			when 35 =>
				result := op_subu;
			
			when 36 =>
				result := op_and;
			
			when 37 =>
				result := op_or;
			
			when 38 =>
				result := op_xor;
			
			when 39 =>
				result := op_nor;
			
			when 42 =>
				result := op_slt;
			
			when 43 =>
				result := op_sltu;
				
			when others => null; -- undef
			
			end case;
			
		when 1 =>
			case rt is

			when 0 =>
				result := op_bltz;
				
			when 1 =>
				result := op_bgez;
			
			when 16 =>
				result := op_bltzal;

			when 17 =>
				result := op_bgezal;
				
			when others => null; -- undef
			
			end case;

		when 2 =>
			result	:= op_j;
			
		when 3 =>
			result	:= op_jal;
			
		when 4 =>
			result	:= op_beq;
			
		when 5 =>
			result	:= op_bne;

		when 6 =>
			result	:= op_blez;

		when 7 =>
			result	:= op_bgtz;

		when 8 =>
			result	:= op_addi;

		when 9 =>
			result	:= op_addiu;

		when 10 =>
			result	:= op_slti;

		when 11 =>
			result	:= op_sltiu;

		when 12 =>
			result	:= op_andi;

		when 13 =>
			result	:= op_ori;

		when 14 =>
			result	:= op_xori;

		when 15 =>
			result	:= op_lui;

		when 16 =>
			result	:= op_cop0;
			case rs is
				when 0 =>
					result	:= op_mfc0;
				when 2 =>
					result	:= op_cfc0;	-- illegal
				when 4 =>
					result	:= op_mtc0;
				when 6 =>
					result	:= op_ctc0;	-- illegal
				when 8 =>
					case rt is
						when 0 =>
							result := op_bcf0;	-- illegal
						when 1 =>
							result := op_bct0;	-- illegal
			
						when others => null; -- undef
					end case;	
							
				when others => null; -- undef
			
			end case;

		when 17 =>
			result	:= op_cop1;
			case rs is
				when 0 =>
					result	:= op_mfc1;
				when 2 =>
					result	:= op_cfc1;
				when 4 =>
					result	:= op_mtc1;
				when 6 =>
					result	:= op_ctc1;
				when 8 =>
					case rt is
						when 0 =>
							result := op_bcf1;
						when 1 =>
							result := op_bct1;
			
						when others => null; -- undef
					end case;	
							
				when others => null; -- undef
			
			end case;

		when 18 =>
			result	:= op_cop2;
			case rs is
				when 0 =>
					result	:= op_mfc2;
				when 2 =>
					result	:= op_cfc2;
				when 4 =>
					result	:= op_mtc2;
				when 6 =>
					result	:= op_ctc2;
				when 8 =>
					case rt is
						when 0 =>
							result := op_bcf2;
						when 1 =>
							result := op_bct2;
			
						when others => null; -- undef
					end case;	
							
				when others => null; -- undef
			
			end case;

		when 19 =>
			result	:= op_cop3;
			case rs is
				when 0 =>
					result	:= op_mfc3;
				when 2 =>
					result	:= op_cfc3;
				when 4 =>
					result	:= op_mtc3;
				when 6 =>
					result	:= op_ctc3;
				when 8 =>
					case rt is
						when 0 =>
							result := op_bcf3;
						when 1 =>
							result := op_bct3;
			
						when others => null; -- undef
					end case;	
							
				when others => null; -- undef
			
			end case;

		when 32 =>
			result	:= op_lb;

		when 33 =>
			result	:= op_lh;

		when 34 =>
			result	:= op_lwl;

		when 35 =>
			result	:= op_lw;

		when 36 =>
			result	:= op_lbu;

		when 37 =>
			result	:= op_lhu;

		when 38 =>
			result	:= op_lwr;

		when 40 =>
			result	:= op_sb;

		when 41 =>
			result	:= op_sh;

		when 42 =>
			result	:= op_swl;

		when 43 =>
			result	:= op_sw;

		when 46 =>
			result	:= op_swr;

		when 48 =>
			result	:= op_lwc0;	-- illegal
			
		when 49 =>
			result	:= op_lwc1;
			
		when 50 =>
			result	:= op_lwc2;

		when 51 =>
			result	:= op_lwc3;

		when 56 =>
			result	:= op_swc0;	-- illegal

		when 57 =>
			result	:= op_swc1;
			
		when 58 =>
			result	:= op_swc2;

		when 59 =>
			result	:= op_swc3;

		when others => null; -- undef

		end case;

		return result;

	end decode_op;

	function ctrl_lines_default return ctrl_lines_t is
	variable result : ctrl_lines_t;
	begin
		result.cop_instr_en				:= '0';
		result.cop_read					:= '0';
		result.jump						:= '0';
		result.jump_long				:= '0';
		result.branch					:= '0';
		result.bc_src					:= bc_eq_ne;
		result.bc_not					:= '0';
		result.alu.outsel				:= alu_adder;
		result.alu.add					:= '1';
		result.alu.shift_right			:= '0';
		result.alu.shift_arith			:= '0';
		result.shamt2_srcsel			:= sa_src_imm;
		result.alu.op1_src				:= alu_src_reg;
		result.alu.op2_src				:= alu_src_reg;
		result.imm_src					:= src_imm16;
		result.reg_write				:= '0';
		result.dmem_we					:= '0';
		result.dmem_en					:= '0';
		result.wptr_srcsel				:= wptr_src_imm;
		result.reg_link					:= '0';
		result.shift_offset				:= "00";
		result.shift_byp				:= '1';
		result.byte_en_byp				:= '1';
		result.sign_ext_byp				:= '1';
		result.word4_en					:= '0';
		result.word2_en					:= '0';
		result.align_left				:= '0';
		result.load_signed				:= '0';
		result.mul_access				:= '0';
		result.mul_hilo_we				:= '0';
		result.mul_start				:= '0';
		result.mul_s_un					:= '0';
		result.mul_mul_divn				:= '0';
		result.mul_hilo_sel				:= '1';
		result.exc_break				:= '0';
		result.exc_syscall				:= '0';
		result.exc_illegal				:= '0';
		result.except_en				:= '0';
		result.alu_exc_en				:= '0';

		return result;
	
	end ctrl_lines_default;

	function opcode_ctrl_lines(instr : word_t) return ctrl_lines_t is
	variable result : ctrl_lines_t;
	variable opc	: integer range 0 to 2**opcode_t'length-1;
	variable func	: integer range 0 to 2**func_t'length-1;
	variable rt		: integer range 0 to 2**reg_ptr_t'length-1;
	variable rs		: integer range 0 to 2**reg_ptr_t'length-1;
	begin
	
		result	:= ctrl_lines_default;
		opc		:= to_integer(extract_opc(instr));
		func 	:= to_integer(extract_func(instr));
		rt 		:= to_integer(extract_rt(instr));
		rs 		:= to_integer(extract_rs(instr));

		case opc is
--		SPECIAL
		when 0 =>	
			case func is

	--		when op_add  =>
			when 32 =>
				result.alu.outsel		:= alu_adder;
				result.alu.add			:= '1';
				result.alu.op1_src		:= alu_src_reg;
				result.alu.op2_src		:= alu_src_reg;
				result.reg_write		:= '1';
				result.alu_exc_en		:= '1';

	--		when op_addu =>
			when 33 =>
				result.alu.outsel		:= alu_adder;
				result.alu.add			:= '1';
				result.alu.op1_src		:= alu_src_reg;
				result.alu.op2_src		:= alu_src_reg;
				result.reg_write		:= '1';

	--		when op_and =>
			when 36 =>
				result.alu.outsel		:= alu_and;
				result.alu.op1_src		:= alu_src_reg;
				result.alu.op2_src		:= alu_src_reg;
				result.reg_write		:= '1';

	--		when op_break =>
			when 13 =>
				result.exc_break		:= '1';
				result.except_en		:= '1';

	--		when op_div =>
			when 26 =>
				result.mul_access		:= '1';
				result.mul_start		:= '1';
				result.mul_s_un			:= '1';
				result.mul_mul_divn		:= '0';

	--		when op_divu =>
			when 27 =>
				result.mul_access		:= '1';
				result.mul_start		:= '1';
				result.mul_s_un			:= '0';
				result.mul_mul_divn		:= '0';

	--		when op_jalr =>
			when 9 =>
				result.jump_long		:= '1';
				result.wptr_srcsel		:= wptr_src_imm;
				result.reg_write		:= '1';
				result.reg_link			:= '1';

	--		when op_jr =>
			when 8 =>
				result.jump_long		:= '1';

	--		when op_mfhi =>
			when 16 =>
				result.reg_write		:= '1';
				result.mul_access		:= '1';
				result.mul_hilo_sel		:= '1';

	--		when op_mflo =>
			when 18 =>
				result.reg_write		:= '1';
				result.mul_access		:= '1';
				result.mul_hilo_sel		:= '0';

	--		when op_mthi =>
			when 17 =>
				result.mul_hilo_we		:= '1';
				result.mul_hilo_sel		:= '1';

	--		when op_mtlo =>
			when 19 =>
				result.mul_hilo_we		:= '1';
				result.mul_hilo_sel		:= '0';

	--		when op_mult =>
			when 24 =>
				result.mul_access		:= '1';
				result.mul_start		:= '1';
				result.mul_s_un			:= '1';
				result.mul_mul_divn		:= '1';

	--		when op_multu =>
			when 25 =>
				result.mul_access		:= '1';
				result.mul_start		:= '1';
				result.mul_s_un			:= '0';
				result.mul_mul_divn		:= '1';

	--		when op_or =>
			when 37 =>
				result.alu.outsel		:= alu_or;
				result.alu.op1_src		:= alu_src_reg;
				result.alu.op2_src		:= alu_src_reg;
				result.reg_write		:= '1';

	--		when op_nor =>
			when 39 =>
				result.alu.outsel		:= alu_nor;
				result.alu.op1_src		:= alu_src_reg;
				result.alu.op2_src		:= alu_src_reg;
				result.reg_write		:= '1';

	--		when op_sll =>
			when 0 =>
				result.alu.op2_src		:= alu_src_reg;
				result.alu.outsel		:= alu_shift2;
				result.alu.shift_right	:= '0';
				result.shamt2_srcsel	:= sa_src_imm;
				result.reg_write		:= '1';

	--		when op_sllv =>
			when 4 =>
				result.alu.op2_src		:= alu_src_reg;
				result.alu.outsel		:= alu_shift2;
				result.alu.shift_right	:= '0';
				result.shamt2_srcsel	:= sa_src_reg;
				result.reg_write		:= '1';

	--		when op_slt =>
			when 42 =>
				result.alu.outsel		:= alu_lts;
				result.alu.add			:= '0';
				result.alu.op1_src		:= alu_src_reg;
				result.alu.op2_src		:= alu_src_reg;
				result.reg_write		:= '1';

	--		when op_sltu =>
			when 43 =>
				result.alu.outsel		:= alu_ltu;
				result.alu.add			:= '0';
				result.alu.op1_src		:= alu_src_reg;
				result.alu.op2_src		:= alu_src_reg;
				result.reg_write		:= '1';

	--		when op_sra =>
			when 3 =>
				result.alu.op2_src		:= alu_src_reg;
				result.alu.outsel		:= alu_shift2;
				result.alu.shift_right	:= '1';
				result.alu.shift_arith	:= '1';
				result.shamt2_srcsel	:= sa_src_imm;
				result.reg_write		:= '1';

	--		when op_srav =>
			when 7 =>
				result.alu.op2_src		:= alu_src_reg;
				result.alu.outsel		:= alu_shift2;
				result.alu.shift_right	:= '1';
				result.alu.shift_arith	:= '1';
				result.shamt2_srcsel	:= sa_src_reg;
				result.reg_write		:= '1';

	--		when op_srl =>
			when 2 =>
				result.alu.op2_src		:= alu_src_reg;
				result.alu.outsel		:= alu_shift2;
				result.alu.shift_right	:= '1';
				result.alu.shift_arith	:= '0';
				result.shamt2_srcsel	:= sa_src_imm;
				result.reg_write		:= '1';

	--		when op_srlv =>
			when 6 =>
				result.alu.op2_src		:= alu_src_reg;
				result.alu.outsel		:= alu_shift2;
				result.alu.shift_right	:= '1';
				result.alu.shift_arith	:= '0';
				result.shamt2_srcsel	:= sa_src_reg;
				result.reg_write		:= '1';

	--		when op_sub =>
			when 34 =>
				result.alu.outsel		:= alu_adder;
				result.alu.add			:= '0';
				result.alu.op1_src		:= alu_src_reg;
				result.alu.op2_src		:= alu_src_reg;
				result.reg_write		:= '1';
				result.alu_exc_en		:= '1';

	--		when op_subu =>
			when 35 =>
				result.alu.outsel		:= alu_adder;
				result.alu.add			:= '0';
				result.alu.op1_src		:= alu_src_reg;
				result.alu.op2_src		:= alu_src_reg;
				result.reg_write		:= '1';

	--		when op_syscall =>
			when 12 =>
				result.exc_syscall		:= '1';
				result.except_en		:= '1';

	--		when op_xor =>
			when 38 =>
				result.alu.outsel		:= alu_xor;
				result.alu.op1_src		:= alu_src_reg;
				result.alu.op2_src		:= alu_src_reg;
				result.reg_write		:= '1';

			when others => 
				result.exc_illegal		:= '1';

			end case;

--		REGIMM
		when 1 =>	
			case rt is

	--		when op_bgez =>
			when 1 =>
				result.branch			:= '1';
				result.bc_src			:= bc_ltz_gez;
				result.bc_not			:= '1';

	--		when op_bgezal =>
			when 17 =>
				result.branch			:= '1';
				result.bc_src			:= bc_ltz_gez;
				result.bc_not			:= '1';
				result.wptr_srcsel		:= wptr_src_const;
				result.reg_write		:= '1';
				result.reg_link			:= '1';

	--		when op_bltz =>
			when 0 =>
				result.branch			:= '1';
				result.bc_src			:= bc_ltz_gez;
				result.bc_not			:= '0';

	--		when op_bltzal =>
			when 16 =>
				result.branch			:= '1';
				result.bc_src			:= bc_ltz_gez;
				result.bc_not			:= '0';
				result.wptr_srcsel		:= wptr_src_const;
				result.reg_write		:= '1';
				result.reg_link			:= '1';

			when others => 
				result.exc_illegal		:= '1';

			end case;

--		when COPz =>
		when 16 | 17 | 18 | 19 =>			
			result.cop_instr_en		:= '1';
			case rs is
				when 0 =>	-- MFCz
					result.cop_read		:= '1';
					result.reg_write	:= '1';
				when 2 =>	-- CFCz
					result.cop_read		:= '1';
					result.reg_write	:= '1';
							
				when others => null; -- undef
			
			end case;
			
			
--		when op_addi =>
		when 8 =>
			result.imm_src			:= src_imm32;
			result.alu.outsel		:= alu_adder;
			result.alu.add			:= '1';
			result.alu.op1_src		:= alu_src_reg;
			result.alu.op2_src		:= alu_src_imm;
			result.reg_write		:= '1';
			result.alu_exc_en		:= '1';

--		when op_addiu =>
		when 9 =>
			result.imm_src			:= src_imm32;
			result.alu.outsel		:= alu_adder;
			result.alu.add			:= '1';
			result.alu.op1_src		:= alu_src_reg;
			result.alu.op2_src		:= alu_src_imm;
			result.reg_write		:= '1';

--		when op_andi =>
		when 12 =>
			result.imm_src			:= src_imm16;
			result.alu.outsel		:= alu_and;
			result.alu.op1_src		:= alu_src_reg;
			result.alu.op2_src		:= alu_src_imm;
			result.reg_write		:= '1';

--		when op_beq =>
		when 4 =>
			result.branch			:= '1';
			result.bc_src			:= bc_eq_ne;
			result.bc_not			:= '0';
			
--		when op_bgtz =>
		when 7 =>
			result.branch			:= '1';
			result.bc_src			:= bc_lez_gtz;
			result.bc_not			:= '1';
			
--		when op_blez =>
		when 6 =>
			result.branch			:= '1';
			result.bc_src			:= bc_lez_gtz;
			result.bc_not			:= '0';
			
--		when op_bne =>
		when 5 =>
			result.branch			:= '1';
			result.bc_src			:= bc_eq_ne;
			result.bc_not			:= '1';

--		when op_j =>
		when 2 =>
			result.jump				:= '1';

--		when op_jal =>
		when 3 =>
			result.jump				:= '1';
			result.wptr_srcsel		:= wptr_src_const;
			result.reg_write		:= '1';
			result.reg_link			:= '1';

--		when op_lb =>
		when 32 =>
			result.imm_src			:= src_imm32;
			result.dmem_en			:= '1';
			result.reg_write		:= '1';
			result.shift_byp		:= '0';
			result.byte_en_byp		:= '1';
			result.sign_ext_byp		:= '0';
			result.load_signed		:= '1';
			result.word4_en			:= '1';
			
--		when op_lbu =>
		when 36 =>
			result.imm_src			:= src_imm32;
			result.dmem_en			:= '1';
			result.reg_write		:= '1';
			result.shift_byp		:= '0';
			result.byte_en_byp		:= '1';
			result.sign_ext_byp		:= '0';
			result.load_signed		:= '0';
			result.word4_en			:= '1';
			
--		when op_lh =>
		when 33 =>
			result.imm_src			:= src_imm32;
			result.dmem_en			:= '1';
			result.reg_write		:= '1';
			result.shift_byp		:= '0';
			result.sign_ext_byp		:= '0';
			result.byte_en_byp		:= '1';
			result.load_signed		:= '1';
			result.word2_en			:= '1';
			result.except_en		:= '1';
			
--		when op_lhu =>
		when 37 =>
			result.imm_src			:= src_imm32;
			result.dmem_en			:= '1';
			result.reg_write		:= '1';
			result.shift_byp		:= '0';
			result.sign_ext_byp		:= '0';
			result.byte_en_byp		:= '1';
			result.load_signed		:= '0';
			result.word2_en			:= '1';
			result.except_en		:= '1';
			
--		when op_lui =>
		when 15 =>
			result.imm_src			:= src_imm16_high;
			result.alu.op1_src		:= alu_src_reg;
			result.alu.op2_src		:= alu_src_imm;
			result.alu.outsel		:= alu_adder;
			result.reg_write		:= '1';
			result.alu.add			:= '1';

--		when op_lw =>
		when 35 =>
--			result.imm_src			:= src_imm32;
			result.dmem_en			:= '1';
			result.reg_write		:= '1';
			result.except_en		:= '1';
			
--		when op_lwcz =>
		when 48 | 49 | 50 | 51 =>
--			result.imm_src			:= src_imm32;
			result.dmem_en			:= '1';
			result.except_en		:= '1';
			result.cop_instr_en		:= '1';
			
--		when op_lwl =>
		when 34 =>
--			result.imm_src			:= src_imm32;
			result.dmem_en			:= '1';
			result.reg_write		:= '1';
			result.shift_byp		:= '0';
			result.byte_en_byp		:= '0';
			result.shift_offset		:= "01";
			result.align_left		:= '1';
			
--		when op_lwr =>
		when 38 =>
--			result.imm_src			:= src_imm32;
			result.dmem_en			:= '1';
			result.reg_write		:= '1';
			result.shift_byp		:= '0';
			result.byte_en_byp		:= '0';
			result.shift_offset		:= "00";
			result.align_left		:= '0';
			
--		when op_ori =>
		when 13 =>
			result.imm_src			:= src_imm16;
			result.alu.outsel		:= alu_or;
			result.alu.op1_src		:= alu_src_reg;
			result.alu.op2_src		:= alu_src_imm;
			result.reg_write		:= '1';

--		when op_sb =>
		when 40 =>
			result.dmem_en			:= '1';
			result.dmem_we			:= '1';
--			result.imm_src			:= src_imm32;
			result.shift_byp		:= '0';
			result.byte_en_byp		:= '0';
			result.word4_en			:= '1';
			
--		when op_sh =>
		when 41 =>
			result.dmem_en			:= '1';
			result.dmem_we			:= '1';
--			result.imm_src			:= src_imm32;
			result.shift_byp		:= '0';
			result.byte_en_byp		:= '0';
			result.word2_en			:= '1';
			result.except_en		:= '1';
			
--		when op_slti =>
		when 10 =>
			result.alu.outsel		:= alu_lts;
			result.alu.add			:= '0';
			result.alu.op1_src		:= alu_src_reg;
			result.alu.op2_src		:= alu_src_imm;
			result.imm_src			:= src_imm32;
			result.reg_write		:= '1';

--		when op_sltiu =>
		when 11 =>
			result.alu.outsel		:= alu_ltu;
			result.alu.add			:= '0';
			result.alu.op1_src		:= alu_src_reg;
			result.alu.op2_src		:= alu_src_imm;
			result.imm_src			:= src_imm32;
			result.reg_write		:= '1';

--		when op_sw =>
		when 43 =>
			result.dmem_en			:= '1';
			result.dmem_we			:= '1';
--			result.imm_src			:= src_imm32;
			result.except_en		:= '1';
			
--		when op_swcz =>
		when 56 | 57 | 58 | 59 =>
			result.dmem_en			:= '1';
			result.dmem_we			:= '1';
--			result.imm_src			:= src_imm32;
			result.except_en		:= '1';
			result.cop_instr_en		:= '1';
			result.cop_read			:= '1';

--		when op_swl =>
		when 42 =>
			result.dmem_en			:= '1';
			result.dmem_we			:= '1';
--			result.imm_src			:= src_imm32;
			result.shift_byp		:= '0';
			result.byte_en_byp		:= '0';
			result.shift_offset		:= "01";
			
--		when op_swr =>
		when 46 =>
			result.dmem_en			:= '1';
			result.dmem_we			:= '1';
--			result.imm_src			:= src_imm32;
			result.shift_byp		:= '0';
			result.byte_en_byp		:= '0';
			result.align_left		:= '1';
			
--		when op_xori =>
		when 14 =>
			result.imm_src			:= src_imm16;
			result.alu.outsel		:= alu_xor;
			result.alu.op1_src		:= alu_src_reg;
			result.alu.op2_src		:= alu_src_imm;
			result.reg_write		:= '1';

		when others => 
			result.exc_illegal		:= '1';

		end case;
		
		return result;
	
	end opcode_ctrl_lines;

end mips_instr;

--------------------------------------------------------------------------
--------------------------------------------------------------------------

