2023-05-11 15:28:10 +00:00
|
|
|
/* 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/>. */
|
|
|
|
|
2023-05-11 11:11:17 +00:00
|
|
|
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!!*/
|
2023-05-17 10:05:20 +00:00
|
|
|
/* */ ,input set_initial_values, output reg next_exec
|
2023-05-11 11:11:17 +00:00
|
|
|
/* 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;
|
|
|
|
|
2023-05-11 15:28:10 +00:00
|
|
|
/*############ ALU / Execution units ################################################## */
|
|
|
|
|
2023-05-11 11:11:17 +00:00
|
|
|
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(
|
2023-05-11 15:28:10 +00:00
|
|
|
/* 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)
|
|
|
|
);
|
2023-05-11 11:11:17 +00:00
|
|
|
|
2023-05-11 15:28:10 +00:00
|
|
|
/*############ Execute logic ########################################################## */
|
2023-05-11 11:11:17 +00:00
|
|
|
|
2023-05-17 20:28:50 +00:00
|
|
|
always @(valid_input) begin
|
|
|
|
exec_state <= init_state;
|
|
|
|
reg_write_we <= 1;
|
|
|
|
biu_jump_req <= 0;
|
|
|
|
use_exec_reg_addr <= 0;
|
2023-05-11 11:11:17 +00:00
|
|
|
end
|
|
|
|
|
2023-05-16 15:29:48 +00:00
|
|
|
always @( set_initial_values) begin
|
2023-05-11 11:11:17 +00:00
|
|
|
PARAM1 <= PARAM1_INIT;
|
|
|
|
PARAM2 <= PARAM2_INIT;
|
|
|
|
end
|
|
|
|
|
|
|
|
always @(negedge reset) begin
|
2023-05-17 20:28:50 +00:00
|
|
|
exec_state <= `EXEC_WAIT;
|
2023-05-11 11:11:17 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
always @(posedge reset) begin
|
|
|
|
exec_state <= `EXEC_RESET;
|
|
|
|
end
|
|
|
|
|
2023-05-17 20:28:50 +00:00
|
|
|
`define unimpl_addressing_mode exec_state <= `EXEC_WAIT;ERROR <= `ERR_UNIMPL_ADDRESSING_MODE;
|
|
|
|
|
|
|
|
`define finished_instruction next_exec<=!next_exec; exec_state <= `EXEC_WAIT;
|
2023-05-13 05:51:35 +00:00
|
|
|
|
2023-05-11 11:11:17 +00:00
|
|
|
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;
|
2023-05-17 20:28:50 +00:00
|
|
|
exec_state <= `EXEC_WAIT;
|
2023-05-17 10:05:20 +00:00
|
|
|
next_exec <= 0;
|
2023-05-11 11:11:17 +00:00
|
|
|
ERROR <= `ERR_NO_ERROR;
|
|
|
|
end
|
2023-05-17 20:28:50 +00:00
|
|
|
`EXEC_WAIT:begin
|
2023-05-11 11:11:17 +00:00
|
|
|
reg_write_we <= 1;
|
|
|
|
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
|
2023-05-17 20:28:50 +00:00
|
|
|
`finished_instruction
|
2023-05-11 11:11:17 +00:00
|
|
|
/*necessary for biu to see we went on another state from decode to give us a new instruction*/
|
|
|
|
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;
|
2023-05-17 20:28:50 +00:00
|
|
|
`finished_instruction
|
2023-05-11 11:11:17 +00:00
|
|
|
end
|
|
|
|
3'b100:begin /*No output*/
|
2023-05-17 20:28:50 +00:00
|
|
|
`finished_instruction
|
2023-05-11 11:11:17 +00:00
|
|
|
end
|
|
|
|
3'b101:begin /* Program Counter*/
|
|
|
|
BIU_ADDRESS_INPUT <= ALU_O[15:0];
|
|
|
|
biu_jump_req <= 1;
|
2023-05-16 12:33:08 +00:00
|
|
|
exec_state <= `EXEC_JUMP_RELEASE;
|
2023-05-11 11:11:17 +00:00
|
|
|
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;
|
2023-05-17 20:28:50 +00:00
|
|
|
`finished_instruction
|
2023-05-11 11:11:17 +00:00
|
|
|
end
|
|
|
|
default:begin
|
|
|
|
`unimpl_addressing_mode
|
|
|
|
end
|
|
|
|
endcase
|
|
|
|
end
|
2023-05-16 12:33:08 +00:00
|
|
|
`EXEC_JUMP_RELEASE:begin
|
|
|
|
biu_jump_req <= 0;
|
2023-05-17 20:28:50 +00:00
|
|
|
`finished_instruction
|
2023-05-16 12:33:08 +00:00
|
|
|
end
|
2023-05-11 11:11:17 +00:00
|
|
|
`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;
|
2023-05-17 20:28:50 +00:00
|
|
|
`finished_instruction
|
2023-05-17 10:05:20 +00:00
|
|
|
end
|
2023-05-11 11:11:17 +00:00
|
|
|
|
|
|
|
end
|
|
|
|
default:begin
|
|
|
|
end
|
|
|
|
endcase
|
|
|
|
end
|
|
|
|
`undef unimpl_addressing_mode
|
|
|
|
|
|
|
|
endmodule
|