module main(
 
 
 
 // clocks
 
 input fclk,
 
 output clkz_out,
 
 input clkz_in,
 
 
 
 // z80
 
 input iorq_n,
 
 input mreq_n,
 
 input rd_n,
 
 input wr_n,
 
 input m1_n,
 
 input rfsh_n,
 
 input int_n,
 
 input nmi_n,
 
 input wait_n,
 
 output res,
 
 
 
 inout [7:0] d,
 
 output [15:0] a,
 
 
 
 // zxbus and related
 
 output csrom,
 
 output romoe_n,
 
 output romwe_n,
 
 
 
 output rompg0_n,
 
 output dos_n, // aka rompg1
 
 output rompg2,
 
 output rompg3,
 
 output rompg4,
 
 
 
 input iorqge1,
 
 input iorqge2,
 
 output iorq1_n,
 
 output iorq2_n,
 
 
 
 // DRAM
 
 input [15:0] rd,
 
 input [9:0] ra,
 
 output rwe_n,
 
 output rucas_n,
 
 output rlcas_n,
 
 output rras0_n,
 
 output rras1_n,
 
 
 
 // video
 
 output reg [1:0] vred,
 
 output reg [1:0] vgrn,
 
 output reg [1:0] vblu,
 
 
 
 output vhsync,
 
 output vvsync,
 
 output vcsync,
 
 
 
 // AY control and audio/tape
 
 input ay_clk,
 
 output ay_bdir,
 
 output ay_bc1,
 
 
 
 output beep,
 
 
 
 // IDE
 
 input [2:0] ide_a,
 
 input [15:0] ide_d,
 
 
 
 output ide_dir,
 
 
 
 input ide_rdy,
 
 
 
 output ide_cs0_n,
 
 output ide_cs1_n,
 
 output ide_rs_n,
 
 output ide_rd_n,
 
 output ide_wr_n,
 
 
 
 // VG93 and diskdrive
 
 input vg_clk,
 
 
 
 output vg_cs_n,
 
 output vg_res_n,
 
 
 
 input vg_hrdy,
 
 input vg_rclk,
 
 input vg_rawr,
 
 input [1:0] vg_a, // disk drive selection
 
 input vg_wrd,
 
 input vg_side,
 
 
 
 input step,
 
 input vg_sl,
 
 input vg_sr,
 
 input vg_tr43,
 
 input rdat_b_n,
 
 input vg_wf_de,
 
 input vg_drq,
 
 input vg_irq,
 
 input vg_wd,
 
 
 
 // serial links (atmega-fpga, sdcard)
 
 output sdcs_n,
 
 output sddo,
 
 output sdclk,
 
 input sddi,
 
 
 
 input spics_n,
 
 input spick,
 
 input spido,
 
 output spidi,
 
 input spiint_n
 
);
 
 
 
//--Dummy----------------------------------------------------------------------
 
 
 
 assign iorq1_n = 1'b1;
 
 assign iorq2_n = 1'b1;
 
 
 
 assign res= 1'b1;
 
 
 
 assign rwe_n   = 1'b1;
 
 assign rucas_n = 1'b1;
 
 assign rlcas_n = 1'b1;
 
 assign rras0_n = 1'b1;
 
 assign rras1_n = 1'b1;
 
 
 
 assign ay_bdir = 1'b0;
 
 assign ay_bc1  = 1'b0;
 
 
 
 assign vg_cs_n  = 1'b1;
 
 assign vg_res_n = 1'b0;
 
 
 
 assign ide_dir=1'b1;
 
 assign ide_rs_n = 1'b0;
 
 assign ide_cs0_n = 1'b1;
 
 assign ide_cs1_n = 1'b1;
 
 assign ide_rd_n = 1'b1;
 
 assign ide_wr_n = 1'b1;
 
 
 
 assign a[15:14] = 2'b00;
 
 
 
//-----------------------------------------------------------------------------
 
 
 
 reg [2:0] main_osc;
 
 
 
 always @(posedge fclk)
 
  main_osc <= main_osc + 3'h1;
 
 
 
 assign clkz_out = main_osc[2]; // 3.5 MHz
 
 assign beep = spiint_n;
 
 
 
//--Video----------------------------------------------------------------------
 
 
 
 localparam HBLNK_BEG  = 9'd384;
 
 localparam CSYNC_CUT  = 9'd415;
 
//localparam CSYNC_CUT2 = 9'd382;
 
 localparam HSYNC_BEG  = 9'd0;
 
 localparam HSYNC_END  = 9'd33;
 
 localparam HSYNC_END2 = 9'd53;
 
 localparam HBLNK_END  = 9'd128;
 
 localparam HMAX       = 9'd447;
 
 localparam VBLNK_BEG  = 10'd512; // 256
 
 localparam VSYNC_BEG  = 10'd0;   // 0
 
 localparam VSYNC_END  = 10'd4;   // 2
 
 localparam VBLNK_END  = 10'd128; // 64
 
 localparam VMAX       = 10'd623; // 311
 
 
 
 reg [8:0] hcount;
 
 reg [9:0] vcount;
 
 reg [5:0] hcharcount;
 
 reg [2:0] vcharline;
 
 reg [6:0] voffset;
 
 reg hsync, hblank, vsync, vblank, csync;
 
 wire [9:0] video_addr;
 
 wire [6:0] charcode;
 
 wire [7:0] charpix;
 
 wire pixel;
 
 wire [5:0] fcolor;
 
 wire [5:0] bcolor;
 
 wire [5:0] color;
 
 
 
 always @(posedge fclk)
 
  begin
 
   //
 
   if ( {(main_osc[1]&scr_tv_mode),main_osc[0]}==2'h0 )
 
    begin
 
 
 
     if ( hcount[2:0]==3'h0 )
 
      begin
 
       if ( hblank )
 
        hcharcount <= 6'h00;
 
       else
 
        hcharcount <= hcharcount + 6'h01;
 
      end
 
 
 
     if ( hcount==HMAX )
 
      hcount <= 9'd0;
 
     else
 
      hcount <= hcount + 9'd1;
 
 
 
     if ( hcount==HBLNK_BEG )
 
      hblank <= 1'b1;
 
     else if ( hcount==HBLNK_END )
 
      hblank <= 1'b0;
 
 
 
     if ( hcount==HSYNC_BEG )
 
      begin
 
       hsync <= 1'b1;
 
       if ( vc0 )
 
        csync <= 1'b1;
 
      end
 
 
 
     if ( (~scr_tv_mode) && (hcount==HSYNC_END2) )
 
      begin
 
       hsync <= 1'b0;
 
       if ( !vsync )
 
        csync <= 1'b0;
 
      end
 
 
 
     if ( scr_tv_mode && (hcount==HSYNC_END) )
 
      begin
 
       hsync <= 1'b0;
 
       if ( !vsync )
 
        csync <= 1'b0;
 
      end
 
 
 
     if ( (~vc0) && (hcount==HBLNK_BEG) ) // localparam CSYNC_CUT2 = 9'd382;
 
      csync <= 1'b0;
 
 
 
     if ( scr_tv_mode && (hcount==CSYNC_CUT) )
 
      csync <= 1'b0;
 
 
 
     vgrn[1] <= color[5];
 
     vgrn[0] <= color[4];
 
     vred[1] <= color[3];
 
     vred[0] <= color[2];
 
     vblu[1] <= color[1];
 
     vblu[0] <= color[0];
 
 
 
    end
 
   //
 
   if ( (main_osc[1:0]==2'h3) && (hcount==HSYNC_BEG) )
 
    begin
 
 
 
     if ( vblank )
 
      begin
 
       voffset <= 7'd0;
 
       vcharline <= 3'h0;
 
      end
 
     else
 
      begin
 
       if ( (vcharline==3'h7) && vc0 )
 
        voffset <= voffset + 7'd4;  //  32 / 8 = 4
 
       vcharline <= vcharline + {2'b00,vc0};
 
      end
 
 
 
     if ( {vcount[9:1],vc0}==VMAX )
 
      vcount <= 10'd0;
 
     else
 
      vcount <= {vcount[9:1],vc0} + 10'd1;
 
 
 
     if ( vcount==VBLNK_BEG )
 
      vblank <= 1'b1;
 
     else if ( vcount==VBLNK_END )
 
      vblank <= 1'b0;
 
 
 
     if ( vcount==VSYNC_BEG )
 
      vsync <= 1'b1;
 
     else if ( vcount==VSYNC_END )
 
      vsync <= 1'b0;
 
 
 
    end
 
   //
 
  end
 
 
 
 assign vc0 = vcount[0] | scr_tv_mode;
 
 assign video_addr = { voffset[6:0], 3'h0 } + { 4'h0, hcharcount[5:0] };
 
 lpm_ram_dp0 scr_mem  ( .data(scr_char), .rdaddress(video_addr), .wraddress(scr_addr), .wren(scr_wren_c), .q(charcode) );
 
 lpm_rom0 chargen ( .address({ charcode, vcharline[2:0] }), .q(charpix) );
 
 
 
 assign fcolor = 6'b111111;
 
 assign bcolor = 6'b000001;
 
 assign pixel = charpix[~(hcount[2:0]-3'h1)];
 
 assign color = (hblank | vblank) ? 6'h00 : ( pixel ? fcolor : bcolor ) ;
 
 
 
 assign vhsync = hsync;
 
 assign vvsync = vsync;
 
 assign vcsync = ~csync;
 
 
 
//--AVRSPI--FlashROM-----------------------------------------------------------
 
 
 
 localparam SD_CS0        = 8'h57;
 
 localparam SD_CS1        = 8'h5f;
 
 localparam FLASH_LOADDR  = 8'hf0;
 
 localparam FLASH_MIDADDR = 8'hf1;
 
 localparam FLASH_HIADDR  = 8'hf2;
 
 localparam FLASH_DATA    = 8'hf3;
 
 localparam FLASH_CTRL    = 8'hf4;
 
 localparam SCR_LOADDR    = 8'h40;
 
 localparam SCR_HIADDR    = 8'h41;
 
 localparam SCR_CHAR      = 8'h44;
 
 localparam SCR_MODE      = 8'h4e;
 
 
 
 reg [7:0] number;
 
 reg [7:0] indata;
 
 reg [7:0] outdata;
 
 reg [2:0] bitptr;
 
 reg [1:0] spick_resync;
 
 reg [1:0] spicsn_resync;
 
 reg [18:0] flash_addr;
 
 reg flash_cs;
 
 reg flash_oe;
 
 reg flash_we;
 
 reg [7:0] flash_data_out;
 
 reg [9:0] scr_addr;
 
 reg [6:0] scr_char;
 
 reg scr_wren_c;
 
 reg scr_tv_mode;
 
 wire spicsn_rising;
 
 wire spicsn_falling;
 
 wire sd_selected;
 
 
 
 always @(posedge spick)
 
  begin
 
   if ( spics_n )
 
    number <= { number[6:0], spido };
 
   else
 
    indata <= { indata[6:0], spido };
 
  end
 
 
 
 always @(negedge spick or posedge spics_n)
 
  begin
 
   if ( spics_n )
 
    bitptr <= 3'b111;
 
   else
 
    bitptr <= bitptr - 3'b001;
 
  end
 
 
 
 always @(posedge fclk)
 
  begin
 
 
 
   spicsn_resync <= { spicsn_resync[0], spics_n };
 
 
 
   if ( spicsn_rising )
 
    case ( number )
 
     FLASH_LOADDR:  flash_addr[7:0] <= indata;
 
     FLASH_MIDADDR: flash_addr[15:8] <= indata;
 
     FLASH_HIADDR:  flash_addr[18:16] <= indata[2:0];
 
     FLASH_DATA:    flash_data_out <= indata;
 
     FLASH_CTRL:    begin
 
                     flash_cs <= indata[0];
 
                     flash_oe <= indata[1];
 
                     flash_we <= indata[2];
 
                    end
 
     SCR_LOADDR:    scr_addr[7:0] <= indata;
 
     SCR_HIADDR:    scr_addr[9:8] <= indata[1:0];
 
     SCR_CHAR:      begin
 
                     scr_char <= indata[6:0];
 
                     scr_wren_c <= 1'b1;
 
                    end
 
     SCR_MODE:      scr_tv_mode <= ~indata[0];
 
    endcase
 
 
 
   if ( spicsn_falling )
 
    begin
 
     scr_wren_c <= 1'b0;
 
     if ( number==SCR_CHAR )
 
      scr_addr <= scr_addr + 10'd1;
 
     if ( number==FLASH_DATA )
 
      outdata <= d;
 
     else
 
      outdata <= 8'hff;
 
    end
 
 
 
  end
 
 
 
 assign spicsn_rising  = (spicsn_resync==2'b01);
 
 assign spicsn_falling = (spicsn_resync==2'b10);
 
 
 
 assign sd_selected = ( ( (number==SD_CS0) || (number==SD_CS1) ) && (~spics_n) );
 
 assign spidi = sd_selected ? sddi : outdata[bitptr];
 
 assign sddo  = sd_selected ? spido : 1'b1;
 
 assign sdclk = sd_selected ? spick : 1'b0;
 
 assign sdcs_n = !( (number==SD_CS0) && (~spics_n) );
 
 
 
 assign a[13:0]  =  flash_addr[13:0];
 
 assign rompg0_n = ~flash_addr[14];
 
 assign { rompg4, rompg3, rompg2, dos_n } = flash_addr[18:15];
 
 assign csrom   =  flash_cs;
 
 assign romoe_n = ~flash_oe;
 
 assign romwe_n = ~flash_we;
 
 assign d = flash_oe ? 8'bZZZZZZZZ : flash_data_out;
 
 
 
//-----------------------------------------------------------------------------
 
 
 
endmodule