/* decoder.v - Implementation of instruction decoding logic

   This file is part of the 9086 project.

   Copyright (c) 2024 Efthymios Kritikos

   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/>.  */

`include "exec_state_def.v"
`include "alu_header.v"
`include "ucode_header.v"
`include "error_header.v"
`include "config.v"

`define DE_STATE_BITS	2
`define DE_STATE_ENTRY	2'b01
`define DE_HALT		2'b10

module decoder(
	/*****************   GENERAL   *****************/
	/* Input from sys. */  input clock, input reset
	/* Output to sys.  */ ,output reg MEM_OR_IO_LATCHED, output reg [`ERROR_BITS-1:0] ERROR_LATCHED, output reg HALT_LATCHED

	/***************  INPUT FROM IF  ***************/
	/*                 */ ,input wire [31:0] IF2DE_INSTRUCTION, input wire VALID_INSTRUCTION
	/*                 */ ,input wire [15:0] INSTRUCTION_LOCATION

	/***************  OUTPUT TO IF   ***************/
	/* OUTPUT TO IF    */ ,output reg VALID_INSTRUCTION_ACK

	/***************  INPUT FROM EX  ***************/
	/*                 */ ,input wire [7:0] EX2DE_FLAGS,input wire next_exec

	/***************  OUTPUT TO DE   ***************/
	/* SYNC SIGNALS    */ ,output reg set_initial_values, output reg valid_exec_data
	/* INSTR. PARAMS   */ ,output reg Wbit_LATCHED, output reg [2:0] IN_MOD_LATCHED, output reg [2:0] OUT_MOD_LATCHED, output reg [2:0] RM_LATCHED
	/* DATA            */ ,output reg [15:0] PARAM1_LATCHED, output reg [15:0] PARAM2_LATCHED,output reg [15:0] ProgCount
	/* STATE CONTROL   */ ,output reg [`EXEC_STATE_BITS-1:0] next_state_LATCHED
        /* ALU CONTROL     */ ,output reg [1:0] in_alu_sel1_LATCHED, output reg [1:0] in_alu_sel2_LATCHED,output reg [2:0] ALU_OP_LATCHED
	/* OTHER           */ ,output reg memio_address_select_LATCHED

	/************* OUTPUT TO REGISTERS  ************/
	/*                 */ ,output reg [3:0] reg_write_addr_LATCHED, output reg [3:0] reg_read_port2_addr_LATCHED, output reg [3:0] reg_read_port1_addr_LATCHED

`ifdef CALCULATE_IPC
	/*  STATISTICS     */ ,output reg new_instruction
`endif

);

reg SIMPLE_MICRO; /* use simple decodings (=0) or microcode data (=1) */
wire [`UCODE_ADDR_BITS-1:0] ucode_seq_addr_entry;
reg [`UCODE_ADDR_BITS-1:0] ucode_seq_addr;
/* verilator lint_off UNUSEDSIGNAL */
wire DEPENDS_ON_PREVIOUS;
/* verilator lint_on UNUSEDSIGNAL */
wire set_params;

wire MEM_OR_IO, HALT,Wbit,memio_address_select;
wire [1:0] in_alu_sel1,in_alu_sel2;
wire [2:0] IN_MOD,OUT_MOD,RM,ALU_OP;
wire [3:0] reg_write_addr,reg_read_port2_addr,reg_read_port1_addr;
wire [15:0] PARAM1,PARAM2;
wire [`EXEC_STATE_BITS-1:0] next_state;
wire [`ERROR_BITS-1:0] ERROR;

instruction_decode instruction_decode(
	/*   INPUT   */  IF2DE_INSTRUCTION,{8'h0,EX2DE_FLAGS}, clock
	/* MICROCODE */ ,ucode_seq_addr_entry,SIMPLE_MICRO,ucode_seq_addr
	/*   OUTPUT  */ ,DEPENDS_ON_PREVIOUS, set_params, MEM_OR_IO,ERROR, HALT

	/***************  INPUT FROM DE  ***************/
	/* INSTR. PARAMS  */ ,Wbit, IN_MOD, OUT_MOD, RM
	/* DATA           */ ,PARAM1, PARAM2
	/* STATE CONTROL  */ ,next_state
        /* ALU CONTROL    */ ,in_alu_sel1,in_alu_sel2, ALU_OP
	/* OTHER          */ ,memio_address_select

	/*****************  REGISTERS  *****************/
	/*                */ ,reg_write_addr, reg_read_port2_addr, reg_read_port1_addr
);



wire [2:0] instr_end;
InstrSize InstrSize({IF2DE_INSTRUCTION[31:24],IF2DE_INSTRUCTION[21:19]},instr_end);

reg owe_set_init;

reg [1:0] wait_;

always @(posedge clock)begin
	if(reset==0)begin
		`ifdef CALCULATE_IPC
		new_instruction<=0;
		`endif
		valid_exec_data<=0;
		ucode_seq_addr <= `UCODE_NO_INSTRUCTION;
		SIMPLE_MICRO <= 0;
		owe_set_init <= 0;
		set_initial_values<=0;
		first_ucode <= 0;
		HALT_LATCHED <= 0;
		ERROR_LATCHED <= `ERROR_BITS'h0;
		VALID_INSTRUCTION_ACK <= 0;
		wait_<=0;
	end else begin
		if(wait_==2) begin
				//`define LATCH(VAR) VAR_LATCHED <= VAR; //TODO would this work?
				IN_MOD_LATCHED <= IN_MOD;
				OUT_MOD_LATCHED <= OUT_MOD;
				RM_LATCHED <= RM;
				MEM_OR_IO_LATCHED <= MEM_OR_IO;
				PARAM1_LATCHED <= PARAM1;
				PARAM2_LATCHED <= PARAM2;
				ALU_OP_LATCHED <= ALU_OP;
				in_alu_sel1_LATCHED <= in_alu_sel1;
				in_alu_sel2_LATCHED <= in_alu_sel2;
				reg_read_port1_addr_LATCHED <= reg_read_port1_addr;
				reg_read_port2_addr_LATCHED <= reg_read_port2_addr;
				reg_write_addr_LATCHED <= reg_write_addr;
				Wbit_LATCHED <= Wbit;
				ERROR_LATCHED <= ERROR;
				HALT_LATCHED <= HALT;
				next_state_LATCHED <= next_state;
				memio_address_select_LATCHED <= memio_address_select;

				if ( (ucode_seq_addr==`UCODE_NO_INSTRUCTION) && (ucode_seq_addr_entry!=`UCODE_NO_INSTRUCTION) )begin
					/* switch to microcode decoding */
					ucode_seq_addr <= ucode_seq_addr_entry;
					SIMPLE_MICRO <= 1;
					first_ucode <= 1;
					set_initial_values <= 1;
					valid_exec_data <= 0;
					wait_<=1;
				end else begin
					if(SIMPLE_MICRO==0||first_ucode==1||owe_set_init==1)begin
						first_ucode <= 0;
						/* This runs at the start of the execution of an 8086 instruction */
						`ifdef DEBUG_PC_ADDRESS
							$display("Running command at %04x (%08x)",INSTRUCTION_LOCATION,IF2DE_INSTRUCTION);
						`endif
						`ifdef CALCULATE_IPC
							new_instruction <= !new_instruction;
						`endif
						owe_set_init<=0;
						ProgCount <= INSTRUCTION_LOCATION+{12'b0,instr_end};
						VALID_INSTRUCTION_ACK <= 1;
					end
					if(set_params)begin
						set_initial_values <= 1;
					end
					/* This runs at the start of each execution cycle, with microcode this is more than once per 8086 instruction */
					valid_exec_data<=1;
					wait_<=1;
					if( SIMPLE_MICRO == 1 ) begin
						ucode_seq_addr <= ucode_seq_addr_entry; /*Reused for next address*/
						if( ucode_seq_addr_entry == `UCODE_NO_INSTRUCTION )begin
							/*Finished microcode*/
							SIMPLE_MICRO <= 0;
						end
					end
				end
		end else if(wait_!=0) begin
			set_initial_values <= 0;
			wait_<=0;
			VALID_INSTRUCTION_ACK<=0;
		end else if(next_exec==1'b1)begin
			if ( ( VALID_INSTRUCTION == 1 || SIMPLE_MICRO == 1 ) /*&& DEPENDS_ON_PREVIOUS == 0 && ucode_seq_addr_entry==`UCODE_NO_INSTRUCTION*/) begin
				wait_<=2;
			end else
				valid_exec_data<=0;
		end else
			valid_exec_data<=0;
	end
end

reg first_ucode;

endmodule


/////////////////////////  Instruction specific decoding  ///////////////////////////////////


module microcode(
	 input [`UCODE_ADDR_BITS-1:0] ADDR
	,output [`UCODE_DATA_BITS-1:0] DATA
);

initial begin
`ifndef YOSYS
	string ucode_path;
	if($value$plusargs("MICROCODE=%s",ucode_path))begin
		$readmemb(ucode_path,ucode_rom,0,`UCODE_SIZE-1);
	end else begin
		$display("Please supply microcode rom file as a runtime vvp argument +MICROCODE=<path>");
		$finish;
	end
`else
	//TODO: don't have it hard coded
	$readmemb("simplified_ucode.txt",ucode_rom,0,`UCODE_SIZE-1);
`endif
end

reg [`UCODE_DATA_BITS-1:0] ucode_rom [ 0:`UCODE_SIZE-1 ];

assign DATA=ucode_rom[ADDR];

endmodule

module instruction_decode(
/* verilator lint_off UNUSEDSIGNAL */
	/*   INPUTS       */  input wire [31:0] INSTRUCTION,input wire [15:0] FLAGS,input clock
/* verilator lint_on UNUSEDSIGNAL */
	/* MICROCODE      */ ,output reg [`UCODE_ADDR_BITS-1:0] seq_addr_entry, input wire SIMPLE_MICRO, input wire [`UCODE_ADDR_BITS-1:0] seq_addr_input
	/*   OUTPUT       */ ,output reg DEPENDS_ON_PREVIOUS, output reg set_params,output reg MEM_OR_IO, output reg [`ERROR_BITS-1:0] ERROR, output reg HALT

	/***************  INPUT FROM DE  ***************/
	/* INSTR. PARAMS  */ ,output reg Wbit, output reg [2:0] IN_MOD, output reg [2:0] OUT_MOD, output reg [2:0] RM
	/* DATA           */ ,output reg [15:0] PARAM1, output reg [15:0] PARAM2
	/* STATE CONTROL  */ ,output reg [`EXEC_STATE_BITS-1:0] next_state
        /* ALU CONTROL    */ ,output reg [1:0] in_alu_sel1, output reg [1:0] in_alu_sel2,output reg [2:0] ALU_OP
	/* OTHER          */ ,output reg memio_address_select

	/*****************  REGISTERS  *****************/
	/*                */ ,output reg [3:0]  reg_write_addr, output reg [3:0]  reg_read_port2_addr, output reg [3:0]  reg_read_port1_addr
);

/* DEPENDS_ON_PREVIOUS -  This encodes weather the instruction requires the previous to be finished in order to be decoded. This, for example, affects
 *                        conditional jumps since flags are checked during decode.
*/

/* verilator lint_off UNUSEDSIGNAL */
wire [`UCODE_DATA_BITS-1:0] ucode_data;
/* verilator lint_on UNUSEDSIGNAL */

microcode ucode(seq_addr_input,ucode_data);

`define invalid_instruction next_state=`EXEC_WAIT;ERROR<=`ERR_UNIMPL_INSTRUCTION;HALT<=0;IN_MOD=3'b011;seq_addr_entry<=`UCODE_NO_INSTRUCTION;opcode_size=0;DEPENDS_ON_PREVIOUS<=0;
`define unimpl_addressing_mode next_state=`EXEC_WAIT;ERROR <= `ERR_UNIMPL_ADDRESSING_MODE;HALT<=0;IN_MOD=3'b011;seq_addr_entry<=`UCODE_NO_INSTRUCTION;
`define normal_instruction seq_addr_entry<=`UCODE_NO_INSTRUCTION;ERROR<=`ERR_NO_ERROR;HALT<=0;MEM_OR_IO<=0;
`define normal_microcoded  ERROR<=`ERR_NO_ERROR;HALT<=0;MEM_OR_IO<=0;

reg [1:0] PARAM_ACTION;
`define NO_LOAD 2'b00
`define LOAD_8  2'b01
`define LOAD_16 2'b10

reg Sbit,opcode_size;

// I use blocking for basically putting names on the different fields of INSTRUCTION and
// then branching off of that instead of the raw bits. otherwise the code
// would be identical
/* verilator lint_off BLKSEQ */
always @( posedge clock ) begin
	set_params = 1;
	PARAM_ACTION = `NO_LOAD;
	Sbit=0;//TODO: If no Sbit we assume it's 0,right?
	if (SIMPLE_MICRO==0)begin
		casez({INSTRUCTION[31:24],INSTRUCTION[21:19]})
			11'b0000_010?_??? : begin
				/*     ADD - Add Immediate word/byte to accumulator       */
				/* 0 0 0 0  0 1 0 W |       DATA       |     DATA if W   |*/
				opcode_size=0;
				Wbit=INSTRUCTION[24:24];
				Sbit=0;
				IN_MOD=3'b011;
				in_alu_sel1=2'b00;
				in_alu_sel2=2'b01;
				OUT_MOD=3'b011;
				MEM_OR_IO<=0;
				reg_read_port2_addr<={Wbit,3'b000};
				reg_write_addr<={Wbit,3'b000};
				ALU_OP<=`ALU_OP_ADD;
				memio_address_select=0;
				if(Wbit)
					PARAM_ACTION=`LOAD_16;
				else
					PARAM_ACTION=`LOAD_8;
				DEPENDS_ON_PREVIOUS<=0;
				`normal_instruction
			end
			11'b1000_00??_101, /* SUB */
				11'b1000_00??_000 : /* ADD */ begin
				/*                                  ADD - Add Immediate word/byte to register/memory                                      */
				/* 1 0 0 0  0 0 S W | MOD 0 0  0  R/M  |     < DISP LO >  |     < DISP HI >   |      DATA        |      DATA if W    |    */
				/*                                  SUB - Subtract immediate word/byte from register/memory                               */
				/* 1 0 0 0  0 0 S W | MOD 1 0  1  R/M  |     < DISP LO >  |     < DISP HI >   |      DATA        |      DATA if W    |    */
				opcode_size=1;
				Wbit=INSTRUCTION[24:24];
				Sbit=INSTRUCTION[25:25];
				IN_MOD={1'b0,INSTRUCTION[23:22]};
				RM=INSTRUCTION[18:16];
				in_alu_sel1=2'b00;
				if(IN_MOD==3'b011)begin
					in_alu_sel2=2'b01;
					reg_read_port2_addr<={Wbit,RM};
					reg_write_addr<={Wbit,RM};
				end else begin
					in_alu_sel2=2'b00;
				end
				OUT_MOD=IN_MOD;
				MEM_OR_IO<=0;
				memio_address_select=0;
				case({Sbit,Wbit}) // TODO: Isn't this supposed to be just a LOAD_8?
					2'b00,2'b11:begin
						PARAM_ACTION=`LOAD_8;
					end
					2'b01:begin
						PARAM_ACTION=`LOAD_16;
					end
					default:begin
						`invalid_instruction
					end
				endcase
				case(INSTRUCTION[21:19])
					3'b000: ALU_OP<=`ALU_OP_ADD;
					3'b101: ALU_OP<=`ALU_OP_SUB_REVERSE;
					default:begin
						/*Should be impossible*/
						`invalid_instruction
					end
				endcase
				DEPENDS_ON_PREVIOUS<=0;
				`normal_instruction
			end
			11'b1000_00??_111 : begin
				/*                                  CMP - compare Immediate with register / memory                                        */
				/* 1 0 0 0  0 0 S W | MOD 1 1  1  R/M  |     < DISP LO >  |     < DISP HI >   |      DATA        |      DATA if W    |    */
				opcode_size=1;
				Wbit=INSTRUCTION[24:24];
				Sbit=INSTRUCTION[25:25];
				IN_MOD={1'b0,INSTRUCTION[23:22]};
				RM=INSTRUCTION[18:16];
				if ( {Sbit,Wbit} == 2'b10 )begin
					`invalid_instruction
				end
				in_alu_sel1=2'b00;
				OUT_MOD=3'b100;
				MEM_OR_IO<=0;
				ALU_OP<=`ALU_OP_SUB_REVERSE;
				memio_address_select=0;
				if(IN_MOD==3'b011)begin
					/*compare register with param*/
					in_alu_sel2=2'b01;
					reg_read_port2_addr<={Wbit,RM};
					next_state=`EXEC_WRITE_ENTRY;
				end else begin
					/*compare register indirect access
					* with param */
					in_alu_sel2=2'b00;
					next_state=`EXEC_MEMIO_READ;
					/*will call MEMIO_READ after EXEC_DE_LOAD..*/
				end
				if(Wbit)
					PARAM_ACTION=`LOAD_16;
				else
					PARAM_ACTION=`LOAD_8;
				DEPENDS_ON_PREVIOUS<=0;
				`normal_instruction
			end
			11'b1011_????_??? : begin
				/*        MOV - Move Immediate byte to register            */
				/* 1 0 1 1  W  REG  |       DATA       |     DATA if W    |*/
				Wbit=INSTRUCTION[27:27]; /* IS 0 */
				opcode_size=0;
				IN_MOD=3'b011;
				in_alu_sel1=2'b00;
				in_alu_sel2=2'b00;
				OUT_MOD=3'b011;
				MEM_OR_IO<=0;
				reg_write_addr<={Wbit,INSTRUCTION[26:24]};
				if(Wbit)
					PARAM_ACTION=`LOAD_16;
				else
					PARAM_ACTION=`LOAD_8;
				PARAM2=0;
				ALU_OP<=`ALU_OP_ADD;
				next_state=`EXEC_WRITE_ENTRY;
				`normal_instruction
				DEPENDS_ON_PREVIOUS<=0;
				memio_address_select=0;
			end
			11'b1000_10??_??? : begin
				/*                      MOV - Reg/Mem to/from register                        */
				/* 1 0 0 0  1 0 D W | MOD   REG    RM  |    < DISP LO >   |    < DISP HI >   |*/
				opcode_size=1;
				RM=INSTRUCTION[18:16];
				Wbit=INSTRUCTION[24:24];
				in_alu_sel1=2'b00;
				PARAM1<=0;
				MEM_OR_IO<=0;
				if(INSTRUCTION[25:25] == 1)begin
					/* Mem/Reg to reg */
					IN_MOD={1'b0,INSTRUCTION[23:22]};
					if(IN_MOD==3'b011)begin
						/*Reg to Reg*/
						in_alu_sel2=2'b01;
						reg_read_port2_addr<={Wbit,RM};
						next_state=`EXEC_WRITE_ENTRY;
					end else begin
						/*Mem to Reg*/
						in_alu_sel2=2'b00;
						next_state=`EXEC_MEMIO_READ;
					end
					OUT_MOD=3'b011;
					reg_write_addr<={Wbit,INSTRUCTION[21:19]};
				end else begin
					/* Reg to Mem/Reg */
					IN_MOD=3'b011;
					OUT_MOD={1'b0,INSTRUCTION[23:22]};
					if(IN_MOD==3'b011)begin
						/*Reg to Reg*/
						in_alu_sel2=2'b01;
						reg_write_addr<={Wbit,RM};
						next_state=`EXEC_WRITE_ENTRY;
					end else begin
						/*Reg to Mem*/
						in_alu_sel2=2'b00;
						next_state=`EXEC_DE_LOAD_REG_TO_PARAM;
					end
					reg_read_port2_addr<={Wbit,INSTRUCTION[21:19]};
				end
				ALU_OP<=`ALU_OP_ADD;

				`normal_instruction
				DEPENDS_ON_PREVIOUS<=0;
				memio_address_select=0;
			end
			11'b0100_????_???:begin//DEC
				/* DEC - Decrement Register */
				/*   | 0 1 0 0  1  REG  |   */
				/* INC - Increment Register */
				/*   | 0 1 0 0  0  REG  |   */
				opcode_size=0;
				Wbit=1;
				in_alu_sel1=2'b01;
				in_alu_sel2=2'b00;
				OUT_MOD=3'b011;
				MEM_OR_IO<=0;
				IN_MOD=3'b011;
				PARAM2=1;
				reg_read_port1_addr<={1'b1,INSTRUCTION[26:24]};
				reg_write_addr<={1'b1,INSTRUCTION[26:24]};
				if(INSTRUCTION[27:27]==0)
					ALU_OP<=`ALU_OP_ADD;
				else
					ALU_OP<=`ALU_OP_SUB;
				next_state=`EXEC_WRITE_ENTRY;
				`normal_instruction
				DEPENDS_ON_PREVIOUS<=0;
				memio_address_select=0;
			end
			11'b1111_111?_00? : begin
				/*                          INC - Register/Memory                            */
				/* 1 1 1 1  1 1 1 W | MOD 0 0  0  R/M  |    < DISP LO>    |    < DISP HI>    */
				/*                          DEC - Register/Memory                            */
				/* 1 1 1 1  1 1 1 W | MOD 0 0  1  R/M  |    < DISP LO>    |    < DISP HI>    */
				opcode_size=1;
				Wbit=INSTRUCTION[24:24];
				IN_MOD={1'b0,INSTRUCTION[23:22]};
				RM=INSTRUCTION[18:16];
				in_alu_sel2=(IN_MOD==3'b011)? 2'b01 : 2'b00;
				in_alu_sel1=2'b00;/* number 1 */
				PARAM1<=16'd1;
				OUT_MOD=IN_MOD;
				MEM_OR_IO<=0;

				/*in case IN_MOD=011 */
				reg_read_port2_addr<={1'b0,RM};
				reg_write_addr<={1'b0,RM};

				ALU_OP<=(INSTRUCTION[19:19]==1)?`ALU_OP_SUB_REVERSE:`ALU_OP_ADD;
				if ( IN_MOD == 3'b011 )
					next_state=`EXEC_WRITE_ENTRY;
				else
					next_state=`EXEC_MEMIO_READ;
				`normal_instruction
				DEPENDS_ON_PREVIOUS<=0;
				memio_address_select=0;
			end
			11'b1111_0100_??? : begin
				/*     HLT - Halt     */
				/* 1 1 1 1  0 1 0 0 | */
				IN_MOD=3'b011;
				HALT<=1;
				ERROR<=`ERR_NO_ERROR;
				MEM_OR_IO<=0;
				seq_addr_entry<=`UCODE_NO_INSTRUCTION;

				opcode_size=0;
				Wbit=1;
				in_alu_sel1=2'b10;
				in_alu_sel2=2'b00;
				PARAM2=16'hFFFF;
				ALU_OP<=`ALU_OP_ADD_SIGNED_B;
				OUT_MOD=3'b101;
				MEM_OR_IO<=0;
				next_state=`EXEC_WRITE_ENTRY;
				DEPENDS_ON_PREVIOUS<=0;
				memio_address_select=0;
			end
			11'b0011_110?_??? : begin
				/*         CMP - Compare Immediate with accumulator        */
				/* 0 0 1 1  1 1 0 W |       DATA       |     DATA if W    |*/
				/*                                                         */
				/* NOTE: 8086 doc doesn't show the third byte but the      */
				/* W flag and my assembler seem to disagree                */
				Wbit=INSTRUCTION[24:24];
				opcode_size=0;
				IN_MOD=3'b011;
				in_alu_sel1=2'b00;
				in_alu_sel2=2'b01;
				reg_read_port2_addr<={Wbit,3'b000};
				OUT_MOD=3'b100;
				ALU_OP<=`ALU_OP_SUB_REVERSE;
				MEM_OR_IO<=0;
				if(Wbit==1)
					PARAM_ACTION=`LOAD_16;
				else begin
					PARAM_ACTION=`LOAD_8;
				end
				next_state=`EXEC_WRITE_ENTRY;
				`normal_instruction
				DEPENDS_ON_PREVIOUS<=0;
				memio_address_select=0;
			end
			11'b0111_????_???:begin
				/*     Conditional relative jumps       */
				/*        JE/JZ - Jump on Zero          */
				/* 0 1 1 1  0 1 0 0 |     IP-INC8      |*/
				/*         JS - Jump on Sign            */
				/* 0 1 1 1  1 0 0 0 |     IP-INC8      |*/
				/*       JNS -Jump on not Sign          */
				/* 0 1 1 1  1 0 0 1 |     IP-INC8      |*/
				/*                ....                  */
				Wbit=1;
				opcode_size=0;
				in_alu_sel1=2'b10;
				in_alu_sel2=2'b00;
				PARAM2={{8{INSTRUCTION[23:23]}},INSTRUCTION[23:16]};
				ALU_OP<=`ALU_OP_ADD_SIGNED_B;
				MEM_OR_IO<=0;
				OUT_MOD=3'b101;
				case(INSTRUCTION[27:25])
					3'b000: begin
						/* Jump on (not) Overflow */
						if(FLAGS[11:11]==INSTRUCTION[24:24])
							next_state=`EXEC_NEXT_INSTRUCTION;
						else begin
							next_state=`EXEC_WRITE_ENTRY;
						end
						`normal_instruction
					end
					3'b010: begin
						/* Jump on (not) Zero */
						if(FLAGS[6:6]==INSTRUCTION[24:24])
							next_state=`EXEC_NEXT_INSTRUCTION;
						else
							next_state=`EXEC_WRITE_ENTRY;
						`normal_instruction
					end
					3'b100: begin
						/* Jump on (not) Sign */
						if(FLAGS[7:7]==INSTRUCTION[24:24])
							next_state=`EXEC_NEXT_INSTRUCTION;
						else
							next_state=`EXEC_WRITE_ENTRY;
						`normal_instruction
					end
					3'b101: begin
						/* Jump on (not) Parity */
						if(FLAGS[2:2]==INSTRUCTION[24:24])
							next_state=`EXEC_NEXT_INSTRUCTION;
						else
							next_state=`EXEC_WRITE_ENTRY;
						`normal_instruction
					end
					3'b001: begin
						/* Jump on (not) Carry */
						if(FLAGS[0:0]==INSTRUCTION[24:24])
							next_state=`EXEC_NEXT_INSTRUCTION;
						else
							next_state=`EXEC_WRITE_ENTRY;
						`normal_instruction
					end
					default:begin
						`invalid_instruction /*We don't support that condition*/
					end
				endcase
				DEPENDS_ON_PREVIOUS<=1;
				memio_address_select=0;
			end
			11'b1110_1011_???:begin
				/* JMP - Unconditional jump direct within segment (short) */
				/*        | 1 1 1 0  1 0 1 1 |     IP-INC-LO    |         */
				opcode_size=0;
				Wbit=1;
				in_alu_sel1=2'b10;
				in_alu_sel2=2'b00;
				PARAM2={{8{INSTRUCTION[23:23]}},INSTRUCTION[23:16]};
				ALU_OP<=`ALU_OP_ADD_SIGNED_B;
				OUT_MOD=3'b101;
				MEM_OR_IO<=0;
				next_state=`EXEC_WRITE_ENTRY;
				`normal_instruction
				DEPENDS_ON_PREVIOUS<=0;
				memio_address_select=0;
			end
			11'b1110_1000_???:begin
				/*            CALL - Direct call within segment            */
				/* 1 1 1 0  1 0 0 0 |    IP-INC-LO     |    IP-INC-HI     |*/

				// Microcode instruction
				opcode_size=0;
				Wbit=1;
				Sbit=1;
				PARAM2=2; //subtract from sp
				seq_addr_entry<=`UCODE_CALL_ENTRY;
				`normal_microcoded
				DEPENDS_ON_PREVIOUS<=0;
				memio_address_select=0;
			end
			11'b1100_0011_???:begin
				/*  RET - Return from call within segment */
				/*           | 1 1 0 0  0 0 1 1 |         */

				// Microcode instruction
				opcode_size=0;
				Wbit=1;
				Sbit=0;
				PARAM1<=2;
				seq_addr_entry<=`UCODE_RET_ENTRY;
				`normal_microcoded
				DEPENDS_ON_PREVIOUS<=0;
				memio_address_select=0;
			end
			11'b1010_101?_???:begin
				/*  STOS - Write byte/word to [DI] and increment accordingly */
				/*                     | 1 0 1 0  1 0 1 W |                  */
				opcode_size=0;
				Wbit=INSTRUCTION[24:24];
				Sbit=0;
				RM=3'b101;
				seq_addr_entry<=`UCODE_STOS_ENTRY;
				`normal_microcoded
				PARAM2=(Wbit==1)?2:1;
				DEPENDS_ON_PREVIOUS<=0;
				memio_address_select=0;
			end
			11'b0101_0???_???:begin
				/*  PUSH -  SP-=2; [SP]=REG   */
				/*    | 0 1 0 1  0  REG  |    */
				opcode_size=0;
				Wbit=1;
				Sbit=0;
				PARAM2=2;
				reg_read_port2_addr<={1'b1,INSTRUCTION[26:24]};
				seq_addr_entry<=`UCODE_PUSH_ENTRY;
				`normal_microcoded
				memio_address_select=0;
				DEPENDS_ON_PREVIOUS<=0;
			end
			11'b1111_011?_000:begin
				/*             TEST - Bitwise AND of immediate and registers/memory affecting only flags                           */
				/* 1 1 1 1  0 1 1 W | MOD 0 0  0  R/M  |    < DISP-LO >   |    < DISP-HI >   |       DATA       |    DATA if W     */
				opcode_size=1;
				Wbit=INSTRUCTION[24:24];
				IN_MOD={1'b0,INSTRUCTION[23:22]};
				RM={INSTRUCTION[18:16]};
				MEM_OR_IO<=0;
				if(Wbit==1)begin
					PARAM_ACTION=`LOAD_16;
				end else begin
					PARAM_ACTION=`LOAD_8;
				end
				in_alu_sel1=2'b00; /* PARAM1 */
				ALU_OP<=`ALU_OP_AND;
				case(IN_MOD)
					3'b011:begin
						in_alu_sel2=2'b01;
						reg_read_port2_addr<={Wbit,RM};
						next_state=`EXEC_WRITE_ENTRY;
					end
					default:begin
						`invalid_instruction
						next_state=`EXEC_MEMIO_READ;
					end
				endcase
				OUT_MOD=3'b100;/*NULL*/
				`normal_instruction
				DEPENDS_ON_PREVIOUS<=0;
				memio_address_select=0;
			end
			11'b1010_100?_???:begin
				/*      TEST - Bitwise AND of immediate and accumulator affecting only flags           */
				/*               1 0 1 0  1 0 0 W |       DATA       |    DATA if W      |             */
				opcode_size=0;
				Wbit=INSTRUCTION[24:24];
				IN_MOD=3'b011;
				RM=3'b000;
				MEM_OR_IO<=0;
				if(Wbit==1)begin
					PARAM_ACTION=`LOAD_16;
				end else begin
					PARAM_ACTION=`LOAD_8;
				end
				next_state=`EXEC_WRITE_ENTRY;
				in_alu_sel1=2'b00; /* PARAM1 */
				ALU_OP<=`ALU_OP_AND;
				in_alu_sel2=2'b01;
				reg_read_port2_addr<={Wbit,RM};
				OUT_MOD=3'b100;/*NULL*/
				`normal_instruction
				DEPENDS_ON_PREVIOUS<=0;
				memio_address_select=0;
			end
			11'b0101_1???_???:begin
				/*  POP - REG=[SP]; SP+=2   */
				/*    | 0 1 0 1  1  REG  |    */
				opcode_size=0;
				Wbit=1;
				Sbit=0;
				PARAM1<=2;
				reg_write_addr<={1'b1,INSTRUCTION[26:24]};
				seq_addr_entry<=`UCODE_POP_ENTRY;
				`normal_microcoded
				DEPENDS_ON_PREVIOUS<=0;
				memio_address_select=0;
			end
			11'b1111_1111_100:begin
				/*            JMP - Unconditional indirect within segment jump               */
				/* 1 1 1 1  1 1 1 1 | MOD 1 0  0  R/M  |   < DISP-LO >    |    < DISP-HI >   */
				opcode_size=1;
				Wbit=1;
				IN_MOD={1'b0,INSTRUCTION[23:22]};
				RM=INSTRUCTION[18:16];
				MEM_OR_IO<=0;
				in_alu_sel1=2'b11;
				if (IN_MOD==3'b011)begin
					in_alu_sel2=2'b01;
					reg_read_port2_addr<={Wbit,RM};
					next_state=`EXEC_WRITE_ENTRY;
				end else begin
					in_alu_sel2=2'b00;
					next_state=`EXEC_MEMIO_READ;
				end
				ALU_OP<=`ALU_OP_ADD;
				OUT_MOD=3'b101;
				`normal_instruction
				DEPENDS_ON_PREVIOUS<=0;
				memio_address_select=0;
			end
			11'b1100_011?_000:begin
				/*                                MOV - Move immediate to register/memory                                          */
				/* 1 1 0 0  0 1 1 W | MOD 0 0  0  R/M  |    < DISP-LO >   |    < DISP-HI >   |       DATA       |    DATA if W     */
				Wbit=INSTRUCTION[24:24];
				opcode_size=1;
				in_alu_sel1=2'b00;
				in_alu_sel2=2'b11;
				MEM_OR_IO<=0;
				if(Wbit==1)begin
					PARAM_ACTION=`LOAD_16;
				end else begin
					PARAM_ACTION=`LOAD_8;
				end

				OUT_MOD={1'b0,INSTRUCTION[23:22]};
				IN_MOD=3'b011;
				RM=INSTRUCTION[18:16];
				`normal_instruction
				DEPENDS_ON_PREVIOUS<=0;
				memio_address_select=0;
				next_state=`EXEC_WRITE_ENTRY;
			end
			11'b1100_1101_???:begin
				/*    INT - Execute interrupt handler   */
				/* 1 1 0 0  1 1 0 1 |       DATA       |*/
				// [skipped] 1) push flags
				// [skipped] 2) clear trap and interrupt enable flag
				// [skipped] 3) push CS
				// [skipped] 4) fetch CS from interrupt table
				//           5) push ProgCount
				//           6) fetch ProgCount from interrupt table
				opcode_size=0;
				Wbit=1;
				Sbit=0;
				PARAM2=2;
				seq_addr_entry<=`UCODE_INT_ENTRY;
				`normal_microcoded
				DEPENDS_ON_PREVIOUS<=0;
				memio_address_select=0;
			end
			11'b1110_011?_???:begin
				/*  OUT - Write AL or AX to a defined output port */
				/*    | 1 1 1 0  0 1 1 W |     DATA 8       |     */
				memio_address_select=1;
				Wbit=INSTRUCTION[24:24];
				opcode_size=0;
				in_alu_sel1=2'b00;
				in_alu_sel2=2'b11;
				reg_read_port1_addr<={Wbit,3'b000};
				PARAM_ACTION=`LOAD_8;
				HALT <= 0;
				PARAM1<=0;
				OUT_MOD={3'b000};
				DEPENDS_ON_PREVIOUS<=0;
				IN_MOD=3'b011;
				next_state=`EXEC_WRITE_ENTRY;
				`normal_instruction
				MEM_OR_IO<=1;
				ALU_OP<=`ALU_OP_ADD;
			end
			11'b1100_1111_???:begin
				/*  IRET - Return from interrupt  */
				/*      | 1 1 0 0  1 1 1 1 |      */
				// Since we only push one thing on the stack
				// on INT we can just reuse the code from RET
				opcode_size=0;
				Wbit=1;
				Sbit=0;
				PARAM1<=2;
				seq_addr_entry<=`UCODE_RET_ENTRY;
				`normal_microcoded
				DEPENDS_ON_PREVIOUS<=0;
				memio_address_select=0;
			end
			11'b1000_000?_100,11'b1000_000?_001:begin
				/*                                     OR - Bitwise OR immediate and register/mem                                */
				/* 1 0 0 0  0 0 0 W | MOD 0 0  1  R/M  |    < DISP-LO >   |    < DISP-HI >   |       DATA       |    DATA if W     */
				/*                                     AND - Bitwise AND immediate and register/mem                                */
				/* 1 0 0 0  0 0 0 W | MOD 1 0  0  R/M  |    < DISP-LO >   |    < DISP-HI >   |       DATA       |    DATA if W     */
				opcode_size=1;
				Wbit=INSTRUCTION[24:24];
				IN_MOD={1'b0,INSTRUCTION[23:22]};
				RM={INSTRUCTION[18:16]};
				MEM_OR_IO<=0;
				if(Wbit==1)begin
					PARAM_ACTION=`LOAD_16;
				end else begin
					PARAM_ACTION=`LOAD_8;
				end
				in_alu_sel1=2'b00; /* PARAM1 */
				case(INSTRUCTION[21:19])
					3'b100: ALU_OP<=`ALU_OP_AND;
					3'b001: ALU_OP<=`ALU_OP_OR;
					default:begin end
				endcase
				case(IN_MOD)
					3'b011:begin
						in_alu_sel2=2'b01;
						reg_read_port2_addr<={Wbit,RM};
						reg_write_addr<={Wbit,RM};
						next_state=`EXEC_WRITE_ENTRY;
					end
					default:begin
						`unimpl_addressing_mode
						next_state=`EXEC_MEMIO_READ;
					end
				endcase
				OUT_MOD=IN_MOD;
				DEPENDS_ON_PREVIOUS<=0;
				memio_address_select=0;
				`normal_instruction
			end
			11'b0000_00??_???,11'b0010_10??_???,11'b0011_10??_???:begin
				/*                CMP - Compare Register/memory and register                     */
				/* 0 0 1 1  1 0 D W | MOD  REG    R/M  |     < DISP LO >  |     < DISP HI >   |  */
				/*                 SUB - Reg/memory with register to either                      */
				/* 0 0 1 0  1 0 D W | MOD  REG    R/M  |     < DISP LO >  |     < DISP HI >   |  */
				/*                 ADD - Reg/memory with register to either                      */
				/* 0 0 0 0  0 0 D W | MOD  REG    R/M  |     < DISP LO >  |     < DISP HI >   |  */
				opcode_size=1;
				Wbit=INSTRUCTION[24:24];
				Sbit=0;
				IN_MOD=3'b011;
				RM=INSTRUCTION[18:16];
				in_alu_sel1=2'b01;//constantly register
				reg_read_port1_addr<={Wbit,INSTRUCTION[21:19]};
				if(IN_MOD==3'b011)begin
					in_alu_sel2=2'b01;
					reg_read_port2_addr<={Wbit,RM};
					reg_write_addr<={Wbit,RM};
					next_state=`EXEC_WRITE_ENTRY;
				end else begin
					in_alu_sel2=2'b00;
					if(Wbit==1)begin
						PARAM_ACTION=`LOAD_16;
					end else begin
						PARAM_ACTION=`LOAD_8;
					end
				end
				MEM_OR_IO<=0;
				memio_address_select=0;
				case (INSTRUCTION[29:26])
					4'b0000: ALU_OP<=`ALU_OP_ADD;
					4'b1010: ALU_OP<=`ALU_OP_SUB;
					4'b1110: ALU_OP<=`ALU_OP_SUB_REVERSE;
					default: begin end
				endcase
				case (INSTRUCTION[29:26])
					4'b0000: OUT_MOD={1'b0,INSTRUCTION[23:22]};
					4'b1010: OUT_MOD={1'b0,INSTRUCTION[23:22]};
					4'b1110: OUT_MOD=3'b100; /* NULL */
					default: begin end
				endcase
				DEPENDS_ON_PREVIOUS<=0;
				next_state=`EXEC_WRITE_ENTRY;
				if(INSTRUCTION[25:25]==1'b0) begin
					`normal_instruction
				end else begin
					`unimpl_addressing_mode
				end
			end
			11'b1110_010?_???:begin
				/*  IN - Read from a defined port to AL or AX     */
				/*    | 1 1 1 0  0 1 0 W |     DATA 8       |     */
				memio_address_select=1;
				OUT_MOD=3'b011;
				Wbit=INSTRUCTION[24:24];
				opcode_size=0;
				in_alu_sel1=2'b00;
				in_alu_sel2=2'b00;
				PARAM2= {8'b0,INSTRUCTION[23:16]}; //TODO: this is a bit of a hack, i should've used PARAM_ACTION but it loads into PARAM1 and messes up my next_state
				PARAM1<=0;
				reg_write_addr<={Wbit,3'b000};
				reg_read_port1_addr<={Wbit,3'b000};
				DEPENDS_ON_PREVIOUS<=0;
				IN_MOD=3'b110;
				MEM_OR_IO<=1;
				HALT<=0;
				ERROR<=0;
				ALU_OP<=`ALU_OP_ADD;
				next_state=`EXEC_MEMIO_READ_SETADDR;
				seq_addr_entry<=`UCODE_NO_INSTRUCTION;
			end
			default:begin
				`invalid_instruction
			end
		endcase
	end else begin
		/*Microcode output*/
		//Sbit, Wbit, opcode_size and the others are still latched
		//from when we ordered the switch to microcode
		seq_addr_entry <= ucode_data[`UCODE_ADDR_BITS-1:0];
		case(ucode_data[8:6])
			3'b000: begin next_state=`EXEC_WRITE_ENTRY; set_params = 0; end
			3'b001: begin next_state=`EXEC_WRITE_ENTRY; PARAM_ACTION=`LOAD_16;end
			3'b010: begin next_state=`EXEC_WRITE_ENTRY; PARAM_ACTION=`LOAD_8;end
			3'b011: begin next_state=`EXEC_MEMIO_READ;set_params = 0; end
			3'b100: begin next_state=`EXEC_MEMIO_READ_SETADDR;set_params = 0; end
			default: begin end /*impossible*/
		endcase
		if(ucode_data[36:36]==0) /*Set reg write address*/
			reg_write_addr <= ucode_data[12:9 ];
		in_alu_sel1  = ucode_data[14:13];
		in_alu_sel2  = ucode_data[16:15];
		OUT_MOD       = ucode_data[19:17];
		/*1:1 map essentially but I want to keep the spec for these bits separate
		* from the alu op select bits*/
		case(ucode_data[22:20])
			3'b000: ALU_OP<=`ALU_OP_ADD;
			3'b001: ALU_OP<=`ALU_OP_SUB;
			3'b010: ALU_OP<=`ALU_OP_AND;
			3'b011: ALU_OP<=`ALU_OP_OR;
			3'b100: ALU_OP<=`ALU_OP_XOR;
			3'b101: ALU_OP<=`ALU_OP_ADD_SIGNED_B;
			3'b110: ALU_OP<=`ALU_OP_SUB_REVERSE;
			3'b111: ALU_OP<=`ALU_OP_SHIFT_LEFT;
			default: begin end
		endcase
		if(ucode_data[34:34]==0) /* Set reg read port 1 address */
			reg_read_port1_addr<=ucode_data[26:23];
		IN_MOD=ucode_data[29:27];
		if(ucode_data[35:35]==0) /* Set reg read port 1 address */
			reg_read_port2_addr<=ucode_data[33:30];
		if(ucode_data[37:37]==1) /* Overwrite Wbit */
			Wbit=ucode_data[38:38];
		memio_address_select=ucode_data[39:39];
		MEM_OR_IO<=0;
		HALT <= 0;
		ERROR <= 0; //TODO probably, right?
	end

	if(PARAM_ACTION==`LOAD_8)begin
		if(opcode_size==0)begin
			if({Sbit,Wbit}==2'b11)begin
				/*signed "16bit" read*/
				PARAM1 <= {{8{INSTRUCTION[23:23]}},INSTRUCTION[23:16]};
			end else begin
				//PARAM1[7:0] = INSTRUCTION[23:16];
				PARAM1 <= {8'b0,INSTRUCTION[23:16]};
			end
		end else begin
			if({Sbit,Wbit}==2'b11)begin
				/*signed "16bit" read*/
				PARAM1 <= {{8{INSTRUCTION[15:15]}},INSTRUCTION[15:8]};
			end else begin
				//PARAM1[7:0] = INSTRUCTION[15:8];
				PARAM1 <= {8'b0,INSTRUCTION[15:8]};
			end
		end
		case(IN_MOD)
			3'b000,3'b001,3'b010: next_state = `EXEC_MEMIO_READ;
			default:              next_state = `EXEC_WRITE_ENTRY;
		endcase
	end else if (PARAM_ACTION == `LOAD_16) begin
		if(opcode_size==0)begin
			PARAM1[7:0] <= INSTRUCTION[23:16];
			PARAM1[15:8] <= INSTRUCTION[15:8];
		end else begin
			PARAM1[15:8] <= INSTRUCTION[7:0];
			PARAM1[7:0] <= INSTRUCTION[15:8];
		end
		case(IN_MOD)
			3'b000,3'b001,3'b010: next_state = `EXEC_MEMIO_READ;
			default:              next_state = `EXEC_WRITE_ENTRY;
		endcase
	end
end
`undef invalid_instruction

endmodule
/* verilator lint_on BLKSEQ */


/* IN: {INSTRUCTION[31:24],INSTRUCTION[21:19]} */
/* OUT: number in bytes */
module InstrSize ( input [10:0] IN, output reg [2:0] VERDICT );
	always @* begin
		casez(IN)
			11'b0000_010?_??? : VERDICT = 3'd2+{2'b0,IN[3:3]};          /*     ADD  - Add Immediate word/byte to accumulator                */
			11'b1000_00??_101 : VERDICT = 3'd3+{2'b0,(IN[4:3]==2'b01)}; /*     SUB  - Subtract immediate word/byte from register/memory     */
			11'b1000_00??_000 : VERDICT = 3'd3+{2'b0,(IN[4:3]==2'b01)}; /*     ADD  - Add Immediate word/byte to register/memory            */
			11'b1000_00??_111 : VERDICT = 3'd3+{2'b0,(IN[4:3]==2'b01)}; /*     CMP  - compare Immediate with register / memory              */
			11'b1011_????_??? : VERDICT = 3'd2+{2'b0,IN[6:6]};          /*     MOV  - Move Immediate byte to register                       */
			11'b1000_10??_??? : VERDICT = 3'd2;                         /*     MOV  - Reg/Mem to/from register                              */
			11'b0100_????_??? : VERDICT = 3'd1;                         /*     DEC  - Decrement Register | INC - Increment Register         */
			11'b1111_111?_00? : VERDICT = 3'd2;                         /*     INC  - Register/Memory    | DEC - Register/Memory            */
			11'b1111_0100_??? : VERDICT = 3'd1;                         /*     HLT  - Halt                                                  */
			11'b0011_110?_??? : VERDICT = 3'd2+{2'b0,IN[3:3]};          /*     CMP  - Compare Immediate with accumulator                    */
			11'b0111_????_??? : VERDICT = 3'd2;                         /*     Conditional relative jumps ( JE/JZ, JS/JNS ... )             */
			11'b1110_1011_??? : VERDICT = 3'd2;                         /*     JMP  - Unconditional jump direct within segment (short)      */
			11'b1110_1000_??? : VERDICT = 3'd3;                         /*     CALL - Direct call within segment                            */
			11'b1100_0011_??? : VERDICT = 3'd1;                         /*     RET  - Return from call within segment                       */
			11'b1010_101?_??? : VERDICT = 3'd1;                         /*     STOS - Write byte/word to [DI] and increment accordingly     */
			11'b0101_0???_??? : VERDICT = 3'd1;                         /*     PUSH - SP-=2; [SP]=REG                                       */
			11'b1111_011?_000 : VERDICT = 3'd3+{2'b0,IN[3:3]};          /*     TEST - Bitwise AND affecting only flags                      */
			11'b0101_1???_??? : VERDICT = 3'd1;                         /*     POP  - REG=[SP]; SP+=2                                       */
			11'b1111_1111_100 : VERDICT = 3'd2;                         /*     JMP  - Unconditional indirect within segment jump            */
			11'b1100_011?_000 : VERDICT = 3'd3+{2'b0,IN[3:3]};          /*     MOV  - Move immediate to register/memory                     */
			11'b1100_1101_??? : VERDICT = 3'd2;                         /*     INT  - execute interrupt handler                             */
			11'b1110_011?_??? : VERDICT = 3'd2;                         /*     OUT  - write AL or AX to a defined output port               */
			11'b1100_1111_??? : VERDICT = 3'd1;                         /*     IRET - Return from interrupt                                 */
			11'b1000_000?_100 : VERDICT = 3'd3+{2'b0,IN[3:3]};          /*     AND  - Bitwise AND immediate and register/mem                */
			11'b1000_000?_001 : VERDICT = 3'd3+{2'b0,IN[3:3]};          /*     OR   - Bitwise OR immediate and register/mem                 */
			11'b1010_100?_??? : VERDICT = 3'd2+{2'b0,IN[3:3]};          /*     TEST - Bitwise AND affecting only flags                      */
			11'b0000_00??_??? : VERDICT = 3'd2;                         /*     ADD  - Reg/memory with register to either                    */
			11'b0010_10??_??? : VERDICT = 3'd2;                         /*     SUB  - Reg/memory with register to either                    */
			11'b0011_10??_??? : VERDICT = 3'd2;                         /*     CMP  - Compare Register/memory and register                  */
			11'b1110_010?_??? : VERDICT = 3'd2;                         /*     IN   - Read from a defined port to AL or AX                  */
			default: VERDICT = 3'd7;
		endcase
	end
endmodule

`ifdef INCLUDE_EARLY_CALC_CIRCUIT
module Is1 ( input [7:0] IN, output reg VERDICT );
	always @* begin
		casez(IN)
			8'b0100_???? : VERDICT = 1;                         /*     DEC  - Decrement Register | INC - Increment Register         */
			8'b1111_0100 : VERDICT = 1;                         /*     HLT  - Halt                                                  */
			8'b1100_0011 : VERDICT = 1;                         /*     RET  - Return from call within segment                       */
			8'b1010_101? : VERDICT = 1;                         /*     STOS - Write byte/word to [DI] and increment accordingly     */
			8'b0101_0??? : VERDICT = 1;                         /*     PUSH - SP-=2; [SP]=REG                                       */
			8'b0101_1??? : VERDICT = 1;                         /*     POP  - REG=[SP]; SP+=2                                       */
			8'b1100_1111 : VERDICT = 1;                         /*     IRET - Return from interrupt                                 */
			default:begin VERDICT = 0; end
		endcase
	end
endmodule
`endif

`undef unimpl_addressing_mode
