`include <params.svh>

`include <interface.sv>
`include <hub.sv>

module fabric(input logic                        rst_raw,
              input logic                        internal_clk,
	      input logic [INTERFACE_CNT - 1:0]  sclk,
	      input logic [INTERFACE_CNT - 1:0]  cs_n,
	      input logic [INTERFACE_CNT - 1:0]  mosi,
	      output logic [INTERFACE_CNT - 1:0] miso,
              output logic [INTERFACE_CNT - 1:0] tx_active,
              output logic [INTERFACE_CNT - 1:0] sig_fabric_ready,
              output logic                       fabric_ready,
              output logic                       hub_ready);

    timeunit 1ns;
    timeprecision 1ps;
    
    logic sys_clk;
    // TODO: add PPL module for a boosted system clock
    
    logic rst;
    assign fabric_ready = hub_ready & (~rst);
    
    reset_sync rst_sync(.sys_clk(sys_clk),
                        .rst_raw(rst_raw),
                        .rst(rst));

    logic [7:0]                   rx_byte [INTERFACE_CNT];
    logic                         rx_valid [INTERFACE_CNT];
    logic                         rx_ready [INTERFACE_CNT];
    logic [PACKET_ADDR_LEN - 1:0] rx_pkt_addr [INTERFACE_CNT];
    logic [7:0]                   tx_byte [INTERFACE_CNT];
    logic                         tx_valid [INTERFACE_CNT];
    logic                         tx_ready [INTERFACE_CNT];
    logic [PACKET_ADDR_LEN - 1:0] tx_pkt_addr [INTERFACE_CNT];
    logic [QUEUE_ADDR_LEN - 1:0]  tx_queue_addr [INTERFACE_CNT];
    logic [QUEUE_ADDR_LEN - 1:0]  tx_new_queue [INTERFACE_CNT];
    logic                         tx_new_queue_valid [INTERFACE_CNT];
    logic                         tx_new_queue_ready [INTERFACE_CNT];

    genvar i;
    generate
        for (i = 0; i < INTERFACE_CNT; i = i + 1) begin : gen_interfaces
            assign sig_fabric_ready[i] = fabric_ready;
            
            spi_interface spi(.rst(rst),
                              .sys_clk(sys_clk),
                              .sclk(sclk[i]),
                              .cs_n(cs_n[i]),
                              .mosi(mosi[i]),
                              .miso(miso[i]),
                              .rx_byte(rx_byte[i]),
                              .rx_valid(rx_valid[i]),
                              .rx_ready(rx_ready[i]),
                              .rx_pkt_addr(rx_pkt_addr[i]),
                              .tx_active(tx_active[i]),
                              .tx_byte(tx_byte[i]),
                              .tx_valid(tx_valid[i]),
                              .tx_ready(tx_ready[i]),
                              .tx_pkt_addr(tx_pkt_addr[i]),
                              .tx_queue_addr(tx_queue_addr[i]),
                              .tx_new_queue(tx_new_queue[i]),
                              .tx_new_queue_valid(tx_new_queue_valid[i]),
                              .tx_new_queue_ready(tx_new_queue_ready[i]));
        end
    endgenerate

    hub the_hub(.rst(rst),
                .sys_clk(sys_clk),
                .rx_byte(rx_byte),
                .rx_valid(rx_valid),
                .rx_ready(rx_ready),
                .rx_pkt_addr(rx_pkt_addr),
                .tx_byte(tx_byte),
                .tx_valid(tx_valid),
                .tx_ready(tx_ready),
                .tx_pkt_addr(tx_pkt_addr),
                .tx_queue_addr(tx_queue_addr),
                .tx_new_queue(tx_new_queue),
                .tx_new_queue_valid(tx_new_queue_valid),
                .tx_new_queue_ready(tx_new_queue_ready),
                .hub_ready(hub_ready));
    
endmodule // fabric

module reset_sync (input logic  sys_clk,
                   input logic  rst_raw,
                   output logic rst);

    timeunit 1ns;
    timeprecision 1ps;

    
    logic rst_sync_0 = 0;
    logic rst_sync_1 = 0;

    always_ff @(posedge sys_clk or posedge rst_raw) begin
	if (rst_raw) begin
	    rst_sync_0 <= 1;
	    rst_sync_1 <= 1;
	end else begin
	    rst_sync_0 <= 0;
	    rst_sync_1 <= rst_sync_0;
	end
    end

    assign rst = rst_sync_1;
endmodule
