`timescale 1 ns / 1 ns
//////////////////////////////////////////////////////////////////////////////////
// Company: Rehkopf
// Engineer: Rehkopf
// 
// Create Date:    01:13:46 05/09/2009 
// Design Name: 
// Module Name:    main 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: Master Control FSM
//
// Dependencies: address
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module main(
   /* input clock */
    input CLKIN,
    
   /* SNES signals */
    input [23:0] SNES_ADDR,
    input SNES_READ,
    input SNES_WRITE,
    input SNES_CS,
    inout [7:0] SNES_DATA,
    input SNES_CPU_CLK,
    input SNES_REFRESH,
    inout SNES_IRQ,
    output SNES_DATABUS_OE,
    output SNES_DATABUS_DIR,
    output IRQ_DIR,
	 input SNES_SYSCLK,

   /* SRAM signals */
    inout [15:0] ROM_DATA,
    output [22:0] ROM_ADDR,
    output ROM_CE,
    output ROM_OE,
    output ROM_WE,
    output ROM_BHE,
    output ROM_BLE,

   /* MCU signals */
    input SPI_MOSI,
    inout SPI_MISO,
    input SPI_SS,
    inout SPI_SCK,
    input MCU_OVR,
	 
	 output DAC_MCLK,
	 output DAC_LRCK,
	 output DAC_SDOUT,
	 
	/* SD signals */
    input [3:0] SD_DAT,
	 inout SD_CMD,
	 inout SD_CLK
	 
   /* debug */
   //output DCM_IN_STOPPED,
   //output DCM_FX_STOPPED
   //input DCM_RST
    );
	 
assign DAC_MCLK = 1'b0;
assign DAC_LRCK = 1'b0;
assign DAC_SDOUT = 1'b0;

wire [7:0] spi_cmd_data;
wire [7:0] spi_param_data;
wire [7:0] spi_input_data;
wire [31:0] spi_byte_cnt;
wire [2:0] spi_bit_cnt;
wire [23:0] MCU_ADDR;
wire [7:0] mcu_data_in;
wire [7:0] mcu_data_out;
wire [7:0] MCU_IN_DATA;
wire [7:0] MCU_OUT_DATA;
wire [3:0] MAPPER;
wire [23:0] SAVERAM_MASK;
wire [23:0] ROM_MASK;
wire [7:0] SD_DMA_SRAM_DATA;
wire [1:0] SD_DMA_TGT;
wire [10:0] SD_DMA_PARTIAL_START;
wire [10:0] SD_DMA_PARTIAL_END;

wire [10:0] dac_addr;
//wire [7:0] dac_volume;
wire [7:0] msu_volumerq_out;
wire [6:0] msu_status_out;
wire [31:0] msu_addressrq_out;
wire [15:0] msu_trackrq_out;
wire [13:0] msu_write_addr;
wire [13:0] msu_ptr_addr;
wire [7:0] MSU_SNES_DATA_IN;
wire [7:0] MSU_SNES_DATA_OUT;
wire [5:0] msu_status_reset_bits;
wire [5:0] msu_status_set_bits;

 
spi snes_spi(.clk(CLK2),
             .MOSI(SPI_MOSI),
             .MISO(SPI_MISO),
             .SSEL(SPI_SS),
             .SCK(SPI_SCK),
             .cmd_ready(spi_cmd_ready),
             .param_ready(spi_param_ready),
             .cmd_data(spi_cmd_data),
             .param_data(spi_param_data),
             .endmessage(spi_endmessage),
             .startmessage(spi_startmessage),
             .input_data(spi_input_data),
             .byte_cnt(spi_byte_cnt),
             .bit_cnt(spi_bit_cnt)
);


mcu_cmd snes_mcu_cmd(
    .clk(CLK2),
    .cmd_ready(spi_cmd_ready),
    .param_ready(spi_param_ready),
    .cmd_data(spi_cmd_data),
    .param_data(spi_param_data),
    .mcu_mapper(MAPPER),
    .mcu_sram_size(SRAM_SIZE),
    .mcu_read(MCU_READ),
    .mcu_write(MCU_WRITE),
    .mcu_data_in(MCU_OUT_DATA),
    .mcu_data_out(MCU_IN_DATA),
    .spi_byte_cnt(spi_byte_cnt),
    .spi_bit_cnt(spi_bit_cnt),
    .spi_data_out(spi_input_data),
    .addr_out(MCU_ADDR),
    .endmessage(spi_endmessage),
    .startmessage(spi_startmessage),
    .saveram_mask_out(SAVERAM_MASK),
    .rom_mask_out(ROM_MASK)
);

// dcm1: dfs 4x
my_dcm snes_dcm(.CLKIN(CLKIN),
                  .CLKFX(CLK2),
                  .LOCKED(DCM_LOCKED),
                  .RST(DCM_RST),
                  .STATUS(DCM_STATUS)
                );
                
assign DCM_RST=0;

/*
dcm_srl16 snes_dcm_resetter(.CLK(CLKIN),
                              .Q(DCM_RST)
                           );
*/
//wire DCM_FX_STOPPED = DCM_STATUS[2];
//always @(posedge CLKIN) begin
//   if(DCM_FX_STOPPED)
//      DCM_RSTr <= 1'b1;
//   else
//      DCM_RSTr <= 1'b0;
//end

/*reg DO_DCM_RESET, DCM_RESETTING;
reg DCM_RSTr;
assign DCM_RST = DCM_RSTr;
reg [2:0] DCM_RESET_CNT;
initial DO_DCM_RESET = 1'b0;
initial DCM_RESETTING = 1'b0;

always @(posedge CLKIN) begin
   if(!DCM_LOCKED && !DCM_RESETTING) begin
      DCM_RSTr <= 1'b1;
      DO_DCM_RESET <= 1'b1;
      DCM_RESET_CNT <= 3'b0;
   end else if (DO_DCM_RESET) begin
      DCM_RSTr <= 1'b0;
      DCM_RESET_CNT <= DCM_RESET_CNT + 1;
   end
end

always @(posedge CLKIN) begin
   if (DO_DCM_RESET)
      DCM_RESETTING <= 1'b1;
   else if (DCM_RESET_CNT == 3'b110)
      DCM_RESETTING <= 1'b0;
end
*/
wire SNES_RW;
reg [1:0] SNES_READr;
reg [1:0] SNES_WRITEr;
reg [1:0] SNES_CSr;
reg [5:0] SNES_CPU_CLKr;
reg [5:0] SNES_RWr;
reg [23:0] SNES_ADDRr;
reg [23:0] SNES_ADDR_PREVr;
reg [3:0] SNES_ADDRCHGr;

wire SNES_READs = (SNES_READr == 2'b11);
wire SNES_WRITEs = (SNES_WRITEr == 2'b11);
wire SNES_CSs = (SNES_CSr == 2'b11);
wire SNES_CPU_CLKs = SNES_CPU_CLK; // (SNES_CPU_CLKr == 2'b11);
wire SNES_RW_start = (SNES_RWr == 6'b111110); // falling edge marks beginning of cycle
wire SNES_cycle_start = (SNES_CPU_CLKr == 6'b000001);
wire SNES_ADDRCHG = (SNES_ADDRr != SNES_ADDR_PREVr);
wire SNES_addr_start = (SNES_ADDRCHGr[0] == 1'b1);

assign SNES_RW = (SNES_READ & SNES_WRITE);

always @(posedge CLK2) begin
   SNES_READr <= {SNES_READr[0], SNES_READ};
   SNES_WRITEr <= {SNES_WRITEr[0], SNES_WRITE};
   SNES_CSr <= {SNES_CSr[0], SNES_CS};
   SNES_CPU_CLKr <= {SNES_CPU_CLKr[4:0], SNES_CPU_CLK};
   SNES_RWr <= {SNES_RWr[4:0], SNES_RW};
end

reg ADDR_WRITE;

//reg [23:0] SNES_ADDRr;
//wire [23:0] SNES_ADDRw = SNES_ADDR;

wire ROM_SEL;

address snes_addr(
    .CLK(CLK2),
    .MAPPER(MAPPER),
    .SNES_ADDR(SNES_ADDR),   // requested address from SNES
    .SNES_CS(SNES_CS),            // "CART" pin from SNES (active low)
    .ROM_ADDR(ROM_ADDR),  // Address to request from SRAM (active low)
    .ROM_SEL(ROM_SEL),     // which SRAM unit to access
    .MCU_OVR(MCU_OVR),            // enable MCU mode (active low)
	 .MODE(MODE),               // MCU(1) or SNES(0) ("bus phase")
    .IS_SAVERAM(IS_SAVERAM),
    .IS_ROM(IS_ROM),
    .MCU_ADDR(MCU_ADDR),
    .ROM_ADDR0(ROM_ADDR0),
    .SAVERAM_MASK(SAVERAM_MASK),
    .ROM_MASK(ROM_MASK)
    );

wire SNES_READ_CYCLEw;
wire SNES_WRITE_CYCLEw;
wire MCU_READ_CYCLEw;
wire MCU_WRITE_CYCLEw;

data snes_data(.CLK(CLK2),
      .SNES_READ(SNES_READ),
      .SNES_WRITE(SNES_WRITE),
      .MCU_READ(MCU_READ),
      .MCU_WRITE(MCU_WRITE),
      .SNES_DATA(SNES_DATA),
      .ROM_DATA(ROM_DATA),
      .MODE(MODE),
      .SNES_DATA_TO_MEM(SNES_DATA_TO_MEM),
      .MCU_DATA_TO_MEM(MCU_DATA_TO_MEM),
      .ROM_DATA_TO_SNES_MEM(ROM_DATA_TO_SNES_MEM),
      .ROM_DATA_TO_MCU_MEM(ROM_DATA_TO_MCU_MEM),
      .MCU_OVR(MCU_OVR),
      .MCU_IN_DATA(MCU_IN_DATA),
      .MCU_OUT_DATA(MCU_OUT_DATA),
      .ROM_ADDR0(ROM_ADDR0),
		.MSU_DATA_IN(MSU_SNES_DATA_IN),
		.MSU_DATA_OUT(MSU_SNES_DATA_OUT),
		.msu_enable(msu_enable)
      );
      
parameter MODE_SNES = 1'b0;
parameter MODE_MCU = 1'b1;

parameter STATE_0    = 14'b00000000000001;
parameter STATE_1    = 14'b00000000000010;
parameter STATE_2    = 14'b00000000000100;
parameter STATE_3    = 14'b00000000001000;
parameter STATE_4    = 14'b00000000010000;
parameter STATE_5    = 14'b00000000100000;
parameter STATE_6    = 14'b00000001000000;
parameter STATE_7    = 14'b00000010000000;
parameter STATE_8    = 14'b00000100000000;
parameter STATE_9    = 14'b00001000000000;
parameter STATE_10   = 14'b00010000000000;
parameter STATE_11   = 14'b00100000000000;
parameter STATE_12	= 14'b01000000000000;
parameter STATE_IDLE = 14'b10000000000000;

reg [13:0] STATE;
reg [3:0] STATEIDX;

reg [1:0] CYCLE_RESET;
reg ROM_WE_MASK;
reg ROM_OE_MASK;

reg [13:0] ROM_WE_ARRAY [3:0];
reg [13:0] ROM_OE_ARRAY [3:0];

reg [13:0] SNES_DATA_TO_MEM_ARRAY[1:0];
reg [13:0] MCU_DATA_TO_MEM_ARRAY[1:0];
reg [13:0] ROM_DATA_TO_SNES_MEM_ARRAY[1:0];
reg [13:0] ROM_DATA_TO_MCU_MEM_ARRAY[1:0];

reg [13:0] MODE_ARRAY;

reg SNES_READ_CYCLE;
reg SNES_WRITE_CYCLE;
reg MCU_READ_CYCLE;
reg MCU_WRITE_CYCLE;
reg MCU_SPI_WRITEONCE;
reg MCU_SPI_READONCE;
reg MCU_SPI_WRITE;
reg MCU_SPI_READ;
reg MCU_SPI_ADDR_INCREMENT;
reg [7:0] MCU_DATA_IN;
reg [3:0] MAPPER_BUF;

reg SNES_DATABUS_OE_BUF;
reg SNES_DATABUS_DIR_BUF;

assign MODE = !MCU_OVR ? MODE_MCU : MODE_ARRAY[STATEIDX];

initial begin
   CYCLE_RESET = 2'b0;
   
   STATE = STATE_IDLE;
   STATEIDX = 13;
   ROM_WE_MASK = 1'b1;
   ROM_OE_MASK = 1'b1;
   SNES_READ_CYCLE = 1'b1;
   SNES_WRITE_CYCLE = 1'b1;
   MCU_READ_CYCLE = 1'b1;
   MCU_WRITE_CYCLE = 1'b1;
   MODE_ARRAY = 14'b0_000000_1111111;
   
   ROM_WE_ARRAY[2'b00] = 14'b1_000000_0000000;
   ROM_WE_ARRAY[2'b01] = 14'b1_000000_1111111;
   ROM_WE_ARRAY[2'b10] = 14'b1_111111_0000000;
   ROM_WE_ARRAY[2'b11] = 14'b1_111111_1111111;

   ROM_OE_ARRAY[2'b00] = 14'b1_111111_1111111;
   ROM_OE_ARRAY[2'b01] = 14'b1_111111_0000000;
   ROM_OE_ARRAY[2'b10] = 14'b0_000000_1111111;
   ROM_OE_ARRAY[2'b11] = 14'b0_000000_0000000;
   
   SNES_DATA_TO_MEM_ARRAY[1'b0] = 14'b0_000100_0000000;  // SNES write
   /* 13'b0001000000000 */
   SNES_DATA_TO_MEM_ARRAY[1'b1] = 14'b0_000000_0000000;  // SNES read
   
   MCU_DATA_TO_MEM_ARRAY[1'b0] = 14'b1_111111_1111111;  // MCU write
//   MCU_DATA_TO_MEM_ARRAY[1'b0] = 13'b0000000001000;  // MCU write

   MCU_DATA_TO_MEM_ARRAY[1'b1] = 14'b0_000000_0000000;  // MCU read
   
   ROM_DATA_TO_SNES_MEM_ARRAY[1'b0] = 14'b0_000000_0000000;  // SNES write
   ROM_DATA_TO_SNES_MEM_ARRAY[1'b1] = 14'b0_000010_0000000;  // SNES read
   /* 13'b0000100000000; */
   
   ROM_DATA_TO_MCU_MEM_ARRAY[1'b0] = 14'b0_000000_0000000;  // MCU write
   ROM_DATA_TO_MCU_MEM_ARRAY[1'b1] = 14'b0_000000_0000001;  // MCU read
//   SRAM_DATA_TO_MCU_MEM_ARRAY[1'b1] = 13'b0000000000001;  // MCU read

end 

// falling edge of SNES /RD or /WR marks the beginning of a new cycle
// SNES READ or WRITE always starts @posedge CLK !!
// CPU cycle can be 6, 8 or 12 CLKIN cycles so we must satisfy
// the minimum of 6 SNES cycles to get everything done.
// we have 24 internal cycles to work with. (CLKIN * 4)

always @(posedge CLK2) begin
	CYCLE_RESET <= {CYCLE_RESET[0], SNES_cycle_start};
end

always @(posedge CLK2) begin
       MCU_READ_CYCLE <= MCU_READ;
       MCU_WRITE_CYCLE <= MCU_WRITE;
       if (SNES_cycle_start) begin
           SNES_READ_CYCLE <= SNES_READ;
           SNES_WRITE_CYCLE <= SNES_WRITE;
           STATE <= STATE_0;
           STATEIDX <= 12;
       end else begin
           case (STATE)
              STATE_0: begin
                 STATE <= STATE_1; STATEIDX <= 11;
              end
              STATE_1: begin
                 STATE <= STATE_2; STATEIDX <= 10;
              end
              STATE_2: begin
                 STATE <= STATE_3; STATEIDX <= 9;
              end
              STATE_3: begin
                 STATE <= STATE_4; STATEIDX <= 8;
              end
              STATE_4: begin
                 STATE <= STATE_5; STATEIDX <= 7;
              end
              STATE_5: begin
                 STATE <= STATE_6; STATEIDX <= 6;
              end
              STATE_6: begin
                 STATE <= STATE_7; STATEIDX <= 5;
              end
              STATE_7: begin
                 STATE <= STATE_8; STATEIDX <= 4;
              end
              STATE_8: begin
                 STATE <= STATE_9; STATEIDX <= 3;
              end
              STATE_9: begin
                 STATE <= STATE_10; STATEIDX <= 2;
              end
              STATE_10: begin
                 STATE <= STATE_11; STATEIDX <= 1;
              end
              STATE_11: begin
                 STATE <= STATE_12; STATEIDX <= 0;
              end
				  STATE_12: begin
				     STATE <= STATE_IDLE; STATEIDX <= 13;
				  end
              STATE_IDLE: begin
                 STATE <= STATE_IDLE; STATEIDX <= 13;
              end
              default: begin
                 STATE <= STATE_IDLE; STATEIDX <= 13;
              end
           endcase
       end
end
/*
always @(posedge CLK2) begin

   case (STATE)   
      STATE_9: begin
         STATEIDX <= 9;
      end
      
      STATE_0: begin
         STATEIDX <= 8;
      end
      
      STATE_1: begin
         STATEIDX <= 7;
      end
      
      STATE_2: begin
         STATEIDX <= 6;
      end
      
      STATE_3: begin
         STATEIDX <= 5;
      end
      
      STATE_4: begin
         STATEIDX <= 4;
      end
      
      STATE_5: begin
         STATEIDX <= 3;
      end
      
      STATE_6: begin
         STATEIDX <= 2;
      end

      STATE_7: begin
         STATEIDX <= 1;
      end

      STATE_8: begin
         STATEIDX <= 0;
      end
      default:
         STATEIDX <= 9;
   endcase      
end
*/
// When in MCU mode, enable SRAM_WE according to MCU programming
// else enable SRAM_WE according to state&cycle
assign ROM_WE = !MCU_OVR ? MCU_WRITE
                          : ((!IS_SAVERAM & !MODE) | ROM_WE_ARRAY[{SNES_WRITE_CYCLE, MCU_WRITE_CYCLE}][STATEIDX]);

// When in MCU mode, enable SRAM_OE whenever not writing
// else enable SRAM_OE according to state&cycle
assign ROM_OE = !MCU_OVR ? MCU_READ 
                          : ROM_OE_ARRAY[{SNES_WRITE_CYCLE, MCU_WRITE_CYCLE}][STATEIDX];

assign ROM_CE = 1'b0; // !MCU_OVR ? (MCU_READ & MCU_WRITE) : ROM_SEL;

assign ROM_BHE = !ROM_WE ? ROM_ADDR0 : 1'b0;
assign ROM_BLE = !ROM_WE ? !ROM_ADDR0 : 1'b0;

//assign SRAM_BHE = SRAM_ADDR0;
//assign SRAM_BLE = ~SRAM_ADDR0;

// dumb version
//assign SRAM_OE = !MCU_ENA ? MCU_READ : SNES_READs;
//assign SRAM_WE = !MCU_ENA ? MCU_WRITE : 1'b1;

//assign SNES_DATABUS_OE = (!IS_SAVERAM & SNES_CS) | (SNES_READ & SNES_WRITE);
assign SNES_DATABUS_OE = msu_enable ? 1'b0 : ((IS_ROM & SNES_CS) | (!IS_ROM & !IS_SAVERAM) | (SNES_READ & SNES_WRITE));
assign SNES_DATABUS_DIR = !SNES_READ ? 1'b1 : 1'b0;

assign SNES_DATA_TO_MEM = SNES_DATA_TO_MEM_ARRAY[SNES_WRITE_CYCLE][STATEIDX];
assign MCU_DATA_TO_MEM = MCU_DATA_TO_MEM_ARRAY[MCU_WRITE_CYCLE][STATEIDX];

assign ROM_DATA_TO_SNES_MEM = ROM_DATA_TO_SNES_MEM_ARRAY[SNES_WRITE_CYCLE][STATEIDX];
assign ROM_DATA_TO_MCU_MEM = ROM_DATA_TO_MCU_MEM_ARRAY[MCU_WRITE_CYCLE][STATEIDX];

assign SNES_READ_CYCLEw = SNES_READ_CYCLE;
assign SNES_WRITE_CYCLEw = SNES_WRITE_CYCLE;
assign IRQ_DIR = 1'b0;
assign SNES_IRQ = 1'bZ;

endmodule
