Fixed copyright notices, did some major cleanup and bumped README's versions

This commit is contained in:
(Tim) Efthimis Kritikos 2023-05-11 16:28:10 +01:00
parent a8ab6b2dc7
commit 539fb8416b
6 changed files with 281 additions and 302 deletions

View File

@ -19,11 +19,11 @@ A CPU that aims to be binary compatible with the 8086 and with as many optimisat
Both Verilator and Icarus Verilog can be used for simulation. You can select which one you want with the SIM variable on [common.mk](./common.mk) Both Verilator and Icarus Verilog can be used for simulation. You can select which one you want with the SIM variable on [common.mk](./common.mk)
Specifically this list shows the software needed and the versions used during development (other versions should work as well) Specifically this list shows the software needed and the versions used during development (other versions should work as well)
* Icarus Verilog : version 11.0 OR **(preferred)** Verilator : 5.006 * Icarus Verilog : version 11.0 OR **(preferred)** Verilator : 5.008
* bin86 : 0.16.21 * bin86 : 0.16.21
* GNU Make : 4.4.1 * GNU Make : 4.4.1
* xxd : 2022-01-14 * xxd : 2022-01-14
* POSIX coreutils : GNU coreutils 9.1 * POSIX coreutils : GNU coreutils 9.3
After that you can run `make` on the top level directory and it should build everything and start the simulation After that you can run `make` on the top level directory and it should build everything and start the simulation

View File

@ -1,4 +1,4 @@
/* processor.v - implementation of the 9086 bus interface unit. The logic that /* biu.v - implementation of the 9086 bus interface unit. The logic that
controls all external bus functions controls all external bus functions
This file is part of the 9086 project. This file is part of the 9086 project.
@ -18,7 +18,7 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */ along with this program. If not, see <http://www.gnu.org/licenses/>. */
//IOMEM: 1=IO 0=MEM `include "config.v"
`define BIU_HALT 4'b0000 `define BIU_HALT 4'b0000
`define BIU_NEXT_ACTION 4'b0001 `define BIU_NEXT_ACTION 4'b0001
@ -38,11 +38,11 @@
`define BIU_GET_SECOND_BYTE1 4'b1110 `define BIU_GET_SECOND_BYTE1 4'b1110
module BIU ( module BIU (
/*outside world*/ input clock, input reset, output reg [19:0] external_address_bus, /* Outside world */ input clock, input reset, output reg [19:0] external_address_bus,
/* */ inout [15:0] external_data_bus,output reg read, output reg write,output reg BHE,output reg IOMEM, /* */ inout [15:0] external_data_bus,output reg read, output reg write,output reg BHE,output reg IOMEM,
/* internal */ output reg [31:0] INSTRUCTION, output reg VALID_INSTRUCTION, output reg [15:0] INSTRUCTION_LOCATION, input jump_req, /* Internal */ output reg [31:0] INSTRUCTION, output reg VALID_INSTRUCTION, output reg [15:0] INSTRUCTION_LOCATION, input jump_req,
/* */ input[15:0] ADDRESS_INPUT, inout [15:0] DATA, input write_request, input read_request, input Wbit, output reg VALID_DATA, input MEM_OR_IO, /* */ input[15:0] ADDRESS_INPUT, inout [15:0] DATA, input write_request, input read_request, input Wbit, output reg VALID_DATA, input MEM_OR_IO,
/* */ input [`PROC_STATE_BITS-1:0] proc_state, input SIMPLE_MICRO /* */ input [`PROC_STATE_BITS-1:0] proc_state, input SIMPLE_MICRO
); );
reg [15:0] data_bus_output_register; reg [15:0] data_bus_output_register;
@ -52,12 +52,11 @@ reg [15:0] DATA_OUT;
reg DATA_DIR; reg DATA_DIR;
assign DATA=DATA_DIR ? 16'hz:DATA_OUT; assign DATA=DATA_DIR ? 16'hz:DATA_OUT;
`define L1_CACHE_SIZE 4 // Don't change this! some parts of the code assume this `define FIFO_SIZE_BYTES $rtoi($pow(2,`L1_CACHE_SIZE))
`define FIFO_SIZE_BYTES 16 //$pow(2,`L1_CACHE_SIZE)
reg [7:0] INPUT_FIFO [`FIFO_SIZE_BYTES-1:0]; reg [7:0] INPUT_FIFO [`FIFO_SIZE_BYTES-1:0];
reg [`L1_CACHE_SIZE-1:0] FIFO_start; /*inclusive*/ reg [`L1_CACHE_SIZE-1:0] FIFO_start; /*inclusive*/
reg [`L1_CACHE_SIZE-1:0] FIFO_end; /*exclusive*/ reg [`L1_CACHE_SIZE-1:0] FIFO_end; /*exclusive*/
wire [`L1_CACHE_SIZE-1:0] FIFO_SIZE = FIFO_end-FIFO_start; wire [`L1_CACHE_SIZE-1:0] FIFO_SIZE = FIFO_end-FIFO_start;
reg [3:0] biu_state; reg [3:0] biu_state;
@ -65,7 +64,6 @@ reg [3:0] biu_state;
always @(negedge reset) begin always @(negedge reset) begin
biu_state <= `BIU_HALT; biu_state <= `BIU_HALT;
end end
always @(posedge reset) begin always @(posedge reset) begin
biu_state <= `BIU_RESET; biu_state <= `BIU_RESET;
end end
@ -76,10 +74,8 @@ reg func;
reg [19:0]INSTRUCTION_ADDRESS; reg [19:0]INSTRUCTION_ADDRESS;
reg [19:0]DATA_ADDRESS; reg [19:0]DATA_ADDRESS;
assign external_address_bus= func? INSTRUCTION_ADDRESS : DATA_ADDRESS ; assign external_address_bus= func? INSTRUCTION_ADDRESS : DATA_ADDRESS ;
/* Read into the FIFO */
always @(posedge clock) begin always @(posedge clock) begin
if ( jump_req_latch ) begin if ( jump_req_latch ) begin
/* verilator lint_off BLKSEQ */ /* verilator lint_off BLKSEQ */
@ -145,33 +141,30 @@ always @(posedge clock) begin
end end
end end
/*************** INSTRUCTION FIFO READ ***************/ /*************** INSTRUCTION FIFO READ ***************/
`BIU_READ: begin `BIU_READ: begin
/* verilator lint_off BLKSEQ */
if(INSTRUCTION_ADDRESS[0:0]==0 && FIFO_SIZE<4'hD)begin if(INSTRUCTION_ADDRESS[0:0]==0 && FIFO_SIZE<4'hD)begin
INPUT_FIFO[FIFO_end] = external_data_bus[7:0]; INPUT_FIFO[FIFO_end] <= external_data_bus[7:0];
INPUT_FIFO[FIFO_end+4'd1] = external_data_bus[15:8]; INPUT_FIFO[FIFO_end+4'd1] <= external_data_bus[15:8];
FIFO_end <= FIFO_end+4'd2; FIFO_end <= FIFO_end+4'd2;
INSTRUCTION_ADDRESS <= INSTRUCTION_ADDRESS+20'd2; INSTRUCTION_ADDRESS <= INSTRUCTION_ADDRESS+20'd2;
end else if(INSTRUCTION_ADDRESS[0:0]==0)begin end else if(INSTRUCTION_ADDRESS[0:0]==0)begin
INPUT_FIFO[FIFO_end] = external_data_bus[7:0]; INPUT_FIFO[FIFO_end] <= external_data_bus[7:0];
FIFO_end <= FIFO_end+4'd1; FIFO_end <= FIFO_end+4'd1;
INSTRUCTION_ADDRESS <= INSTRUCTION_ADDRESS+1; INSTRUCTION_ADDRESS <= INSTRUCTION_ADDRESS+1;
end else begin end else begin
INPUT_FIFO[FIFO_end] = external_data_bus[15:8]; INPUT_FIFO[FIFO_end] <= external_data_bus[15:8];
FIFO_end <= FIFO_end+4'd1; FIFO_end <= FIFO_end+4'd1;
INSTRUCTION_ADDRESS <= INSTRUCTION_ADDRESS+1; INSTRUCTION_ADDRESS <= INSTRUCTION_ADDRESS+1;
end end
/* verilator lint_on BLKSEQ */
biu_state <= `BIU_NEXT_ACTION; biu_state <= `BIU_NEXT_ACTION;
read<=1; read<=1;
end end
/*************** DATA WRITE ***************/ /*************** DATA WRITE ***************/
//TODO TODO TODO flush fifo, self modifying code //TODO TODO TODO flush fifo, self modifying code
`BIU_PUT_UNALIGNED_16BIT_DATA:begin `BIU_PUT_UNALIGNED_16BIT_DATA:begin
//TODO Put that in the previous stage, save a clock cycle
`ifdef DEBUG_DATA_READ_WRITES `ifdef DEBUG_DATA_READ_WRITES
$display("Writing 16bit %04x at %04x",DATA,DATA_ADDRESS); $display("Writing 16bit %04x at %04x",DATA,DATA_ADDRESS);
`endif `endif
@ -194,7 +187,6 @@ always @(posedge clock) begin
write <= 0; write <= 0;
biu_state <= `BIU_WRITE_RELEASE; biu_state <= `BIU_WRITE_RELEASE;
end end
`BIU_PUT_BYTE:begin `BIU_PUT_BYTE:begin
`ifdef DEBUG_DATA_READ_WRITES `ifdef DEBUG_DATA_READ_WRITES
$display("Writing 8bit %02x at %04x",DATA[7:0],DATA_ADDRESS); $display("Writing 8bit %02x at %04x",DATA[7:0],DATA_ADDRESS);
@ -288,10 +280,9 @@ end
wire [2:0] Isize; wire [2:0] Isize;
InstrSize InstrSize({INSTRUCTION[31:24],INSTRUCTION[21:19]},Isize); InstrSize InstrSize({INSTRUCTION[31:24],INSTRUCTION[21:19]},Isize);
/* verilator lint_off UNDRIVEN */
wire [2:0] fifoIsize; wire [2:0] fifoIsize;
wire Isit1; wire Isit1;
/* verilator lint_on UNDRIVEN */
`ifdef EARLY_VALID_INSTRUCTION `ifdef EARLY_VALID_INSTRUCTION
InstrSize fifoInstrSize({INPUT_FIFO[FIFO_start][7:0],INPUT_FIFO[FIFO_start+1][5:3]},fifoIsize); InstrSize fifoInstrSize({INPUT_FIFO[FIFO_start][7:0],INPUT_FIFO[FIFO_start+1][5:3]},fifoIsize);
Is1 Is1(INPUT_FIFO[FIFO_start][7:0],Isit1); Is1 Is1(INPUT_FIFO[FIFO_start][7:0],Isit1);
@ -310,16 +301,16 @@ always @( proc_state ) begin
was_dec<=0; was_dec<=0;
/* verilator lint_off BLKSEQ */ /* verilator lint_off BLKSEQ */
FIFO_start = FIFO_start + {1'b0,Isize}; FIFO_start = FIFO_start + {1'b0,Isize};
INSTRUCTION_LOCATION <= INSTRUCTION_LOCATION + {12'b0,Isize};;
/* verilator lint_on BLKSEQ */ /* verilator lint_on BLKSEQ */
INSTRUCTION_LOCATION <= INSTRUCTION_LOCATION + {12'b0,Isize};;
VALID_INSTRUCTION <= 0; VALID_INSTRUCTION <= 0;
end else if ( SIMPLE_MICRO==1 && was_simple == 1) begin end else if ( SIMPLE_MICRO==1 && was_simple == 1) begin
was_simple<=0; was_simple<=0;
was_dec<=0; was_dec<=0;
/* verilator lint_off BLKSEQ */ /* verilator lint_off BLKSEQ */
FIFO_start = FIFO_start + {1'b0,Isize}; FIFO_start = FIFO_start + {1'b0,Isize};
INSTRUCTION_LOCATION <= INSTRUCTION_LOCATION + {12'b0,Isize};;
/* verilator lint_on BLKSEQ */ /* verilator lint_on BLKSEQ */
INSTRUCTION_LOCATION <= INSTRUCTION_LOCATION + {12'b0,Isize};;
VALID_INSTRUCTION <= 0; VALID_INSTRUCTION <= 0;
end end
end end
@ -336,54 +327,3 @@ always @( posedge jump_req ) begin
end end
endmodule endmodule
/* Pre-Decode the instruction size */
/* IN: {CIR[15:8],CIR[5:3]} */
/* OUT: number in bytes */
module InstrSize ( input [10:0] IN, output reg [2:0] VERDICT );
always @( IN ) 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 */
default:begin end
endcase
end
endmodule
`ifdef EARLY_VALID_INSTRUCTION
module Is1 ( input [7:0] IN, output reg VERDICT );
always @( IN ) 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

View File

@ -29,9 +29,16 @@
* for the maximum instruction size worth of bytes */ * for the maximum instruction size worth of bytes */
`define EARLY_VALID_INSTRUCTION `define EARLY_VALID_INSTRUCTION
/* Size is in powers of two with minimal 3.
* 3 : 8 Bytes
* 4 : 16 Bytes
* 5 : 32 Bytes
* . : ... */
`define L1_CACHE_SIZE 4 // Don't change it! some parts of code still assume it to be 4
/* Internal */
/********** Internal **********/
`ifdef EARLY_VALID_INSTRUCTION `ifdef EARLY_VALID_INSTRUCTION
`define EARLY_VALID_INSTRUCTION_ 1 `define EARLY_VALID_INSTRUCTION_ 1
`else `else

View File

@ -43,37 +43,64 @@ assign DATA=ucode_rom[ADDR];
endmodule endmodule
// verilator lint_off UNUSEDSIGNAL
module decoder( module decoder(
input wire [15:0] CIR,input wire [15:0] FLAGS, output wire [2:0] INSTRUCTION_INFO, output wire [`ERROR_BITS:0] DECODER_SIGNALS, output reg [`EXEC_STATE_BITS-1:0] next_state /* INPUTS */ input wire [15:0] CIR,input wire [15:0] FLAGS
,output reg [2:0]IN_MOD, output reg [2:0]RM, output reg [15:0] PARAM1,output reg [15:0] PARAM2 /* 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 reg [1:0]in_alu_sel1,output reg [1:0]in_alu_sel2,output reg [2:0]OUT_MOD /* OUTPUT */ ,output wire [`EXEC_STATE_BITS+`ERROR_BITS+65:0] OUTPUT
,output wire [11:0]REGISTER_FILE_CONTROL
,output reg [2:0]ALU_1OP
,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 reg memio_address_select
,output reg MEM_OR_IO
); );
// verilator lint_on UNUSEDSIGNAL
reg [2:0]IN_MOD;
assign OUTPUT[2:0] = IN_MOD;
reg [2:0]RM;
assign OUTPUT[5:3] = RM;
reg memio_address_select;
assign OUTPUT[6:6] = memio_address_select;
reg MEM_OR_IO;
assign OUTPUT[7:7] = MEM_OR_IO;
reg [15:0] PARAM1;
assign OUTPUT[23:8] = PARAM1;
reg [15:0] PARAM2;
assign OUTPUT[39:24] = PARAM2;
reg [2:0]ALU_OP;
assign OUTPUT[42:40] = ALU_OP;
reg [1:0]in_alu_sel1;
assign OUTPUT[44:43] = in_alu_sel1;
reg [1:0]in_alu_sel2;
assign OUTPUT[46:45] = in_alu_sel2;
reg [2:0]OUT_MOD;
assign OUTPUT[49:47] = OUT_MOD;
reg [3:0]reg_read_port1_addr; reg [3:0]reg_read_port1_addr;
reg [3:0]reg_read_port2_addr; assign OUTPUT[53:50] = reg_read_port1_addr;
reg [3:0]reg_write_addr;
assign REGISTER_FILE_CONTROL={reg_write_addr,reg_read_port1_addr,reg_read_port2_addr}; reg [3:0]reg_read_port2_addr;
assign OUTPUT[57:54] = reg_read_port2_addr;
reg [3:0]reg_write_addr;
assign OUTPUT[61:58] = reg_write_addr;
/* For correct fetching of instructions and global options for the alu */
reg Wbit,Sbit,opcode_size; reg Wbit,Sbit,opcode_size;
assign INSTRUCTION_INFO={Wbit,Sbit,opcode_size}; assign OUTPUT[64:62] = {Wbit,Sbit,opcode_size};
reg [`ERROR_BITS-1:0] ERROR; reg [`ERROR_BITS-1:0] ERROR;
reg HALT; reg HALT;
assign DECODER_SIGNALS={ERROR,HALT}; assign OUTPUT[`ERROR_BITS+65:65]={ERROR,HALT};
reg [`EXEC_STATE_BITS-1:0] next_state;
assign OUTPUT[`EXEC_STATE_BITS+`ERROR_BITS+65:`ERROR_BITS+66] = next_state;
/* verilator lint_off UNUSEDSIGNAL */
// verilator lint_off UNUSEDSIGNAL
wire [`UCODE_DATA_BITS-1:0] ucode_data; wire [`UCODE_DATA_BITS-1:0] ucode_data;
// verilator lint_on UNUSEDSIGNAL /* verilator lint_on UNUSEDSIGNAL */
microcode ucode(seq_addr_input,ucode_data); microcode ucode(seq_addr_input,ucode_data);
@ -97,7 +124,7 @@ always @( FLAGS or CIR or SIMPLE_MICRO or seq_addr_input ) begin
11'b0000_010?_??? : begin 11'b0000_010?_??? : begin
/* ADD - Add Immediate word/byte to accumulator */ /* ADD - Add Immediate word/byte to accumulator */
/* 0 0 0 0 0 1 0 W | DATA | DATA if W |*/ /* 0 0 0 0 0 1 0 W | DATA | DATA if W |*/
opcode_size=0; //TODO: move the decoding done in BIU here and use theat size checker opcode_size=0;
Wbit=CIR[8:8]; Wbit=CIR[8:8];
IN_MOD=3'b011; IN_MOD=3'b011;
in_alu_sel1=2'b00; in_alu_sel1=2'b00;
@ -106,7 +133,7 @@ always @( FLAGS or CIR or SIMPLE_MICRO or seq_addr_input ) begin
MEM_OR_IO=0; MEM_OR_IO=0;
reg_read_port2_addr={Wbit,3'b000}; reg_read_port2_addr={Wbit,3'b000};
reg_write_addr={Wbit,3'b000}; reg_write_addr={Wbit,3'b000};
ALU_1OP=`ALU_OP_ADD; ALU_OP=`ALU_OP_ADD;
memio_address_select=0; memio_address_select=0;
if(Wbit) if(Wbit)
next_state=`EXEC_DE_LOAD_16_PARAM; next_state=`EXEC_DE_LOAD_16_PARAM;
@ -148,8 +175,8 @@ always @( FLAGS or CIR or SIMPLE_MICRO or seq_addr_input ) begin
end end
endcase endcase
case(CIR[5:3]) case(CIR[5:3])
3'b000: ALU_1OP=`ALU_OP_ADD; 3'b000: ALU_OP=`ALU_OP_ADD;
3'b101: ALU_1OP=`ALU_OP_SUB_REVERSE; 3'b101: ALU_OP=`ALU_OP_SUB_REVERSE;
default:begin default:begin
/*Should be impossible*/ /*Should be impossible*/
`invalid_instruction `invalid_instruction
@ -171,7 +198,7 @@ always @( FLAGS or CIR or SIMPLE_MICRO or seq_addr_input ) begin
in_alu_sel1=2'b00; in_alu_sel1=2'b00;
OUT_MOD=3'b100; OUT_MOD=3'b100;
MEM_OR_IO=0; MEM_OR_IO=0;
ALU_1OP=`ALU_OP_SUB; ALU_OP=`ALU_OP_SUB;
memio_address_select=0; memio_address_select=0;
if(IN_MOD==3'b011)begin if(IN_MOD==3'b011)begin
/*compare register with param*/ /*compare register with param*/
@ -199,7 +226,7 @@ always @( FLAGS or CIR or SIMPLE_MICRO or seq_addr_input ) begin
reg_write_addr={1'b0,CIR[10:8]}; reg_write_addr={1'b0,CIR[10:8]};
PARAM1[7:0]=CIR[7:0]; PARAM1[7:0]=CIR[7:0];
PARAM2=0; PARAM2=0;
ALU_1OP=`ALU_OP_ADD; ALU_OP=`ALU_OP_ADD;
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
`normal_instruction; `normal_instruction;
memio_address_select=0; memio_address_select=0;
@ -214,7 +241,7 @@ always @( FLAGS or CIR or SIMPLE_MICRO or seq_addr_input ) begin
OUT_MOD=3'b011; OUT_MOD=3'b011;
MEM_OR_IO=0; MEM_OR_IO=0;
reg_write_addr={1'b1,CIR[10:8]}; reg_write_addr={1'b1,CIR[10:8]};
ALU_1OP=`ALU_OP_ADD; ALU_OP=`ALU_OP_ADD;
PARAM2=0; PARAM2=0;
next_state=`EXEC_DE_LOAD_16_PARAM; next_state=`EXEC_DE_LOAD_16_PARAM;
`normal_instruction; `normal_instruction;
@ -260,7 +287,7 @@ always @( FLAGS or CIR or SIMPLE_MICRO or seq_addr_input ) begin
end end
reg_read_port2_addr={Wbit,CIR[5:3]}; reg_read_port2_addr={Wbit,CIR[5:3]};
end end
ALU_1OP=`ALU_OP_ADD; ALU_OP=`ALU_OP_ADD;
`normal_instruction; `normal_instruction;
memio_address_select=0; memio_address_select=0;
@ -281,9 +308,9 @@ always @( FLAGS or CIR or SIMPLE_MICRO or seq_addr_input ) begin
reg_read_port1_addr={1'b1,CIR[10:8]}; reg_read_port1_addr={1'b1,CIR[10:8]};
reg_write_addr={1'b1,CIR[10:8]}; reg_write_addr={1'b1,CIR[10:8]};
if(CIR[11:11]==0) if(CIR[11:11]==0)
ALU_1OP=`ALU_OP_ADD; ALU_OP=`ALU_OP_ADD;
else else
ALU_1OP=`ALU_OP_SUB; ALU_OP=`ALU_OP_SUB;
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
`normal_instruction; `normal_instruction;
memio_address_select=0; memio_address_select=0;
@ -307,7 +334,7 @@ always @( FLAGS or CIR or SIMPLE_MICRO or seq_addr_input ) begin
reg_read_port2_addr={1'b0,RM}; reg_read_port2_addr={1'b0,RM};
reg_write_addr={1'b0,RM}; reg_write_addr={1'b0,RM};
ALU_1OP=(CIR[3:3]==1)?`ALU_OP_SUB_REVERSE:`ALU_OP_ADD; ALU_OP=(CIR[3:3]==1)?`ALU_OP_SUB_REVERSE:`ALU_OP_ADD;
if ( IN_MOD == 3'b011 ) if ( IN_MOD == 3'b011 )
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
else else
@ -340,7 +367,7 @@ always @( FLAGS or CIR or SIMPLE_MICRO or seq_addr_input ) begin
in_alu_sel2=2'b01; in_alu_sel2=2'b01;
reg_read_port2_addr={Wbit,3'b000}; reg_read_port2_addr={Wbit,3'b000};
OUT_MOD=3'b100; OUT_MOD=3'b100;
ALU_1OP=`ALU_OP_SUB; ALU_OP=`ALU_OP_SUB;
MEM_OR_IO=0; MEM_OR_IO=0;
if(Wbit==1) if(Wbit==1)
next_state=`EXEC_DE_LOAD_16_PARAM; next_state=`EXEC_DE_LOAD_16_PARAM;
@ -365,7 +392,7 @@ always @( FLAGS or CIR or SIMPLE_MICRO or seq_addr_input ) begin
in_alu_sel1=2'b10; in_alu_sel1=2'b10;
in_alu_sel2=2'b00; in_alu_sel2=2'b00;
PARAM2={{8{CIR[7:7]}},CIR[7:0]}; PARAM2={{8{CIR[7:7]}},CIR[7:0]};
ALU_1OP=`ALU_OP_ADD_SIGNED_B; ALU_OP=`ALU_OP_ADD_SIGNED_B;
MEM_OR_IO=0; MEM_OR_IO=0;
OUT_MOD=3'b101; OUT_MOD=3'b101;
case(CIR[11:9]) case(CIR[11:9])
@ -413,7 +440,7 @@ always @( FLAGS or CIR or SIMPLE_MICRO or seq_addr_input ) begin
in_alu_sel1=2'b10; in_alu_sel1=2'b10;
in_alu_sel2=2'b00; in_alu_sel2=2'b00;
PARAM2={{8{CIR[7:7]}},CIR[7:0]}; PARAM2={{8{CIR[7:7]}},CIR[7:0]};
ALU_1OP=`ALU_OP_ADD_SIGNED_B; ALU_OP=`ALU_OP_ADD_SIGNED_B;
OUT_MOD=3'b101; OUT_MOD=3'b101;
MEM_OR_IO=0; MEM_OR_IO=0;
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
@ -484,7 +511,7 @@ always @( FLAGS or CIR or SIMPLE_MICRO or seq_addr_input ) begin
next_state=`EXEC_DE_LOAD_8_PARAM; next_state=`EXEC_DE_LOAD_8_PARAM;
end end
in_alu_sel1=2'b00; /* PARAM1 */ in_alu_sel1=2'b00; /* PARAM1 */
ALU_1OP=`ALU_OP_AND; ALU_OP=`ALU_OP_AND;
case(IN_MOD) case(IN_MOD)
3'b011:begin 3'b011:begin
in_alu_sel2=2'b01; in_alu_sel2=2'b01;
@ -527,7 +554,7 @@ always @( FLAGS or CIR or SIMPLE_MICRO or seq_addr_input ) begin
in_alu_sel2=2'b00; in_alu_sel2=2'b00;
next_state=`EXEC_MEMIO_READ; next_state=`EXEC_MEMIO_READ;
end end
ALU_1OP=`ALU_OP_ADD; ALU_OP=`ALU_OP_ADD;
OUT_MOD=3'b101; OUT_MOD=3'b101;
`normal_instruction; `normal_instruction;
memio_address_select=0; memio_address_select=0;
@ -623,14 +650,14 @@ always @( FLAGS or CIR or SIMPLE_MICRO or seq_addr_input ) begin
/*1:1 map essentially but I want to keep the spec for these bits separate /*1:1 map essentially but I want to keep the spec for these bits separate
* from the alu op select bits*/ * from the alu op select bits*/
case(ucode_data[22:20]) case(ucode_data[22:20])
3'b000: ALU_1OP=`ALU_OP_ADD; 3'b000: ALU_OP=`ALU_OP_ADD;
3'b001: ALU_1OP=`ALU_OP_SUB; 3'b001: ALU_OP=`ALU_OP_SUB;
3'b010: ALU_1OP=`ALU_OP_AND; 3'b010: ALU_OP=`ALU_OP_AND;
3'b011: ALU_1OP=`ALU_OP_OR; 3'b011: ALU_OP=`ALU_OP_OR;
3'b100: ALU_1OP=`ALU_OP_XOR; 3'b100: ALU_OP=`ALU_OP_XOR;
3'b101: ALU_1OP=`ALU_OP_ADD_SIGNED_B; 3'b101: ALU_OP=`ALU_OP_ADD_SIGNED_B;
3'b110: ALU_1OP=`ALU_OP_SUB_REVERSE; 3'b110: ALU_OP=`ALU_OP_SUB_REVERSE;
3'b111: ALU_1OP=`ALU_OP_SHIFT_LEFT; 3'b111: ALU_OP=`ALU_OP_SHIFT_LEFT;
default: begin end default: begin end
endcase endcase
if(ucode_data[34:34]==0) /* Set reg read port 1 address */ if(ucode_data[34:34]==0) /* Set reg read port 1 address */
@ -649,3 +676,54 @@ end
endmodule endmodule
// verilator lint_on BLKSEQ // verilator lint_on BLKSEQ
/* IN: {CIR[15:8],CIR[5:3]} */
/* OUT: number in bytes */
module InstrSize ( input [10:0] IN, output reg [2:0] VERDICT );
always @( IN ) 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 */
default:begin end
endcase
end
endmodule
`ifdef EARLY_VALID_INSTRUCTION
module Is1 ( input [7:0] IN, output reg VERDICT );
always @( IN ) 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

View File

@ -1,3 +1,22 @@
/* execute.v - Implements the instruction execution 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 <http://www.gnu.org/licenses/>. */
module execute_unit ( module execute_unit (
/* GENERAL */ input clock, input reset ,input Wbit, input Sbit, input opcode_size,input [23:0] INSTRUCTION_BUFFER,input valid_input /* GENERAL */ input clock, input reset ,input Wbit, input Sbit, input opcode_size,input [23:0] INSTRUCTION_BUFFER,input valid_input
/* */ ,input [2:0] IN_MOD, input [2:0] OUT_MOD, input memio_address_select, input [15:0] ProgCount, input [2:0] RM, output reg [`ERROR_BITS-1:0] ERROR , input write /*TODO: REMOVE!!*/ /* */ ,input [2:0] IN_MOD, input [2:0] OUT_MOD, input memio_address_select, input [15:0] ProgCount, input [2:0] RM, output reg [`ERROR_BITS-1:0] ERROR , input write /*TODO: REMOVE!!*/
@ -13,12 +32,11 @@ module execute_unit (
assign _exec_state_ = exec_state; assign _exec_state_ = exec_state;
assign _ALU_O_ = ALU_O; assign _ALU_O_ = ALU_O;
/*############ ALU / Execution units ########################################################## */
// ALU 1
reg [`EXEC_STATE_BITS-1:0] exec_state; reg [`EXEC_STATE_BITS-1:0] exec_state;
reg [15:0] PARAM1,PARAM2; reg [15:0] PARAM1,PARAM2;
/*############ ALU / Execution units ################################################## */
mux4 #(.WIDTH(16)) MUX16_1A( mux4 #(.WIDTH(16)) MUX16_1A(
/*0*/ PARAM1, /*0*/ PARAM1,
/*1*/ reg_read_port1_data, /*1*/ reg_read_port1_data,
@ -41,28 +59,24 @@ wire [15:0] ALU_O;
wire [7:0] ALU_FLAGS; wire [7:0] ALU_FLAGS;
ALU ALU1( ALU ALU1(
.A(ALU_A), /* INPUT 1 */ .A(ALU_A),
.B(ALU_B), /* INPUT 2 */ .B(ALU_B),
.OUT(ALU_O), /* OUTPUT */ .OUT(ALU_O),
.op(ALU_OP), /* OPERATION */ .op(ALU_OP),
.FLAGS(ALU_FLAGS), /* FLAGS */ .FLAGS(ALU_FLAGS),
.Wbit(Wbit) /* Wbit */ .Wbit(Wbit)
); );
//reg valid_input_; /*############ Execute logic ########################################################## */
always @(posedge valid_input) begin always @(posedge valid_input) begin
exec_state <= init_state; exec_state <= init_state;
//valid_input_ <= 1;
end end
always @(negedge set_initial_values) begin always @(negedge set_initial_values) begin
PARAM1 <= PARAM1_INIT; PARAM1 <= PARAM1_INIT;
PARAM2 <= PARAM2_INIT; PARAM2 <= PARAM2_INIT;
end end
//always @(negedge valid_input) begin
// valid_input_ <= 0;
//end
always @(negedge reset) begin always @(negedge reset) begin
exec_state <= `EXEC_HALT; exec_state <= `EXEC_HALT;
@ -76,7 +90,6 @@ end
always @(posedge clock) begin always @(posedge clock) begin
case (exec_state) case (exec_state)
`EXEC_RESET: begin `EXEC_RESET: begin
//valid_input_ <= 0;
biu_write_request <= 0; biu_write_request <= 0;
biu_read_request <= 0; biu_read_request <= 0;
biu_data_direction <= 0; biu_data_direction <= 0;
@ -87,7 +100,6 @@ always @(posedge clock) begin
end end
`EXEC_DONE:begin `EXEC_DONE:begin
reg_write_we <= 1; reg_write_we <= 1;
//valid_input_ <= 0;
biu_jump_req <= 0; biu_jump_req <= 0;
use_exec_reg_addr <= 0; use_exec_reg_addr <= 0;
end end

View File

@ -23,194 +23,159 @@
`include "ucode_header.v" `include "ucode_header.v"
`include "error_header.v" `include "error_header.v"
//HALT: active high
//IOMEM: 1=IO 0=MEM
//write: active low
//read: active low
//reset: active low
`define PROC_STATE_BITS 3 `define PROC_STATE_BITS 3
`define PROC_RESET 3'b000 `define PROC_RESET 3'b000
`define PROC_DE_STATE_ENTRY 3'b001 `define PROC_DE_STATE_ENTRY 3'b001
`define PROC_WAIT 3'b010 `define PROC_WAIT 3'b010
`define PROC_HALT 3'b011 `define PROC_HALT 3'b011
module processor ( input clock, input reset, output [19:0] external_address_bus, inout [15:0] external_data_bus,output read, output write,output BHE,output IOMEM, output reg HALT,output [`ERROR_BITS-1:0] ERROR); //HALT: active high
//IOMEM: 1=IO 0=MEM
//BHE: active low
//write: active low
//read: active low
//reset: active low
module processor ( input clock, input reset, output [19:0] external_address_bus, inout [15:0] external_data_bus,output read, output write,output BHE,output IOMEM, output wire HALT,output [`ERROR_BITS-1:0] ERROR);
/* If there is an error either from the decoder or execution unit set it to ERROR */ /* If there is an error either from the decoder or execution unit set it to ERROR */
assign ERROR=(DE_ERROR_sampled!=`ERR_NO_ERROR)?DE_ERROR_sampled:(EXEC_ERROR!=`ERR_NO_ERROR)?EXEC_ERROR:`ERR_NO_ERROR; assign ERROR=(DE_ERROR!=`ERR_NO_ERROR)?DE_ERROR:(EXEC_ERROR!=`ERR_NO_ERROR)?EXEC_ERROR:`ERR_NO_ERROR;
/*** Global Definitions ***/
reg [`PROC_STATE_BITS-1:0] state; reg [`PROC_STATE_BITS-1:0] state;
/*############ Execution Unit ################################################## */ /*############ Execution Unit ################################################### */
reg [1:0] in_alu_sel1;
reg [1:0] in_alu_sel2; wire [1:0] in_alu_sel1, in_alu_sel2;
assign in_alu_sel1 = DE_OUTPUT_sampled[44:43];
assign in_alu_sel2 = DE_OUTPUT_sampled[46:45];
wire [`EXEC_STATE_BITS-1:0] exec_state; wire [`EXEC_STATE_BITS-1:0] exec_state;
reg valid_exec_data; reg valid_exec_data, set_initial_values;
wire [`ERROR_BITS-1:0] EXEC_ERROR; wire [`ERROR_BITS-1:0] EXEC_ERROR;
wire use_exec_reg_addr; wire use_exec_reg_addr;
wire [3:0] EXEC_reg_read_port1_addr; wire [3:0] EXEC_reg_read_port1_addr;
reg [2:0] IN_MOD,OUT_MOD;
reg [`EXEC_STATE_BITS-1:0] exec_state_init;
reg [`ALU_OP_BITS-1:0] ALU_OP;
wire [15:0] ALU_O; wire [15:0] ALU_O;
wire [7:0]EXEC_FLAGS; wire [7:0]EXEC_FLAGS;
reg [15:0] PARAM1_INIT;
reg [15:0] PARAM2_INIT; wire [15:0] PARAM1_INIT, PARAM2_INIT;
reg set_initial_values; assign PARAM1_INIT = DE_OUTPUT_sampled[23:8];
assign PARAM2_INIT = DE_OUTPUT_sampled[39:24];
wire [2:0] IN_MOD,OUT_MOD;
assign IN_MOD=DE_OUTPUT_sampled[2:0];
assign OUT_MOD=DE_OUTPUT_sampled[49:47];
wire [`ALU_OP_BITS-1:0] ALU_OP;
assign ALU_OP = DE_OUTPUT_sampled[42:40];
execute_unit execute_unit ( execute_unit execute_unit (
/* GENERAL */ clock, reset, Wbit, Sbit, opcode_size, INSTRUCTION_BUFFER,valid_exec_data /* GENERAL */ clock, reset, Wbit, Sbit, opcode_size, INSTRUCTION_BUFFER,valid_exec_data
/* */ ,IN_MOD, OUT_MOD,memio_address_select, ProgCount, RM, EXEC_ERROR, write /* */ ,IN_MOD, OUT_MOD,memio_address_select, ProgCount, RM, EXEC_ERROR, write
/* */ ,set_initial_values /* */ ,set_initial_values
/* PARAM */ ,PARAM1_INIT,PARAM2_INIT /* PARAM */ ,PARAM1_INIT,PARAM2_INIT
/* STATE CONTROL */ ,exec_state, exec_state_init /* STATE CONTROL */ ,exec_state, next_state
/* ALU CONTROL */ ,in_alu_sel1, in_alu_sel2, ALU_OP, ALU_O /* ALU CONTROL */ ,in_alu_sel1, in_alu_sel2, ALU_OP, ALU_O
/* REGISTER DATA */ ,reg_read_port1_data, reg_read_port2_data, EXEC_reg_read_port1_addr, use_exec_reg_addr, reg_write_we /* REGISTER DATA */ ,reg_read_port1_data, reg_read_port2_data, EXEC_reg_read_port1_addr, use_exec_reg_addr, reg_write_we
/* FLAFS */ ,EXEC_FLAGS /* FLAFS */ ,EXEC_FLAGS
/* BIU */ ,BIU_ADDRESS_INPUT, biu_write_request, biu_read_request, BIU_VALID_DATA, BIU_DATA, biu_data_direction, biu_jump_req /* BIU */ ,BIU_ADDRESS_INPUT, biu_write_request, biu_read_request, BIU_VALID_DATA, BIU_DATA, biu_data_direction, biu_jump_req
); );
/*############ Bus Interface Unit ############################################### */ /*############ Bus Interface Unit ############################################### */
wire [31:0] INSTRUCTION; wire [15:0] INSTRUCTION_LOCATION, BIU_ADDRESS_INPUT;
wire biu_jump_req;
wire VALID_INSTRUCTION;
wire [15:0] INSTRUCTION_LOCATION;
wire [15:0] BIU_ADDRESS_INPUT;
wire [15:0] BIU_DATA; wire [15:0] BIU_DATA;
wire biu_write_request; wire [31:0] INSTRUCTION;
wire biu_data_direction; wire biu_write_request, biu_read_request, BIU_VALID_DATA;
wire biu_read_request; wire biu_jump_req, biu_data_direction,VALID_INSTRUCTION;
wire BIU_VALID_DATA;
BIU BIU( BIU BIU(
clock,reset,external_address_bus,external_data_bus,read,write,BHE,IOMEM, /* Outside world */ clock,reset,external_address_bus
INSTRUCTION,VALID_INSTRUCTION,INSTRUCTION_LOCATION,biu_jump_req,BIU_ADDRESS_INPUT,BIU_DATA,biu_write_request,biu_read_request,Wbit,BIU_VALID_DATA,MEM_OR_IO, /* */ ,external_data_bus,read,write,BHE,IOMEM
state,SIMPLE_MICRO /* Internal */ ,INSTRUCTION,VALID_INSTRUCTION,INSTRUCTION_LOCATION,biu_jump_req
); /* */ ,BIU_ADDRESS_INPUT,BIU_DATA,biu_write_request,biu_read_request,Wbit,BIU_VALID_DATA,MEM_OR_IO
/* */ ,state,SIMPLE_MICRO
);
assign BIU_DATA= biu_data_direction ? 16'hz : (memio_address_select ? reg_read_port1_data : ALU_O); assign BIU_DATA= biu_data_direction ? 16'hz : (memio_address_select ? reg_read_port1_data : ALU_O);
/*############ Decoder ########################################################## */ /*############ Decoder ########################################################## */
reg Wbit, Sbit, opcode_size;
wire DE_Wbit, DE_Sbit, DE_opcode_size;
wire [`EXEC_STATE_BITS-1:0] next_state;
reg [2:0]RM;
wire [15:0]DE_PARAM1;// Input param1 form decoder to alu
wire [15:0]DE_PARAM2;
wire [2:0]DE_IN_MOD;
wire [2:0]DE_RM;
wire [2:0]DE_OUT_MOD;
wire [`ERROR_BITS-1:0] DE_ERROR;
wire DE_HALT;
wire [3:0]DE_reg_read_port1_addr,DE_reg_write_addr,DE_reg_read_port2_addr;
wire [11:0]DE_REGISTER_CONTROL;
wire [2:0]INSTRUCTION_INFO;
wire [`ERROR_BITS:0]DECODER_SIGNALS;
wire [`UCODE_ADDR_BITS-1:0] ucode_seq_addr_entry; wire [`UCODE_ADDR_BITS-1:0] ucode_seq_addr_entry;
reg SIMPLE_MICRO; /* output simple decodings (=0) or microcode data (=1) */
//TODO : remove completely?
reg memio_address_select;
wire DE_memio_address_select;
wire DE_MEM_OR_IO;
reg MEM_OR_IO;
wire [1:0] DE_in_alu_sel1;
wire [1:0] DE_in_alu_sel2;
reg [`ALU_OP_BITS-1:0] DE_ALU_OP;
decoder decoder(
.CIR(INSTRUCTION[31:16]),
.FLAGS(FLAGS),
.INSTRUCTION_INFO(INSTRUCTION_INFO),
.DECODER_SIGNALS(DECODER_SIGNALS),
.next_state(next_state),
.IN_MOD(DE_IN_MOD),
.RM(DE_RM),
.PARAM1(DE_PARAM1),
.PARAM2(DE_PARAM2),
.in_alu_sel1(DE_in_alu_sel1),
.in_alu_sel2(DE_in_alu_sel2),
.OUT_MOD(DE_OUT_MOD),
.REGISTER_FILE_CONTROL(DE_REGISTER_CONTROL),
.ALU_1OP(DE_ALU_OP),
.seq_addr_entry(ucode_seq_addr_entry),
.SIMPLE_MICRO(SIMPLE_MICRO),
.seq_addr_input(ucode_seq_addr),
.memio_address_select(DE_memio_address_select),
.MEM_OR_IO(DE_MEM_OR_IO)
);
assign DE_Wbit=INSTRUCTION_INFO[2:2];
assign DE_Sbit=INSTRUCTION_INFO[1:1];
assign DE_opcode_size=INSTRUCTION_INFO[0:0];
assign DE_reg_write_addr=DE_REGISTER_CONTROL[11:8];
assign DE_reg_read_port1_addr=DE_REGISTER_CONTROL[7:4];
assign DE_reg_read_port2_addr=DE_REGISTER_CONTROL[3:0];
assign DE_HALT=DECODER_SIGNALS[0:0];
assign DE_ERROR=DECODER_SIGNALS[`ERROR_BITS:1];
reg [`ERROR_BITS-1:0] DE_ERROR_sampled;
reg [`UCODE_ADDR_BITS-1:0] ucode_seq_addr; reg [`UCODE_ADDR_BITS-1:0] ucode_seq_addr;
reg SIMPLE_MICRO; /* output simple decodings (=0) or microcode data (=1) */
/*############ REGISTERS ########################################################## */ wire [`EXEC_STATE_BITS+`ERROR_BITS+65:0] DE_OUTPUT;
reg [`EXEC_STATE_BITS+`ERROR_BITS+65:0] DE_OUTPUT_sampled;
decoder decoder(
/* INPUTS */ INSTRUCTION[31:16],FLAGS,
/* MICROCODE */ ucode_seq_addr_entry,SIMPLE_MICRO,ucode_seq_addr,
/* OUTPUT */ DE_OUTPUT
);
wire [2:0] RM;
assign RM = DE_OUTPUT_sampled[5:3];
wire memio_address_select;
assign memio_address_select=DE_OUTPUT_sampled[6:6];
wire [3:0] DE_reg_read_port1_addr,DE_reg_read_port2_addr;
assign DE_reg_read_port1_addr=DE_OUTPUT_sampled[53:50];
assign DE_reg_read_port2_addr=DE_OUTPUT_sampled[57:54];
wire [3:0] reg_write_addr;
assign reg_write_addr=DE_OUTPUT_sampled[61:58];
wire MEM_OR_IO;
assign MEM_OR_IO = DE_OUTPUT_sampled[7:7];
wire Wbit, Sbit, opcode_size;
assign opcode_size=DE_OUTPUT_sampled[62:62];
assign Sbit=DE_OUTPUT_sampled[63:63];
assign Wbit=DE_OUTPUT_sampled[64:64];
wire [`ERROR_BITS-1:0] DE_ERROR;
assign HALT = DE_OUTPUT_sampled[65:65];
assign DE_ERROR = DE_OUTPUT_sampled[`ERROR_BITS+65:66];
wire [`EXEC_STATE_BITS-1:0] next_state;
assign next_state=DE_OUTPUT_sampled[`EXEC_STATE_BITS+`ERROR_BITS+65:`ERROR_BITS+66];
/*############ Registers ######################################################## */
// verilator lint_off UNDRIVEN
reg [15:0] FLAGS; reg [15:0] FLAGS;
// verilator lint_on UNDRIVEN
//Architectural Register file
reg [3:0] reg_write_addr;
wire [15:0] reg_write_data;
wire reg_write_we;
wire [3:0] reg_read_port1_addr;
reg [15:0] reg_read_port1_data;
reg [3:0] reg_read_port2_addr;
reg [15:0] reg_read_port2_data;
reg [1:0] reg_write_in_sel;
mux4 #(.WIDTH(16)) REG_FILE_WRITE_IN_MUX(
ALU_O,
16'hz,
16'hz,
16'hz,
reg_write_in_sel,
reg_write_data);
register_file register_file(
.write_port1_addr(reg_write_addr),
.write_port1_data(reg_write_data),
.write_port1_we(reg_write_we),
.read_port1_addr(reg_read_port1_addr),
.read_port1_data(reg_read_port1_data),
.read_port2_addr(reg_read_port2_addr),
.read_port2_data(reg_read_port2_data)
);
assign reg_read_port1_addr = use_exec_reg_addr ? EXEC_reg_read_port1_addr : reg_read_port1_addr_latched;
reg [15:0] ProgCount; reg [15:0] ProgCount;
/*############ Processor state machine ########################################################## */ wire [3:0] reg_read_port1_addr;
reg [3:0] reg_read_port1_addr_latched; assign reg_read_port1_addr = use_exec_reg_addr ? EXEC_reg_read_port1_addr : DE_reg_read_port1_addr;
wire [15:0] reg_read_port1_data, reg_read_port2_data;
wire reg_write_we;
register_file register_file(
/* WRITE */ .write_port1_addr(reg_write_addr),
/* */ .write_port1_data(ALU_O),
/* */ .write_port1_we(reg_write_we),
/* READ 1 */ .read_port1_addr(reg_read_port1_addr),
/* */ .read_port1_data(reg_read_port1_data),
/* READ 2 */ .read_port2_addr(DE_reg_read_port2_addr),
/* */ .read_port2_data(reg_read_port2_data)
);
/*############ Processor State Machine ########################################## */
/*** RESET LOGIC ***/ /*** RESET LOGIC ***/
/* verilator lint_off MULTIDRIVEN */
always @(negedge reset) begin always @(negedge reset) begin
state <= `PROC_HALT; //TODO: race condition ?? state <= `PROC_HALT; //TODO: race condition ??
end end
always @(posedge reset) begin always @(posedge reset) begin
state <= `PROC_RESET; state <= `PROC_RESET;
end end
/* verilator lint_on MULTIDRIVEN */
/*** Processor stages ***/ /*** Processor stages ***/
@ -219,49 +184,28 @@ InstrSize InstrSize({INSTRUCTION[31:24],INSTRUCTION[21:19]},instr_end);
reg [23:0] INSTRUCTION_BUFFER; reg [23:0] INSTRUCTION_BUFFER;
always @(posedge clock) begin always @(posedge clock) begin
case(state) case(state)
`PROC_RESET:begin `PROC_RESET:begin
ucode_seq_addr <= `UCODE_NO_INSTRUCTION; ucode_seq_addr <= `UCODE_NO_INSTRUCTION;
HALT <= 0; DE_OUTPUT_sampled <= 0;
SIMPLE_MICRO <= 0; SIMPLE_MICRO <= 0;
state <= `PROC_DE_STATE_ENTRY; state <= `PROC_DE_STATE_ENTRY;
reg_write_in_sel <= 2'b00; //only got wirtten in IF
end end
`PROC_DE_STATE_ENTRY:begin `PROC_DE_STATE_ENTRY:begin
if(VALID_INSTRUCTION==1) begin if(VALID_INSTRUCTION==1) begin
DE_OUTPUT_sampled <= DE_OUTPUT;
if(SIMPLE_MICRO==0)begin if(SIMPLE_MICRO==0)begin
/* We cannot set these directly within set_initial_values<=0;
* microcode so don't overwrite useful values
* each tie the next microcode is executed.
* Note this still allows to set initial values
* at the start of the microcode */
PARAM1_INIT <= DE_PARAM1;
PARAM2_INIT <= DE_PARAM2;
`ifdef DEBUG_PC_ADDRESS `ifdef DEBUG_PC_ADDRESS
$display("Running command at %04x (%08x)",INSTRUCTION_LOCATION,INSTRUCTION); $display("Running command at %04x (%08x)",INSTRUCTION_LOCATION,INSTRUCTION);
`endif `endif
ProgCount <= INSTRUCTION_LOCATION+{12'b0,instr_end}; ProgCount <= INSTRUCTION_LOCATION+{12'b0,instr_end};
INSTRUCTION_BUFFER<=INSTRUCTION[23:0]; INSTRUCTION_BUFFER<=INSTRUCTION[23:0];
set_initial_values<=0;
end end
DE_ERROR_sampled <= DE_ERROR;
IN_MOD <= DE_IN_MOD;
OUT_MOD <= DE_OUT_MOD;
RM <= DE_RM;
HALT <= DE_HALT;
Wbit <= DE_Wbit;
Sbit <= DE_Sbit;
opcode_size <= DE_opcode_size;
memio_address_select<=DE_memio_address_select;
reg_read_port1_addr_latched <= DE_reg_read_port1_addr;
reg_read_port2_addr <= DE_reg_read_port2_addr;
reg_write_addr <= DE_reg_write_addr;
MEM_OR_IO <= DE_MEM_OR_IO;
in_alu_sel1 <= DE_in_alu_sel1;
in_alu_sel2 <= DE_in_alu_sel2;
ALU_OP <= DE_ALU_OP;
if ( (ucode_seq_addr==`UCODE_NO_INSTRUCTION) && (ucode_seq_addr_entry!=`UCODE_NO_INSTRUCTION) )begin if ( (ucode_seq_addr==`UCODE_NO_INSTRUCTION) && (ucode_seq_addr_entry!=`UCODE_NO_INSTRUCTION) )begin
/*switch to microcode decoding*/ /*switch to microcode decoding*/
ucode_seq_addr <= ucode_seq_addr_entry; ucode_seq_addr <= ucode_seq_addr_entry;
@ -269,7 +213,6 @@ always @(posedge clock) begin
/*keep state the same and rerun decode this time with all the data from the microcode rom*/ /*keep state the same and rerun decode this time with all the data from the microcode rom*/
end else begin end else begin
valid_exec_data <= 1; valid_exec_data <= 1;
exec_state_init <= next_state;
state <= `PROC_WAIT; state <= `PROC_WAIT;
end end
end end
@ -277,10 +220,10 @@ always @(posedge clock) begin
`PROC_WAIT:begin `PROC_WAIT:begin
set_initial_values<=1; set_initial_values<=1;
if( exec_state == `EXEC_DONE ) begin if( exec_state == `EXEC_DONE ) begin
FLAGS[7:0] <= EXEC_FLAGS; //don't set all of them all the time! FLAGS <= {8'b0,EXEC_FLAGS}; //TODO: don't set all of them all the time!
valid_exec_data<=0; valid_exec_data<=0;
state <= `PROC_DE_STATE_ENTRY; state <= `PROC_DE_STATE_ENTRY;
if(SIMPLE_MICRO == 1 ) begin if( SIMPLE_MICRO == 1 ) begin
ucode_seq_addr <= ucode_seq_addr_entry; /*Reused for next address*/ ucode_seq_addr <= ucode_seq_addr_entry; /*Reused for next address*/
if( ucode_seq_addr_entry == `UCODE_NO_INSTRUCTION )begin if( ucode_seq_addr_entry == `UCODE_NO_INSTRUCTION )begin
/*Finished microcode*/ /*Finished microcode*/
@ -296,5 +239,4 @@ always @(posedge clock) begin
endcase endcase
end end
endmodule endmodule