`timescale 1ns / 1ps
`include "cpu.h"

module cpu_top(
    input         clk,
    input         resetn,
    // inst ram interface
    output        instr_ram_en,
    output [ 3:0] instr_ram_wen,
    output [31:0] instr_ram_addr,
    output [31:0] instr_ram_wdata,
    input  [31:0] instr_ram_rdata,
    // data ram interface
    output        data_ram_en,
    output [ 3:0] data_ram_wen,
    output [31:0] data_ram_addr,
    output [31:0] data_ram_wdata,
    input  [31:0] data_ram_rdata,
    // trace debug interface
    output [31:0] debug_wb_pc,
    output [ 3:0] debug_wb_rf_wen,
    output [ 4:0] debug_wb_rf_wnum,
    output [31:0] debug_wb_rf_wdata,
    input  [ 4:0] rf_raddr,
    output [31:0] rf_rdata
    );
    
    reg  reset;
    always @(posedge clk) reset <= ~resetn;

    
    wire                         ds_allowin;
    wire                         es_allowin;
    wire                         ms_allowin;
    wire                         ws_allowin;
    wire                         fs_to_ds_valid;
    wire                         ds_to_es_valid;
    wire                         es_to_ms_valid;
    wire                         ms_to_ws_valid;
    wire [`FS_TO_DS_BUS_WD -1:0] fs_to_ds_bus;
    wire [`DS_TO_ES_BUS_WD -1:0] ds_to_es_bus;
    wire [`ES_TO_MS_BUS_WD -1:0] es_to_ms_bus;
    wire [`MS_TO_WS_BUS_WD -1:0] ms_to_ws_bus;
    wire [`WS_TO_RF_BUS_WD -1:0] ws_to_rf_bus;
    
    wire [`BR_BUS_WD       -1:0] br_bus;
    
    wire [`DS_TO_FW_BUS_WD -1:0] ds_to_fw_bus;
    wire [`ES_TO_FW_BUS_WD -1:0] es_to_fw_bus;
    wire [`MS_TO_FW_BUS_WD -1:0] ms_to_fw_bus;
    wire [`FW_TO_ES_BUS_WD -1:0] fw_to_es_bus;
    wire [`MS_TO_ES_BUS_WD -1:0] ms_to_es_bus;
    wire [`WS_TO_ES_BUS_WD -1:0] ws_to_es_bus;
    
    wire [`DS_TO_LU_BUS_WD -1:0] ds_to_lu_bus;
    wire [`ES_TO_LU_BUS_WD -1:0] es_to_lu_bus;
    
    wire                         lu_stall;
    wire                         dh_flush;
    wire                         dh_stall;
    
    wire                         fs_stall;
    wire                         fs_flush;
    wire                         ds_flush;
    wire                         es_flush;
    wire                         ms_flush;
    wire                         ws_flush;
    
    // IF stage
    if_stage if_stage(
        .clk            (clk            ),
        .reset          (reset          ),
        .fs_flush       (fs_flush       ),
        .fs_stall       (fs_stall       ),
        //allowin
        .ds_allowin     (ds_allowin     ),
        //brbus
        .br_bus         (br_bus         ),
        //outputs
        .fs_to_ds_valid (fs_to_ds_valid ),
        .fs_to_ds_bus   (fs_to_ds_bus   ),
        // inst ram interface
        .instr_ram_en   (instr_ram_en   ),
        .instr_ram_wen  (instr_ram_wen  ),
        .instr_ram_addr (instr_ram_addr ),
        .instr_ram_wdata(instr_ram_wdata),
        .instr_ram_rdata(instr_ram_rdata)
    );
    // ID stage
    id_stage id_stage(
        .clk            (clk            ),
        .reset          (reset          ),
        .ds_flush       (ds_flush       ),
        .stall          (lu_stall       ),
        //allowin
        .es_allowin     (es_allowin     ),
        .ds_allowin     (ds_allowin     ),
        //from fs
        .fs_to_ds_valid (fs_to_ds_valid ),
        .fs_to_ds_bus   (fs_to_ds_bus   ),
        //to es
        .ds_to_es_valid (ds_to_es_valid ),
        .ds_to_es_bus   (ds_to_es_bus   ),
        //to fw
        .ds_to_fw_bus   (ds_to_fw_bus   ),
        //to lu
        .ds_to_lu_bus   (ds_to_lu_bus   ),
        //to rf: for write back
        .ws_to_rf_bus   (ws_to_rf_bus   ),
        //to pipctr
        .dh_flush       (dh_flush       ),
        .dh_stall       (dh_stall       ),
        
        .rf_raddr       (rf_raddr       ),
        .rf_rdata       (rf_rdata       )

    );
    // EXE stage
    exe_stage exe_stage(
        .clk            (clk            ),
        .reset          (reset          ),
        .es_flush       (es_flush       ),
        //allowin
        .ms_allowin     (ms_allowin     ),
        .es_allowin     (es_allowin     ),
        //from ds
        .ds_to_es_valid (ds_to_es_valid ),
        .ds_to_es_bus   (ds_to_es_bus   ),
        //from ms
        .ms_to_es_bus   (ms_to_es_bus   ),
        //from ws
        .ws_to_es_bus   (ws_to_es_bus   ),
        //from fw
        .fw_to_es_bus   (fw_to_es_bus   ),
        //to lu
        .es_to_lu_bus   (es_to_lu_bus   ),
        //to fw
        .es_to_fw_bus   (es_to_fw_bus   ),
        //to ms
        .es_to_ms_valid (es_to_ms_valid ),
        .es_to_ms_bus   (es_to_ms_bus   ),
        // data ram interface
        .data_ram_en    (data_ram_en    ),
        .data_ram_wen   (data_ram_wen   ),
        .data_ram_addr  (data_ram_addr  ),
        .data_ram_wdata (data_ram_wdata )
    );
    // MEM stage
    mem_stage mem_stage(
        .clk            (clk            ),
        .reset          (reset          ),
        .ms_flush       (ms_flush       ),
        //allowin
        .ws_allowin     (ws_allowin     ),
        .ms_allowin     (ms_allowin     ),
        //from es
        .es_to_ms_valid (es_to_ms_valid ),
        .es_to_ms_bus   (es_to_ms_bus   ),
        //to fs
        .br_bus         (br_bus         ),
        //to es: for forward
        .ms_to_es_bus   (ms_to_es_bus   ),
        //to fw
        .ms_to_fw_bus   (ms_to_fw_bus   ),
        //to ws
        .ms_to_ws_valid (ms_to_ws_valid ),
        .ms_to_ws_bus   (ms_to_ws_bus   ),
        //from data-ram
        .data_ram_rdata (data_ram_rdata)
    );
    // WB stage
    wb_stage wb_stage(
        .clk            (clk            ),
        .reset          (reset          ),
        .ws_flush       (ws_flush       ),
        //allowin
        .ws_allowin     (ws_allowin     ),
        //from ms
        .ms_to_ws_valid (ms_to_ws_valid ),
        .ms_to_ws_bus   (ms_to_ws_bus   ),
        //to rf: for write back
        .ws_to_rf_bus   (ws_to_rf_bus   ),
        //to es: for forward
        .ws_to_es_bus   (ws_to_es_bus   ),
        //trace debug interface
        .debug_wb_pc      (debug_wb_pc      ),
        .debug_wb_rf_wen  (debug_wb_rf_wen  ),
        .debug_wb_rf_wnum (debug_wb_rf_wnum ),
        .debug_wb_rf_wdata(debug_wb_rf_wdata)
    );
    // Forward
    forward u_forward(    
        .clk          (clk         ),    
        .ds_to_fw_bus (ds_to_fw_bus),
        .es_to_fw_bus (es_to_fw_bus),
        .ms_to_fw_bus (ms_to_fw_bus),
        
        .fw_to_es_bus (fw_to_es_bus)
    );
    // Load Use
    loaduse u_loaduse(
        .clk          (clk         ),
        .reset        (reset       ),
        .ds_to_lu_bus (ds_to_lu_bus),
        .es_to_lu_bus (es_to_lu_bus),
        .ds_stall     (lu_stall    ),
        .es_flush     (lu_flush    )
    );
    
    piplinectr u_piplinectr(
        .clk          (clk     ),
        .reset        (reset   ),
        .lu_flush     (lu_flush),
        .dh_flush     (dh_flush),
        .dh_stall     (dh_stall),
    
        .fs_stall     (fs_stall),
        .fs_flush     (fs_flush),
        .ds_flush     (ds_flush),
        .es_flush     (es_flush),
        .ms_flush     (ms_flush),
        .ws_flush     (ws_flush)
    );
    
    
    
endmodule
