/* -*- tab-width: 4 -*- */



module mmc_disk(/*AUTOARG*/
   // Outputs
   SD_DAT3, SD_CMD, SD_CLK, mmc_read_kbd, SPI_active, disk_data, 
   MMC_addr, MMC_data, disk_buff_do, z80_cpu_di, 
   // Inputs
   SD_DAT, z80_cen, mreq_n, track, mclk28, reset_in, mmc_init_mode, 
   iorq_n, cpu_wt, z80_cpu_addr, z80_cpu_do
   );

   input  	SD_DAT,z80_cen,mreq_n;
   output 	SD_DAT3, SD_CMD, SD_CLK,mmc_read_kbd,SPI_active;
   input [5:0] track;
   input       mclk28, reset_in, mmc_init_mode;

   output [7:0] disk_data;
   output [12:0] MMC_addr;
   output [7:0]  MMC_data;
   output [7:0]  disk_buff_do;
   

   input 			iorq_n,cpu_wt;
   input [15:0] 	z80_cpu_addr;
   input [7:0] 		z80_cpu_do;
   
   output [7:0] 	z80_cpu_di;   
      

   wire [12:0] 		MMC_addr;
   wire [7:0] 		MMC_data;

   // the block address for the MMC controller
   reg [7:0] 		block_addr_lo; // i/o at 0xf0
   reg [7:0] 		block_addr_mid; // i/o at 0xf1
   reg [7:0] 		block_addr_high; // i/o at 0xf2
   
   reg [7:0] 		DMA_addr_lo; // i/o at 0xf3
   reg [7:0] 		DMA_addr_high; // i/o at 0xf4
   reg 				track_mode;

   reg [7:0] 		SPI_write_data;


   reg 				SPI_control;
   reg 				SPI_start;
   reg 				SPI_block;
   reg 				DMA_enable;

   assign 			mmc_read_kbd = read_kbd;
   


   always @ (posedge mclk28)
     if(reset_in) begin
		SPI_control <= 0;
		SPI_start <= 0;
		if(mmc_init_mode) begin
		   track_mode <= 0;
		   block_addr_lo <= 0;
		   block_addr_mid <= 0;
		   block_addr_high <= 0;
		end   
     end else begin
	
	if(~iorq_n && mmc_init_mode) begin
	   if((z80_cpu_addr[7:0] == 8'haa) && ~cpu_wt)
	     SPI_write_data <= z80_cpu_do;
	   
	   if((z80_cpu_addr[7:0] == 8'hab) && ~cpu_wt)	begin 
	      SPI_start <= z80_cpu_do[0];
	      SPI_block <= z80_cpu_do[1];
	      DMA_enable <= z80_cpu_do[3];
	      track_mode <= z80_cpu_do[6]; 
	   end	
	   
	   if((z80_cpu_addr[7:0] == 8'hac) && ~cpu_wt)
	     SPI_control <= z80_cpu_do[0];

	   if((z80_cpu_addr[7:0] == 8'hf0) && ~cpu_wt)	
	     block_addr_lo <= z80_cpu_do;

	   if((z80_cpu_addr[7:0] == 8'hf1) && ~cpu_wt)	
	     block_addr_mid <= z80_cpu_do;

	   if((z80_cpu_addr[7:0] == 8'hf2) && ~cpu_wt)	
	     block_addr_high <= z80_cpu_do;
	   
	   if((z80_cpu_addr[7:0] == 8'hf3) && ~cpu_wt)	
	     DMA_addr_lo <= z80_cpu_do;
	   
	   if((z80_cpu_addr[7:0] == 8'hf4) && ~cpu_wt)	
	     DMA_addr_high <= z80_cpu_do;

	   
	end		
     end 

   mmc_fat_rom mmc_fat_rom (
			    .address(z80_cpu_addr[11:0]),
			    .clock(mclk28),
			    .q(mmc_romdata)
			    );

   wire [7:0]    mmc_romdata;
   wire [7:0] 	 disk_buff_do;
   wire [7:0] 	 disk_buff_di = MMC_is_idle ? z80_cpu_do : MMC_data;   
   wire 		 disk_buff_space = (z80_cpu_addr[15:9] == 7'b0010000);
   wire [12:0] 	 disk_buff_addr = MMC_is_idle ? z80_cpu_addr : MMC_addr;
   wire 		 cpu_write_to_buff = (((mreq_n | cpu_wt) == 0) && 
									  z80_cen && disk_buff_space ); // mapped at 0x2000
   wire 		 SPI_active = ~MMC_is_idle;

   
   assign 	   membuff_ram_we = MMC_is_idle ? cpu_write_to_buff : mmc_ram_we;   
   assign 	   z80_cpu_di = disk_buff_space ? disk_buff_do : mmc_romdata;	
   
   buff_ram	buff_ram (
					  .address(disk_buff_addr),
					  .clock(mclk28),
					  .data(disk_buff_di),
					  .wren(membuff_ram_we),
					  .q(disk_buff_do)
					  );
 spi_controller 
   spi_controller1(
				   .CS_N (SD_DAT3),      
				   .MOSI(SD_CMD),           
    			   .MISO(SD_DAT),           
    			   .SCLK(SD_CLK),           
				   
    			   .ram_write_addr(MMC_addr), //: out unsigned(13 downto 0);
    			   .ram_di(MMC_data),         //: out unsigned(7 downto 0);
    			   .ram_we(mmc_ram_we),         //: out std_logic;
								
    			   .track(track),          // in  0 - 34
    			   .block_to_read({block_addr_high,block_addr_mid,block_addr_lo}),
    			   .block_read_cmd(SPI_start),	
				   .track_mode(track_mode),	      
				   
    			   .CLK_14M(mclk28),     
				   .reset(reset_in),     
				   .is_idle(MMC_is_idle)
				   );

   //***************************** keyboard intface ********************
   
   wire [6:0] kbd_ascii;
   wire kbd_available;
   wire read_kbd;
   assign kbd_data = {kbd_available, kbd_ascii};

   wire   z80_reading_kbd = (~iorq_n && (z80_cpu_addr[7:0] == 8'h00) && z80_cen);
   reg 	  prepare_to_reset_kbd = 0;
		
   always @ (posedge mclk28)
     if(z80_reading_kbd) begin
	if(prepare_to_reset_kbd == 1) 
	  prepare_to_reset_kbd <= 0;
	else	
	  prepare_to_reset_kbd <= 1;
     end			
	
   

   assign read_kbd = prepare_to_reset_kbd && z80_reading_kbd;



endmodule