/* 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 . */ module execute_unit ( /* 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 set_initial_values /* 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 /* 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 /* FLAFS */ ,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; reg [15:0] PARAM1,PARAM2; /*############ 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 ########################################################## */ always @(posedge valid_input) begin exec_state <= init_state; end always @(negedge set_initial_values) begin PARAM1 <= PARAM1_INIT; PARAM2 <= PARAM2_INIT; end always @(negedge reset) begin exec_state <= `EXEC_HALT; end always @(posedge reset) begin exec_state <= `EXEC_RESET; end `define unimpl_addressing_mode exec_state <= `EXEC_DONE;ERROR <= `ERR_UNIMPL_ADDRESSING_MODE; always @(posedge clock) begin case (exec_state) `EXEC_RESET: begin biu_write_request <= 0; biu_read_request <= 0; biu_data_direction <= 0; biu_jump_req <= 0; reg_write_we <= 1; exec_state <= `EXEC_DONE; ERROR <= `ERR_NO_ERROR; end `EXEC_DONE:begin reg_write_we <= 1; biu_jump_req <= 0; use_exec_reg_addr <= 0; 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_DE_LOAD_8_PARAM:begin if(opcode_size==0)begin if({Sbit,Wbit}==2'b11)begin /*signed "16bit" read*/ PARAM1 <= {{8{INSTRUCTION_BUFFER[23:23]}},INSTRUCTION_BUFFER[23:16]}; end else begin PARAM1[7:0] <= INSTRUCTION_BUFFER[23:16]; end case(IN_MOD) 3'b000,3'b001,3'b010: exec_state <= `EXEC_MEMIO_READ; default: exec_state <= `EXEC_WRITE_ENTRY; endcase end else begin if({Sbit,Wbit}==2'b11)begin /*signed "16bit" read*/ PARAM1 <= {{8{INSTRUCTION_BUFFER[15:15]}},INSTRUCTION_BUFFER[15:8]}; end else begin PARAM1[7:0] <= INSTRUCTION_BUFFER[15:8]; end end case(IN_MOD) 3'b000,3'b001,3'b010: exec_state <= `EXEC_MEMIO_READ; default: exec_state <= `EXEC_WRITE_ENTRY; endcase end `EXEC_DE_LOAD_16_PARAM:begin if(opcode_size==0)begin PARAM1[7:0] <= INSTRUCTION_BUFFER[23:16]; PARAM1[15:8] <= INSTRUCTION_BUFFER[15:8]; end else begin PARAM1[15:8] <= INSTRUCTION_BUFFER[7:0]; PARAM1[7:0] <= INSTRUCTION_BUFFER[15:8]; end 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) 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_DATA; biu_read_request <= 0; biu_data_direction <= 0; end else begin biu_data_direction <= 1; biu_read_request <= 1; end end `EXEC_NEXT_INSTRUCTION:begin /*necessary for biu to see we went on another state from decode to give us a new instruction*/ exec_state <= `EXEC_DONE; end `EXEC_WRITE_ENTRY:begin 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; exec_state <= `EXEC_DONE; end 3'b100:begin /*No output*/ exec_state <= `EXEC_DONE; end 3'b101:begin /* Program Counter*/ BIU_ADDRESS_INPUT <= ALU_O[15:0]; biu_jump_req <= 1; exec_state <= `EXEC_DONE; 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; exec_state <= `EXEC_DONE; end default:begin `unimpl_addressing_mode end endcase 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 was or better yet don't do it at all somehow biu_write_request <= 0; exec_state <= `EXEC_DONE; end end `EXEC_HALT:begin end default:begin end endcase end `undef unimpl_addressing_mode endmodule