/* processor.v - Connects the different modules comprising the processor

   This file is part of the 9086 project.

   Copyright (c) 2024 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/>.  */

`include "exec_state_def.v"
`include "alu_header.v"
`include "config.v"
`include "error_header.v"

//HALT: active high
//IOMEM: 1=IO  0=MEM
//BHE: active low
//write: active low
//read: active low
//reset: active low

module processor (

	/*     MISC    */  input clock, input reset, output wire HALT,output [`ERROR_BITS-1:0] ERROR
	/* MEMORY / IO */ ,output [19:0] external_address_bus, input [15:0] external_data_bus_read, output [15:0] external_data_bus_write, input wait_state, output read, output write,output BHE,output IOMEM

`ifdef CALCULATE_IPC
	/*  STATISTICS */ ,output wire new_instruction
`endif
`ifdef OUTPUT_JSON_STATISTICS
	/*             */ ,output wire [`L1_CACHE_SIZE-1:0] L1_SIZE_STAT, output wire VALID_INSTRUCTION_STAT, output wire jump_req_debug
`endif

);


`ifdef OUTPUT_JSON_STATISTICS
assign jump_req_debug=biu_jump_req;
`endif

/* 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;


/*############ Execution Unit ################################################### */

wire [`ERROR_BITS-1:0] EXEC_ERROR;

wire biu_read_request,biu_jump_req,biu_write_request,use_exec_reg_addr;
wire [3:0] EXEC_reg_read_port1_addr;
wire [15:0] ALU_O;
wire [7:0] EX2DE_FLAGS;
wire [15:0] BIU_ADDRESS_INPUT;
wire reg_write_we;
wire next_exec;

execute_unit execute_unit (
	/*****************   GENERAL   *****************/
	/*                */  clock, reset, write, EXEC_ERROR

	/***************  INPUT FROM DE  ***************/
	/* SYNC SIGNALS   */ ,valid_exec_data,set_initial_values
	/* INSTR. PARAMS  */ ,Wbit, IN_MOD, OUT_MOD, RM
	/* DATA           */ ,PARAM1_INIT,PARAM2_INIT,ProgCount
	/* STATE CONTROL  */ ,next_state
        /* ALU CONTROL    */ ,in_alu_sel1, in_alu_sel2, ALU_OP, ALU_O
	/* OTHER          */ ,memio_address_select

	/**************** OUTPUT TO DE  ****************/
	/* SYNC SIGNALS   */ ,next_exec
	/* FLAGS          */ ,EX2DE_FLAGS

	/**************** OUTPUT TO BIU ****************/
	/*                */ ,BIU_ADDRESS_INPUT
	/*                */ ,biu_read_request, biu_jump_req, biu_write_request

	/*************** INPUT FROM BIU ****************/
	/*                */ ,BIU_VALID_DATA,BIU_EX_DATA_READ

	/**************** OUTPUT TO BIU ****************/
	/*                */ ,BIU_EX_DATA_WRITE

	/*****************  REGISTERS  *****************/
	/*                */ ,reg_read_port1_data, reg_read_port2_data, EXEC_reg_read_port1_addr
	/*                */ ,use_exec_reg_addr, reg_write_we

);

/*############ Bus Interface Unit ############################################### */

wire [15:0] INSTRUCTION_LOCATION;
wire [15:0] BIU_EX_DATA_READ,BIU_EX_DATA_WRITE;
wire [31:0] IF2DE_INSTRUCTION;
wire BIU_VALID_DATA;
wire VALID_INSTRUCTION;

BIU BIU(
	/*****************   GENERAL   *****************/
	/*               */  clock,reset

	/**************** OUTSIDE WORLD ****************/
	/*               */ ,external_address_bus
	/*               */ ,external_data_bus_read,external_data_bus_write,read,write,BHE,IOMEM
	/*               */ ,wait_state

	/**************** OUTPUT TO DE  ****************/
	/*               */ ,IF2DE_INSTRUCTION,VALID_INSTRUCTION,INSTRUCTION_LOCATION
	/*               */ ,BIU_VALID_DATA

	/**************** INPUT FROM DE ****************/
	                    ,Wbit,MEM_OR_IO,VALID_INSTRUCTION_ACK

	/**************** INPUT FROM EX ****************/
	/*               */ ,biu_jump_req,biu_write_request,biu_read_request
	/*               */ ,BIU_ADDRESS_INPUT,BIU_EX_DATA_WRITE

	/***************** OUTPUT TO EX ****************/
	/*               */ ,BIU_EX_DATA_READ

`ifdef OUTPUT_JSON_STATISTICS
	/***************** STATISTICS  *****************/
	/*               */ ,L1_SIZE_STAT, VALID_INSTRUCTION_STAT
`endif

);


/*############ Decoder ########################################################## */


wire [`ERROR_BITS-1:0] DE_ERROR;
wire valid_exec_data, set_initial_values, Wbit;
wire memio_address_select, MEM_OR_IO, VALID_INSTRUCTION_ACK;
wire [1:0] in_alu_sel1, in_alu_sel2;
wire [2:0] IN_MOD,OUT_MOD, RM;
wire [3:0] DE_reg_read_port1_addr,DE_reg_read_port2_addr, reg_write_addr;
wire [15:0] PARAM1_INIT, PARAM2_INIT, ProgCount;
wire [`ALU_OP_BITS-1:0] ALU_OP;
wire [`EXEC_STATE_BITS-1:0] next_state;

decoder decoder(
	/*****************   GENERAL   *****************/
	/* Input from sys. */  clock, reset
	/* Output to sys.  */ ,MEM_OR_IO, DE_ERROR, HALT

	/***************  INPUT FROM IF  ***************/
	/*                 */ ,IF2DE_INSTRUCTION, VALID_INSTRUCTION
	/*                 */ ,INSTRUCTION_LOCATION

	/***************  OUTPUT TO IF   ***************/
	/*                 */ ,VALID_INSTRUCTION_ACK

	/***************  INPUT FROM EX  ***************/
	/*                 */ ,EX2DE_FLAGS[7:0], next_exec

	/***************  OUTPUT TO DE   ***************/
	/* SYNC SIGNALS    */ ,set_initial_values, valid_exec_data
	/* INSTR. PARAMS   */ ,Wbit, IN_MOD, OUT_MOD, RM
	/* DATA            */ ,PARAM1_INIT, PARAM2_INIT, ProgCount
	/* STATE CONTROL   */ ,next_state
        /* ALU CONTROL     */ ,in_alu_sel1, in_alu_sel2, ALU_OP
	/* OTHER           */ ,memio_address_select

	/************* OUTPUT TO REGISTERS  ************/
	/*                 */ , reg_write_addr,DE_reg_read_port2_addr, DE_reg_read_port1_addr

`ifdef CALCULATE_IPC
	/*  STATISTICS     */ , new_instruction
`endif

);

/*############ Registers ######################################################## */


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;

wire [15:0] reg_read_port1_data, reg_read_port2_data;

register_file register_file(
	/*   WRITE  */ .write_port1_addr(reg_write_addr), //TODO: should this come from exec instead?
	/*          */ .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),
	/*  GENERAL */ .clock(clock)
	);

/*############################################################################### */


endmodule
