// Wrapper around verilog-6502

// memory map:
// 0x0000-0x00FF    Zero Page       (Hard coded)
// 0x0100-0x01FF    Stack           (Hard coded)
// 0x0200-0xCFFF    Internal Memory 
// 0xE000-0xEFFF    External AXI
// 0xF000-0xFFFF    Processor IO 

module verilog6502_wrapper(
    input   clk,
    input   rst,

    taxi_apb_if.slv     s_apb,

    taxi_axil_if.wr_mst m_axil_wr,
    taxi_axil_if.rd_mst m_axil_rd,
    taxi_axi_if.rd_slv  s_axi_rd,
    taxi_axi_if.wr_slv  s_axi_wr,

    output logic        o_irq_ext,
    input  logic        i_irq_ext,
    input  logic        i_nmi_ext
);

taxi_apb_if internal_apb();

taxi_apb_if s_apb_mux[2]();
taxi_apb_if m_apb_mux[1]();
taxi_apb_if m_apb();

taxi_apb_tie u_external_apb_tie(
    .s_apb(s_apb),
    .m_apb(s_apb_mux[0])
);

taxi_apb_tie u_internal_apb_tie(
    .s_apb(internal_apb),
    .m_apb(s_apb_mux[1])
);

taxi_apb_tie u_master_apb_tie(
    .s_apb(m_apb_mux[0]),
    .m_apb(m_apb)
);

taxi_apb_interconnect #(
  .S_CNT(2),
  .M_CNT(1),
  .ADDR_W(32)
) u_apb_interconnect (
    .clk        (clk),
    .rst        (rst),

    .s_apb      (s_apb_mux),
    .m_apb      (m_apb_mux)
);


logic cpu_clk;
logic cpu_reset;
logic [15:0] cpu_addr;
logic [7:0] cpu_data_in;
logic [7:0] cpu_data_out;

logic cpu_we;
logic cpu_irq;
logic cpu_nmi;
logic cpu_rdy;
logic cpu_rdy_o;
logic cpu_sync;

assign cpu_clk = clk;
assign cpu_reset = hwif_out.core_ctrl.reset.value;

assign cpu_irq = i_irq_ext;
assign cpu_nmi = i_nmi_ext;

logic [15:0]    mem_addr;
logic [7:0]     mem_data_in;
logic [7:0]     mem_data_out;
logic           mem_rd;
logic           mem_we;
logic           mem_rdy;

logic [15:0]    ext_addr;
logic [7:0]     ext_data_in;
logic [7:0]     ext_data_out;
logic           ext_rd;
logic           ext_we;
logic           ext_rdy;

logic [15:0]    io_addr;
logic [7:0]     io_data_in;
logic [7:0]     io_data_out;
logic           io_rd;
logic           io_we;
logic           io_rdy;

verilog6502_io_regs_pkg::verilog6502_io_regs__out_t hwif_out;

cpu_65c02 u_cpu_6502(
    .clk        (cpu_clk),
    .reset      (cpu_reset),

    .AB         (cpu_addr),
    .DI         (cpu_data_in),
    .DO         (cpu_data_out),
    .WE         (cpu_we),
    .IRQ        (cpu_irq),
    .NMI        (cpu_nmi),
    .RDY        (cpu_rdy),
    .RDY_O      (cpu_rdy_o),
    .SYNC       (cpu_sync)
);

verilog6502_addr_decoder u_addr_decoder(
    .i_clk              (cpu_clk),
    .i_rst              (cpu_reset),

    .i_cpu_addr         (cpu_addr),
    .i_cpu_data         (cpu_data_out),
    .o_cpu_data         (cpu_data_in),
    .i_cpu_we           (cpu_we),
    .i_cpu_rdy          (cpu_rdy_o),
    .o_cpu_rdy          (cpu_rdy),

    .o_mem_addr         (mem_addr),
    .o_mem_data         (mem_data_in),
    .i_mem_data         (mem_data_out),
    .o_mem_rd           (mem_rd),
    .o_mem_we           (mem_we),
    .i_mem_rdy          (mem_rdy),

    .o_external_addr    (ext_addr),
    .o_external_data    (ext_data_in),
    .i_external_data    (ext_data_out),
    .o_external_rd      (ext_rd),
    .o_external_we      (ext_we),
    .i_external_rdy     (ext_rdy),

    .o_io_addr          (io_addr),
    .o_io_data          (io_data_in),
    .i_io_data          (io_data_out),
    .o_io_rd            (io_rd),
    .o_io_we            (io_we),
    .i_io_rdy           (io_rdy)
);

verilog6502_internal_memory u_internal_memory(
    .i_clk              (cpu_clk),
    .i_rst              (rst),

    .s_axi_rd           (s_axi_rd),
    .s_axi_wr           (s_axi_wr),

    .i_addr             (mem_addr),
    .i_data             (mem_data_in),
    .o_data             (mem_data_out),
    .i_rd               (mem_rd),
    .i_we               (mem_we),
    .o_rdy              (mem_rdy)
);

verilog6502_external_memory u_external_memory (
    .i_clk              (clk),
    .i_rst              (rst),

    .i_addr             (ext_addr),
    .i_data             (ext_data_in),
    .o_data             (ext_data_out),
    .i_rd               (ext_rd),
    .i_we               (ext_we),
    .o_rdy              (ext_rdy),

    .i_axi_base_addr    (hwif_out.axi_base_address.val.value),

    .m_axil_rd          (m_axil_rd),
    .m_axil_wr          (m_axil_wr)
);

verilog6502_apb_adapter u_io_apb_adapter(
    .i_clk              (cpu_clk),
    .i_rst              (rst),

    .i_addr             (io_addr),
    .i_data             (io_data_in),
    .o_data             (io_data_out),
    .i_rd               (io_rd),
    .i_we               (io_we),
    .o_rdy              (io_rdy),

    .m_apb              (internal_apb)
);


verilog6502_io_regs u_io_regs (
    .clk                (cpu_clk),
    .rst                (rst),    
    .s_apb              (m_apb),

    .hwif_out           (hwif_out)
);

endmodule