/* 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 . */ `include "exec_state_def.v" `include "alu_header.v" `include "error_header.v" module execute_unit ( /***************** GENERAL *****************/ /* */ input clock, input reset, input write /*TODO: REMOVE!!*/, output reg [`ERROR_BITS-1:0] ERROR /*************** INPUT FROM DE ***************/ /* SYNC SIGNALS */ ,input valid_input,input set_initial_values /* INSTR. PARAMS */ ,input Wbit ,input [2:0] IN_MOD, input [2:0] OUT_MOD, input [2:0] RM /* DATA */ ,input [15:0] PARAM1_INIT, input [15:0] PARAM2_INIT, input [15:0] ProgCount /* 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_ /* OTHER */ ,input memio_address_select /**************** OUTPUT TO DE ****************/ /* SYNC SIGNALS */ ,output reg next_exec /* FLAGS */ ,output reg [7:0] EX2DE_FLAGS /**************** OUTPUT TO BIU ****************/ /* */ ,output reg [15:0] BIU_ADDRESS_INPUT /* */ ,output reg biu_read_request, output reg biu_jump_req,output reg biu_write_request /*************** INPUT FROM BIU ****************/ /* */ ,input BIU_VALID_DATA,input [15:0] BIU_EX_DATA_READ /**************** OUTPUT TO BIU ****************/ /* */ ,output [15:0] BIU_EX_DATA_WRITE /***************** REGISTERS *****************/ /* */ ,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 ); assign _ALU_O_ = ALU_O; reg [`EXEC_STATE_BITS-1:0] exec_state; reg [15:0] PARAM1,PARAM2; assign BIU_EX_DATA_WRITE = memio_address_select ? reg_read_port1_data : ALU_O; /*############ ALU / Execution units ################################################## */ mux4 #(.WIDTH(16)) MUX16_1A( /*0*/ PARAM1, /*1*/ reg_read_port1_data, /*2*/ ProgCount[15:0], /*3*/ 16'd0, /*0 Constant*/ in_alu_sel1, ALU_A); mux4 #(.WIDTH(16)) MUX16_1B( /*0*/ PARAM2, /*1*/ reg_read_port2_data, /*2*/ ProgCount[15:0], /*3*/ 16'd0, /*0 Constant*/ in_alu_sel2, ALU_B); wire [15:0] ALU_A; wire [15:0] ALU_B; wire [15:0] ALU_O; wire [7:0] ALU_FLAGS; ALU ALU1( /* INPUT 1 */ .A(ALU_A), /* INPUT 2 */ .B(ALU_B), /* OUTPUT */ .OUT(ALU_O), /* OPERATION */ .op(ALU_OP), /* FLAGS */ .FLAGS(ALU_FLAGS), /* Wbit */ .Wbit(Wbit) ); /*############ Execute logic ########################################################## */ `define unimpl_addressing_mode exec_state <= `EXEC_WAIT;ERROR <= `ERR_UNIMPL_ADDRESSING_MODE; `define finished_instruction exec_state <= `EXEC_WAIT;next_exec<=1; always @(posedge clock) begin if ( !reset ) begin exec_state <= `EXEC_RESET; end else begin if ( set_initial_values )begin PARAM1 <= PARAM1_INIT; PARAM2 <= PARAM2_INIT; end begin case (exec_state) `EXEC_RESET: begin biu_write_request <= 0; biu_read_request <= 0; biu_jump_req <= 0; reg_write_we <= 1; exec_state <= `EXEC_WAIT; ERROR <= `ERR_NO_ERROR; end `EXEC_WAIT:begin if(valid_input)begin exec_state <= init_state; next_exec<=0; end else begin next_exec<=1; end biu_jump_req <= 0; reg_write_we <= 1; use_exec_reg_addr <= 0; ERROR<=`ERR_NO_ERROR; end `EXEC_DE_LOAD_REG_TO_PARAM:begin PARAM2<=reg_read_port2_data; case(IN_MOD) 3'b000,3'b001,3'b010: exec_state <= `EXEC_MEMIO_READ; default: exec_state <= `EXEC_WRITE_ENTRY; endcase end `EXEC_MEMIO_READ:begin /*Decode MOD R/M, read the data and place it to PARAM1*/ case (IN_MOD) 3'b000, 3'b001, 3'b010:begin case (RM) 3'b000:begin /*[BX]+[SI]*/ `unimpl_addressing_mode end 3'b001:begin /*[BX]+[SI]*/ `unimpl_addressing_mode end 3'b010:begin /*[BP]+[SI]*/ `unimpl_addressing_mode end 3'b011:begin /*[BP]+[DI]*/ `unimpl_addressing_mode end 3'b100:begin /*[SI]*/ reg_read_port1_addr <= 4'b1110; use_exec_reg_addr <= 1; exec_state <= `EXEC_MEMIO_READ_SETADDR; end 3'b101:begin /*[DI]*/ reg_read_port1_addr <= 4'b1111; use_exec_reg_addr <= 1; exec_state <= `EXEC_MEMIO_READ_SETADDR; end 3'b110:begin /*d16 */ `unimpl_addressing_mode end 3'b111:begin /*[BX]*/ reg_read_port1_addr <= 4'b1011; use_exec_reg_addr <= 1; exec_state <= `EXEC_MEMIO_READ_SETADDR; end endcase if(IN_MOD!=3'b000)begin /*Actually check if 01 and add the 8bits or if 10 add the 16bits ....*/ `unimpl_addressing_mode; end end 3'b110:begin /* SP Indirect read*/ reg_read_port1_addr <= 4'b1100; use_exec_reg_addr <= 1; exec_state <= `EXEC_MEMIO_READ_SETADDR; end default:begin `unimpl_addressing_mode end endcase end `EXEC_MEMIO_READ_SETADDR:begin /* if memio_address_select == 0 ADDRESS: reg_read_port1_data DATA:ALU1_O */ /* if memio_address_select == 1 ADDRESS: ALU1_O DATA: reg_read_port1_data */ if(memio_address_select==0) BIU_ADDRESS_INPUT <= reg_read_port1_data[15:0]; else BIU_ADDRESS_INPUT <= ALU_O; if ( BIU_VALID_DATA == 1 ) begin exec_state <= `EXEC_WRITE_ENTRY; PARAM2 <= BIU_EX_DATA_READ; biu_read_request <= 0; end else begin biu_read_request <= 1; end end `EXEC_NEXT_INSTRUCTION:begin `finished_instruction /*necessary for biu to see we went on another state from decode to give us a new instruction*/ end `EXEC_WRITE_ENTRY:begin EX2DE_FLAGS[7:0] <= ALU_FLAGS[7:0]; case(OUT_MOD) 3'b000, 3'b001, 3'b010 : begin if(memio_address_select==1) exec_state <= `EXEC_MEMIO_WRITE; else case (RM) /* Duplicate code with write... */ 3'b000:begin /*[BX]+[SI]*/ `unimpl_addressing_mode end 3'b001:begin /*[BX]+[SI]*/ `unimpl_addressing_mode end 3'b010:begin /*[BP]+[SI]*/ `unimpl_addressing_mode end 3'b011:begin /*[BP]+[DI]*/ `unimpl_addressing_mode end 3'b100:begin /*[SI]*/ reg_read_port1_addr <= 4'b1110; use_exec_reg_addr <= 1; exec_state <= `EXEC_MEMIO_WRITE; end 3'b101:begin /*[DI]*/ reg_read_port1_addr <= 4'b1111; use_exec_reg_addr <= 1; exec_state <= `EXEC_MEMIO_WRITE; end 3'b110:begin /*d16 */ `unimpl_addressing_mode end 3'b111:begin /*[BX]*/ reg_read_port1_addr <= 4'b1011; use_exec_reg_addr <= 1; exec_state <= `EXEC_MEMIO_WRITE; end endcase end 3'b011:begin reg_write_we <= 0; `finished_instruction end 3'b100:begin /*No output*/ `finished_instruction end 3'b101:begin /* Program Counter*/ BIU_ADDRESS_INPUT <= ALU_O[15:0]; biu_jump_req <= 1; exec_state <= `EXEC_JUMP_RELEASE; end 3'b110:begin /* SP Indirect write*/ reg_read_port1_addr <= 4'b1100; use_exec_reg_addr <= 1; exec_state <= `EXEC_MEMIO_WRITE; end 3'b111:begin /* Write to PRAM1 (for microcode calculations) */ PARAM1 <= ALU_O; `finished_instruction end default:begin `unimpl_addressing_mode end endcase end `EXEC_JUMP_RELEASE:begin biu_jump_req <= 0; `finished_instruction end `EXEC_MEMIO_WRITE:begin /* if memio_address_select == 0 ADDRESS: reg_read_port1_data DATA:ALU1_O */ /* if memio_address_select == 1 ADDRESS: ALU1_O DATA: reg_read_port1_data */ biu_write_request <= 1; if(memio_address_select==0) BIU_ADDRESS_INPUT <= reg_read_port1_data[15:0]; else BIU_ADDRESS_INPUT <= ALU_O; if (write == 0) begin //TODO: don't do it that way or better yet don't do it at all somehow biu_write_request <= 0; `finished_instruction end end default:begin end endcase end end end endmodule `undef unimpl_addressing_mode