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