From af63ef1d68c69ba4b4646be4c59a21566cc1354f Mon Sep 17 00:00:00 2001 From: "(Tim) Efthimis Kritikos" Date: Sat, 27 May 2023 23:35:00 +0100 Subject: [PATCH] Moved the decoder logic to decoder.v Now processor.v only connects the different modules --- system/decoder.v | 144 +++++++++++++++++++++++++++++++++- system/execute.v | 3 +- system/processor.v | 191 ++++++++++----------------------------------- 3 files changed, 185 insertions(+), 153 deletions(-) diff --git a/system/decoder.v b/system/decoder.v index 6facfe1..f4018e7 100644 --- a/system/decoder.v +++ b/system/decoder.v @@ -21,6 +21,147 @@ `include "alu_header.v" `include "ucode_header.v" `include "error_header.v" +`include "config.v" + +//TODO: rename CIR to OPCODE where applicable +//TODO: check all includes + +module decoder( + /* GENERAL */ input clock, input reset + /* INPUT FROM IF */ ,input wire [31:0] IF2DE_INSTRUCTION,input wire VALID_INSTRUCTION, input [15:0] INSTRUCTION_LOCATION + /* INPUT FROM EX */ ,input wire [7:0] EX2DE_FLAGS,input wire next_exec + /* OUTPUT TO EX */ ,output reg [`EXEC_STATE_BITS+`ERROR_BITS+65:0] DE_OUTPUT_sampled, output reg [23:0] DE2EX_INSTRUCTION + /* */ ,output reg [15:0] ProgCount, output reg set_initial_values,output reg valid_exec_data + /* OUTPUT TO IF */ ,output reg VALID_INSTRUCTION_ACK +`ifdef CALCULATE_IPC + /* STATISTICS */ ,output reg new_instruction +`endif +`ifdef DEBUG_PC_ADDRESS + /* DEBUG */ ,input FULL_INSTRUCTION +`endif +); + +reg SIMPLE_MICRO; /* output simple decodings (=0) or microcode data (=1) */ +wire [`UCODE_ADDR_BITS-1:0] ucode_seq_addr_entry; +reg [`UCODE_ADDR_BITS-1:0] ucode_seq_addr; +wire DEPENDS_ON_PREVIOUS; + +wire [`EXEC_STATE_BITS+`ERROR_BITS+65:0] DE_OUTPUT; + +instruction_decode instruction_decode( + /* INPUT */ IF2DE_INSTRUCTION[31:16],{8'h0,EX2DE_FLAGS}, + /* MICROCODE */ ucode_seq_addr_entry,SIMPLE_MICRO,ucode_seq_addr, + /* OUTPUT */ DE_OUTPUT,DEPENDS_ON_PREVIOUS + ); + +reg [`PROC_STATE_BITS-1:0] proc_state; + +/*** RESET LOGIC ***/ + +always @(negedge reset) begin + proc_state <= `PROC_HALT; //TODO: race condition ?? + `ifdef CALCULATE_IPC + new_instruction<=0; + `endif +end +always @(posedge reset) begin + proc_state <= `PROC_RESET; + /* need early init */ + VALID_INSTRUCTION_ACK <= 0; + instant_response <= 0; + stalled_response <= 0; +end + +/*** Processor stages ***/ +wire [2:0] instr_end; +InstrSize InstrSize({IF2DE_INSTRUCTION[31:24],IF2DE_INSTRUCTION[21:19]},instr_end); + +reg owe_set_init; + +//TODO: Why do we need to make a local copy on a register for the code inside the always @(next_state) to read it? +// For some reason the raw VALID_INSTRUCTION signal reads always 1 and it has something to do with the block +// being triggered by next_exec +reg VALID_INSTRUCTION_lc; +always @(VALID_INSTRUCTION)begin VALID_INSTRUCTION_lc<=VALID_INSTRUCTION; end + +reg instant_response, stalled_response; +reg wait_exec; + +always @(next_exec) begin + proc_state<=`PROC_DE_STATE_ENTRY; + if ( VALID_INSTRUCTION_lc == 1 && DEPENDS_ON_PREVIOUS == 0 && ucode_seq_addr_entry==`UCODE_NO_INSTRUCTION) begin + instant_response <= !instant_response; + end else begin + wait_exec<=0; + end +end + +always @(instant_response or stalled_response) begin + DE_OUTPUT_sampled <= DE_OUTPUT; + + if(SIMPLE_MICRO==0||owe_set_init==1)begin + /* This runs at the start of the execution of an 8086 instruction */ + `ifdef DEBUG_PC_ADDRESS + $display("Running command at %04x (%08x)",INSTRUCTION_LOCATION,FULL_INSTRUCTION); + `endif + `ifdef CALCULATE_IPC + new_instruction <= !new_instruction; + `endif + VALID_INSTRUCTION_ACK <= !VALID_INSTRUCTION_ACK; + owe_set_init<=0; + set_initial_values <= !set_initial_values; + ProgCount <= INSTRUCTION_LOCATION+{12'b0,instr_end}; + DE2EX_INSTRUCTION <= IF2DE_INSTRUCTION[23:0]; // First byte is never useful to execute + end + + if ( (ucode_seq_addr==`UCODE_NO_INSTRUCTION) && (ucode_seq_addr_entry!=`UCODE_NO_INSTRUCTION) )begin + /* switch to microcode decoding */ + ucode_seq_addr <= ucode_seq_addr_entry; + SIMPLE_MICRO <= 1; + /*keep proc_state the same and rerun decode this time with all the data from the microcode rom*/ + end else begin + /* This runs at the start of each execution cycle, with microcode this is more than once per 8086 instruction */ + valid_exec_data<=!valid_exec_data; + if( SIMPLE_MICRO == 1 ) begin + ucode_seq_addr <= ucode_seq_addr_entry; /*Reused for next address*/ + if( ucode_seq_addr_entry == `UCODE_NO_INSTRUCTION )begin + /*Finished microcode*/ + SIMPLE_MICRO <= 0; + end + end + wait_exec<=1; + end +end + +always @(posedge clock) begin + case(proc_state) + `PROC_RESET:begin + ucode_seq_addr <= `UCODE_NO_INSTRUCTION; + DE_OUTPUT_sampled <= 0; + SIMPLE_MICRO <= 0; + proc_state <= `PROC_DE_STATE_ENTRY; + owe_set_init <= 0; + set_initial_values<=0; + wait_exec<=0; + valid_exec_data<=0; + end + `PROC_DE_STATE_ENTRY:begin + if ( ( VALID_INSTRUCTION==1 || SIMPLE_MICRO == 1 ) && wait_exec==0) begin + stalled_response <= !stalled_response; + end + end + `PROC_HALT:begin + end + default:begin + end + endcase +end + +endmodule + + + + module microcode( input [`UCODE_ADDR_BITS-1:0] ADDR, @@ -43,11 +184,12 @@ assign DATA=ucode_rom[ADDR]; endmodule -module decoder( +module instruction_decode( /* INPUTS */ input wire [15:0] CIR,input wire [15:0] FLAGS /* MICROCODE */ ,output reg [`UCODE_ADDR_BITS-1:0] seq_addr_entry, input wire SIMPLE_MICRO, input wire [`UCODE_ADDR_BITS-1:0] seq_addr_input /* OUTPUT */ ,output wire [`EXEC_STATE_BITS+`ERROR_BITS+65:0] OUTPUT, output reg DEPENDS_ON_PREVIOUS ); + /* DEPENDS_ON_PREVIOUS - This encodes weather the instruction requires the previous to be finished in order to be decoded. This, for example, affects * conditional jumps since flags are checked during decode. */ diff --git a/system/execute.v b/system/execute.v index 2a6aa1e..93afb87 100644 --- a/system/execute.v +++ b/system/execute.v @@ -22,14 +22,13 @@ module execute_unit ( /* */ ,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 set_initial_values, output reg next_exec /* PARAM */ ,input [15:0] PARAM1_INIT, input [15:0] PARAM2_INIT - /* STATE CONTROL */ ,output [`EXEC_STATE_BITS-1:0] _exec_state_, input [`EXEC_STATE_BITS-1:0] init_state + /* STATE CONTROL */ ,input [`EXEC_STATE_BITS-1:0] init_state /* ALU CONTROL */ ,input [1:0] in_alu_sel1, input [1:0] in_alu_sel2, input [`ALU_OP_BITS-1:0] ALU_OP, output [15:0] _ALU_O_ /* REGISTER DATA */ ,input [15:0] reg_read_port1_data ,input [15:0] reg_read_port2_data, output reg [3:0] reg_read_port1_addr, output reg use_exec_reg_addr, output reg reg_write_we /* FLAGS */ ,output reg [7:0] FLAGS /* BIU */ ,output reg [15:0] BIU_ADDRESS_INPUT,output reg biu_write_request, output reg biu_read_request, input BIU_VALID_DATA, input [15:0] BIU_DATA, output reg biu_data_direction, output reg biu_jump_req ); -assign _exec_state_ = exec_state; assign _ALU_O_ = ALU_O; reg [`EXEC_STATE_BITS-1:0] exec_state; diff --git a/system/processor.v b/system/processor.v index f62b6e4..9506760 100644 --- a/system/processor.v +++ b/system/processor.v @@ -39,13 +39,14 @@ module processor ( /* MISC */ input clock, input reset, output wire HALT,output [`ERROR_BITS-1:0] ERROR /* MEMORY / IO */ ,output [19:0] external_address_bus, inout [15:0] external_data_bus,output read, output write,output BHE,output IOMEM `ifdef CALCULATE_IPC - /* STATISTICS */ ,output reg new_instruction + /* STATISTICS */ ,output wire new_instruction `endif `ifdef OTUPUT_JSON_STATISTICS /* */ ,output wire [`L1_CACHE_SIZE-1:0] L1_SIZE_STAT, output wire VALID_INSTRUCTION_STAT, output wire jump_req_debug `endif ); + `ifdef OTUPUT_JSON_STATISTICS assign jump_req_debug=biu_jump_req; `endif @@ -53,17 +54,14 @@ assign jump_req_debug=biu_jump_req; /* If there is an error either from the decoder or execution unit set it to ERROR */ assign ERROR=(DE_ERROR!=`ERR_NO_ERROR)?DE_ERROR:(EXEC_ERROR!=`ERR_NO_ERROR)?EXEC_ERROR:`ERR_NO_ERROR; -reg [`PROC_STATE_BITS-1:0] proc_state; /*############ Execution Unit ################################################### */ 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]; +assign in_alu_sel1 = DE_OUTPUT[44:43]; +assign in_alu_sel2 = DE_OUTPUT[46:45]; -wire [`EXEC_STATE_BITS-1:0] exec_state; - -reg valid_exec_data, set_initial_values; +wire valid_exec_data, set_initial_values; wire [`ERROR_BITS-1:0] EXEC_ERROR; @@ -71,29 +69,31 @@ wire use_exec_reg_addr; wire [3:0] EXEC_reg_read_port1_addr; wire [15:0] ALU_O; -wire [7:0]EXEC_FLAGS; +wire [7:0]EX2DE_FLAGS; wire [15:0] PARAM1_INIT, PARAM2_INIT; -assign PARAM1_INIT = DE_OUTPUT_sampled[23:8]; -assign PARAM2_INIT = DE_OUTPUT_sampled[39:24]; +assign PARAM1_INIT = DE_OUTPUT[23:8]; +assign PARAM2_INIT = DE_OUTPUT[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]; +assign IN_MOD=DE_OUTPUT[2:0]; +assign OUT_MOD=DE_OUTPUT[49:47]; wire [`ALU_OP_BITS-1:0] ALU_OP; -assign ALU_OP = DE_OUTPUT_sampled[42:40]; +assign ALU_OP = DE_OUTPUT[42:40]; + +wire [23:0] DE2EX_INSTRUCTION; wire next_exec; execute_unit execute_unit ( - /* GENERAL */ clock, reset, Wbit, Sbit, opcode_size, INSTRUCTION_BUFFER,valid_exec_data + /* GENERAL */ clock, reset, Wbit, Sbit, opcode_size, DE2EX_INSTRUCTION[23:0] , valid_exec_data /* */ ,IN_MOD, OUT_MOD,memio_address_select, ProgCount, RM, EXEC_ERROR, write /* */ ,set_initial_values,next_exec /* PARAM */ ,PARAM1_INIT,PARAM2_INIT - /* STATE CONTROL */ ,exec_state, next_state + /* STATE CONTROL */ ,next_state /* 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 - /* FLAGS */ ,EXEC_FLAGS + /* FLAGS */ ,EX2DE_FLAGS /* BIU */ ,BIU_ADDRESS_INPUT, biu_write_request, biu_read_request, BIU_VALID_DATA, BIU_DATA, biu_data_direction, biu_jump_req ); @@ -104,14 +104,14 @@ wire [15:0] BIU_DATA; wire [31:0] INSTRUCTION; wire biu_write_request, biu_read_request, BIU_VALID_DATA; wire biu_jump_req, biu_data_direction,VALID_INSTRUCTION; -reg valid_instruction_ack; +wire VALID_INSTRUCTION_ACK; BIU BIU( /* Outside world */ clock,reset,external_address_bus /* */ ,external_data_bus,read,write,BHE,IOMEM /* 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 - /* */ ,valid_instruction_ack + /* */ ,VALID_INSTRUCTION_ACK `ifdef OTUPUT_JSON_STATISTICS /* Statistics */ ,L1_SIZE_STAT, VALID_INSTRUCTION_STAT `endif @@ -121,53 +121,52 @@ assign BIU_DATA= biu_data_direction ? 16'hz : (memio_address_select ? reg_read_p /*############ Decoder ########################################################## */ -wire [`UCODE_ADDR_BITS-1:0] ucode_seq_addr_entry; -reg [`UCODE_ADDR_BITS-1:0] ucode_seq_addr; -reg SIMPLE_MICRO; /* output simple decodings (=0) or microcode data (=1) */ wire [`EXEC_STATE_BITS+`ERROR_BITS+65:0] DE_OUTPUT; -reg [`EXEC_STATE_BITS+`ERROR_BITS+65:0] DE_OUTPUT_sampled; - -wire DE_DEPENDS_ON_PREVIOUS; decoder decoder( - /* INPUT */ INSTRUCTION[31:16],FLAGS, - /* MICROCODE */ ucode_seq_addr_entry,SIMPLE_MICRO,ucode_seq_addr, - /* OUTPUT */ DE_OUTPUT,DE_DEPENDS_ON_PREVIOUS + /* GENERAL */ clock, reset, + /* INPUT FROM IF */ INSTRUCTION,VALID_INSTRUCTION,INSTRUCTION_LOCATION + /* INPUT FROM EX */ ,EX2DE_FLAGS[7:0],next_exec + /* OUTPUT TO EX */ ,DE_OUTPUT,DE2EX_INSTRUCTION + /* */ ,ProgCount,set_initial_values,valid_exec_data + /* OUTPUT TO IF */ ,VALID_INSTRUCTION_ACK +`ifdef CALCULATE_IPC + /* STATISTICS */ , new_instruction +`endif ); wire [2:0] RM; -assign RM = DE_OUTPUT_sampled[5:3]; +assign RM = DE_OUTPUT[5:3]; wire memio_address_select; -assign memio_address_select=DE_OUTPUT_sampled[6:6]; +assign memio_address_select=DE_OUTPUT[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]; +assign DE_reg_read_port1_addr=DE_OUTPUT[53:50]; +assign DE_reg_read_port2_addr=DE_OUTPUT[57:54]; wire [3:0] reg_write_addr; -assign reg_write_addr=DE_OUTPUT_sampled[61:58]; +assign reg_write_addr=DE_OUTPUT[61:58]; wire MEM_OR_IO; -assign MEM_OR_IO = DE_OUTPUT_sampled[7:7]; +assign MEM_OR_IO = DE_OUTPUT[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]; +assign opcode_size=DE_OUTPUT[62:62]; +assign Sbit=DE_OUTPUT[63:63]; +assign Wbit=DE_OUTPUT[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]; +assign HALT = DE_OUTPUT[65:65]; +assign DE_ERROR = DE_OUTPUT[`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]; +assign next_state=DE_OUTPUT[`EXEC_STATE_BITS+`ERROR_BITS+65:`ERROR_BITS+66]; /*############ Registers ######################################################## */ -reg [15:0] FLAGS; -reg [15:0] ProgCount; +wire [15:0] ProgCount; wire [3:0] reg_read_port1_addr; assign reg_read_port1_addr = use_exec_reg_addr ? EXEC_reg_read_port1_addr : DE_reg_read_port1_addr; @@ -186,115 +185,7 @@ register_file register_file( /* */ .read_port2_data(reg_read_port2_data) ); -/*############ Processor State Machine ########################################## */ +/*############################################################################### */ -/*** RESET LOGIC ***/ - -always @(negedge reset) begin - proc_state <= `PROC_HALT; //TODO: race condition ?? - `ifdef CALCULATE_IPC - new_instruction<=0; - `endif -end -always @(posedge reset) begin - proc_state <= `PROC_RESET; - /* need early init */ - valid_instruction_ack <= 0; - instant_response <= 0; - stalled_response <= 0; -end - -/*** Processor stages ***/ - -wire [2:0] instr_end; -InstrSize InstrSize({INSTRUCTION[31:24],INSTRUCTION[21:19]},instr_end); - -reg [23:0] INSTRUCTION_BUFFER; - -reg owe_set_init; - -//TODO: Why do we need to make a local copy on a register for the code inside the always @(next_state) to read it? -// For some reason the raw VALID_INSTRUCTION signal reads always 1 and it has something to do with the block -// being triggered by next_exec -reg VALID_INSTRUCTION_lc; -always @(VALID_INSTRUCTION)begin VALID_INSTRUCTION_lc<=VALID_INSTRUCTION; end - -reg instant_response, stalled_response; -reg wait_exec; - -always @(next_exec) begin - proc_state<=`PROC_DE_STATE_ENTRY; - if ( VALID_INSTRUCTION_lc == 1 && DE_DEPENDS_ON_PREVIOUS == 0 && ucode_seq_addr_entry==`UCODE_NO_INSTRUCTION) begin - instant_response <= !instant_response; - end else begin - wait_exec<=0; - end -end - -always @(instant_response or stalled_response) begin - DE_OUTPUT_sampled <= DE_OUTPUT; - - if(SIMPLE_MICRO==0||owe_set_init==1)begin - /* This runs at the start of the execution of an 8086 instruction */ - `ifdef DEBUG_PC_ADDRESS - $display("Running command at %04x (%08x)",INSTRUCTION_LOCATION,INSTRUCTION); - `endif - `ifdef CALCULATE_IPC - new_instruction <= !new_instruction; - `endif - valid_instruction_ack <= !valid_instruction_ack; - owe_set_init<=0; - set_initial_values<= !set_initial_values; - ProgCount <= INSTRUCTION_LOCATION+{12'b0,instr_end}; - INSTRUCTION_BUFFER<=INSTRUCTION[23:0]; - end - - if ( (ucode_seq_addr==`UCODE_NO_INSTRUCTION) && (ucode_seq_addr_entry!=`UCODE_NO_INSTRUCTION) )begin - /* switch to microcode decoding */ - ucode_seq_addr <= ucode_seq_addr_entry; - SIMPLE_MICRO <= 1; - /*keep proc_state the same and rerun decode this time with all the data from the microcode rom*/ - end else begin - /* This runs at the start of each execution cycle, with microcode this is more than once per 8086 instruction */ - valid_exec_data<=!valid_exec_data; - if( SIMPLE_MICRO == 1 ) begin - ucode_seq_addr <= ucode_seq_addr_entry; /*Reused for next address*/ - if( ucode_seq_addr_entry == `UCODE_NO_INSTRUCTION )begin - /*Finished microcode*/ - SIMPLE_MICRO <= 0; - end - end - wait_exec<=1; - end -end - -always @(posedge clock) begin - case(proc_state) - `PROC_RESET:begin - ucode_seq_addr <= `UCODE_NO_INSTRUCTION; - DE_OUTPUT_sampled <= 0; - SIMPLE_MICRO <= 0; - proc_state <= `PROC_DE_STATE_ENTRY; - owe_set_init <= 0; - set_initial_values<=0; - wait_exec<=0; - valid_exec_data<=0; - end - `PROC_DE_STATE_ENTRY:begin - if ( ( VALID_INSTRUCTION==1 || SIMPLE_MICRO == 1 ) && wait_exec==0) begin - stalled_response <= !stalled_response; - end - end - `PROC_HALT:begin - end - default:begin - end - endcase -end - -always @(exec_state) begin - if(exec_state == `EXEC_WAIT) - FLAGS <= {8'b0,EXEC_FLAGS}; //TODO: don't set all of them all the time! -end endmodule