diff --git a/8086_documentation.md b/8086_documentation.md
index af3bbd5..9901a01 100644
--- a/8086_documentation.md
+++ b/8086_documentation.md
@@ -23,6 +23,8 @@ On some instructions:
* **V**-bit : V-bit decides the number of shifts for rotate and shift instructions. If V = 0, then count = 1; if V = 1, the count is in CL register. For example, if V = 1 and CL = 2 then shift or rotate instruction shifts or rotates 2-bits
* **Z**-bit : Used as a compare bit with the zero flag in conditional repeat and loop instructions. ex branch if zero is set or clear.
+No instruction has parts of its opcode past the first 2 bytes I.e. all bytes after the first two are additional data bytes
+
| Register ID / REG | Register Name |
|:-------------------:|:-------------:|
| 0 0 0 | AL AX |
diff --git a/common.mk b/common.mk
index 461c107..2a61129 100644
--- a/common.mk
+++ b/common.mk
@@ -40,7 +40,7 @@ disas: $(subst .txt,.disas,${BOOT_CODE})
%.run: %.txt ${SYSTEM_VVP}
${QUIET_VVP}
- ${Q}vvp "${SYSTEM_VVP}" +BOOT_CODE="$<"
+ ${Q}vvp -i "${SYSTEM_VVP}" +BOOT_CODE="$<"
%.disas: %.bin
objdump -D -b binary -m i8086 $^ | less
diff --git a/system/Makefile b/system/Makefile
index 2ab5780..0074b11 100644
--- a/system/Makefile
+++ b/system/Makefile
@@ -15,7 +15,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
-SOURCES=processor.v testbench.v memory.v registers.v alu.v
+SOURCES=processor.v testbench.v memory.v registers.v alu.v decoder.v
INCLUDES=proc_state_def.v alu_header.v config.v
SYSTEM_VVP=system.vvp
BOOT_CODE=boot_code.txt
diff --git a/system/decoder.v b/system/decoder.v
new file mode 100644
index 0000000..56d29af
--- /dev/null
+++ b/system/decoder.v
@@ -0,0 +1,447 @@
+/* decoder.v - Implementation of instruction opcode decoding logic
+
+ This file is part of the 9086 project.
+
+ Copyright (c) 2023 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 . */
+
+`include "proc_state_def.v"
+`include "alu_header.v"
+
+
+module decoder(
+ input wire [15:0] CIR,input wire [15:0] FLAGS, output reg Wbit, output reg Sbit, output reg unaligning ,output reg opcode_size, output reg ERROR,output reg [`PROC_STATE_BITS-1:0]next_state
+ ,output reg [1:0]MOD, output reg [2:0]RM, output reg [15:0] PARAM1,output reg [15:0] PARAM2,output reg HALT,output reg has_operands
+ ,output reg [1:0]in_alu1_sel1,output reg [1:0]in_alu1_sel2,output reg [2:0]out_alu1_sel
+ ,output reg [3:0]reg_read_port1_addr, output reg [3:0]reg_write_addr
+ ,output reg [2:0]ALU_1OP
+);
+
+/* 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0 */
+
+`define invalid_instruction next_state=`PROC_IF_STATE_ENTRY;ERROR=1;MOD=2'b11;
+`define start_aligning_instruction unaligning=0;
+`define start_unaligning_instruction unaligning=1;
+
+
+always @( CIR ) begin
+ ERROR=0;HALT=0;
+ MOD=2'b11;/*TODO:remove*/
+ case(CIR[15:10])
+ 6'b000001 : begin
+ /* ADD, ... */
+ if ( CIR[9:9] == 0 )begin
+ /* Add Immediate word/byte to accumulator */
+ /* 0 0 0 0 0 1 0 W | DATA | DATA if W |*/
+ opcode_size=0;
+ has_operands=1;
+ Wbit=CIR[8:8];
+ if(Wbit)
+ `start_unaligning_instruction
+ else
+ `start_aligning_instruction
+ MOD=2'b11;
+ in_alu1_sel1=2'b00;
+ in_alu1_sel2=2'b01;
+ out_alu1_sel=3'b011;
+ reg_read_port1_addr={CIR[8:8],3'b000};
+ reg_write_addr={CIR[8:8],3'b000};
+ ALU_1OP=`ALU_OP_ADD;
+ if(CIR[8:8]==1)
+ next_state=`PROC_DE_LOAD_16_PARAM;
+ else begin
+ PARAM1[7:0]=CIR[7:0];
+ next_state=`PROC_EX_STATE_ENTRY;
+ end
+ end else begin
+ `invalid_instruction
+ end
+ end
+ 6'b100000 : begin
+ /* ADD, ADC, SUB, SBB, CMP , AND, ... */
+ case (CIR[5:3])
+ 3'b000 : begin
+ /* 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 | */
+ opcode_size=1;
+ has_operands=1;
+ `start_aligning_instruction
+ Wbit=CIR[8:8];
+ MOD=2'b11;
+ in_alu1_sel1=2'b00;
+ in_alu1_sel2=2'b01;
+ out_alu1_sel={1'b0,CIR[7:6]};
+ reg_read_port1_addr={CIR[8:8],CIR[2:0]};
+ reg_write_addr={CIR[8:8],CIR[2:0]};
+ ALU_1OP=`ALU_OP_ADD;
+ next_state=`PROC_DE_LOAD_16_PARAM;
+ if(CIR[8:8]==1)
+ next_state=`PROC_DE_LOAD_16_PARAM;
+ else begin
+ `invalid_instruction /*do 8bit loads*/
+ end
+ end
+ 3'b111 : begin
+ /* CMP - compare Immediate with register / memory */
+ /* 1 0 0 0 0 0 S W | MOD 0 0 0 R/M | < DISP LO > | < DISP HI > | DATA | DATA if W | */
+ opcode_size=1;
+ has_operands=1;
+ Wbit=CIR[8:8];
+ Sbit=CIR[9:9];
+ MOD=CIR[7:6];
+ if((Wbit==1)&&(CIR[9:9]==1))begin
+ `start_unaligning_instruction
+ end else begin
+ `invalid_instruction;
+ end
+ if(MOD==2'b11)begin
+ in_alu1_sel1=2'b00;
+ in_alu1_sel2=2'b01;
+ reg_read_port1_addr={CIR[8:8],CIR[2:0]};
+ out_alu1_sel=3'b100;
+ ALU_1OP=`ALU_OP_SUB;
+ next_state=`PROC_DE_LOAD_8_PARAM;
+ end else begin
+ `invalid_instruction
+ end
+
+ end
+ default:begin
+ `invalid_instruction
+ end
+ endcase
+ end
+ 6'b101100,
+ 6'b101101:begin
+ /* MOV - Move Immediate byte to register */
+ /* 1 0 1 1 W REG | DATA | DATA if W |*/
+ has_operands=1;
+ Wbit=CIR[11:11];
+ opcode_size=0;
+ if(Wbit)
+ `start_unaligning_instruction
+ else
+ `start_aligning_instruction
+ MOD=2'b11;
+ in_alu1_sel1=2'b00;
+ in_alu1_sel2=2'b00;
+ out_alu1_sel=3'b011;
+ reg_write_addr={1'b0,CIR[10:8]};
+ PARAM1[7:0]=CIR[7:0];
+ PARAM2=0;
+ ALU_1OP=`ALU_OP_ADD;
+ next_state=`PROC_EX_STATE_ENTRY;
+ end
+ 6'b101110,
+ 6'b101111 : begin
+ /*MOV - Move Immediate word to register*/
+ has_operands=1;
+ Wbit=CIR[11:11];
+ opcode_size=0;
+ if(Wbit)
+ `start_unaligning_instruction
+ else
+ `start_aligning_instruction
+ MOD=2'b11;
+ in_alu1_sel1=2'b00;
+ in_alu1_sel2=2'b00;
+ out_alu1_sel=3'b011;
+ reg_write_addr={1'b1,CIR[10:8]};
+ ALU_1OP=`ALU_OP_ADD;
+ PARAM2=0;
+ next_state=`PROC_DE_LOAD_16_PARAM;
+ end
+
+ 6'b100010 : begin
+ /* MOV - Reg/Mem to/from register */
+ /* 1 0 0 0 1 0 D W | MOD REG RM | < DISP LO > | < DISP HI > |*/
+ has_operands=0;
+ `start_aligning_instruction
+ opcode_size=1;
+ MOD=CIR[7:6];
+ RM=CIR[2:0];
+ Wbit=CIR[8:8];
+ in_alu1_sel2=2'b00;
+ if(CIR[9:9] == 1)begin
+ /* Mem/Reg to reg */
+ if(MOD==2'b11)begin
+ /*Reg to Reg*/
+ in_alu1_sel1=2'b01;
+ reg_read_port1_addr=CIR[2:0];
+ next_state=`PROC_EX_STATE_ENTRY;
+ end else begin
+ /*Mem to Reg*/
+ in_alu1_sel1=2'b00;
+ next_state=`RPOC_MEMIO_READ;
+ end
+ out_alu1_sel=3'b011;
+ reg_write_addr={Wbit,CIR[5:3]};
+ end else begin
+ /* Reg to Mem/Reg */
+ if(MOD==2'b11)begin
+ /*Reg to Reg*/
+ in_alu1_sel1=2'b01;
+ out_alu1_sel=3'b011;
+ reg_write_addr={Wbit,CIR[2:0]};
+ next_state=`PROC_EX_STATE_ENTRY;
+ end else begin
+ /*Reg to Mem*/
+ in_alu1_sel1=2'b00;
+ reg_read_port1_addr=CIR[5:3];
+ out_alu1_sel={1'b0,MOD};
+ next_state=`PROC_DE_LOAD_REG_TO_PARAM;
+ end
+ reg_read_port1_addr={Wbit,CIR[5:3]};
+ end
+
+ ALU_1OP=`ALU_OP_ADD;
+ PARAM2=0;
+ end
+ 6'b010000,//INC
+ 6'b010001,//INC
+ 6'b010010,//DEC
+ 6'b010011:begin//DEC
+ /* DEC - Decrement Register */
+ /* | 0 1 0 0 1 REG | */
+ /* INC - Increment Register */
+ /* | 0 1 0 0 0 REG | */
+ has_operands=0;
+ opcode_size=0;
+ `start_unaligning_instruction
+ Wbit=1;
+ in_alu1_sel1=2'b01;
+ in_alu1_sel2=2'b00;
+ out_alu1_sel=3'b011;
+ MOD=2'b11;
+ PARAM2=1;
+ reg_read_port1_addr={1'b1,CIR[10:8]};
+ reg_write_addr={1'b1,CIR[10:8]};
+ if(CIR[11:11]==0)
+ ALU_1OP=`ALU_OP_ADD;
+ else
+ ALU_1OP=`ALU_OP_SUB;
+ next_state=`PROC_EX_STATE_ENTRY;
+ end
+ 6'b111111 : begin
+ /* INC */
+ if (CIR[9:9] == 1 ) begin
+ case (CIR[5:3])
+ 3'b000,3'b001 :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> */
+ has_operands=1;
+ opcode_size=1;
+ `start_aligning_instruction
+ Wbit=CIR[8:8];
+ MOD=CIR[7:6];
+ RM=CIR[2:0];
+ in_alu1_sel1=(MOD==2'b11)? 2'b01 : 2'b00;
+ in_alu1_sel2=2'b00;/* number 1 */
+ out_alu1_sel={1'b0,MOD};
+ PARAM2=1;
+
+ /*in case MOD=11 */
+ reg_read_port1_addr={1'b0,RM};
+ reg_write_addr={1'b0,RM};
+
+ ALU_1OP=(CIR[3:3]==1)?`ALU_OP_SUB:`ALU_OP_ADD;
+ if ( CIR[7:6] == 2'b11 )
+ next_state=`PROC_EX_STATE_ENTRY;
+ else
+ next_state=`RPOC_MEMIO_READ;
+ end
+ default:begin
+ `invalid_instruction
+ end
+ endcase
+ end else begin
+ `invalid_instruction
+ end
+ end
+ 6'b111101 : begin
+ /*HLT, CMC, TEST, NOT, NEG, MUL, IMUL, .... */
+ case (CIR[9:8])
+ 2'b00:begin
+ /* HLT - Halt */
+ /* 1 1 1 1 0 1 0 0 | */
+ has_operands=0;
+ opcode_size=0;
+ `start_unaligning_instruction
+ MOD=2'b11;
+ HALT=1;
+ next_state=`PROC_HALT_STATE;
+ end
+ default:begin
+ `invalid_instruction;
+ end
+ endcase
+
+ end
+ 6'b001111 : begin
+ if ( CIR[9:9] == 0 ) 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=CIR[8:8];
+ opcode_size=0;
+ has_operands=1;
+ if(Wbit)
+ `start_unaligning_instruction
+ else
+ `start_aligning_instruction
+ MOD=2'b11;
+ in_alu1_sel1=2'b00;
+ in_alu1_sel2=2'b01;
+ reg_read_port1_addr={CIR[8:8],3'b000};
+ out_alu1_sel=3'b100;
+ ALU_1OP=`ALU_OP_SUB;
+ if(CIR[8:8]==1)
+ next_state=`PROC_DE_LOAD_16_PARAM;
+ else begin
+ PARAM1[7:0]=CIR[7:0];
+ next_state=`PROC_EX_STATE_ENTRY;
+ end
+ end else begin
+ `invalid_instruction
+ end
+ end
+ 6'b011100,
+ 6'b011101,
+ 6'b011110,
+ 6'b011111: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 |*/
+ /* .... */
+ has_operands=1;
+ `start_aligning_instruction
+ Wbit=1;
+ opcode_size=0;
+ in_alu1_sel1=2'b10;
+ in_alu1_sel2=2'b00;
+ PARAM2={{8{CIR[7:7]}},CIR[7:0]};
+ ALU_1OP=`ALU_OP_ADD_SIGNED_B;
+ out_alu1_sel=3'b101;
+ case(CIR[11:9])
+ 4'b000: begin
+ /* Jump on (not) Overflow */
+ if(FLAGS[11:11]==CIR[8:8])
+ next_state=`PROC_IF_STATE_ENTRY;
+ else begin
+ next_state=`PROC_EX_STATE_ENTRY;
+ end
+ end
+ 4'b010: begin
+ /* Jump on (not) Zero */
+ if(FLAGS[6:6]==CIR[8:8])
+ next_state=`PROC_IF_STATE_ENTRY;
+ else
+ next_state=`PROC_EX_STATE_ENTRY;
+ end
+ 4'b100: begin
+ /* Jump on (not) Sign */
+ if(FLAGS[7:7]==CIR[8:8])
+ next_state=`PROC_IF_STATE_ENTRY;
+ else
+ next_state=`PROC_EX_STATE_ENTRY;
+ end
+ 4'b101: begin
+ /* Jump on (not) Parity */
+ if(FLAGS[2:2]==CIR[8:8])
+ next_state=`PROC_IF_STATE_ENTRY;
+ else
+ next_state=`PROC_EX_STATE_ENTRY;
+ end
+ default:begin
+ `invalid_instruction; /*We don't support that condition*/
+ end
+ endcase
+ end
+ 6'b111010:begin
+ /* JMP,CALL */
+ case(CIR[9:8])
+ 2'b00: begin
+ /* CALL - Call direct within segment */
+ /* 1 1 1 0 1 0 0 0 | IP-INC-LO | IP-INC-HI |*/
+ `invalid_instruction
+ end
+ 2'b01: begin
+ /* JMP - Uncoditional Jump direct within segment */
+ /* 1 1 1 0 1 0 0 1 | IP-INC-LO | IP-INC-HI |*/
+ `invalid_instruction
+ end
+ 2'b10: begin
+ /* JMP - Unconditional jump direct intersegment */
+ /* 0 0 0 0 0 0 0 0 | IP-LO | IP-HI | CS-LO | CS-HI | */
+ `invalid_instruction
+ end
+ 2'b11: begin
+ /* JMP - Unconditional jump direct within segment (short) */
+ /* | 1 1 1 0 1 0 0 1 | IP-INC-LO | */
+ `start_aligning_instruction
+ opcode_size=0;
+ has_operands=1;
+ Wbit=1;
+ in_alu1_sel1=2'b10;
+ in_alu1_sel2=2'b00;
+ PARAM2={{8{CIR[7:7]}},CIR[7:0]};
+ ALU_1OP=`ALU_OP_ADD_SIGNED_B;
+ out_alu1_sel=3'b101;
+ next_state=`PROC_EX_STATE_ENTRY;
+ end
+ endcase
+ end
+ 6'b110011:begin
+ case(CIR[9:8])
+ 2'b00:begin
+ `invalid_instruction
+ end
+ 2'b01:begin
+ if(CIR[7:0]==8'h21) begin
+ /* INT - execut interrupt handler */
+ /* 1 1 0 0 1 1 0 1 | DATA |*/
+ has_operands=1;
+ opcode_size=0;
+ `start_aligning_instruction
+ /* Emulate MS-DOS print routines */
+ $write("%s" ,register_file.registers[2][7:0]); /*TODO:Could trigger erroneously while CIR is not final*/
+ next_state=`PROC_IF_STATE_ENTRY;
+ end else begin
+ `invalid_instruction
+ end
+ end
+ 2'b10:begin
+ `invalid_instruction
+ end
+ 2'b11:begin
+ `invalid_instruction
+ end
+ endcase
+ end
+ default:begin
+ `invalid_instruction
+ end
+ endcase
+end
+
+endmodule
diff --git a/system/processor.v b/system/processor.v
index 74f9db5..082f2ac 100644
--- a/system/processor.v
+++ b/system/processor.v
@@ -42,16 +42,33 @@ assign external_data_bus=read?data_bus_output_register:'hz;
// State
reg [`PROC_STATE_BITS-1:0] state;
+/* Decoder */
+wire Wbit, Sbit, unaligning_instruction;
+wire [`PROC_STATE_BITS-1:0] next_state;
+wire [1:0]MOD;
+wire [2:0]RM;
+wire [15:0]DE_PARAM1;
+wire [15:0]DE_PARAM2;
+wire DE_ERROR,DE_HALT;
+wire [3:0]DE_reg_read_port1_addr,DE_reg_write_addr;
+wire opcode_size;
+wire has_operands;
+decoder decoder(
+ CIR,FLAGS,Wbit,Sbit,unaligning_instruction,opcode_size,DE_ERROR,next_state
+ ,MOD,RM,DE_PARAM1,DE_PARAM2,DE_HALT,has_operands
+ ,in_alu1_sel1,in_alu1_sel2,out_alu1_sel
+ ,DE_reg_read_port1_addr,DE_reg_write_addr
+ ,ALU_1OP
+);
+
// Registers
reg [19:0] ProgCount; /*TODO consider having single circuit to increment PC instead of having possible lots of adders all over the code*/
reg [15:0] CIR;
reg [15:0] PARAM1;
reg [15:0] PARAM2;
+reg one_byte_instruction;
reg unaligned_access;
-reg [1:0]MOD;
-reg [2:0]RM;
-reg Wbit;
-reg Sbit;
+
reg [15:0]FLAGS;
/* . . . . O D I T S Z . A . P . C */
// C - Carry flag : carry out or borrow into the high order bit (8bit/16bit)
@@ -90,7 +107,7 @@ always @(negedge reset) begin
@(posedge reset)
@(negedge clock);
state=`PROC_IF_STATE_ENTRY;
- MOD=2'b11;
+ one_byte_instruction=0;
ERROR=0;
end
end
@@ -144,28 +161,32 @@ wire [7:0] ALU_1FLAGS;
ALU ALU1(ALU_1A,ALU_1B,ALU_1OE,ALU_1O,ALU_1OP,ALU_1FLAGS,Wbit);
/*** Processor stages ***/
-
-`define invalid_instruction state=`PROC_IF_STATE_ENTRY;ERROR=1;MOD=2'b11;
-`define start_aligning_instruction if(unaligned_access==0)begin ProgCount=ProgCount+1; external_address_bus <= ProgCount; end /*we normally don't advance PC in case of singly byte unaligning instructions leaving us with two instructions in one read so do that here*/
-`define start_unaligning_instruction unaligned_access=~unaligned_access;
+`define invalid_instruction state=`PROC_IF_STATE_ENTRY;ERROR=1;
always @(negedge clock) begin
case(state)
`PROC_IF_WRITE_CIR:begin
if(unaligned_access)begin
- CIR[15:8] <= external_data_bus[7:0];
- ProgCount=ProgCount+1;
- state=`PROC_IF_STATE_EXTRA_FETCH_SET;
+ if(one_byte_instruction==1)begin /*TODO: have a read buffer so we can do this even with data reads */
+ CIR <= {CIR[7:0],external_data_bus[15:8]};
+ state=`PROC_DE_STATE_ENTRY;
+ end else begin
+ CIR[15:8] <= external_data_bus[7:0];
+ state=`PROC_IF_STATE_EXTRA_FETCH_SET;
+ end
end else begin
CIR <= external_data_bus;
+ ProgCount=ProgCount+1;
state=`PROC_DE_STATE_ENTRY;
end
end
`PROC_IF_STATE_EXTRA_FETCH:begin
CIR[7:0] <= external_data_bus[15:8];
state=`PROC_DE_STATE_ENTRY;
+ ALU_1OE=0;
end
`PROC_EX_STATE_EXIT:begin
+ unaligned_access=unaligning_instruction^unaligned_access;
case(out_alu1_sel) /*TODO: use RM*/
3'b000,
3'b001,
@@ -274,6 +295,7 @@ always @(negedge clock) begin
endcase
end
+
always @(posedge clock) begin
case(state)
`PROC_HALT_STATE:begin
@@ -296,431 +318,77 @@ always @(posedge clock) begin
reg_write_in_sel=2'b00;
end
`PROC_IF_STATE_EXTRA_FETCH_SET:begin
+ ProgCount=ProgCount+1;
external_address_bus <= ProgCount;
state=`PROC_IF_STATE_EXTRA_FETCH;
end
- /* 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0 | 0 0 0 0 0 0 0 0 */
- /* AFTER THE IF STAGE WE HAVE THE FIRST BYTE OF THE
- * INSTRUCTION AND THE ONE FOLLOWING, ALIGNED CORRECTLY TO
- * CIR */
`PROC_DE_STATE_ENTRY:begin
- case(CIR[15:10])
- 6'b000001 : begin
- /* ADD, ... */
- if ( CIR[9:9] == 0 )begin
- /* Add Immediate word/byte to accumulator */
- /* 0 0 0 0 0 1 0 W | DATA | DATA if W |*/
- Wbit=CIR[8:8];
- if(Wbit)
- `start_unaligning_instruction
- else
- `start_aligning_instruction
- MOD=2'b11;
- in_alu1_sel1=2'b00;
- in_alu1_sel2=2'b01;
- out_alu1_sel=3'b011;
- reg_read_port1_addr={CIR[8:8],3'b000};
- reg_write_addr={CIR[8:8],3'b000};
- ALU_1OE=0;
- ALU_1OP=`ALU_OP_ADD;
- if(CIR[8:8]==1)
- state=`PROC_DE_LOAD_16_PARAM;
- else begin
- PARAM1[7:0]=CIR[7:0];
- state=`PROC_EX_STATE_ENTRY;
- end
- end else begin
- `invalid_instruction
- end
- end
- 6'b100000 : begin
- /* ADD, ADC, SUB, SBB, CMP , AND, ... */
- case (CIR[5:3])
- 3'b000 : begin
- /* 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 | */
- `start_aligning_instruction
- Wbit=CIR[8:8];
- MOD=2'b11;
- in_alu1_sel1=2'b00;
- in_alu1_sel2=2'b01;
- out_alu1_sel={1'b0,CIR[7:6]};
- reg_read_port1_addr={CIR[8:8],CIR[2:0]};
- reg_write_addr={CIR[8:8],CIR[2:0]};
- ALU_1OE=0;
- ALU_1OP=`ALU_OP_ADD;
- state=`PROC_DE_LOAD_16_PARAM;
- if(CIR[8:8]==1)
- state=`PROC_DE_LOAD_16_PARAM;
- else begin
- `invalid_instruction /*do 8bit loads*/
- end
- end
- 3'b111 : begin
- /* CMP - compare Immediate with register / memory */
- /* 1 0 0 0 0 0 S W | MOD 0 0 0 R/M | < DISP LO > | < DISP HI > | DATA | DATA if W | */
- Wbit=CIR[8:8];
- Sbit=CIR[9:9];
- MOD=CIR[7:6];
- if((Wbit==1)&&(CIR[9:9]==1))begin
- `start_unaligning_instruction
- end else begin
- `invalid_instruction;
- end
- if(MOD==2'b11)begin
- in_alu1_sel1=2'b00;
- in_alu1_sel2=2'b01;
- reg_read_port1_addr={CIR[8:8],CIR[2:0]};
- out_alu1_sel=3'b100;
- ALU_1OE=0;
- ALU_1OP=`ALU_OP_SUB;
- state=`PROC_DE_LOAD_8_PARAM;
- end else begin
- `invalid_instruction
- end
-
- end
- default:begin
- `invalid_instruction
- end
- endcase
- end
- 6'b101100,
- 6'b101101:begin
- /* MOV - Move Immediate byte to register */
- /* 1 0 1 1 W REG | DATA | DATA if W |*/
- Wbit=CIR[11:11];
- if(Wbit)
- `start_unaligning_instruction
- else
- `start_aligning_instruction
- MOD=2'b11;
- in_alu1_sel1=2'b00;
- in_alu1_sel2=2'b00;
- out_alu1_sel=3'b011;
- reg_write_addr={1'b0,CIR[10:8]};
- PARAM1[7:0]=CIR[7:0];
- PARAM2=0;
- ALU_1OE=0;
- ALU_1OP=`ALU_OP_ADD;
- state=`PROC_EX_STATE_ENTRY;
- end
- 6'b101110,
- 6'b101111 : begin
- /*MOV - Move Immediate word to register*/
- Wbit=CIR[11:11];
- if(Wbit)
- `start_unaligning_instruction
- else
- `start_aligning_instruction
- MOD=2'b11;
- in_alu1_sel1=2'b00;
- in_alu1_sel2=2'b00;
- out_alu1_sel=3'b011;
- reg_write_addr={1'b1,CIR[10:8]};
- ALU_1OE=0;
- ALU_1OP=`ALU_OP_ADD;
- PARAM2=0;
- state=`PROC_DE_LOAD_16_PARAM;
- end
-
- 6'b100010 : begin
- /* MOV - Reg/Mem to/from register */
- /* 1 0 0 0 1 0 D W | MOD REG RM | < DISP LO > | < DISP HI > |*/
- `start_aligning_instruction
- MOD=CIR[7:6];
- RM=CIR[2:0];
- Wbit=CIR[8:8];
- in_alu1_sel2=2'b00;
- if(CIR[9:9] == 1)begin
- /* Mem/Reg to reg */
- if(MOD==2'b11)begin
- /*Reg to Reg*/
- in_alu1_sel1=2'b01;
- reg_read_port1_addr=CIR[2:0];
- state=`PROC_EX_STATE_ENTRY;
- end else begin
- /*Mem to Reg*/
- in_alu1_sel1=2'b00;
- state=`RPOC_MEMIO_READ;
- end
- out_alu1_sel=3'b011;
- reg_write_addr={Wbit,CIR[5:3]};
- end else begin
- /* Reg to Mem/Reg */
- if(MOD==2'b11)begin
- /*Reg to Reg*/
- in_alu1_sel1=2'b01;
- out_alu1_sel=3'b011;
- reg_write_addr={Wbit,CIR[2:0]};
- state=`PROC_EX_STATE_ENTRY;
- end else begin
- /*Reg to Mem*/
- in_alu1_sel1=2'b00;
- reg_read_port1_addr=CIR[5:3];
- out_alu1_sel={1'b0,MOD};
- state=`PROC_DE_LOAD_REG_TO_PARAM;
- end
- reg_read_port1_addr={Wbit,CIR[5:3]};
- end
-
- ALU_1OE=0;
- ALU_1OP=`ALU_OP_ADD;
- PARAM2=0;
- end
- 6'b010000,//INC
- 6'b010001,//INC
- 6'b010010,//DEC
- 6'b010011:begin//DEC
- /* DEC - Decrement Register */
- /* | 0 1 0 0 1 REG | */
- /* INC - Increment Register */
- /* | 0 1 0 0 0 REG | */
- `start_unaligning_instruction
- Wbit=1;
- in_alu1_sel1=2'b01;
- in_alu1_sel2=2'b00;
- out_alu1_sel=3'b011;
- MOD=2'b11;
- PARAM2=1;
- reg_read_port1_addr={1'b1,CIR[10:8]};
- reg_write_addr={1'b1,CIR[10:8]};
- ALU_1OE=0;
- if(CIR[11:11]==0)
- ALU_1OP=`ALU_OP_ADD;
- else
- ALU_1OP=`ALU_OP_SUB;
- state=`PROC_EX_STATE_ENTRY;
- end
- 6'b111111 : begin
- /* INC */
- if (CIR[9:9] == 1 ) begin
- case (CIR[5:3])
- 3'b000,3'b001 :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> */
- `start_aligning_instruction
- Wbit=CIR[8:8];
- MOD=CIR[7:6];
- RM=CIR[2:0];
- in_alu1_sel1=(MOD==2'b11)? 2'b01 : 2'b00;
- in_alu1_sel2=2'b00;/* number 1 */
- out_alu1_sel={1'b0,MOD};
- PARAM2=1;
-
- /*in case MOD=11 */
- reg_read_port1_addr={1'b0,RM};
- reg_write_addr={1'b0,RM};
-
- ALU_1OE=0;
- ALU_1OP=(CIR[3:3]==1)?`ALU_OP_SUB:`ALU_OP_ADD;
- if ( CIR[7:6] == 2'b11 )
- state=`PROC_EX_STATE_ENTRY;
- else
- state=`RPOC_MEMIO_READ;
- end
- default:begin
- `invalid_instruction
- end
- endcase
- end else begin
- `invalid_instruction
- end
- end
- 6'b111101 : begin
- /*HLT, CMC, TEST, NOT, NEG, MUL, IMUL, .... */
- case (CIR[9:8])
- 2'b00:begin
- /* HLT - Halt */
- /* 1 1 1 1 0 1 0 0 | */
- `start_unaligning_instruction
- MOD=2'b11;
- HALT=1;
- state=`PROC_HALT_STATE;
- end
- default:begin
- `invalid_instruction;
- end
- endcase
-
- end
- 6'b001111 : begin
- if ( CIR[9:9] == 0 ) 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=CIR[8:8];
- if(Wbit)
- `start_unaligning_instruction
- else
- `start_aligning_instruction
- MOD=2'b11;
- in_alu1_sel1=2'b00;
- in_alu1_sel2=2'b01;
- reg_read_port1_addr={CIR[8:8],3'b000};
- out_alu1_sel=3'b100;
- ALU_1OE=0;
- ALU_1OP=`ALU_OP_SUB;
- if(CIR[8:8]==1)
- state=`PROC_DE_LOAD_16_PARAM;
- else begin
- PARAM1[7:0]=CIR[7:0];
- state=`PROC_EX_STATE_ENTRY;
- end
- end else begin
- `invalid_instruction
- end
- end
- 6'b011100,
- 6'b011101,
- 6'b011110,
- 6'b011111: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 |*/
- /* .... */
- `start_aligning_instruction
- Wbit=1;
- in_alu1_sel1=2'b10;
- in_alu1_sel2=2'b00;
- PARAM2={{8{CIR[7:7]}},CIR[7:0]};
- ALU_1OE=0;
- ALU_1OP=`ALU_OP_ADD_SIGNED_B;
- out_alu1_sel=3'b101;
- case(CIR[11:9])
- 4'b000: begin
- /* Jump on (not) Overflow */
- if(FLAGS[11:11]==CIR[8:8])
- state=`PROC_IF_STATE_ENTRY;
- else begin
- state=`PROC_EX_STATE_ENTRY;
- end
- end
- 4'b010: begin
- /* Jump on (not) Zero */
- if(FLAGS[6:6]==CIR[8:8])
- state=`PROC_IF_STATE_ENTRY;
- else
- state=`PROC_EX_STATE_ENTRY;
- end
- 4'b100: begin
- /* Jump on (not) Sign */
- if(FLAGS[7:7]==CIR[8:8])
- state=`PROC_IF_STATE_ENTRY;
- else
- state=`PROC_EX_STATE_ENTRY;
- end
- 4'b101: begin
- /* Jump on (not) Parity */
- if(FLAGS[2:2]==CIR[8:8])
- state=`PROC_IF_STATE_ENTRY;
- else
- state=`PROC_EX_STATE_ENTRY;
- end
- default:begin
- `invalid_instruction; /*We don't support that condition*/
- end
- endcase
- end
- 6'b111010:begin
- /* JMP,CALL */
- case(CIR[9:8])
- 2'b00: begin
- /* CALL - Call direct within segment */
- /* 1 1 1 0 1 0 0 0 | IP-INC-LO | IP-INC-HI |*/
- `invalid_instruction
- end
- 2'b01: begin
- /* JMP - Uncoditional Jump direct within segment */
- /* 1 1 1 0 1 0 0 1 | IP-INC-LO | IP-INC-HI |*/
- `invalid_instruction
- end
- 2'b10: begin
- /* JMP - Unconditional jump direct intersegment */
- /* 0 0 0 0 0 0 0 0 | IP-LO | IP-HI | CS-LO | CS-HI | */
- `invalid_instruction
- end
- 2'b11: begin
- /* JMP - Unconditional jump direct within segment (short) */
- /* | 1 1 1 0 1 0 0 1 | IP-INC-LO | */
- `start_aligning_instruction
- Wbit=1;
- in_alu1_sel1=2'b10;
- in_alu1_sel2=2'b00;
- PARAM2={{8{CIR[7:7]}},CIR[7:0]};
- ALU_1OE=0;
- ALU_1OP=`ALU_OP_ADD_SIGNED_B;
- out_alu1_sel=3'b101;
- state=`PROC_EX_STATE_ENTRY;
- end
- endcase
- end
- 6'b110011:begin
- case(CIR[9:8])
- 2'b00:begin
- `invalid_instruction
- end
- 2'b01:begin
- if(CIR[7:0]==8'h21) begin
- /* INT - execut interrupt handler */
- /* 1 1 0 0 1 1 0 1 | DATA |*/
- `start_aligning_instruction
- /* Emulate MS-DOS print routines */
- $write("%s" ,register_file.registers[2][7:0]);
- state=`PROC_IF_STATE_ENTRY;
- end else begin
- `invalid_instruction
- end
- end
- 2'b10:begin
- `invalid_instruction
- end
- 2'b11:begin
- `invalid_instruction
- end
- endcase
- end
- default:begin
- `invalid_instruction
- end
- endcase
+ /* IF we are unaligned, the address bus contains the
+ * ProgCount and points to the second word containing
+ * the nest unread byte in extenral_data_bus[7:0]. If
+ * we are aligned the address bus points to the first
+ * word of the instruction which contains no useful
+ * data anymore but the ProgCount has the correct
+ * address so update it now so that whatever the case
+ * external_data_bus contains at leat some unkown data */
+ one_byte_instruction=(!has_operands)&&(!opcode_size);
+ external_address_bus <= ProgCount;
+ state=next_state;
+ PARAM1=DE_PARAM1;
+ PARAM2=DE_PARAM2;
+ ERROR=DE_ERROR;
+ HALT=DE_HALT;
+ reg_read_port1_addr=DE_reg_read_port1_addr;
+ reg_write_addr=DE_reg_write_addr;
end
`PROC_DE_LOAD_REG_TO_PARAM:begin
PARAM1=reg_read_port1_data;
state=`PROC_EX_STATE_ENTRY;
end
`PROC_DE_LOAD_8_PARAM:begin
- ProgCount=ProgCount+1;
- if(unaligned_access==0)begin
+ if(opcode_size==0)begin
if({Sbit,Wbit}==2'b11)begin
- PARAM1 = {{8{external_data_bus[7:7]}},external_data_bus[7:0]};
+ /*signed "16bit" read*/
+ PARAM1 = {{8{CIR[7:7]}},CIR[7:0]};
end else begin
- PARAM1[7:0] = external_data_bus[7:0];
+ PARAM1[7:0] = CIR[7:0];
end
state=`PROC_EX_STATE_ENTRY;
end else begin
- external_address_bus=ProgCount;
- state=`PROC_DE_LOAD_8_PARAM_UNALIGNED;
+ if(unaligned_access==1)begin
+ if({Sbit,Wbit}==2'b11)begin
+ /*signed "16bit" read*/
+ PARAM1 = {{8{external_data_bus[7:7]}},external_data_bus[7:0]};
+ end else begin
+ PARAM1[7:0] = external_data_bus[7:0];
+ end
+ ProgCount=ProgCount+1;
+ state=`PROC_EX_STATE_ENTRY;
+ end else begin
+ external_address_bus=ProgCount;
+ state=`PROC_DE_LOAD_8_PARAM_UNALIGNED;
+ end
end
end
`PROC_DE_LOAD_16_PARAM:begin
- if(unaligned_access==1)begin
- PARAM1[7:0] = external_data_bus[7:0];
- ProgCount=ProgCount+1;
- state=`PROC_DE_LOAD_16_EXTRA_FETCH_SET;
+ if(opcode_size==0)begin
+ if(unaligned_access==1)begin
+ PARAM1 = {external_data_bus[7:0],external_data_bus[15:8]};
+ ProgCount=ProgCount+1;
+ state=`PROC_EX_STATE_ENTRY;
+ end else begin
+ PARAM1 = {external_data_bus[15:8],CIR[7:0]};
+ state=`PROC_EX_STATE_ENTRY;
+ end
end else begin
- PARAM1[7:0] = external_data_bus[15:8];
- PARAM1[15:8] = external_data_bus[7:0];
ProgCount=ProgCount+1;
- state=`PROC_EX_STATE_ENTRY;
+ if(unaligned_access==1)begin
+ PARAM1[7:0] = external_data_bus[7:0];
+ state=`PROC_DE_LOAD_16_EXTRA_FETCH_SET;
+ end else begin
+ PARAM1 = {external_data_bus[7:0],external_data_bus[15:8]};
+ state=`PROC_EX_STATE_ENTRY;
+ end
end
end
`PROC_DE_LOAD_16_EXTRA_FETCH:begin