diff --git a/cores/gameboy/data_io.v b/cores/gameboy/data_io.v index c1a3ffc..0ab2635 100644 --- a/cores/gameboy/data_io.v +++ b/cores/gameboy/data_io.v @@ -1,10 +1,12 @@ // // data_io.v // -// io controller writable ram for the MiST board -// https://github.com/mist-devel +// data_io for the MiST board +// http://code.google.com/p/mist-board/ // -// Copyright (c) 2015 Till Harbaum +// Copyright (c) 2014 Till Harbaum +// Copyright (c) 2015-2017 Sorgelig +// Copyright (c) 2019 György Szombathelyi // // This source file is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published @@ -19,99 +21,124 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////// -module data_io ( - // io controller spi interface - input sck, - input ss, - input sdi, +module data_io +( + // Global clock. It should be around 100MHz (higher is better). + input clk_sys, - output downloading, // signal indicating an active download - output reg [4:0] index, // menu index used to upload the file - - // external ram interface - input clk, - output reg wr, - output reg [23:0] addr, - output reg [15:0] data + // Global SPI clock from ARM. 24MHz + input SPI_SCK, + input SPI_SS2, + input SPI_DI, + + // ARM -> FPGA download + input ioctl_clkref, + output reg ioctl_download = 0, // signal indicating an active download + output reg [7:0] ioctl_index, // menu index used to upload the file + output reg ioctl_wr = 0, + output reg [24:0] ioctl_addr, + output reg [15:0] ioctl_dout ); -// ********************************************************************************* -// spi client -// ********************************************************************************* +/////////////////////////////// DOWNLOADING /////////////////////////////// -// this core supports only the display related OSD commands -// of the minimig -reg [14:0] sbuf; -reg [7:0] cmd; -reg [4:0] cnt; -reg rclk; - -reg [23:0] laddr; -reg [15:0] ldata; - localparam UIO_FILE_TX = 8'h53; localparam UIO_FILE_TX_DAT = 8'h54; localparam UIO_FILE_INDEX = 8'h55; +// SPI receiver IO -> FPGA -assign downloading = downloading_reg; -reg downloading_reg = 1'b0; +reg spi_receiver_strobe_r = 0; +reg spi_transfer_end_r = 1; +reg [7:0] spi_byte_in; // data_io has its own SPI interface to the io controller -always@(posedge sck, posedge ss) begin - if(ss == 1'b1) - cnt <= 5'd0; - else begin - rclk <= 1'b0; +// Read at spi_sck clock domain, assemble bytes for transferring to clk_sys +always@(posedge SPI_SCK or posedge SPI_SS2) begin - // don't shift in last bit. It is evaluated directly - // when writing to ram - if(cnt != 23) - sbuf <= { sbuf[13:0], sdi}; - - // count 0-7 8-15 16-23 8-15 16-23 ... - if(cnt < 23) cnt <= cnt + 4'd1; - else cnt <= 4'd8; + reg [6:0] sbuf; + reg [2:0] bit_cnt; - // finished command byte - if(cnt == 7) - cmd <= {sbuf[6:0], sdi}; - - // prepare/end transmission - if((cmd == UIO_FILE_TX) && (cnt == 15)) begin - // prepare - if(sdi) begin - // download rom to address 0 - laddr <= 24'h0 - 24'd1; - downloading_reg <= 1'b1; - end else - downloading_reg <= 1'b0; - end + if(SPI_SS2) begin + spi_transfer_end_r <= 1; + bit_cnt <= 0; + end else begin + spi_transfer_end_r <= 0; - // command 0x54: UIO_FILE_TX - if((cmd == UIO_FILE_TX_DAT) && (cnt == 23)) begin - ldata <= {sbuf, sdi}; - laddr <= laddr + 24'd1; - rclk <= 1'b1; + bit_cnt <= bit_cnt + 1'd1; + + if(bit_cnt != 7) + sbuf[6:0] <= { sbuf[5:0], SPI_DI }; + + // finished reading a byte, prepare to transfer to clk_sys + if(bit_cnt == 7) begin + spi_byte_in <= { sbuf, SPI_DI}; + spi_receiver_strobe_r <= ~spi_receiver_strobe_r; end - - // expose file (menu) index - if((cmd == UIO_FILE_INDEX) && (cnt == 15)) - index <= {sbuf[3:0], sdi}; end end -reg rclkD, rclkD2; -always@(posedge clk) begin - // bring all signals from spi clock domain into local clock domain - rclkD <= rclk; - rclkD2 <= rclkD; - wr <= 1'b0; - - if(rclkD && !rclkD2) begin - addr <= laddr; - data <= ldata; - wr <= 1'b1; +always @(posedge clk_sys) begin + + reg spi_receiver_strobe; + reg spi_transfer_end; + reg spi_receiver_strobeD; + reg spi_transfer_endD; + reg [7:0] acmd; + reg [2:0] abyte_cnt; // counts bytes + reg [24:0] addr; + reg wr_int; + reg clkrefD; + reg hi; + + //synchronize between SPI and sys clock domains + spi_receiver_strobeD <= spi_receiver_strobe_r; + spi_receiver_strobe <= spi_receiver_strobeD; + spi_transfer_endD <= spi_transfer_end_r; + spi_transfer_end <= spi_transfer_endD; + + if (~spi_transfer_endD & spi_transfer_end) begin + abyte_cnt <= 3'd0; + end else if (spi_receiver_strobeD ^ spi_receiver_strobe) begin + if(~&abyte_cnt) abyte_cnt <= abyte_cnt + 1'd1; + + if(abyte_cnt == 0) begin + acmd <= spi_byte_in; + hi <= 0; + end else begin + case (acmd) + UIO_FILE_TX: begin + // prepare + if(spi_byte_in) begin + addr <= 0; + ioctl_download <= 1; + end else begin + ioctl_addr <= addr; + ioctl_download <= 0; + end + end + + // transfer + UIO_FILE_TX_DAT: begin + ioctl_addr <= addr; + if (hi) ioctl_dout[7:0] <= spi_byte_in; else ioctl_dout[15:8] <= spi_byte_in; + hi <= ~hi; + if (hi) wr_int <= 1; + end + + // expose file (menu) index + UIO_FILE_INDEX: ioctl_index <= spi_byte_in; + endcase + end + end + + ioctl_wr <= 0; + clkrefD <= ioctl_clkref; + if (wr_int & ~clkrefD & ioctl_clkref) begin + addr <= addr + 1'd1; + ioctl_wr <= 1; + wr_int <= 0; end end diff --git a/cores/gameboy/gb.qsf b/cores/gameboy/gb.qsf index b9f3599..626de96 100644 --- a/cores/gameboy/gb.qsf +++ b/cores/gameboy/gb.qsf @@ -140,7 +140,7 @@ set_location_assignment PIN_43 -to SDRAM_CLK set_global_assignment -name ENABLE_SIGNALTAP OFF -set_global_assignment -name USE_SIGNALTAP_FILE stp1.stp +set_global_assignment -name USE_SIGNALTAP_FILE output_files/clk.stp set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS REGULAR IO" set_global_assignment -name RESERVE_DATA0_AFTER_CONFIGURATION "USE AS REGULAR IO" set_global_assignment -name RESERVE_DATA1_AFTER_CONFIGURATION "USE AS REGULAR IO" @@ -148,7 +148,7 @@ set_global_assignment -name RESERVE_FLASH_NCE_AFTER_CONFIGURATION "USE AS REGULA set_global_assignment -name RESERVE_DCLK_AFTER_CONFIGURATION "USE AS REGULAR IO" set_global_assignment -name OPTIMIZE_HOLD_TIMING "ALL PATHS" set_global_assignment -name OPTIMIZE_MULTI_CORNER_TIMING ON -set_global_assignment -name FITTER_EFFORT "FAST FIT" +set_global_assignment -name FITTER_EFFORT "AUTO FIT" set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "23 MM HEAT SINK WITH 200 LFPM AIRFLOW" set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)" set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top @@ -157,12 +157,36 @@ set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_* set_global_assignment -name VERILOG_INPUT_VERSION VERILOG_2001 set_global_assignment -name VERILOG_SHOW_LMF_MAPPING_MESSAGES OFF +set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC ON +set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_RETIMING ON +set_global_assignment -name PHYSICAL_SYNTHESIS_ASYNCHRONOUS_SIGNAL_PIPELINING ON +set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_DUPLICATION ON +set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC_FOR_AREA ON +set_global_assignment -name PHYSICAL_SYNTHESIS_MAP_LOGIC_TO_MEMORY_FOR_AREA ON +set_global_assignment -name TIMEQUEST_MULTICORNER_ANALYSIS ON +set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files +set_global_assignment -name ENABLE_CONFIGURATION_PINS OFF +set_global_assignment -name ENABLE_NCE_PIN OFF +set_global_assignment -name ENABLE_BOOT_SEL_PIN OFF +set_global_assignment -name VERILOG_FILE gb_mist.v +set_global_assignment -name SYSTEMVERILOG_FILE sdram.sv set_global_assignment -name VERILOG_FILE sigma_delta_dac.v set_global_assignment -name VHDL_FILE gbc_snd.vhd set_global_assignment -name VERILOG_FILE data_io.v -set_global_assignment -name VERILOG_FILE sdram.v set_global_assignment -name VERILOG_FILE user_io.v set_global_assignment -name VERILOG_FILE osd.v +set_global_assignment -name QIP_FILE pll.qip +set_global_assignment -name VERILOG_FILE gb.v +set_global_assignment -name VERILOG_FILE lcd.v +set_global_assignment -name QIP_FILE boot_rom.qip +set_global_assignment -name VERILOG_FILE video.v +set_global_assignment -name VERILOG_FILE sprites.v +set_global_assignment -name VERILOG_FILE sprite.v +set_global_assignment -name VERILOG_FILE sprite_sort.v +set_global_assignment -name VERILOG_FILE timer.v +set_global_assignment -name QIP_FILE iram.qip +set_global_assignment -name QIP_FILE vram.qip +set_global_assignment -name QIP_FILE zpram.qip set_global_assignment -name VHDL_FILE t80/T80.vhd set_global_assignment -name VHDL_FILE t80/Z80.vhd set_global_assignment -name VHDL_FILE t80/T80_Reg.vhd @@ -170,18 +194,4 @@ set_global_assignment -name VHDL_FILE t80/T80_Pack.vhd set_global_assignment -name VHDL_FILE t80/T80_ALU.vhd set_global_assignment -name VHDL_FILE t80/GBse.vhd set_global_assignment -name VHDL_FILE t80/T80_MCode.vhd -set_global_assignment -name QIP_FILE pll.qip -set_global_assignment -name VERILOG_FILE gb.v -set_global_assignment -name VERILOG_FILE lcd.v -set_global_assignment -name QIP_FILE boot_rom.qip -set_global_assignment -name SIGNALTAP_FILE stp1.stp -set_global_assignment -name VERILOG_FILE gb_mist.v -set_global_assignment -name QIP_FILE vram.qip -set_global_assignment -name QIP_FILE iram.qip -set_global_assignment -name VERILOG_FILE video.v -set_global_assignment -name QIP_FILE zpram.qip -set_global_assignment -name VERILOG_FILE sprites.v -set_global_assignment -name VERILOG_FILE sprite.v -set_global_assignment -name VERILOG_FILE sprite_sort.v -set_global_assignment -name VERILOG_FILE timer.v set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file diff --git a/cores/gameboy/gb.sdc b/cores/gameboy/gb.sdc new file mode 100644 index 0000000..8ea82e5 --- /dev/null +++ b/cores/gameboy/gb.sdc @@ -0,0 +1,118 @@ +## Generated SDC file "hello_led.out.sdc" + +## Copyright (C) 1991-2011 Altera Corporation +## Your use of Altera Corporation's design tools, logic functions +## and other software and tools, and its AMPP partner logic +## functions, and any output files from any of the foregoing +## (including device programming or simulation files), and any +## associated documentation or information are expressly subject +## to the terms and conditions of the Altera Program License +## Subscription Agreement, Altera MegaCore Function License +## Agreement, or other applicable license agreement, including, +## without limitation, that your use is for the sole purpose of +## programming logic devices manufactured by Altera and sold by +## Altera or its authorized distributors. Please refer to the +## applicable agreement for further details. + + +## VENDOR "Altera" +## PROGRAM "Quartus II" +## VERSION "Version 11.1 Build 216 11/23/2011 Service Pack 1 SJ Web Edition" + +## DATE "Fri Jul 06 23:05:47 2012" + +## +## DEVICE "EP3C25Q240C8" +## + + +#************************************************************** +# Time Information +#************************************************************** + +set_time_format -unit ns -decimal_places 3 + + + +#************************************************************** +# Create Clock +#************************************************************** + +create_clock -name clk_27 -period 37.037 [get_ports {CLOCK_27[0]}] +create_clock -name {SPI_SCK} -period 41.666 -waveform { 20.8 41.666 } [get_ports {SPI_SCK}] + +#************************************************************** +# Create Generated Clock +#************************************************************** + +derive_pll_clocks + +#************************************************************** +# Set Clock Latency +#************************************************************** + + +#************************************************************** +# Set Clock Uncertainty +#************************************************************** + +derive_clock_uncertainty; + +#************************************************************** +# Set Input Delay +#************************************************************** + +set_input_delay -clock [get_clocks {pll|altpll_component|auto_generated|pll1|clk[0]}] -max 6.4 [get_ports SDRAM_DQ[*]] +set_input_delay -clock [get_clocks {pll|altpll_component|auto_generated|pll1|clk[0]}] -min 3.2 [get_ports SDRAM_DQ[*]] + + +#************************************************************** +# Set Output Delay +#************************************************************** + +set_output_delay -clock [get_clocks {pll|altpll_component|auto_generated|pll1|clk[0]}] -max 1.5 [get_ports {SDRAM_D* SDRAM_A* SDRAM_BA* SDRAM_n* SDRAM_CKE}] +set_output_delay -clock [get_clocks {pll|altpll_component|auto_generated|pll1|clk[0]}] -min -0.8 [get_ports {SDRAM_D* SDRAM_A* SDRAM_BA* SDRAM_n* SDRAM_CKE}] +set_output_delay -clock [get_clocks {pll|altpll_component|auto_generated|pll1|clk[0]}] -max 1.5 [get_ports SDRAM_CLK] +set_output_delay -clock [get_clocks {pll|altpll_component|auto_generated|pll1|clk[0]}] -min -0.8 [get_ports SDRAM_CLK] + +set_output_delay -clock [get_clocks {pll|altpll_component|auto_generated|pll1|clk[0]}] -max 0 [get_ports {VGA_*}] +set_output_delay -clock [get_clocks {pll|altpll_component|auto_generated|pll1|clk[0]}] -min -5 [get_ports {VGA_*}] + +#************************************************************** +# Set Clock Groups +#************************************************************** + +set_clock_groups -asynchronous -group [get_clocks {SPI_SCK}] -group [get_clocks {pll|*}] + +#************************************************************** +# Set False Path +#************************************************************** + +#set_false_path -to [get_ports {VGA_*}] +set_false_path -to [get_ports {UART_TX}] +set_false_path -to [get_ports {AUDIO_L}] +set_false_path -to [get_ports {AUDIO_R}] +set_false_path -to [get_ports {LED}] + +#************************************************************** +# Set Multicycle Path +#************************************************************** + +#set_multicycle_path -to {VGA_*[*]} -setup 2 +#set_multicycle_path -to {VGA_*[*]} -hold 1 + +#************************************************************** +# Set Maximum Delay +#************************************************************** + + + +#************************************************************** +# Set Minimum Delay +#************************************************************** + + + +#************************************************************** +# Set Input Transition +#************************************************************** diff --git a/cores/gameboy/gb_mist.v b/cores/gameboy/gb_mist.v index 77b805a..da2d5af 100644 --- a/cores/gameboy/gb_mist.v +++ b/cores/gameboy/gb_mist.v @@ -58,7 +58,7 @@ module gb_mist ( output [5:0] VGA_B ); -assign LED = 1'b0; // light led +assign LED = ~dio_download; // mix both joysticks to allow the user to use any wire [7:0] joystick = joystick_0 | joystick_1; @@ -83,22 +83,22 @@ wire [1:0] buttons; // include user_io module for arm controller communication user_io #(.STRLEN(CONF_STR_LEN)) user_io ( .conf_str ( CONF_STR ), - + .clk_sys ( clk64 ), .SPI_CLK ( SPI_SCK ), .SPI_SS_IO ( CONF_DATA0 ), .SPI_MISO ( SPI_DO ), .SPI_MOSI ( SPI_DI ), .status ( status ), - .buttons ( buttons ), - + .buttons ( buttons ), + .joystick_0 ( joystick_0 ), .joystick_1 ( joystick_1 ) ); wire reset = (reset_cnt != 0); reg [9:0] reset_cnt; -always @(posedge clk4) begin +always @(posedge clk64) begin if(status[0] || status[3] || buttons[1] || !pll_locked || dio_download) reset_cnt <= 10'd1023; else @@ -120,8 +120,8 @@ sdram sdram ( .sd_cas ( SDRAM_nCAS ), // system interface - .clk ( clk32 ), - .clkref ( clk4 ), + .clk ( clk64 ), + .sync ( clk8 ), .init ( !pll_locked ), // cpu interface @@ -187,7 +187,7 @@ reg mbc1_ram_enable; reg mbc1_mode; reg [4:0] mbc1_rom_bank_reg; reg [1:0] mbc1_ram_bank_reg; -always @(posedge clk4) begin +always @(posedge clk64) begin if(reset) begin mbc1_rom_bank_reg <= 5'd1; mbc1_ram_bank_reg <= 2'd0; @@ -244,7 +244,7 @@ wire [8:0] mbc_bank = mbc1?mbc1_addr: // MBC1, 16k bank 0, 16k bank 1-127 + ram {7'b0000000, cart_addr[14:13]}; // no MBC, 32k linear address -always @(posedge clk4) begin +always @(posedge clk64) begin if(!pll_locked) begin cart_mbc_type <= 8'h00; cart_rom_size <= 8'h00; @@ -262,18 +262,19 @@ end // include ROM download helper data_io data_io ( + .clk_sys ( clk64 ), // io controller spi interface - .sck ( SPI_SCK ), - .ss ( SPI_SS2 ), - .sdi ( SPI_DI ), + .SPI_SCK ( SPI_SCK ), + .SPI_SS2 ( SPI_SS2 ), + .SPI_DI ( SPI_DI ), + + .ioctl_download ( dio_download ), // signal indicating an active rom download - .downloading ( dio_download ), // signal indicating an active rom download - // external ram interface - .clk ( clk4 ), - .wr ( dio_write ), - .addr ( dio_addr ), - .data ( dio_data ) + .ioctl_clkref ( clk8 ), + .ioctl_wr ( dio_write ), + .ioctl_addr ( dio_addr ), + .ioctl_dout ( dio_data ) ); // select appropriate byte from 16 bit word returned by cart @@ -294,10 +295,10 @@ wire [15:0] audio_right; // the gameboy itself gb gb ( .reset ( reset ), - .clk ( clk4 ), // the whole gameboy runs on 4mhnz + .clk ( clk4 ), // the whole gameboy runs on 4mhnz - .fast_boot ( status[2] ), - .joystick ( joystick ), + .fast_boot ( status[2] ), + .joystick ( joystick ), // interface to the "external" game cartridge .cart_addr ( cart_addr ), @@ -309,7 +310,7 @@ gb gb ( // audio .audio_l ( audio_left ), .audio_r ( audio_right ), - + // interface to the lcd .lcd_clkena ( lcd_clkena ), .lcd_data ( lcd_data ), @@ -318,11 +319,11 @@ gb gb ( ); sigma_delta_dac dac ( - .clk ( clk32 ), + .clk ( clk64 ), .ldatasum ( audio_left[15:1] ), .rdatasum ( audio_right[15:1] ), - .left ( AUDIO_L ), - .right ( AUDIO_R ) + .left ( AUDIO_L ), + .right ( AUDIO_R ) ); // the lcd to vga converter @@ -330,7 +331,8 @@ wire [5:0] video_r, video_g, video_b; wire video_hs, video_vs; lcd lcd ( - .pclk ( clk8 ), + .clk64 ( clk64 ), + .pclk_en( ce_pix ), .clk ( clk4 ), .tint ( status[1] ), @@ -350,46 +352,46 @@ lcd lcd ( // include the on screen display osd #(16,0,4) osd ( - .pclk ( clk32 ), + .clk_sys ( clk64 ), // spi for OSD - .sdi ( SPI_DI ), - .sck ( SPI_SCK ), - .ss ( SPI_SS3 ), + .SPI_DI ( SPI_DI ), + .SPI_SCK ( SPI_SCK ), + .SPI_SS3 ( SPI_SS3 ), - .red_in ( video_r ), - .green_in ( video_g ), - .blue_in ( video_b ), - .hs_in ( video_hs ), - .vs_in ( video_vs ), + .R_in ( video_r ), + .G_in ( video_g ), + .B_in ( video_b ), + .HSync ( video_hs ), + .VSync ( video_vs ), - .red_out ( VGA_R ), - .green_out ( VGA_G ), - .blue_out ( VGA_B ), - .hs_out ( VGA_HS ), - .vs_out ( VGA_VS ) + .R_out ( VGA_R ), + .G_out ( VGA_G ), + .B_out ( VGA_B ) ); - -reg clk4; // 4.194304 MHz CPU clock and GB pixel clock -always @(posedge clk8) - clk4 <= !clk4; -reg clk8; // 8.388608 MHz VGA pixel clock -always @(posedge clk16) - clk8 <= !clk8; +assign VGA_HS = video_hs; +assign VGA_VS = video_vs; + +wire clk4 = ce_cpu; +wire clk8 = ce_pix; + +reg ce_pix, ce_cpu; +always @(posedge clk64) begin + reg [3:0] div = 0; + div <= div + 1'd1; + ce_pix <= !div[2:0]; + ce_cpu <= !div[3:0]; +end -reg clk16; // 16.777216 MHz -always @(posedge clk32) - clk16 <= !clk16; - -// 32 Mhz SDRAM clk wire pll_locked; -wire clk32; +wire clk64; pll pll ( .inclk0(CLOCK_27[0]), - .c0(clk32), // 2*16.777216 MHz - .c1(SDRAM_CLK), // same phase shifted + .c0(clk64), // 4*16.777216 MHz .locked(pll_locked) ); +assign SDRAM_CLK = ~clk64; + endmodule diff --git a/cores/gameboy/lcd.v b/cores/gameboy/lcd.v index b1cb290..985a1d3 100644 --- a/cores/gameboy/lcd.v +++ b/cores/gameboy/lcd.v @@ -4,6 +4,7 @@ // The gameboy lcd runs from a shift register which is filled at 4194304 pixels/sec module lcd ( + input clk64, input clk, input clkena, input [1:0] data, @@ -12,7 +13,7 @@ module lcd ( input tint, // pixel clock - input pclk, + input pclk_en, input on, // VGA output @@ -50,7 +51,7 @@ always @(posedge clk) begin p_toggle <= !p_toggle; end end - + // parameter H = 160; // width of visible area parameter HFP = 24; // unused time before hsync @@ -69,7 +70,8 @@ reg[9:0] v_cnt; // vertical pixel counter // horizontal pixel counter reg [1:0] last_mode_h; -always@(posedge pclk) begin +always@(posedge clk64) begin + if (pclk_en) begin last_mode_h <= mode; if(h_cnt==H+HFP+HS+HBP-1) h_cnt <= 0; @@ -83,11 +85,13 @@ always@(posedge pclk) begin // end of hblank if((mode == 2'b10) && (last_mode_h == 2'b00)) h_cnt <= 0; + end end // veritical pixel counter reg [1:0] last_mode_v; -always@(posedge pclk) begin +always@(posedge clk64) begin + if (pclk_en) begin // the vertical counter is processed at the begin of each hsync if(h_cnt == H+HFP+HS+HBP-1) begin if(v_cnt==VS+VFP+V+VBP-1) v_cnt <= 0; @@ -105,6 +109,7 @@ always@(posedge pclk) begin if((mode != 2'b01) && (last_mode_v == 2'b01)) v_cnt <= 616-4; end + end end // ------------------------------------------------------------------------------- @@ -114,7 +119,8 @@ reg blank; reg [1:0] pixel_reg; reg [7:0] shift_reg_rptr; -always@(posedge pclk) begin +always@(posedge clk64) begin + if (pclk_en) begin // visible area? if((v_cnt < V) && (h_cnt < H)) begin blank <= 1'b0; @@ -124,6 +130,7 @@ always@(posedge pclk) begin blank <= 1'b1; shift_reg_rptr <= 8'd0; end + end end wire [1:0] pixel = on?pixel_reg:2'b00; diff --git a/cores/gameboy/osd.v b/cores/gameboy/osd.v index a654b40..bc3ade8 100644 --- a/cores/gameboy/osd.v +++ b/cores/gameboy/osd.v @@ -4,34 +4,32 @@ module osd ( // OSDs pixel clock, should be synchronous to cores pixel clock to // avoid jitter. - input pclk, + input clk_sys, // SPI interface - input sck, - input ss, - input sdi, + input SPI_SCK, + input SPI_SS3, + input SPI_DI, // VGA signals coming from core - input [5:0] red_in, - input [5:0] green_in, - input [5:0] blue_in, - input hs_in, - input vs_in, + input [5:0] R_in, + input [5:0] G_in, + input [5:0] B_in, + input HSync, + input VSync, // VGA signals going to video connector - output [5:0] red_out, - output [5:0] green_out, - output [5:0] blue_out, - output hs_out, - output vs_out + output [5:0] R_out, + output [5:0] G_out, + output [5:0] B_out ); parameter OSD_X_OFFSET = 10'd0; parameter OSD_Y_OFFSET = 10'd0; parameter OSD_COLOR = 3'd0; -localparam OSD_WIDTH = 10'd256; -localparam OSD_HEIGHT = 10'd128; +localparam OSD_WIDTH = 10'd256; +localparam OSD_HEIGHT = 10'd128; // ********************************************************************************* // spi client @@ -39,45 +37,42 @@ localparam OSD_HEIGHT = 10'd128; // this core supports only the display related OSD commands // of the minimig -reg [7:0] sbuf; -reg [7:0] cmd; -reg [4:0] cnt; -reg [10:0] bcnt; -reg osd_enable; - -reg [7:0] osd_buffer [2047:0]; // the OSD buffer itself +reg osd_enable; +(* ramstyle = "no_rw_check" *) reg [7:0] osd_buffer[2047:0]; // the OSD buffer itself // the OSD has its own SPI interface to the io controller -always@(posedge sck, posedge ss) begin - if(ss == 1'b1) begin - cnt <= 5'd0; - bcnt <= 11'd0; - end else begin - sbuf <= { sbuf[6:0], sdi}; +always@(posedge SPI_SCK, posedge SPI_SS3) begin + reg [4:0] cnt; + reg [10:0] bcnt; + reg [7:0] sbuf; + reg [7:0] cmd; - // 0:7 is command, rest payload - if(cnt < 15) - cnt <= cnt + 4'd1; - else - cnt <= 4'd8; + if(SPI_SS3) begin + cnt <= 0; + bcnt <= 0; + end else begin + sbuf <= {sbuf[6:0], SPI_DI}; - if(cnt == 7) begin - cmd <= {sbuf[6:0], sdi}; - - // lower three command bits are line address - bcnt <= { sbuf[1:0], sdi, 8'h00}; + // 0:7 is command, rest payload + if(cnt < 15) cnt <= cnt + 1'd1; + else cnt <= 8; - // command 0x40: OSDCMDENABLE, OSDCMDDISABLE - if(sbuf[6:3] == 4'b0100) - osd_enable <= sdi; - end + if(cnt == 7) begin + cmd <= {sbuf[6:0], SPI_DI}; - // command 0x20: OSDCMDWRITE - if((cmd[7:3] == 5'b00100) && (cnt == 15)) begin - osd_buffer[bcnt] <= {sbuf[6:0], sdi}; - bcnt <= bcnt + 11'd1; - end - end + // lower three command bits are line address + bcnt <= {sbuf[1:0], SPI_DI, 8'h00}; + + // command 0x40: OSDCMDENABLE, OSDCMDDISABLE + if(sbuf[6:3] == 4'b0100) osd_enable <= SPI_DI; + end + + // command 0x20: OSDCMDWRITE + if((cmd[7:3] == 5'b00100) && (cnt == 15)) begin + osd_buffer[bcnt] <= {sbuf[6:0], SPI_DI}; + bcnt <= bcnt + 1'd1; + end + end end // ********************************************************************************* @@ -85,98 +80,100 @@ end // ********************************************************************************* // horizontal counter -reg [9:0] h_cnt; -reg hsD, hsD2; -reg [9:0] hs_low, hs_high; -wire hs_pol = hs_high < hs_low; -wire [9:0] h_dsp_width = hs_pol?hs_low:hs_high; -wire [9:0] h_dsp_ctr = { 1'b0, h_dsp_width[9:1] }; - -always @(posedge pclk) begin - // bring hsync into local clock domain - hsD <= hs_in; - hsD2 <= hsD; - - // falling edge of hs_in - if(!hsD && hsD2) begin - h_cnt <= 10'd0; - hs_high <= h_cnt; - end - - // rising edge of hs_in - else if(hsD && !hsD2) begin - h_cnt <= 10'd0; - hs_low <= h_cnt; - end - - else - h_cnt <= h_cnt + 10'd1; -end +reg [9:0] h_cnt; +reg [9:0] hs_low, hs_high; +wire hs_pol = hs_high < hs_low; +wire [9:0] dsp_width = hs_pol ? hs_low : hs_high; // vertical counter -reg [9:0] v_cnt; -reg vsD, vsD2; -reg [9:0] vs_low, vs_high; -wire vs_pol = vs_high < vs_low; -wire [9:0] v_dsp_width = vs_pol?vs_low:vs_high; -wire [9:0] v_dsp_ctr = { 1'b0, v_dsp_width[9:1] }; +reg [9:0] v_cnt; +reg [9:0] vs_low, vs_high; +wire vs_pol = vs_high < vs_low; +wire [9:0] dsp_height = vs_pol ? vs_low : vs_high; -always @(posedge hs_in) begin - // bring vsync into local clock domain - vsD <= vs_in; - vsD2 <= vsD; +wire doublescan = (dsp_height>350); - // falling edge of vs_in - if(!vsD && vsD2) begin - v_cnt <= 10'd0; - vs_high <= v_cnt; +reg ce_pix; +always @(negedge clk_sys) begin + integer cnt = 0; + integer pixsz, pixcnt; + reg hs; + + cnt <= cnt + 1; + hs <= HSync; + + pixcnt <= pixcnt + 1; + if(pixcnt == pixsz) pixcnt <= 0; + ce_pix <= !pixcnt; + + if(hs && ~HSync) begin + cnt <= 0; + pixsz <= (cnt >> 9) - 1; + pixcnt <= 0; + ce_pix <= 1; end +end - // rising edge of vs_in - else if(vsD && !vsD2) begin - v_cnt <= 10'd0; - vs_low <= v_cnt; - end - - else - v_cnt <= v_cnt + 10'd1; +always @(posedge clk_sys) begin + reg hsD, hsD2; + reg vsD, vsD2; + + if(ce_pix) begin + // bring hsync into local clock domain + hsD <= HSync; + hsD2 <= hsD; + + // falling edge of HSync + if(!hsD && hsD2) begin + h_cnt <= 0; + hs_high <= h_cnt; + end + + // rising edge of HSync + else if(hsD && !hsD2) begin + h_cnt <= 0; + hs_low <= h_cnt; + v_cnt <= v_cnt + 1'd1; + end else begin + h_cnt <= h_cnt + 1'd1; + end + + vsD <= VSync; + vsD2 <= vsD; + + // falling edge of VSync + if(!vsD && vsD2) begin + v_cnt <= 0; + vs_high <= v_cnt; + end + + // rising edge of VSync + else if(vsD && !vsD2) begin + v_cnt <= 0; + vs_low <= v_cnt; + end + end end // area in which OSD is being displayed -wire [9:0] h_osd_start = h_dsp_ctr + OSD_X_OFFSET - (OSD_WIDTH >> 1); -wire [9:0] h_osd_end = h_dsp_ctr + OSD_X_OFFSET + (OSD_WIDTH >> 1) - 1; -wire [9:0] v_osd_start = v_dsp_ctr + OSD_Y_OFFSET - (OSD_HEIGHT >> 1); -wire [9:0] v_osd_end = v_dsp_ctr + OSD_Y_OFFSET + (OSD_HEIGHT >> 1) - 1; +wire [9:0] h_osd_start = ((dsp_width - OSD_WIDTH)>> 1) + OSD_X_OFFSET; +wire [9:0] h_osd_end = h_osd_start + OSD_WIDTH; +wire [9:0] v_osd_start = ((dsp_height- (OSD_HEIGHT<> 1) + OSD_Y_OFFSET; +wire [9:0] v_osd_end = v_osd_start + (OSD_HEIGHT<= h_osd_start) && (h_cnt < h_osd_end) && + (VSync != vs_pol) && (v_cnt >= v_osd_start) && (v_cnt < v_osd_end); -wire osd_de = osd_enable && h_osd_active && v_osd_active; +reg [7:0] osd_byte; +always @(posedge clk_sys) if(ce_pix) osd_byte <= osd_buffer[{doublescan ? osd_vcnt[7:5] : osd_vcnt[6:4], osd_hcnt[7:0]}]; -wire [7:0] osd_hcnt = h_cnt - h_osd_start + 7'd1; // one pixel offset for osd_byte register -wire [6:0] osd_vcnt = v_cnt - v_osd_start; +wire osd_pixel = osd_byte[doublescan ? osd_vcnt[4:2] : osd_vcnt[3:1]]; -wire osd_pixel = osd_byte[osd_vcnt[3:1]]; +assign R_out = !osd_de ? R_in : {osd_pixel, osd_pixel, OSD_COLOR[2], R_in[5:3]}; +assign G_out = !osd_de ? G_in : {osd_pixel, osd_pixel, OSD_COLOR[1], G_in[5:3]}; +assign B_out = !osd_de ? B_in : {osd_pixel, osd_pixel, OSD_COLOR[0], B_in[5:3]}; -reg [7:0] osd_byte; -always @(posedge pclk) - osd_byte <= osd_buffer[{osd_vcnt[6:4], osd_hcnt}]; - -wire [2:0] osd_color = OSD_COLOR; -assign red_out = !osd_de?red_in: {osd_pixel, osd_pixel, osd_color[2], red_in[5:3] }; -assign green_out = !osd_de?green_in:{osd_pixel, osd_pixel, osd_color[1], green_in[5:3]}; -assign blue_out = !osd_de?blue_in: {osd_pixel, osd_pixel, osd_color[0], blue_in[5:3] }; - -assign hs_out = hs_in; -assign vs_out = vs_in; - -endmodule \ No newline at end of file +endmodule diff --git a/cores/gameboy/pll.ppf b/cores/gameboy/pll.ppf new file mode 100644 index 0000000..b7fa3e1 --- /dev/null +++ b/cores/gameboy/pll.ppf @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/cores/gameboy/pll.v b/cores/gameboy/pll.v index dee5100..89437c2 100644 --- a/cores/gameboy/pll.v +++ b/cores/gameboy/pll.v @@ -98,7 +98,7 @@ module pll ( .vcounderrange ()); defparam altpll_component.bandwidth_type = "AUTO", - altpll_component.clk0_divide_by = 70, + altpll_component.clk0_divide_by = 35, altpll_component.clk0_duty_cycle = 50, altpll_component.clk0_multiply_by = 87, altpll_component.clk0_phase_shift = "0", @@ -179,11 +179,11 @@ endmodule // Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c0" // Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "c0" // Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "8" -// Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "70" +// Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "35" // Retrieval info: PRIVATE: DIV_FACTOR1 NUMERIC "70" // Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" // Retrieval info: PRIVATE: DUTY_CYCLE1 STRING "50.00000000" -// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "33.557144" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "67.114288" // Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE1 STRING "33.557144" // Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0" // Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0" @@ -259,7 +259,7 @@ endmodule // Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0" // Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all // Retrieval info: CONSTANT: BANDWIDTH_TYPE STRING "AUTO" -// Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "70" +// Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "35" // Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" // Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "87" // Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0" diff --git a/cores/gameboy/sdram.v b/cores/gameboy/sdram.sv similarity index 53% rename from cores/gameboy/sdram.v rename to cores/gameboy/sdram.sv index 5af8c5c..de8e425 100644 --- a/cores/gameboy/sdram.v +++ b/cores/gameboy/sdram.sv @@ -1,10 +1,9 @@ // -// sdram.v // -// sdram controller implementation for the MiST board -// https://github.com/mist-devel +// sdram controller implementation for the MiST/MiSTer boards // // Copyright (c) 2015 Till Harbaum +// Copyright (c) 2017 Sorgelig // // This source file is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published @@ -20,13 +19,21 @@ // along with this program. If not, see . // -module sdram ( +// +// +// This SDRAM module provides/writes the data in 8 cycles of clock. +// So, with 64MHz of system clock, it can emulate 8MHz asynchronous DRAM. +// +// + +module sdram +( // interface to the MT48LC16M16 chip inout [15:0] sd_data, // 16 bit bidirectional data bus output reg [12:0] sd_addr, // 13 bit multiplexed address bus output reg [1:0] sd_dqm, // two byte masks - output reg[1:0] sd_ba, // two banks + output reg [1:0] sd_ba, // two banks output sd_cs, // a single chip select output sd_we, // write enable output sd_ras, // row address select @@ -34,57 +41,51 @@ module sdram ( // cpu/chipset interface input init, // init signal after FPGA config to initialize RAM - input clk, // sdram is accessed at up to 128MHz - input clkref, // reference clock to sync to - - input [15:0] din, // data input from chipset/cpu - output [15:0] dout, // data output to chipset/cpu - input [23:0] addr, // 24 bit word address - input [1:0] ds, // data strobe for hi/low byte + input clk, // sdram is accessed at 64MHz + input sync, + + input [15:0] din, // data input from chipset/cpu + output reg [15:0] dout, // data output to chipset/cpu + input [23:0] addr, // 24 bit word address + input [1:0] ds, // upper/lower data strobe input oe, // cpu/chipset requests read input we // cpu/chipset requests write ); -// no burst configured -localparam RASCAS_DELAY = 3'd3; // tRCD>=20ns -> 2 cycles@64MHz -localparam BURST_LENGTH = 3'b000; // 000=none, 001=2, 010=4, 011=8 +localparam RASCAS_DELAY = 3'd2; // tRCD=20ns -> 3 cycles@128MHz +localparam BURST_LENGTH = 3'b000; // 000=1, 001=2, 010=4, 011=8 localparam ACCESS_TYPE = 1'b0; // 0=sequential, 1=interleaved -localparam CAS_LATENCY = 3'd3; // 2/3 allowed +localparam CAS_LATENCY = 3'd2; // 2/3 allowed localparam OP_MODE = 2'b00; // only 00 (standard operation) allowed localparam NO_WRITE_BURST = 1'b1; // 0= write burst enabled, 1=only single access write localparam MODE = { 3'b000, NO_WRITE_BURST, OP_MODE, CAS_LATENCY, ACCESS_TYPE, BURST_LENGTH}; + // --------------------------------------------------------------------- // ------------------------ cycle state machine ------------------------ // --------------------------------------------------------------------- -localparam STATE_IDLE = 3'd0; // first state in cycle -localparam STATE_CMD_START = 3'd1; // state in which a new command can be started -localparam STATE_CMD_CONT = STATE_CMD_START + RASCAS_DELAY - 3'd1; // 4 command can be continued -localparam STATE_LAST = 3'd7; // last state in cycle +// The state machine runs at 128Mhz synchronous to the 8 Mhz chipset clock. +// It wraps from T15 to T0 on the rising edge of clk_8 + +localparam STATE_FIRST = 3'd0; // first state in cycle +localparam STATE_CMD_START = 3'd1; // state in which a new command can be started +localparam STATE_CMD_CONT = STATE_CMD_START + RASCAS_DELAY; // command can be continued +localparam STATE_READ = STATE_CMD_CONT + CAS_LATENCY + 4'd1; +localparam STATE_HIGHZ = STATE_READ - 4'd1; // disable output to prevent contention -reg [2:0] q; -always @(posedge clk) begin - // 32Mhz counter synchronous to 4 Mhz clock - // force counter to pass state 5->6 exactly after the rising edge of clkref - // since clkref is two clocks early - if(((q == 7) && ( clkref == 0)) || - ((q == 0) && ( clkref == 1)) || - ((q != 7) && (q != 0))) - q <= q + 3'd1; -end // --------------------------------------------------------------------- // --------------------------- startup/reset --------------------------- // --------------------------------------------------------------------- -// wait 1ms (32 clkref cycles) after FPGA config is done before going +// wait 1ms (32 8Mhz cycles) after FPGA config is done before going // into normal operation. Initialize the ram in the last 16 reset cycles (cycles 15-0) reg [4:0] reset; always @(posedge clk) begin if(init) reset <= 5'h1f; - else if((q == STATE_LAST) && (reset != 0)) + else if((stage == STATE_FIRST) && (reset != 0)) reset <= reset - 5'd1; end @@ -111,39 +112,82 @@ assign sd_ras = sd_cmd[2]; assign sd_cas = sd_cmd[1]; assign sd_we = sd_cmd[0]; -assign sd_data = we?din:16'bZZZZZZZZZZZZZZZZ; +// drive ram data lines when writing, set them as inputs otherwise +assign sd_data = mode[1] ? din_r : 16'bZZZZZZZZZZZZZZZZ; -assign dout = sd_data; +reg [1:0] mode; +reg [15:0] din_r; +reg [2:0] stage; always @(posedge clk) begin - sd_cmd <= CMD_INHIBIT; + reg [12:0] addr_r; + reg [1:0] ds_r; + reg old_sync; + + if(|stage) stage <= stage + 1'd1; + + old_sync <= sync; + if(~old_sync & sync) stage <= 1; + + sd_cmd <= CMD_INHIBIT; // default: idle if(reset != 0) begin - sd_ba <= 2'b00; - sd_dqm <= 2'b00; - - if(reset == 13) sd_addr <= 13'b0010000000000; - else sd_addr <= MODE; + // initialization takes place at the end of the reset phase + if(stage == STATE_CMD_START) begin - if(q == STATE_IDLE) begin - if(reset == 13) sd_cmd <= CMD_PRECHARGE; - if(reset == 2) sd_cmd <= CMD_LOAD_MODE; + if(reset == 13) begin + sd_cmd <= CMD_PRECHARGE; + sd_addr[10] <= 1'b1; // precharge all banks + end + + if(reset == 2) begin + sd_cmd <= CMD_LOAD_MODE; + sd_addr <= MODE; + end + end + mode <= 0; + sd_dqm <= 2'b11; end else begin - if(q <= STATE_CMD_START) begin - sd_addr <= addr[20:8]; - sd_ba <= addr[22:21]; - sd_dqm <= { !ds[1], !ds[0] }; - end else - sd_addr <= { 4'b0010, addr[23], addr[7:0]}; - - if(q == STATE_IDLE) begin - if(we || oe) sd_cmd <= CMD_ACTIVE; - else sd_cmd <= CMD_AUTO_REFRESH; - end else if(q == STATE_CMD_CONT) begin - if(we) sd_cmd <= CMD_WRITE; - else if(oe) sd_cmd <= CMD_READ; - end + + // normal operation + if(stage == STATE_CMD_START) begin + if(we || oe) begin + + mode <= {we, oe}; + + // RAS phase + sd_cmd <= CMD_ACTIVE; + sd_addr <= { 1'b0, addr[19:8] }; + sd_ba <= addr[21:20]; + + ds_r <= ds; + din_r <= din; + addr_r <= { 4'b0010, addr[22], addr[7:0] }; // auto precharge + end + else begin + sd_cmd <= CMD_AUTO_REFRESH; + mode <= 0; + end + end + + // CAS phase + if(stage == STATE_CMD_CONT && mode) begin + sd_cmd <= mode[1] ? CMD_WRITE : CMD_READ; + sd_addr <= addr_r; + + if(mode[1]) sd_dqm <= ~ds_r; + else sd_dqm <= 2'b00; + end + + if(stage == STATE_HIGHZ) begin + sd_dqm <= 2'b11; // disable chip output + mode[1] <= 0; // disable data output + end + + if(stage == STATE_READ && mode) begin + dout <= sd_data; + end end end diff --git a/cores/gameboy/user_io.v b/cores/gameboy/user_io.v index 7812249..fa05d51 100644 --- a/cores/gameboy/user_io.v +++ b/cores/gameboy/user_io.v @@ -22,60 +22,75 @@ // parameter STRLEN and the actual length of conf_str have to match -module user_io #(parameter STRLEN=0) ( +module user_io #(parameter STRLEN=0, parameter PS2DIV=100) ( input [(8*STRLEN)-1:0] conf_str, - input SPI_CLK, - input SPI_SS_IO, - output reg SPI_MISO, - input SPI_MOSI, - - output reg [7:0] joystick_0, - output reg [7:0] joystick_1, - output reg [15:0] joystick_analog_0, - output reg [15:0] joystick_analog_1, - output [1:0] buttons, - output [1:0] switches, + input clk_sys, // clock for system-related messages (kbd, joy, etc...) + input clk_sd, // clock for SD-card related messages - output reg [7:0] status, + input SPI_CLK, + input SPI_SS_IO, + output reg SPI_MISO, + input SPI_MOSI, + + output reg [31:0] joystick_0, + output reg [31:0] joystick_1, + output reg [31:0] joystick_2, + output reg [31:0] joystick_3, + output reg [31:0] joystick_4, + output reg [15:0] joystick_analog_0, + output reg [15:0] joystick_analog_1, + output [1:0] buttons, + output [1:0] switches, + output scandoubler_disable, + output ypbpr, + output reg [31:0] status, // connection to sd card emulation - input [31:0] sd_lba, - input sd_rd, - input sd_wr, - output reg sd_ack, - input sd_conf, - input sd_sdhc, - output [7:0] sd_dout, // valid on rising edge of sd_dout_strobe - output reg sd_dout_strobe, - input [7:0] sd_din, - output reg sd_din_strobe, - + input [31:0] sd_lba, + input sd_rd, + input sd_wr, + output reg sd_ack, + output reg sd_ack_conf, + input sd_conf, + input sd_sdhc, + output reg [7:0] sd_dout, // valid on rising edge of sd_dout_strobe + output reg sd_dout_strobe, + input [7:0] sd_din, + output reg sd_din_strobe, + output reg [8:0] sd_buff_addr, - // ps2 keyboard emulation - input ps2_clk, // 12-16khz provided by core - output ps2_kbd_clk, - output reg ps2_kbd_data, - output ps2_mouse_clk, - output reg ps2_mouse_data, + output reg img_mounted, //rising edge if a new image is mounted + output reg [31:0] img_size, // size of image in bytes + + // ps2 keyboard/mouse emulation + output ps2_kbd_clk, + output reg ps2_kbd_data, + output ps2_mouse_clk, + output reg ps2_mouse_data, + + // mouse data + output reg [7:0] mouse_x, + output reg [7:0] mouse_y, + output reg [7:0] mouse_flags, // YOvfl, XOvfl, dy8, dx8, 1, mbtn, rbtn, lbtn + output reg mouse_strobe, // mouse data is valid on mouse_strobe // serial com port - input [7:0] serial_data, - input serial_strobe + input [7:0] serial_data, + input serial_strobe ); -reg [6:0] sbuf; -reg [7:0] cmd; -reg [2:0] bit_cnt; // counts bits 0-7 0-7 ... -reg [7:0] byte_cnt; // counts bytes -reg [5:0] joystick0; -reg [5:0] joystick1; -reg [3:0] but_sw; -reg [2:0] stick_idx; +reg [6:0] sbuf; +reg [7:0] cmd; +reg [2:0] bit_cnt; // counts bits 0-7 0-7 ... +reg [9:0] byte_cnt; // counts bytes +reg [7:0] but_sw; +reg [2:0] stick_idx; assign buttons = but_sw[1:0]; assign switches = but_sw[3:2]; -assign sd_dout = { sbuf, SPI_MOSI}; +assign scandoubler_disable = but_sw[4]; +assign ypbpr = but_sw[5]; // this variant of user_io is for 8 bit cores (type == a4) only wire [7:0] core_type = 8'ha4; @@ -83,63 +98,22 @@ wire [7:0] core_type = 8'ha4; // command byte read by the io controller wire [7:0] sd_cmd = { 4'h5, sd_conf, sd_sdhc, sd_wr, sd_rd }; -// filter spi clock. the 8 bit gate delay is ~2.5ns in total -wire [7:0] spi_sck_D = { spi_sck_D[6:0], SPI_CLK } /* synthesis keep */; -wire spi_sck = (spi_sck && spi_sck_D != 8'h00) || (!spi_sck && spi_sck_D == 8'hff); - -// drive MISO only when transmitting core id -always@(negedge spi_sck or posedge SPI_SS_IO) begin - if(SPI_SS_IO == 1) begin - SPI_MISO <= 1'bZ; - end else begin - - // first byte returned is always core type, further bytes are - // command dependent - if(byte_cnt == 0) begin - SPI_MISO <= core_type[~bit_cnt]; - - end else begin - // reading serial fifo - if(cmd == 8'h1b) begin - // send alternating flag byte and data - if(byte_cnt[0]) SPI_MISO <= serial_out_status[~bit_cnt]; - else SPI_MISO <= serial_out_byte[~bit_cnt]; - end - - // reading config string - else if(cmd == 8'h14) begin - // returning a byte from string - if(byte_cnt < STRLEN + 1) - SPI_MISO <= conf_str[{STRLEN - byte_cnt,~bit_cnt}]; - else - SPI_MISO <= 1'b0; - end - - // reading sd card status - else if(cmd == 8'h16) begin - if(byte_cnt == 1) - SPI_MISO <= sd_cmd[~bit_cnt]; - else if((byte_cnt >= 2) && (byte_cnt < 6)) - SPI_MISO <= sd_lba[{5-byte_cnt, ~bit_cnt}]; - else - SPI_MISO <= 1'b0; - end - - // reading sd card write data - else if(cmd == 8'h18) - SPI_MISO <= sd_din[~bit_cnt]; - - else - SPI_MISO <= 1'b0; - end - end -end +wire spi_sck = SPI_CLK; // ---------------- PS2 --------------------- - // 8 byte fifos to store ps2 bytes localparam PS2_FIFO_BITS = 3; +reg ps2_clk; +always @(negedge clk_sys) begin + integer cnt; + cnt <= cnt + 1'd1; + if(cnt == PS2DIV) begin + ps2_clk <= ~ps2_clk; + cnt <= 0; + end +end + // keyboard reg [7:0] ps2_kbd_fifo [(2**PS2_FIFO_BITS)-1:0]; reg [PS2_FIFO_BITS-1:0] ps2_kbd_wptr; @@ -155,56 +129,60 @@ assign ps2_kbd_clk = ps2_clk || (ps2_kbd_tx_state == 0); // ps2 transmitter // Takes a byte from the FIFO and sends it in a ps2 compliant serial format. reg ps2_kbd_r_inc; -always@(posedge ps2_clk) begin - ps2_kbd_r_inc <= 1'b0; - - if(ps2_kbd_r_inc) - ps2_kbd_rptr <= ps2_kbd_rptr + 1; +always@(posedge clk_sys) begin + reg ps2_clkD; - // transmitter is idle? - if(ps2_kbd_tx_state == 0) begin - // data in fifo present? - if(ps2_kbd_wptr != ps2_kbd_rptr) begin - // load tx register from fifo - ps2_kbd_tx_byte <= ps2_kbd_fifo[ps2_kbd_rptr]; - ps2_kbd_r_inc <= 1'b1; - - // reset parity - ps2_kbd_parity <= 1'b1; - - // start transmitter - ps2_kbd_tx_state <= 4'd1; + ps2_clkD <= ps2_clk; + if (~ps2_clkD & ps2_clk) begin + ps2_kbd_r_inc <= 1'b0; - // put start bit on data line - ps2_kbd_data <= 1'b0; // start bit is 0 + if(ps2_kbd_r_inc) + ps2_kbd_rptr <= ps2_kbd_rptr + 1'd1; + + // transmitter is idle? + if(ps2_kbd_tx_state == 0) begin + // data in fifo present? + if(ps2_kbd_wptr != ps2_kbd_rptr) begin + // load tx register from fifo + ps2_kbd_tx_byte <= ps2_kbd_fifo[ps2_kbd_rptr]; + ps2_kbd_r_inc <= 1'b1; + + // reset parity + ps2_kbd_parity <= 1'b1; + + // start transmitter + ps2_kbd_tx_state <= 4'd1; + + // put start bit on data line + ps2_kbd_data <= 1'b0; // start bit is 0 + end + end else begin + + // transmission of 8 data bits + if((ps2_kbd_tx_state >= 1)&&(ps2_kbd_tx_state < 9)) begin + ps2_kbd_data <= ps2_kbd_tx_byte[0]; // data bits + ps2_kbd_tx_byte[6:0] <= ps2_kbd_tx_byte[7:1]; // shift down + if(ps2_kbd_tx_byte[0]) + ps2_kbd_parity <= !ps2_kbd_parity; + end + + // transmission of parity + if(ps2_kbd_tx_state == 9) + ps2_kbd_data <= ps2_kbd_parity; + + // transmission of stop bit + if(ps2_kbd_tx_state == 10) + ps2_kbd_data <= 1'b1; // stop bit is 1 + + // advance state machine + if(ps2_kbd_tx_state < 11) + ps2_kbd_tx_state <= ps2_kbd_tx_state + 4'd1; + else + ps2_kbd_tx_state <= 4'd0; end - end else begin - - // transmission of 8 data bits - if((ps2_kbd_tx_state >= 1)&&(ps2_kbd_tx_state < 9)) begin - ps2_kbd_data <= ps2_kbd_tx_byte[0]; // data bits - ps2_kbd_tx_byte[6:0] <= ps2_kbd_tx_byte[7:1]; // shift down - if(ps2_kbd_tx_byte[0]) - ps2_kbd_parity <= !ps2_kbd_parity; - end - - // transmission of parity - if(ps2_kbd_tx_state == 9) - ps2_kbd_data <= ps2_kbd_parity; - - // transmission of stop bit - if(ps2_kbd_tx_state == 10) - ps2_kbd_data <= 1'b1; // stop bit is 1 - - // advance state machine - if(ps2_kbd_tx_state < 11) - ps2_kbd_tx_state <= ps2_kbd_tx_state + 4'd1; - else - ps2_kbd_tx_state <= 4'd0; - end end - + // mouse reg [7:0] ps2_mouse_fifo [(2**PS2_FIFO_BITS)-1:0]; reg [PS2_FIFO_BITS-1:0] ps2_mouse_wptr; @@ -220,53 +198,57 @@ assign ps2_mouse_clk = ps2_clk || (ps2_mouse_tx_state == 0); // ps2 transmitter // Takes a byte from the FIFO and sends it in a ps2 compliant serial format. reg ps2_mouse_r_inc; -always@(posedge ps2_clk) begin - ps2_mouse_r_inc <= 1'b0; - - if(ps2_mouse_r_inc) - ps2_mouse_rptr <= ps2_mouse_rptr + 1; +always@(posedge clk_sys) begin + reg ps2_clkD; - // transmitter is idle? - if(ps2_mouse_tx_state == 0) begin - // data in fifo present? - if(ps2_mouse_wptr != ps2_mouse_rptr) begin - // load tx register from fifo - ps2_mouse_tx_byte <= ps2_mouse_fifo[ps2_mouse_rptr]; - ps2_mouse_r_inc <= 1'b1; - - // reset parity - ps2_mouse_parity <= 1'b1; - - // start transmitter - ps2_mouse_tx_state <= 4'd1; + ps2_clkD <= ps2_clk; + if (~ps2_clkD & ps2_clk) begin + ps2_mouse_r_inc <= 1'b0; - // put start bit on data line - ps2_mouse_data <= 1'b0; // start bit is 0 + if(ps2_mouse_r_inc) + ps2_mouse_rptr <= ps2_mouse_rptr + 1'd1; + + // transmitter is idle? + if(ps2_mouse_tx_state == 0) begin + // data in fifo present? + if(ps2_mouse_wptr != ps2_mouse_rptr) begin + // load tx register from fifo + ps2_mouse_tx_byte <= ps2_mouse_fifo[ps2_mouse_rptr]; + ps2_mouse_r_inc <= 1'b1; + + // reset parity + ps2_mouse_parity <= 1'b1; + + // start transmitter + ps2_mouse_tx_state <= 4'd1; + + // put start bit on data line + ps2_mouse_data <= 1'b0; // start bit is 0 + end + end else begin + + // transmission of 8 data bits + if((ps2_mouse_tx_state >= 1)&&(ps2_mouse_tx_state < 9)) begin + ps2_mouse_data <= ps2_mouse_tx_byte[0]; // data bits + ps2_mouse_tx_byte[6:0] <= ps2_mouse_tx_byte[7:1]; // shift down + if(ps2_mouse_tx_byte[0]) + ps2_mouse_parity <= !ps2_mouse_parity; + end + + // transmission of parity + if(ps2_mouse_tx_state == 9) + ps2_mouse_data <= ps2_mouse_parity; + + // transmission of stop bit + if(ps2_mouse_tx_state == 10) + ps2_mouse_data <= 1'b1; // stop bit is 1 + + // advance state machine + if(ps2_mouse_tx_state < 11) + ps2_mouse_tx_state <= ps2_mouse_tx_state + 4'd1; + else + ps2_mouse_tx_state <= 4'd0; end - end else begin - - // transmission of 8 data bits - if((ps2_mouse_tx_state >= 1)&&(ps2_mouse_tx_state < 9)) begin - ps2_mouse_data <= ps2_mouse_tx_byte[0]; // data bits - ps2_mouse_tx_byte[6:0] <= ps2_mouse_tx_byte[7:1]; // shift down - if(ps2_mouse_tx_byte[0]) - ps2_mouse_parity <= !ps2_mouse_parity; - end - - // transmission of parity - if(ps2_mouse_tx_state == 9) - ps2_mouse_data <= ps2_mouse_parity; - - // transmission of stop bit - if(ps2_mouse_tx_state == 10) - ps2_mouse_data <= 1'b1; // stop bit is 1 - - // advance state machine - if(ps2_mouse_tx_state < 11) - ps2_mouse_tx_state <= ps2_mouse_tx_state + 4'd1; - else - ps2_mouse_tx_state <= 4'd0; - end end @@ -279,7 +261,7 @@ reg [SERIAL_OUT_FIFO_BITS-1:0] serial_out_wptr; reg [SERIAL_OUT_FIFO_BITS-1:0] serial_out_rptr; wire serial_out_data_available = serial_out_wptr != serial_out_rptr; -wire [7:0] serial_out_byte = serial_out_fifo[serial_out_rptr]; +wire [7:0] serial_out_byte = serial_out_fifo[serial_out_rptr] /* synthesis keep */; wire [7:0] serial_out_status = { 7'b1000000, serial_out_data_available}; // status[0] is reset signal from io controller and is thus used to flush @@ -289,7 +271,7 @@ always @(posedge serial_strobe or posedge status[0]) begin serial_out_wptr <= 0; end else begin serial_out_fifo[serial_out_wptr] <= serial_data; - serial_out_wptr <= serial_out_wptr + 1; + serial_out_wptr <= serial_out_wptr + 1'd1; end end @@ -300,113 +282,268 @@ always@(negedge spi_sck or posedge status[0]) begin if((byte_cnt != 0) && (cmd == 8'h1b)) begin // read last bit -> advance read pointer if((bit_cnt == 7) && !byte_cnt[0] && serial_out_data_available) - serial_out_rptr <= serial_out_rptr + 1; + serial_out_rptr <= serial_out_rptr + 1'd1; end end end -// SPI receiver + +// SPI bit and byte counters +always@(posedge spi_sck or posedge SPI_SS_IO) begin + if(SPI_SS_IO == 1) begin + bit_cnt <= 0; + byte_cnt <= 0; + end else begin + if((bit_cnt == 7)&&(~&byte_cnt)) + byte_cnt <= byte_cnt + 8'd1; + + bit_cnt <= bit_cnt + 1'd1; + end +end + +// SPI transmitter FPGA -> IO +reg [7:0] spi_byte_out; + +always@(negedge spi_sck or posedge SPI_SS_IO) begin + if(SPI_SS_IO == 1) begin + SPI_MISO <= 1'bZ; + end else begin + SPI_MISO <= spi_byte_out[~bit_cnt]; + end +end + +always@(posedge spi_sck or posedge SPI_SS_IO) begin + reg [31:0] sd_lba_r; + + if(SPI_SS_IO == 1) begin + spi_byte_out <= core_type; + end else begin + // read the command byte to choose the response + if(bit_cnt == 7) begin + if(!byte_cnt) cmd <= {sbuf, SPI_MOSI}; + + spi_byte_out <= 0; + case({(!byte_cnt) ? {sbuf, SPI_MOSI} : cmd}) + // reading config string + 8'h14: if(byte_cnt < STRLEN) spi_byte_out <= conf_str[(STRLEN - byte_cnt - 1)<<3 +:8]; + + // reading sd card status + 8'h16: if(byte_cnt == 0) begin + spi_byte_out <= sd_cmd; + sd_lba_r <= sd_lba; + end + else if(byte_cnt < 5) spi_byte_out <= sd_lba_r[(4-byte_cnt)<<3 +:8]; + + // reading sd card write data + 8'h18: spi_byte_out <= sd_din; + 8'h1b: + // send alternating flag byte and data + if(byte_cnt[0]) spi_byte_out <= serial_out_status; + else spi_byte_out <= serial_out_byte; + endcase + end + end +end + +// SPI receiver IO -> FPGA + +reg spi_receiver_strobe_r = 0; +reg spi_transfer_end_r = 1; +reg [7:0] spi_byte_in; + +// Read at spi_sck clock domain, assemble bytes for transferring to clk_sys always@(posedge spi_sck or posedge SPI_SS_IO) begin if(SPI_SS_IO == 1) begin - bit_cnt <= 3'd0; - byte_cnt <= 8'd0; - sd_ack <= 1'b0; - sd_dout_strobe <= 1'b0; - sd_din_strobe <= 1'b0; + spi_transfer_end_r <= 1; end else begin - sd_dout_strobe <= 1'b0; - sd_din_strobe <= 1'b0; - + spi_transfer_end_r <= 0; + if(bit_cnt != 7) sbuf[6:0] <= { sbuf[5:0], SPI_MOSI }; - - bit_cnt <= bit_cnt + 3'd1; - if((bit_cnt == 7)&&(byte_cnt != 8'd255)) - byte_cnt <= byte_cnt + 8'd1; - // finished reading command byte - if(bit_cnt == 7) begin - if(byte_cnt == 0) begin - cmd <= { sbuf, SPI_MOSI}; - - // fetch first byte when sectore FPGA->IO command has been seen - if({ sbuf, SPI_MOSI} == 8'h18) - sd_din_strobe <= 1'b1; - - if(({ sbuf, SPI_MOSI} == 8'h17) || ({ sbuf, SPI_MOSI} == 8'h18)) - sd_ack <= 1'b1; - - end else begin - - // buttons and switches - if(cmd == 8'h01) - but_sw <= { sbuf[2:0], SPI_MOSI }; - - if(cmd == 8'h02) - joystick_0 <= { sbuf, SPI_MOSI }; - - if(cmd == 8'h03) - joystick_1 <= { sbuf, SPI_MOSI }; - - if(cmd == 8'h04) begin - // store incoming ps2 mouse bytes - ps2_mouse_fifo[ps2_mouse_wptr] <= { sbuf, SPI_MOSI }; - ps2_mouse_wptr <= ps2_mouse_wptr + 1; - end - - if(cmd == 8'h05) begin - // store incoming ps2 keyboard bytes - ps2_kbd_fifo[ps2_kbd_wptr] <= { sbuf, SPI_MOSI }; - ps2_kbd_wptr <= ps2_kbd_wptr + 1; - end - - if(cmd == 8'h15) - status <= { sbuf[6:0], SPI_MOSI }; - - // send sector IO -> FPGA - if(cmd == 8'h17) begin - // flag that download begins -// sd_dout <= { sbuf, SPI_MOSI}; - sd_dout_strobe <= 1'b1; - end - - // send sector FPGA -> IO - if(cmd == 8'h18) - sd_din_strobe <= 1'b1; - - // send SD config IO -> FPGA - if(cmd == 8'h19) begin - // flag that download begins -// sd_dout <= { sbuf, SPI_MOSI}; - // sd card knows data is config if sd_dout_strobe is asserted - // with sd_ack still being inactive (low) - sd_dout_strobe <= 1'b1; - end - - // joystick analog - if(cmd == 8'h1a) begin - // first byte is joystick indes - if(byte_cnt == 1) - stick_idx <= { sbuf[1:0], SPI_MOSI }; - else if(byte_cnt == 2) begin - // second byte is x axis - if(stick_idx == 0) - joystick_analog_0[15:8] <= { sbuf, SPI_MOSI }; - else if(stick_idx == 1) - joystick_analog_1[15:8] <= { sbuf, SPI_MOSI }; - end else if(byte_cnt == 3) begin - // third byte is y axis - if(stick_idx == 0) - joystick_analog_0[7:0] <= { sbuf, SPI_MOSI }; - else if(stick_idx == 1) - joystick_analog_1[7:0] <= { sbuf, SPI_MOSI }; - end - end - - end + // finished reading a byte, prepare to transfer to clk_sys + if(bit_cnt == 7) begin + spi_byte_in <= { sbuf, SPI_MOSI}; + spi_receiver_strobe_r <= ~spi_receiver_strobe_r; end end end - + +// Process bytes from SPI at the clk_sys domain +always @(posedge clk_sys) begin + + reg spi_receiver_strobe; + reg spi_transfer_end; + reg spi_receiver_strobeD; + reg spi_transfer_endD; + reg [7:0] acmd; + reg [7:0] abyte_cnt; // counts bytes + + reg [7:0] mouse_flags_r; + reg [7:0] mouse_x_r; + + //synchronize between SPI and sys clock domains + spi_receiver_strobeD <= spi_receiver_strobe_r; + spi_receiver_strobe <= spi_receiver_strobeD; + spi_transfer_endD <= spi_transfer_end_r; + spi_transfer_end <= spi_transfer_endD; + + mouse_strobe <= 0; + + if (~spi_transfer_endD & spi_transfer_end) begin + abyte_cnt <= 8'd0; + end else if (spi_receiver_strobeD ^ spi_receiver_strobe) begin + + if(~&abyte_cnt) + abyte_cnt <= abyte_cnt + 8'd1; + + if(abyte_cnt == 0) begin + acmd <= spi_byte_in; + end else begin + case(acmd) + // buttons and switches + 8'h01: but_sw <= spi_byte_in; + 8'h60: if (abyte_cnt < 5) joystick_0[(abyte_cnt-1)<<3 +:8] <= spi_byte_in; + 8'h61: if (abyte_cnt < 5) joystick_1[(abyte_cnt-1)<<3 +:8] <= spi_byte_in; + 8'h62: if (abyte_cnt < 5) joystick_2[(abyte_cnt-1)<<3 +:8] <= spi_byte_in; + 8'h63: if (abyte_cnt < 5) joystick_3[(abyte_cnt-1)<<3 +:8] <= spi_byte_in; + 8'h64: if (abyte_cnt < 5) joystick_4[(abyte_cnt-1)<<3 +:8] <= spi_byte_in; + 8'h04: begin + // store incoming ps2 mouse bytes + ps2_mouse_fifo[ps2_mouse_wptr] <= spi_byte_in; + ps2_mouse_wptr <= ps2_mouse_wptr + 1'd1; + if (abyte_cnt == 1) mouse_flags_r <= spi_byte_in; + else if (abyte_cnt == 2) mouse_x_r <= spi_byte_in; + else if (abyte_cnt == 3) begin + mouse_flags <= mouse_flags_r; + mouse_x <= mouse_x_r; + mouse_y <= spi_byte_in; + mouse_strobe <= 1; + end + end + 8'h05: begin + // store incoming ps2 keyboard bytes + ps2_kbd_fifo[ps2_kbd_wptr] <= spi_byte_in; + ps2_kbd_wptr <= ps2_kbd_wptr + 1'd1; + end + + // joystick analog + 8'h1a: begin + // first byte is joystick index + if(abyte_cnt == 1) + stick_idx <= spi_byte_in[2:0]; + else if(abyte_cnt == 2) begin + // second byte is x axis + if(stick_idx == 0) + joystick_analog_0[15:8] <= spi_byte_in; + else if(stick_idx == 1) + joystick_analog_1[15:8] <= spi_byte_in; + end else if(abyte_cnt == 3) begin + // third byte is y axis + if(stick_idx == 0) + joystick_analog_0[7:0] <= spi_byte_in; + else if(stick_idx == 1) + joystick_analog_1[7:0] <= spi_byte_in; + end + end + + 8'h15: status <= spi_byte_in; + + // status, 32bit version + 8'h1e: if(abyte_cnt<5) status[(abyte_cnt-1)<<3 +:8] <= spi_byte_in; + + endcase + end + end +end + +// Process SD-card related bytes from SPI at the clk_sd domain +always @(posedge clk_sd) begin + + reg spi_receiver_strobe; + reg spi_transfer_end; + reg spi_receiver_strobeD; + reg spi_transfer_endD; + reg sd_wrD; + reg [7:0] acmd; + reg [7:0] abyte_cnt; // counts bytes + + //synchronize between SPI and sd clock domains + spi_receiver_strobeD <= spi_receiver_strobe_r; + spi_receiver_strobe <= spi_receiver_strobeD; + spi_transfer_endD <= spi_transfer_end_r; + spi_transfer_end <= spi_transfer_endD; + + if(sd_dout_strobe) begin + sd_dout_strobe<= 0; + if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1; + end + + sd_din_strobe<= 0; + sd_wrD <= sd_wr; + // fetch the first byte immediately after the write command seen + if (~sd_wrD & sd_wr) begin + sd_buff_addr <= 0; + sd_din_strobe <= 1; + end + + img_mounted <= 0; + + if (~spi_transfer_endD & spi_transfer_end) begin + abyte_cnt <= 8'd0; + sd_ack <= 1'b0; + sd_ack_conf <= 1'b0; + sd_dout_strobe <= 1'b0; + sd_din_strobe <= 1'b0; + sd_buff_addr <= 0; + end else if (spi_receiver_strobeD ^ spi_receiver_strobe) begin + + if(~&abyte_cnt) + abyte_cnt <= abyte_cnt + 8'd1; + + if(abyte_cnt == 0) begin + acmd <= spi_byte_in; + + if(spi_byte_in == 8'h18) begin + sd_din_strobe <= 1'b1; + if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1; + end + + if((spi_byte_in == 8'h17) || (spi_byte_in == 8'h18)) + sd_ack <= 1'b1; + + end else begin + case(acmd) + + // send sector IO -> FPGA + 8'h17: begin + // flag that download begins + sd_dout_strobe <= 1'b1; + sd_dout <= spi_byte_in; + end + + // send sector FPGA -> IO + 8'h18: begin + sd_din_strobe <= 1'b1; + if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1; + end + + // send SD config IO -> FPGA + 8'h19: begin + // flag that download begins + sd_dout_strobe <= 1'b1; + sd_ack_conf <= 1'b1; + sd_dout <= spi_byte_in; + end + + 8'h1c: img_mounted <= 1; + + // send image info + 8'h1d: if(abyte_cnt<5) img_size[(abyte_cnt-1)<<3 +:8] <= spi_byte_in; + endcase + end + end +end + endmodule