data/full_repos/permissive/518460376/verilog/rtl/ips/zero-riscy/zeroriscy_multdiv_slow.v
1: b'%Warning-WIDTH: data/full_repos/permissive/518460376/verilog/rtl/ips/zero-riscy/zeroriscy_multdiv_slow.v:338: Operator COND expects 33 bits on the Conditional True, but Conditional True\'s SEL generates 32 bits.\n                                                                                                            : ... In instance zeroriscy_multdiv_slow\n  multdiv_result_o = (div_en_i ? accum_window_q[31:0] : res_adder_l);\n                               ^\n                ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message.\n%Warning-WIDTH: data/full_repos/permissive/518460376/verilog/rtl/ips/zero-riscy/zeroriscy_multdiv_slow.v:338: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS\'s COND generates 33 bits.\n                                                                                                            : ... In instance zeroriscy_multdiv_slow\n  multdiv_result_o = (div_en_i ? accum_window_q[31:0] : res_adder_l);\n                   ^\n%Warning-WIDTH: data/full_repos/permissive/518460376/verilog/rtl/ips/zero-riscy/zeroriscy_multdiv_slow.v:392: Operator ASSIGNDLY expects 5 bits on the Assign RHS, but Assign RHS\'s CONST \'1\'sh0\' generates 1 bits.\n                                                                                                            : ... In instance zeroriscy_multdiv_slow\n   multdiv_state_q <= 1\'sb0;\n                   ^~\n%Warning-WIDTH: data/full_repos/permissive/518460376/verilog/rtl/ips/zero-riscy/zeroriscy_multdiv_slow.v:393: Operator ASSIGNDLY expects 33 bits on the Assign RHS, but Assign RHS\'s CONST \'1\'sh0\' generates 1 bits.\n                                                                                                            : ... In instance zeroriscy_multdiv_slow\n   accum_window_q <= 1\'sb0;\n                  ^~\n%Warning-WIDTH: data/full_repos/permissive/518460376/verilog/rtl/ips/zero-riscy/zeroriscy_multdiv_slow.v:394: Operator ASSIGNDLY expects 33 bits on the Assign RHS, but Assign RHS\'s CONST \'1\'sh0\' generates 1 bits.\n                                                                                                            : ... In instance zeroriscy_multdiv_slow\n   op_b_shift_q <= 1\'sb0;\n                ^~\n%Warning-WIDTH: data/full_repos/permissive/518460376/verilog/rtl/ips/zero-riscy/zeroriscy_multdiv_slow.v:395: Operator ASSIGNDLY expects 33 bits on the Assign RHS, but Assign RHS\'s CONST \'1\'sh0\' generates 1 bits.\n                                                                                                            : ... In instance zeroriscy_multdiv_slow\n   op_a_shift_q <= 1\'sb0;\n                ^~\n%Warning-WIDTH: data/full_repos/permissive/518460376/verilog/rtl/ips/zero-riscy/zeroriscy_multdiv_slow.v:397: Operator ASSIGNDLY expects 32 bits on the Assign RHS, but Assign RHS\'s CONST \'1\'sh0\' generates 1 bits.\n                                                                                                            : ... In instance zeroriscy_multdiv_slow\n   op_numerator_q <= 1\'sb0;\n                  ^~\n%Warning-WIDTH: data/full_repos/permissive/518460376/verilog/rtl/ips/zero-riscy/zeroriscy_multdiv_slow.v:416: Operator ASSIGNDLY expects 33 bits on the Assign RHS, but Assign RHS\'s CONST \'1\'sh1\' generates 1 bits.\n                                                                                                            : ... In instance zeroriscy_multdiv_slow\n       accum_window_q <= 1\'sb1;\n                      ^~\n%Warning-WIDTH: data/full_repos/permissive/518460376/verilog/rtl/ips/zero-riscy/zeroriscy_multdiv_slow.v:427: Operator ASSIGNDLY expects 33 bits on the Assign RHS, but Assign RHS\'s CONST \'1\'sh0\' generates 1 bits.\n                                                                                                            : ... In instance zeroriscy_multdiv_slow\n     op_a_shift_q <= 1\'sb0;\n                  ^~\n%Warning-WIDTH: data/full_repos/permissive/518460376/verilog/rtl/ips/zero-riscy/zeroriscy_multdiv_slow.v:433: Operator COND expects 33 bits on the Conditional True, but Conditional True\'s VARREF \'alu_adder_i\' generates 32 bits.\n                                                                                                            : ... In instance zeroriscy_multdiv_slow\n     op_b_shift_q <= (sign_b ? alu_adder_i : op_b_i);\n                             ^\n%Warning-WIDTH: data/full_repos/permissive/518460376/verilog/rtl/ips/zero-riscy/zeroriscy_multdiv_slow.v:433: Operator COND expects 33 bits on the Conditional False, but Conditional False\'s VARREF \'op_b_i\' generates 32 bits.\n                                                                                                            : ... In instance zeroriscy_multdiv_slow\n     op_b_shift_q <= (sign_b ? alu_adder_i : op_b_i);\n                             ^\n%Warning-WIDTH: data/full_repos/permissive/518460376/verilog/rtl/ips/zero-riscy/zeroriscy_multdiv_slow.v:481: Operator COND expects 33 bits on the Conditional True, but Conditional True\'s VARREF \'alu_adder_i\' generates 32 bits.\n                                                                                                            : ... In instance zeroriscy_multdiv_slow\n      MD_OP_DIV: accum_window_q <= (div_change_sign ? alu_adder_i : accum_window_q);\n                                                    ^\n%Warning-WIDTH: data/full_repos/permissive/518460376/verilog/rtl/ips/zero-riscy/zeroriscy_multdiv_slow.v:482: Operator COND expects 33 bits on the Conditional True, but Conditional True\'s VARREF \'alu_adder_i\' generates 32 bits.\n                                                                                                            : ... In instance zeroriscy_multdiv_slow\n      default: accum_window_q <= (rem_change_sign ? alu_adder_i : accum_window_q);\n                                                  ^\n%Error: Exiting due to 13 warning(s)\n'
module zeroriscy_multdiv_slow (
	clk,
	rst_n,
	mult_en_i,
	div_en_i,
	operator_i,
	signed_mode_i,
	op_a_i,
	op_b_i,
	alu_adder_ext_i,
	alu_adder_i,
	equal_to_zero,
	alu_operand_a_o,
	alu_operand_b_o,
	multdiv_result_o,
	ready_o
);
parameter OPCODE_SYSTEM    = 7'h73;
parameter OPCODE_FENCE     = 7'h0f;
parameter OPCODE_OP        = 7'h33;
parameter OPCODE_OPIMM     = 7'h13;
parameter OPCODE_STORE     = 7'h23;
parameter OPCODE_LOAD      = 7'h03;
parameter OPCODE_BRANCH    = 7'h63;
parameter OPCODE_JALR      = 7'h67;
parameter OPCODE_JAL       = 7'h6f;
parameter OPCODE_AUIPC     = 7'h17;
parameter OPCODE_LUI       = 7'h37;






parameter OPCODE_LOAD_POST  = 7'h0b;
parameter OPCODE_STORE_POST = 7'h2b;
parameter OPCODE_PULP_OP    = 7'h5b;
parameter OPCODE_VECOP      = 7'h57;
parameter OPCODE_HWLOOP     = 7'h7b;

parameter REGC_S1   = 2'b10;
parameter REGC_RD   = 2'b01;
parameter REGC_ZERO = 2'b11;











parameter ALU_OP_WIDTH = 6;

parameter ALU_ADD   = 6'b011000;
parameter ALU_SUB   = 6'b011001;
parameter ALU_ADDU  = 6'b011010;
parameter ALU_SUBU  = 6'b011011;
parameter ALU_ADDR  = 6'b011100;
parameter ALU_SUBR  = 6'b011101;
parameter ALU_ADDUR = 6'b011110;
parameter ALU_SUBUR = 6'b011111;

parameter ALU_XOR   = 6'b101111;
parameter ALU_OR    = 6'b101110;
parameter ALU_AND   = 6'b010101;


parameter ALU_SRA   = 6'b100100;
parameter ALU_SRL   = 6'b100101;
parameter ALU_ROR   = 6'b100110;
parameter ALU_SLL   = 6'b100111;


parameter ALU_BEXT  = 6'b101000;
parameter ALU_BEXTU = 6'b101001;
parameter ALU_BINS  = 6'b101010;
parameter ALU_BCLR  = 6'b101011;
parameter ALU_BSET  = 6'b101100;


parameter ALU_FF1   = 6'b110110;
parameter ALU_FL1   = 6'b110111;
parameter ALU_CNT   = 6'b110100;
parameter ALU_CLB   = 6'b110101;


parameter ALU_EXTS  = 6'b111110;
parameter ALU_EXT   = 6'b111111;


parameter ALU_LTS   = 6'b000000;
parameter ALU_LTU   = 6'b000001;
parameter ALU_LES   = 6'b000100;
parameter ALU_LEU   = 6'b000101;
parameter ALU_GTS   = 6'b001000;
parameter ALU_GTU   = 6'b001001;
parameter ALU_GES   = 6'b001010;
parameter ALU_GEU   = 6'b001011;
parameter ALU_EQ    = 6'b001100;
parameter ALU_NE    = 6'b001101;


parameter ALU_SLTS  = 6'b000010;
parameter ALU_SLTU  = 6'b000011;
parameter ALU_SLETS = 6'b000110;
parameter ALU_SLETU = 6'b000111;


parameter ALU_ABS   = 6'b010100;
parameter ALU_CLIP  = 6'b010110;
parameter ALU_CLIPU = 6'b010111;


parameter ALU_INS   = 6'b101101;


parameter ALU_MIN   = 6'b010000;
parameter ALU_MINU  = 6'b010001;
parameter ALU_MAX   = 6'b010010;
parameter ALU_MAXU  = 6'b010011;


parameter ALU_DIVU  = 6'b110000;
parameter ALU_DIV   = 6'b110001;
parameter ALU_REMU  = 6'b110010;
parameter ALU_REM   = 6'b110011;

parameter ALU_SHUF  = 6'b111010;
parameter ALU_SHUF2 = 6'b111011;
parameter ALU_PCKLO = 6'b111000;
parameter ALU_PCKHI = 6'b111001;


parameter MD_OP_MULL  = 2'b00;
parameter MD_OP_MULH  = 2'b01;
parameter MD_OP_DIV   = 2'b10;
parameter MD_OP_REM   = 2'b11;


parameter VEC_MODE32 = 2'b00;
parameter VEC_MODE16 = 2'b10;
parameter VEC_MODE8  = 2'b11;












parameter CSR_OP_NONE  = 2'b00;
parameter CSR_OP_WRITE = 2'b01;
parameter CSR_OP_SET   = 2'b10;
parameter CSR_OP_CLEAR = 2'b11;



parameter SP_DVR0       = 16'h3000;
parameter SP_DCR0       = 16'h3008;
parameter SP_DMR1       = 16'h3010;
parameter SP_DMR2       = 16'h3011;

parameter SP_DVR_MSB = 8'h00;
parameter SP_DCR_MSB = 8'h01;
parameter SP_DMR_MSB = 8'h02;
parameter SP_DSR_MSB = 8'h04;


typedef enum logic[1:0] {
  PRIV_LVL_M = 2'b11,
  PRIV_LVL_H = 2'b10,
  PRIV_LVL_S = 2'b01,
  PRIV_LVL_U = 2'b00
} PrivLvl_t;











parameter SEL_REGFILE      = 2'b00;
parameter SEL_FW_EX        = 2'b01;
parameter SEL_FW_WB        = 2'b10;
parameter SEL_MISALIGNED   = 2'b11;


parameter OP_A_REGA_OR_FWD = 3'b000;
parameter OP_A_CURRPC      = 3'b001;
parameter OP_A_IMM         = 3'b010;
parameter OP_A_REGB_OR_FWD = 3'b011;
parameter OP_A_REGC_OR_FWD = 3'b100;


parameter IMMA_Z      = 1'b0;
parameter IMMA_ZERO   = 1'b1;


parameter OP_B_REGB_OR_FWD = 3'b000;
parameter OP_B_REGC_OR_FWD = 3'b001;
parameter OP_B_IMM         = 3'b010;
parameter OP_B_REGA_OR_FWD = 3'b011;
parameter OP_B_BMASK       = 3'b100;
parameter OP_B_ZERO        = 3'b101;


parameter IMMB_I      = 4'b0000;
parameter IMMB_S      = 4'b0001;
parameter IMMB_U      = 4'b0010;
parameter IMMB_PCINCR = 4'b0011;
parameter IMMB_S2     = 4'b0100;
parameter IMMB_S3     = 4'b0101;
parameter IMMB_VS     = 4'b0110;
parameter IMMB_VU     = 4'b0111;
parameter IMMB_SHUF   = 4'b1000;
parameter IMMB_CLIP   = 4'b1001;
parameter IMMB_BI     = 4'b1011;
parameter IMMB_UJ	  = 4'b1100;
parameter IMMB_SB	  = 4'b1101;


parameter BMASK_A_ZERO = 1'b0;
parameter BMASK_A_S3   = 1'b1;

parameter BMASK_B_S2   = 2'b00;
parameter BMASK_B_S3   = 2'b01;
parameter BMASK_B_ZERO = 2'b10;
parameter BMASK_B_ONE  = 2'b11;

parameter BMASK_A_REG  = 1'b0;
parameter BMASK_A_IMM  = 1'b1;
parameter BMASK_B_REG  = 1'b0;
parameter BMASK_B_IMM  = 1'b1;













parameter PC_BOOT          = 3'b000;
parameter PC_JUMP          = 3'b010;
parameter PC_EXCEPTION     = 3'b100;
parameter PC_ERET          = 3'b101;
parameter PC_DBG_NPC       = 3'b111;


parameter EXC_PC_ILLINSN   = 2'b00;
parameter EXC_PC_ECALL     = 2'b01;
parameter EXC_PC_LOAD      = 2'b10;
parameter EXC_PC_STORE     = 2'b10;
parameter EXC_PC_IRQ       = 2'b11;


parameter EXC_CAUSE_ILLEGAL_INSN = 6'h02;
parameter EXC_CAUSE_BREAKPOINT   = 6'h03;
parameter EXC_CAUSE_ECALL_MMODE  = 6'h0B;




parameter EXC_OFF_RST      = 8'h80;
parameter EXC_OFF_ILLINSN  = 8'h84;
parameter EXC_OFF_ECALL    = 8'h88;
parameter EXC_OFF_LSUERR   = 8'h8c;



parameter DBG_SETS_W = 6;

parameter DBG_SETS_IRQ    = 5;
parameter DBG_SETS_ECALL  = 4;
parameter DBG_SETS_EILL   = 3;
parameter DBG_SETS_ELSU   = 2;
parameter DBG_SETS_EBRK   = 1;
parameter DBG_SETS_SSTE   = 0;

parameter DBG_CAUSE_HALT   = 6'h1F;
	input wire clk;
	input wire rst_n;
	input wire mult_en_i;
	input wire div_en_i;
	input wire [1:0] operator_i;
	input wire [1:0] signed_mode_i;
	input wire [31:0] op_a_i;
	input wire [31:0] op_b_i;
	input wire [33:0] alu_adder_ext_i;
	input wire [31:0] alu_adder_i;
	input wire equal_to_zero;
	output reg [32:0] alu_operand_a_o;
	output reg [32:0] alu_operand_b_o;
	output reg [31:0] multdiv_result_o;
	output wire ready_o;
	reg [4:0] multdiv_state_q;
	wire [4:0] multdiv_state_n;
	reg [2:0] curr_state_q;
	reg [32:0] accum_window_q;
	wire [32:0] res_adder_l;
	wire [32:0] res_adder_h;
	reg [32:0] op_b_shift_q;
	reg [32:0] op_a_shift_q;
	wire [32:0] op_a_ext;
	wire [32:0] op_b_ext;
	wire [32:0] one_shift;
	wire [32:0] op_a_bw_pp;
	wire [32:0] op_a_bw_last_pp;
	wire [31:0] b_0;
	wire sign_a;
	wire sign_b;
	wire [32:0] next_reminder;
	wire [32:0] next_quotient;
	wire [32:0] op_remainder;
	reg [31:0] op_numerator_q;
	reg is_greater_equal;
	wire div_change_sign;
	wire rem_change_sign;
	assign res_adder_l = alu_adder_ext_i[32:0];
	assign res_adder_h = alu_adder_ext_i[33:1];
	always @(*) begin
		alu_operand_a_o = accum_window_q;
		multdiv_result_o = (div_en_i ? accum_window_q[31:0] : res_adder_l);
		case (operator_i)
			MD_OP_MULL: alu_operand_b_o = op_a_bw_pp;
			MD_OP_MULH:
				if (curr_state_q == 3'd4)
					alu_operand_b_o = op_a_bw_last_pp;
				else
					alu_operand_b_o = op_a_bw_pp;
			default:
				case (curr_state_q)
					3'd0: begin
						alu_operand_a_o = 33'b000000000000000000000000000000001;
						alu_operand_b_o = {~op_b_i, 1'b1};
					end
					3'd1: begin
						alu_operand_a_o = 33'b000000000000000000000000000000001;
						alu_operand_b_o = {~op_a_i, 1'b1};
					end
					3'd2: begin
						alu_operand_a_o = 33'b000000000000000000000000000000001;
						alu_operand_b_o = {~op_b_i, 1'b1};
					end
					3'd5: begin
						alu_operand_a_o = 33'b000000000000000000000000000000001;
						alu_operand_b_o = {~accum_window_q[31:0], 1'b1};
					end
					default: begin
						alu_operand_a_o = {accum_window_q[31:0], 1'b1};
						alu_operand_b_o = {~op_b_shift_q[31:0], 1'b1};
					end
				endcase
		endcase
	end
	always @(*)
		if ((accum_window_q[31] ^ op_b_shift_q[31]) == 0)
			is_greater_equal = res_adder_h[31] == 0;
		else
			is_greater_equal = accum_window_q[31];
	assign one_shift = 33'b000000000000000000000000000000001 << multdiv_state_q;
	assign next_reminder = (is_greater_equal ? res_adder_h : op_remainder);
	assign next_quotient = (is_greater_equal ? op_a_shift_q | one_shift : op_a_shift_q);
	assign b_0 = {32 {op_b_shift_q[0]}};
	assign op_a_bw_pp = {~(op_a_shift_q[32] & op_b_shift_q[0]), op_a_shift_q[31:0] & b_0};
	assign op_a_bw_last_pp = {op_a_shift_q[32] & op_b_shift_q[0], ~(op_a_shift_q[31:0] & b_0)};
	assign sign_a = op_a_i[31] & signed_mode_i[0];
	assign sign_b = op_b_i[31] & signed_mode_i[1];
	assign op_a_ext = {sign_a, op_a_i};
	assign op_b_ext = {sign_b, op_b_i};
	assign op_remainder = accum_window_q[32:0];
	assign multdiv_state_n = multdiv_state_q - 1;
	assign div_change_sign = sign_a ^ sign_b;
	assign rem_change_sign = sign_a;
	always @(posedge clk or negedge rst_n) begin : proc_multdiv_state_q
		if (~rst_n) begin
			multdiv_state_q <= 1'sb0;
			accum_window_q <= 1'sb0;
			op_b_shift_q <= 1'sb0;
			op_a_shift_q <= 1'sb0;
			curr_state_q <= 3'd0;
			op_numerator_q <= 1'sb0;
		end
		else if (mult_en_i | div_en_i)
			case (curr_state_q)
				3'd0: begin
					case (operator_i)
						MD_OP_MULL: begin
							op_a_shift_q <= op_a_ext << 1;
							accum_window_q <= {~(op_a_ext[32] & op_b_i[0]), op_a_ext[31:0] & {32 {op_b_i[0]}}};
							op_b_shift_q <= op_b_ext >> 1;
							curr_state_q <= 3'd3;
						end
						MD_OP_MULH: begin
							op_a_shift_q <= op_a_ext;
							accum_window_q <= {1'b1, ~(op_a_ext[32] & op_b_i[0]), op_a_ext[31:1] & {31 {op_b_i[0]}}};
							op_b_shift_q <= op_b_ext >> 1;
							curr_state_q <= 3'd3;
						end
						MD_OP_DIV: begin
							accum_window_q <= 1'sb1;
							curr_state_q <= (equal_to_zero ? 3'd6 : 3'd1);
						end
						default: begin
							accum_window_q <= op_a_ext;
							curr_state_q <= (equal_to_zero ? 3'd6 : 3'd1);
						end
					endcase
					multdiv_state_q <= 5'd31;
				end
				3'd1: begin
					op_a_shift_q <= 1'sb0;
					op_numerator_q <= (sign_a ? alu_adder_i : op_a_i);
					curr_state_q <= 3'd2;
				end
				3'd2: begin
					accum_window_q <= {32'h00000000, op_numerator_q[31]};
					op_b_shift_q <= (sign_b ? alu_adder_i : op_b_i);
					curr_state_q <= 3'd3;
				end
				3'd3: begin
					multdiv_state_q <= multdiv_state_n;
					case (operator_i)
						MD_OP_MULL: begin
							accum_window_q <= res_adder_l;
							op_a_shift_q <= op_a_shift_q << 1;
							op_b_shift_q <= op_b_shift_q >> 1;
						end
						MD_OP_MULH: begin
							accum_window_q <= res_adder_h;
							op_a_shift_q <= op_a_shift_q;
							op_b_shift_q <= op_b_shift_q >> 1;
						end
						default: begin
							accum_window_q <= {next_reminder[31:0], op_numerator_q[multdiv_state_n]};
							op_a_shift_q <= next_quotient;
						end
					endcase
					if (multdiv_state_q == 5'd1)
						curr_state_q <= 3'd4;
					else
						curr_state_q <= 3'd3;
				end
				3'd4:
					case (operator_i)
						MD_OP_MULL: begin
							accum_window_q <= res_adder_l;
							curr_state_q <= 3'd0;
						end
						MD_OP_MULH: begin
							accum_window_q <= res_adder_l;
							curr_state_q <= 3'd0;
						end
						MD_OP_DIV: begin
							accum_window_q <= next_quotient;
							curr_state_q <= 3'd5;
						end
						default: begin
							accum_window_q <= {1'b0, next_reminder[31:0]};
							curr_state_q <= 3'd5;
						end
					endcase
				3'd5: begin
					curr_state_q <= 3'd6;
					case (operator_i)
						MD_OP_DIV: accum_window_q <= (div_change_sign ? alu_adder_i : accum_window_q);
						default: accum_window_q <= (rem_change_sign ? alu_adder_i : accum_window_q);
					endcase
				end
				3'd6: curr_state_q <= 3'd0;
				default:
					;
			endcase
	end
	assign ready_o = (curr_state_q == 3'd6) | ((curr_state_q == 3'd4) & ((operator_i == MD_OP_MULL) | (operator_i == MD_OP_MULH)));
endmodule
module zeroriscy_multdiv_slow (
	clk,
	rst_n,
	mult_en_i,
	div_en_i,
	operator_i,
	signed_mode_i,
	op_a_i,
	op_b_i,
	alu_adder_ext_i,
	alu_adder_i,
	equal_to_zero,
	alu_operand_a_o,
	alu_operand_b_o,
	multdiv_result_o,
	ready_o
);

parameter OPCODE_SYSTEM    = 7'h73;
parameter OPCODE_FENCE     = 7'h0f;
parameter OPCODE_OP        = 7'h33;
parameter OPCODE_OPIMM     = 7'h13;
parameter OPCODE_STORE     = 7'h23;
parameter OPCODE_LOAD      = 7'h03;
parameter OPCODE_BRANCH    = 7'h63;
parameter OPCODE_JALR      = 7'h67;
parameter OPCODE_JAL       = 7'h6f;
parameter OPCODE_AUIPC     = 7'h17;
parameter OPCODE_LUI       = 7'h37;






parameter OPCODE_LOAD_POST  = 7'h0b;
parameter OPCODE_STORE_POST = 7'h2b;
parameter OPCODE_PULP_OP    = 7'h5b;
parameter OPCODE_VECOP      = 7'h57;
parameter OPCODE_HWLOOP     = 7'h7b;

parameter REGC_S1   = 2'b10;
parameter REGC_RD   = 2'b01;
parameter REGC_ZERO = 2'b11;











parameter ALU_OP_WIDTH = 6;

parameter ALU_ADD   = 6'b011000;
parameter ALU_SUB   = 6'b011001;
parameter ALU_ADDU  = 6'b011010;
parameter ALU_SUBU  = 6'b011011;
parameter ALU_ADDR  = 6'b011100;
parameter ALU_SUBR  = 6'b011101;
parameter ALU_ADDUR = 6'b011110;
parameter ALU_SUBUR = 6'b011111;

parameter ALU_XOR   = 6'b101111;
parameter ALU_OR    = 6'b101110;
parameter ALU_AND   = 6'b010101;


parameter ALU_SRA   = 6'b100100;
parameter ALU_SRL   = 6'b100101;
parameter ALU_ROR   = 6'b100110;
parameter ALU_SLL   = 6'b100111;


parameter ALU_BEXT  = 6'b101000;
parameter ALU_BEXTU = 6'b101001;
parameter ALU_BINS  = 6'b101010;
parameter ALU_BCLR  = 6'b101011;
parameter ALU_BSET  = 6'b101100;


parameter ALU_FF1   = 6'b110110;
parameter ALU_FL1   = 6'b110111;
parameter ALU_CNT   = 6'b110100;
parameter ALU_CLB   = 6'b110101;


parameter ALU_EXTS  = 6'b111110;
parameter ALU_EXT   = 6'b111111;


parameter ALU_LTS   = 6'b000000;
parameter ALU_LTU   = 6'b000001;
parameter ALU_LES   = 6'b000100;
parameter ALU_LEU   = 6'b000101;
parameter ALU_GTS   = 6'b001000;
parameter ALU_GTU   = 6'b001001;
parameter ALU_GES   = 6'b001010;
parameter ALU_GEU   = 6'b001011;
parameter ALU_EQ    = 6'b001100;
parameter ALU_NE    = 6'b001101;


parameter ALU_SLTS  = 6'b000010;
parameter ALU_SLTU  = 6'b000011;
parameter ALU_SLETS = 6'b000110;
parameter ALU_SLETU = 6'b000111;


parameter ALU_ABS   = 6'b010100;
parameter ALU_CLIP  = 6'b010110;
parameter ALU_CLIPU = 6'b010111;


parameter ALU_INS   = 6'b101101;


parameter ALU_MIN   = 6'b010000;
parameter ALU_MINU  = 6'b010001;
parameter ALU_MAX   = 6'b010010;
parameter ALU_MAXU  = 6'b010011;


parameter ALU_DIVU  = 6'b110000;
parameter ALU_DIV   = 6'b110001;
parameter ALU_REMU  = 6'b110010;
parameter ALU_REM   = 6'b110011;

parameter ALU_SHUF  = 6'b111010;
parameter ALU_SHUF2 = 6'b111011;
parameter ALU_PCKLO = 6'b111000;
parameter ALU_PCKHI = 6'b111001;


parameter MD_OP_MULL  = 2'b00;
parameter MD_OP_MULH  = 2'b01;
parameter MD_OP_DIV   = 2'b10;
parameter MD_OP_REM   = 2'b11;


parameter VEC_MODE32 = 2'b00;
parameter VEC_MODE16 = 2'b10;
parameter VEC_MODE8  = 2'b11;












parameter CSR_OP_NONE  = 2'b00;
parameter CSR_OP_WRITE = 2'b01;
parameter CSR_OP_SET   = 2'b10;
parameter CSR_OP_CLEAR = 2'b11;



parameter SP_DVR0       = 16'h3000;
parameter SP_DCR0       = 16'h3008;
parameter SP_DMR1       = 16'h3010;
parameter SP_DMR2       = 16'h3011;

parameter SP_DVR_MSB = 8'h00;
parameter SP_DCR_MSB = 8'h01;
parameter SP_DMR_MSB = 8'h02;
parameter SP_DSR_MSB = 8'h04;


typedef enum logic[1:0] {
  PRIV_LVL_M = 2'b11,
  PRIV_LVL_H = 2'b10,
  PRIV_LVL_S = 2'b01,
  PRIV_LVL_U = 2'b00
} PrivLvl_t;











parameter SEL_REGFILE      = 2'b00;
parameter SEL_FW_EX        = 2'b01;
parameter SEL_FW_WB        = 2'b10;
parameter SEL_MISALIGNED   = 2'b11;


parameter OP_A_REGA_OR_FWD = 3'b000;
parameter OP_A_CURRPC      = 3'b001;
parameter OP_A_IMM         = 3'b010;
parameter OP_A_REGB_OR_FWD = 3'b011;
parameter OP_A_REGC_OR_FWD = 3'b100;


parameter IMMA_Z      = 1'b0;
parameter IMMA_ZERO   = 1'b1;


parameter OP_B_REGB_OR_FWD = 3'b000;
parameter OP_B_REGC_OR_FWD = 3'b001;
parameter OP_B_IMM         = 3'b010;
parameter OP_B_REGA_OR_FWD = 3'b011;
parameter OP_B_BMASK       = 3'b100;
parameter OP_B_ZERO        = 3'b101;


parameter IMMB_I      = 4'b0000;
parameter IMMB_S      = 4'b0001;
parameter IMMB_U      = 4'b0010;
parameter IMMB_PCINCR = 4'b0011;
parameter IMMB_S2     = 4'b0100;
parameter IMMB_S3     = 4'b0101;
parameter IMMB_VS     = 4'b0110;
parameter IMMB_VU     = 4'b0111;
parameter IMMB_SHUF   = 4'b1000;
parameter IMMB_CLIP   = 4'b1001;
parameter IMMB_BI     = 4'b1011;
parameter IMMB_UJ	  = 4'b1100;
parameter IMMB_SB	  = 4'b1101;


parameter BMASK_A_ZERO = 1'b0;
parameter BMASK_A_S3   = 1'b1;

parameter BMASK_B_S2   = 2'b00;
parameter BMASK_B_S3   = 2'b01;
parameter BMASK_B_ZERO = 2'b10;
parameter BMASK_B_ONE  = 2'b11;

parameter BMASK_A_REG  = 1'b0;
parameter BMASK_A_IMM  = 1'b1;
parameter BMASK_B_REG  = 1'b0;
parameter BMASK_B_IMM  = 1'b1;













parameter PC_BOOT          = 3'b000;
parameter PC_JUMP          = 3'b010;
parameter PC_EXCEPTION     = 3'b100;
parameter PC_ERET          = 3'b101;
parameter PC_DBG_NPC       = 3'b111;


parameter EXC_PC_ILLINSN   = 2'b00;
parameter EXC_PC_ECALL     = 2'b01;
parameter EXC_PC_LOAD      = 2'b10;
parameter EXC_PC_STORE     = 2'b10;
parameter EXC_PC_IRQ       = 2'b11;


parameter EXC_CAUSE_ILLEGAL_INSN = 6'h02;
parameter EXC_CAUSE_BREAKPOINT   = 6'h03;
parameter EXC_CAUSE_ECALL_MMODE  = 6'h0B;




parameter EXC_OFF_RST      = 8'h80;
parameter EXC_OFF_ILLINSN  = 8'h84;
parameter EXC_OFF_ECALL    = 8'h88;
parameter EXC_OFF_LSUERR   = 8'h8c;



parameter DBG_SETS_W = 6;

parameter DBG_SETS_IRQ    = 5;
parameter DBG_SETS_ECALL  = 4;
parameter DBG_SETS_EILL   = 3;
parameter DBG_SETS_ELSU   = 2;
parameter DBG_SETS_EBRK   = 1;
parameter DBG_SETS_SSTE   = 0;

parameter DBG_CAUSE_HALT   = 6'h1F;
	input wire clk;
	input wire rst_n;
	input wire mult_en_i;
	input wire div_en_i;
	input wire [1:0] operator_i;
	input wire [1:0] signed_mode_i;
	input wire [31:0] op_a_i;
	input wire [31:0] op_b_i;
	input wire [33:0] alu_adder_ext_i;
	input wire [31:0] alu_adder_i;
	input wire equal_to_zero;
	output reg [32:0] alu_operand_a_o;
	output reg [32:0] alu_operand_b_o;
	output reg [31:0] multdiv_result_o;
	output wire ready_o;
	reg [4:0] multdiv_state_q;
	wire [4:0] multdiv_state_n;
	reg [2:0] curr_state_q;
	reg [32:0] accum_window_q;
	wire [32:0] res_adder_l;
	wire [32:0] res_adder_h;
	reg [32:0] op_b_shift_q;
	reg [32:0] op_a_shift_q;
	wire [32:0] op_a_ext;
	wire [32:0] op_b_ext;
	wire [32:0] one_shift;
	wire [32:0] op_a_bw_pp;
	wire [32:0] op_a_bw_last_pp;
	wire [31:0] b_0;
	wire sign_a;
	wire sign_b;
	wire [32:0] next_reminder;
	wire [32:0] next_quotient;
	wire [32:0] op_remainder;
	reg [31:0] op_numerator_q;
	reg is_greater_equal;
	wire div_change_sign;
	wire rem_change_sign;
	assign res_adder_l = alu_adder_ext_i[32:0];
	assign res_adder_h = alu_adder_ext_i[33:1];
	always @(*) begin
		alu_operand_a_o = accum_window_q;
		multdiv_result_o = (div_en_i ? accum_window_q[31:0] : res_adder_l);
		case (operator_i)
			MD_OP_MULL: alu_operand_b_o = op_a_bw_pp;
			MD_OP_MULH:
				if (curr_state_q == 3'd4)
					alu_operand_b_o = op_a_bw_last_pp;
				else
					alu_operand_b_o = op_a_bw_pp;
			default:
				case (curr_state_q)
					3'd0: begin
						alu_operand_a_o = 33'b000000000000000000000000000000001;
						alu_operand_b_o = {~op_b_i, 1'b1};
					end
					3'd1: begin
						alu_operand_a_o = 33'b000000000000000000000000000000001;
						alu_operand_b_o = {~op_a_i, 1'b1};
					end
					3'd2: begin
						alu_operand_a_o = 33'b000000000000000000000000000000001;
						alu_operand_b_o = {~op_b_i, 1'b1};
					end
					3'd5: begin
						alu_operand_a_o = 33'b000000000000000000000000000000001;
						alu_operand_b_o = {~accum_window_q[31:0], 1'b1};
					end
					default: begin
						alu_operand_a_o = {accum_window_q[31:0], 1'b1};
						alu_operand_b_o = {~op_b_shift_q[31:0], 1'b1};
					end
				endcase
		endcase
	end
	always @(*)
		if ((accum_window_q[31] ^ op_b_shift_q[31]) == 0)
			is_greater_equal = res_adder_h[31] == 0;
		else
			is_greater_equal = accum_window_q[31];
	assign one_shift = 33'b000000000000000000000000000000001 << multdiv_state_q;
	assign next_reminder = (is_greater_equal ? res_adder_h : op_remainder);
	assign next_quotient = (is_greater_equal ? op_a_shift_q | one_shift : op_a_shift_q);
	assign b_0 = {32 {op_b_shift_q[0]}};
	assign op_a_bw_pp = {~(op_a_shift_q[32] & op_b_shift_q[0]), op_a_shift_q[31:0] & b_0};
	assign op_a_bw_last_pp = {op_a_shift_q[32] & op_b_shift_q[0], ~(op_a_shift_q[31:0] & b_0)};
	assign sign_a = op_a_i[31] & signed_mode_i[0];
	assign sign_b = op_b_i[31] & signed_mode_i[1];
	assign op_a_ext = {sign_a, op_a_i};
	assign op_b_ext = {sign_b, op_b_i};
	assign op_remainder = accum_window_q[32:0];
	assign multdiv_state_n = multdiv_state_q - 1;
	assign div_change_sign = sign_a ^ sign_b;
	assign rem_change_sign = sign_a;
	always @(posedge clk or negedge rst_n) begin : proc_multdiv_state_q
		if (~rst_n) begin
			multdiv_state_q <= 1'sb0;
			accum_window_q <= 1'sb0;
			op_b_shift_q <= 1'sb0;
			op_a_shift_q <= 1'sb0;
			curr_state_q <= 3'd0;
			op_numerator_q <= 1'sb0;
		end
		else if (mult_en_i | div_en_i)
			case (curr_state_q)
				3'd0: begin
					case (operator_i)
						MD_OP_MULL: begin
							op_a_shift_q <= op_a_ext << 1;
							accum_window_q <= {~(op_a_ext[32] & op_b_i[0]), op_a_ext[31:0] & {32 {op_b_i[0]}}};
							op_b_shift_q <= op_b_ext >> 1;
							curr_state_q <= 3'd3;
						end
						MD_OP_MULH: begin
							op_a_shift_q <= op_a_ext;
							accum_window_q <= {1'b1, ~(op_a_ext[32] & op_b_i[0]), op_a_ext[31:1] & {31 {op_b_i[0]}}};
							op_b_shift_q <= op_b_ext >> 1;
							curr_state_q <= 3'd3;
						end
						MD_OP_DIV: begin
							accum_window_q <= 1'sb1;
							curr_state_q <= (equal_to_zero ? 3'd6 : 3'd1);
						end
						default: begin
							accum_window_q <= op_a_ext;
							curr_state_q <= (equal_to_zero ? 3'd6 : 3'd1);
						end
					endcase
					multdiv_state_q <= 5'd31;
				end
				3'd1: begin
					op_a_shift_q <= 1'sb0;
					op_numerator_q <= (sign_a ? alu_adder_i : op_a_i);
					curr_state_q <= 3'd2;
				end
				3'd2: begin
					accum_window_q <= {32'h00000000, op_numerator_q[31]};
					op_b_shift_q <= (sign_b ? alu_adder_i : op_b_i);
					curr_state_q <= 3'd3;
				end
				3'd3: begin
					multdiv_state_q <= multdiv_state_n;
					case (operator_i)
						MD_OP_MULL: begin
							accum_window_q <= res_adder_l;
							op_a_shift_q <= op_a_shift_q << 1;
							op_b_shift_q <= op_b_shift_q >> 1;
						end
						MD_OP_MULH: begin
							accum_window_q <= res_adder_h;
							op_a_shift_q <= op_a_shift_q;
							op_b_shift_q <= op_b_shift_q >> 1;
						end
						default: begin
							accum_window_q <= {next_reminder[31:0], op_numerator_q[multdiv_state_n]};
							op_a_shift_q <= next_quotient;
						end
					endcase
					if (multdiv_state_q == 5'd1)
						curr_state_q <= 3'd4;
					else
						curr_state_q <= 3'd3;
				end
				3'd4:
					case (operator_i)
						MD_OP_MULL: begin
							accum_window_q <= res_adder_l;
							curr_state_q <= 3'd0;
						end
						MD_OP_MULH: begin
							accum_window_q <= res_adder_l;
							curr_state_q <= 3'd0;
						end
						MD_OP_DIV: begin
							accum_window_q <= next_quotient;
							curr_state_q <= 3'd5;
						end
						default: begin
							accum_window_q <= {1'b0, next_reminder[31:0]};
							curr_state_q <= 3'd5;
						end
					endcase
				3'd5: begin
					curr_state_q <= 3'd6;
					case (operator_i)
						MD_OP_DIV: accum_window_q <= (div_change_sign ? alu_adder_i : accum_window_q);
						default: accum_window_q <= (rem_change_sign ? alu_adder_i : accum_window_q);
					endcase
				end
				3'd6: curr_state_q <= 3'd0;
				default:
					;
			endcase
	end
	assign ready_o = (curr_state_q == 3'd6) | ((curr_state_q == 3'd4) & ((operator_i == MD_OP_MULL) | (operator_i == MD_OP_MULH)));
endmodule