diff --git a/.gitignore b/.gitignore index 7713507..912a071 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,14 @@ out/ +db/ +incremental_db/ +greybox_tmp PLLJ_PLLSPE_INFO.txt *.qws +*.bak +*.jdi +*.sof +*.done +*.pin +*.rpt +*.smsg +*.summary diff --git a/cores/bbc/fpga/mist/bbc_mist.sdc b/cores/bbc/fpga/mist/bbc_mist.sdc index 2252a6b..855259c 100644 --- a/cores/bbc/fpga/mist/bbc_mist.sdc +++ b/cores/bbc/fpga/mist/bbc_mist.sdc @@ -40,6 +40,9 @@ set_clock_groups -asynchronous -group [get_clocks {SPI_SCK}] -group [get_clocks set_output_delay -clock [get_clocks {CLOCKS|altpll_component|auto_generated|pll1|clk[0]}] -max 0 [get_ports {VGA_*}] set_output_delay -clock [get_clocks {CLOCKS|altpll_component|auto_generated|pll1|clk[0]}] -min -5 [get_ports {VGA_*}] +set_multicycle_path -to {VGA_*[*]} -setup 2 +set_multicycle_path -to {VGA_*[*]} -hold 1 + # SDRAM delays set_input_delay -clock [get_clocks {CLOCKS|altpll_component|auto_generated|pll1|clk[0]}] -max 6.4 [get_ports SDRAM_DQ[*]] set_input_delay -clock [get_clocks {CLOCKS|altpll_component|auto_generated|pll1|clk[0]}] -min 3.2 [get_ports SDRAM_DQ[*]] diff --git a/cores/bbc/fpga/mist/bbc_mist_top.qsf b/cores/bbc/fpga/mist/bbc_mist_top.qsf index 8a251ba..f0905ab 100644 --- a/cores/bbc/fpga/mist/bbc_mist_top.qsf +++ b/cores/bbc/fpga/mist/bbc_mist_top.qsf @@ -157,20 +157,29 @@ set_global_assignment -name ALLOW_POWER_UP_DONT_CARE OFF set_location_assignment PIN_7 -to LED set_global_assignment -name ADV_NETLIST_OPT_SYNTH_WYSIWYG_REMAP ON -set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "2.5 V" +set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "3.3-V LVTTL" -set_global_assignment -name VERILOG_FILE ../../rtl/adc.v +set_global_assignment -name VERILOG_FILE bbc_mist_top.v set_global_assignment -name VERILOG_FILE sdram.v +set_global_assignment -name VERILOG_FILE sd_card.v +set_global_assignment -name VERILOG_FILE user_io.v +set_global_assignment -name VERILOG_FILE osd.v +set_global_assignment -name VERILOG_FILE data_io.v +set_global_assignment -name VERILOG_FILE clockgen.v +set_global_assignment -name VERILOG_FILE ../rtl/sigma_delta_dac.v +set_global_assignment -name VERILOG_FILE ../rtl/audio.v +set_global_assignment -name VERILOG_FILE ../rtl/scandoubler.v +set_global_assignment -name VERILOG_FILE ../../rtl/adc.v set_global_assignment -name VERILOG_FILE ../../rtl/mc6845.v set_global_assignment -name VERILOG_FILE ../../rtl/ps2_intf.v set_global_assignment -name VERILOG_FILE ../../rtl/vidproc.v set_global_assignment -name VERILOG_FILE ../../rtl/keyboard.v -set_global_assignment -name VERILOG_FILE ../rtl/sigma_delta_dac.v -set_global_assignment -name VERILOG_FILE ../rtl/audio.v -set_global_assignment -name VERILOG_FILE ../../rtl/saa5050/saa5050_rom.v -set_global_assignment -name VERILOG_FILE ../../rtl/saa5050/saa5050.v set_global_assignment -name VERILOG_FILE ../../rtl/clocks.v set_global_assignment -name VERILOG_FILE ../../rtl/address_decode.v +set_global_assignment -name VERILOG_FILE ../../rtl/bbc.v +set_global_assignment -name VHDL_FILE ../../rtl/m6522.vhd +set_global_assignment -name VERILOG_FILE ../../rtl/saa5050/saa5050_rom.v +set_global_assignment -name VERILOG_FILE ../../rtl/saa5050/saa5050.v set_global_assignment -name VHDL_FILE "../../rtl/sn76489-1.0/sn76489_top-c.vhd" set_global_assignment -name VHDL_FILE "../../rtl/sn76489-1.0/sn76489_top.vhd" set_global_assignment -name VHDL_FILE "../../rtl/sn76489-1.0/sn76489_tone-c.vhd" @@ -184,19 +193,16 @@ set_global_assignment -name VHDL_FILE "../../rtl/sn76489-1.0/sn76489_clock_div-c set_global_assignment -name VHDL_FILE "../../rtl/sn76489-1.0/sn76489_clock_div.vhd" set_global_assignment -name VHDL_FILE "../../rtl/sn76489-1.0/sn76489_attenuator-c.vhd" set_global_assignment -name VHDL_FILE "../../rtl/sn76489-1.0/sn76489_attenuator.vhd" -set_global_assignment -name VERILOG_FILE sd_card.v -set_global_assignment -name VERILOG_FILE user_io.v -set_global_assignment -name VERILOG_FILE osd.v -set_global_assignment -name VERILOG_FILE data_io.v -set_global_assignment -name VERILOG_FILE clockgen.v -set_global_assignment -name VERILOG_FILE ../rtl/scandoubler.v -set_global_assignment -name VERILOG_FILE ../../rtl/bbc.v -set_global_assignment -name CDF_FILE output_files/Chain4.cdf -set_global_assignment -name VHDL_FILE ../../rtl/m6522.vhd set_global_assignment -name QIP_FILE ../../rtl/T65/T65.qip set_global_assignment -name QIP_FILE mmfs.qip set_global_assignment -name QIP_FILE os12.qip set_global_assignment -name QIP_FILE basic2.qip set_global_assignment -name QIP_FILE dfs09.qip set_global_assignment -name SDC_FILE bbc_mist.sdc +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_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file diff --git a/cores/bbc/fpga/mist/bbc_mist_top.v b/cores/bbc/fpga/mist/bbc_mist_top.v index 0b1f7fe..7f6b20a 100755 --- a/cores/bbc/fpga/mist/bbc_mist_top.v +++ b/cores/bbc/fpga/mist/bbc_mist_top.v @@ -92,10 +92,6 @@ wire [1:0] switches; wire ps2_clk; wire ps2_dat; -// ~14khz clock generation -reg [10:0] clk_14k_div; -wire clk_14k = clk_14k_div[10] /* synthesis keep */; - // the top file should generate the correct clocks for the machine assign SDRAM_CLK = !clk_32m; @@ -112,19 +108,20 @@ reg clk_12m; always @(posedge clk_24m) clk_12m <= !clk_12m; -wire clk_osd = scandoubler_disable?clk_12m:clk_24m; +wire ce_pix = scandoubler_disable?clk_12m:1'd1; osd #(0,0,4) OSD ( - .pclk ( clk_osd ), + .clk_sys ( clk_24m ), + .ce_pix ( ce_pix ), // spi for OSD .sdi ( SPI_DI ), .sck ( SPI_SCK ), .ss ( SPI_SS3 ), - .red_in ( video_r ), - .green_in ( video_g ), - .blue_in ( video_b ), + .red_in ( scandoubler_disable? {5{video_r[0]}} : {3{video_r}} ), + .green_in ( scandoubler_disable? {5{video_g[0]}} : {3{video_g}} ), + .blue_in ( scandoubler_disable? {5{video_b[0]}} : {3{video_b}} ), .hs_in ( video_hs ), .vs_in ( video_vs ), @@ -133,9 +130,7 @@ osd #(0,0,4) OSD ( .green_out ( VGA_G ), .blue_out ( VGA_B ), .hs_out ( v_hs ), - .vs_out ( v_vs ), - - .tv15khz ( scandoubler_disable ) + .vs_out ( v_vs ) ); wire v_hs, v_vs; @@ -159,6 +154,8 @@ wire [7:0] sd_din; wire sd_din_strobe; wire [8:0] sd_buff_addr; wire sd_ack_conf; +wire img_mounted; +wire [31:0] img_size; wire [7:0] joystick_0; wire [7:0] joystick_1; @@ -168,14 +165,15 @@ wire [15:0] joystick_analog_1; wire scandoubler_disable; user_io #(.STRLEN(CONF_STR_LEN)) user_io( - .conf_str ( CONF_STR ), + .conf_str ( CONF_STR ), .clk_sys(clk_32m), + .clk_sd(clk_32m), - // the spi interface - .SPI_CLK ( SPI_SCK ), - .SPI_SS_IO ( CONF_DATA0 ), - .SPI_MISO ( SPI_DO ), // tristate handling inside user_io - .SPI_MOSI ( SPI_DI ), + // the spi interface + .SPI_CLK ( SPI_SCK ), + .SPI_SS_IO ( CONF_DATA0 ), + .SPI_MISO ( SPI_DO ), // tristate handling inside user_io + .SPI_MOSI ( SPI_DI ), // use mist joystick 1 as bbc primary joystick .joystick_0 ( joystick_1 ), @@ -183,28 +181,30 @@ user_io #(.STRLEN(CONF_STR_LEN)) user_io( .joystick_analog_0 ( joystick_analog_1 ), .joystick_analog_1 ( joystick_analog_0 ), - .status ( status ), + .status ( status ), .switches ( switches ), - .buttons ( buttons ), + .buttons ( buttons ), .scandoubler_disable ( scandoubler_disable ), // interface to embedded legacy sd card wrapper - .sd_lba ( sd_lba ), - .sd_rd ( sd_rd ), - .sd_wr ( sd_wr ), - .sd_ack ( sd_ack ), - .sd_conf ( sd_conf ), - .sd_sdhc ( sd_sdhc ), - .sd_dout ( sd_dout ), - .sd_dout_strobe(sd_dout_strobe ), - .sd_din ( sd_din ), - .sd_din_strobe (sd_din_strobe ), - .sd_buff_addr (sd_buff_addr ), - .sd_ack_conf (sd_ack_conf ), + .sd_lba ( sd_lba ), + .sd_rd ( sd_rd ), + .sd_wr ( sd_wr ), + .sd_ack ( sd_ack ), + .sd_conf ( sd_conf ), + .sd_sdhc ( sd_sdhc ), + .sd_dout ( sd_dout ), + .sd_dout_strobe ( sd_dout_strobe), + .sd_din ( sd_din ), + .sd_din_strobe ( sd_din_strobe ), + .sd_buff_addr ( sd_buff_addr ), + .sd_ack_conf ( sd_ack_conf ), - .ps2_clk ( clk_14k ), - .ps2_kbd_clk ( ps2_clk ), - .ps2_kbd_data ( ps2_dat ) + .img_mounted ( img_mounted ), + .img_size ( img_size ), + + .ps2_kbd_clk ( ps2_clk ), + .ps2_kbd_data ( ps2_dat ) ); // wire the sd card to the user port @@ -215,20 +215,21 @@ wire sd_sdo; sd_card sd_card ( // connection to io controller - .clk(clk_32m), - .io_lba (sd_lba ), - .io_rd (sd_rd), - .io_wr (sd_wr), - .io_ack (sd_ack), - .io_ack_conf (sd_ack_conf ), - .io_conf (sd_conf), - .io_sdhc (sd_sdhc), - .io_din (sd_dout), - .io_din_strobe (sd_dout_strobe), - .io_dout (sd_din), - .io_dout_strobe ( sd_din_strobe), - .io_buff_addr (sd_buff_addr ), - .allow_sdhc ( 1'b1), // SDHC not supported + .clk_sys(clk_32m), + .sd_lba (sd_lba ), + .sd_rd (sd_rd), + .sd_wr (sd_wr), + .sd_ack (sd_ack), + .sd_ack_conf (sd_ack_conf ), + .sd_conf (sd_conf), + .sd_sdhc (sd_sdhc), + .sd_buff_dout (sd_dout), + .sd_buff_wr (sd_dout_strobe), + .sd_buff_din (sd_din), + .sd_buff_addr (sd_buff_addr ), + .img_mounted (img_mounted), + .img_size (img_size), + .allow_sdhc ( 1'b1), // connection to local CPU .sd_cs ( sd_cs ), @@ -457,9 +458,6 @@ wire [1:0] video_b = scandoubler_disable?core_b:sd_b; wire video_hs = scandoubler_disable?core_hs:sd_hs; wire video_vs = scandoubler_disable?core_vs:sd_vs; -always @(posedge clk_32m) - clk_14k_div <= clk_14k_div + 'd1; - // map 64k sideways ram to bank 4,5,6 and 7 wire sideways_ram = (mem_adr[15:14] == 2'b10) && (mem_romsel[3:2] == 2'b01); diff --git a/cores/bbc/fpga/mist/osd.v b/cores/bbc/fpga/mist/osd.v old mode 100755 new mode 100644 index f851698..460fb0d --- a/cores/bbc/fpga/mist/osd.v +++ b/cores/bbc/fpga/mist/osd.v @@ -1,214 +1,209 @@ -// -// osd.v -// -// On Screen Display implementation for the MiST board -// http://code.google.com/p/mist-board/ -// -// Copyright (c) 2013 Till Harbaum -// -// 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 -// by the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This source file is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - - -// A simple OSD implementation. Can be hooked up between a cores -// VGA output and the physical VGA pins - -module osd ( - // OSDs pixel clock, should be synchronous to cores pixel clock to - // avoid jitter. - input pclk, - - // SPI interface - input sck, - input ss, - input sdi, - - // VGA signals coming from core - input [1:0] red_in, - input [1:0] green_in, - input [1:0] blue_in, - input hs_in, - input vs_in, - - // 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, - - input tv15khz -); - -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; - -// ********************************************************************************* -// spi client -// ********************************************************************************* - -// 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 = 1'b0; - -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}; - - // 0:7 is command, rest payload - if(cnt < 15) - cnt <= cnt + 4'd1; - else - cnt <= 5'd8; - - if(cnt == 7) begin - cmd <= {sbuf[6:0], sdi}; - - // lower three command bits are line address - bcnt <= { sbuf[1:0], sdi, 8'h00}; - - // command 0x40: OSDCMDENABLE, OSDCMDDISABLE - if(sbuf[6:3] == 4'b0100) - osd_enable <= sdi; - end - - // 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 -end - -// ********************************************************************************* -// video timing and sync polarity anaylsis -// ********************************************************************************* - -// 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 - -// vertical counter -reg [10:0] v_cnt; -reg vsD, vsD2; -reg [10:0] vs_low, vs_high; -wire vs_pol = vs_high < vs_low; -wire [10:0] v_dsp_width = vs_pol?vs_low:vs_high; -wire [10:0] v_dsp_ctr = { 1'b0, v_dsp_width[10:1] }; - -always @(posedge hs_in) begin - // bring vsync into local clock domain - vsD <= vs_in; - vsD2 <= vsD; - - // falling edge of vs_in - if(!vsD && vsD2) begin - v_cnt <= 'd0; - vs_high <= v_cnt; - end - - // rising edge of vs_in - else if(vsD && !vsD2) begin - v_cnt <= 'd0; - vs_low <= v_cnt; - end - - else - v_cnt <= v_cnt + 10'd1; -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 [10:0] v_osd_start = v_dsp_ctr + OSD_Y_OFFSET - (OSD_HEIGHT >> 1); -wire [10:0] v_osd_end = v_dsp_ctr + OSD_Y_OFFSET + (OSD_HEIGHT >> 1) - 1; - -reg h_osd_active, v_osd_active; -always @(posedge pclk) begin - if(hs_in != hs_pol) begin - if(h_cnt == h_osd_start) h_osd_active <= 1'b1; - if(h_cnt == h_osd_end) h_osd_active <= 1'b0; - end - if(vs_in != vs_pol) begin - if(v_cnt == v_osd_start) v_osd_active <= 1'b1; - if(v_cnt == v_osd_end) v_osd_active <= 1'b0; - end -end - -wire osd_de = osd_enable && h_osd_active && v_osd_active; - -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[osd_vcnt[3:1]]; - -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; - -// RGB 15khz output is different to fix dull colours, VGA not affected. -// BBC only uses one bit per colour but video engine uses a 2-bit vector, MSB is only used. -// BBC has a fixed palette of 8 colours. -wire [5:0] r_in = tv15khz? {5{red_in[0]}} : {3{red_in}}; -wire [5:0] g_in = tv15khz? {5{green_in[0]}} : {3{green_in}}; -wire [5:0] b_in = tv15khz? {5{blue_in[0]}} : {3{blue_in}}; - -assign red_out = !osd_de? r_in : {osd_pixel, osd_pixel, osd_color[2], {red_in, red_in[1]} }; -assign green_out = !osd_de? g_in : {osd_pixel, osd_pixel, osd_color[1], {green_in, green_in[1]} }; -assign blue_out = !osd_de? b_in : {osd_pixel, osd_pixel, osd_color[0], {blue_in, blue_in[1]} }; - -assign hs_out = hs_in; -assign vs_out = vs_in; - -endmodule +// +// osd.v +// +// A simple OSD implementation. Can be hooked up between a cores +// VGA output and the physical VGA pins +// +// Sinclair QL for the MiST +// https://github.com/mist-devel +// +// Copyright (c) 2015 Till Harbaum +// +// 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 +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This source file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +module osd ( + // OSDs pixel clock, should be synchronous to cores pixel clock to + // avoid jitter. + input clk_sys, + input ce_pix, + + // SPI interface + input sck, + input ss, + input sdi, + + // 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, + + // 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 +); + +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; + +// ********************************************************************************* +// spi client +// ********************************************************************************* + +// 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 + +// 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}; + + // 0:7 is command, rest payload + if(cnt < 15) + cnt <= cnt + 4'd1; + else + cnt <= 4'd8; + + if(cnt == 7) begin + cmd <= {sbuf[6:0], sdi}; + + // lower three command bits are line address + bcnt <= { sbuf[1:0], sdi, 8'h00}; + + // command 0x40: OSDCMDENABLE, OSDCMDDISABLE + if(sbuf[6:3] == 4'b0100) + osd_enable <= sdi; + end + + // 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 +end + +// ********************************************************************************* +// video timing and sync polarity anaylsis +// ********************************************************************************* + +// horizontal counter +reg [9:0] h_cnt; +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 clk_sys) begin + reg hsD; + + if (ce_pix) begin + hsD <= hs_in; + + // falling edge of hs_in + if(!hs_in && hsD) begin + h_cnt <= 10'd0; + hs_high <= h_cnt; + end + + // rising edge of hs_in + else if(hs_in && !hsD) begin + h_cnt <= 10'd0; + hs_low <= h_cnt; + end + + else + h_cnt <= h_cnt + 10'd1; + end +end + +// vertical counter +reg [9:0] v_cnt; +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] }; + +always @(posedge clk_sys) begin + reg hsD, vsD; + + hsD <= hs_in; + + if (~hsD & hs_in) begin + vsD <= vs_in; + + // falling edge of vs_in + if(!vs_in && vsD) begin + v_cnt <= 10'd0; + vs_high <= v_cnt; + end + + // rising edge of vs_in + else if(vs_in && !vsD) begin + v_cnt <= 10'd0; + vs_low <= v_cnt; + end + + else + v_cnt <= v_cnt + 10'd1; + 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; + +reg h_osd_active, v_osd_active; +always @(posedge clk_sys) begin + if(hs_in != hs_pol) begin + if(h_cnt == h_osd_start) h_osd_active <= 1'b1; + if(h_cnt == h_osd_end) h_osd_active <= 1'b0; + end + if(vs_in != vs_pol) begin + if(v_cnt == v_osd_start) v_osd_active <= 1'b1; + if(v_cnt == v_osd_end) v_osd_active <= 1'b0; + end +end + +wire osd_de = osd_enable && h_osd_active && v_osd_active; + +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[osd_vcnt[3:1]]; + +reg [7:0] osd_byte; +always @(posedge clk_sys) + if (ce_pix) 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 diff --git a/cores/bbc/fpga/mist/sd_card.v b/cores/bbc/fpga/mist/sd_card.v index fa7ef95..dfd97de 100644 --- a/cores/bbc/fpga/mist/sd_card.v +++ b/cores/bbc/fpga/mist/sd_card.v @@ -1,4 +1,4 @@ -// +// // sd_card.v // // This file implelents a sd card for the MIST board since on the board @@ -25,58 +25,41 @@ // http://elm-chan.org/docs/mmc/mmc_e.html module sd_card ( - input clk, - // link to user_io for io controller - output [31:0] io_lba, - output reg io_rd, - output reg io_wr, - input io_ack, - input io_ack_conf, - output io_conf, - output io_sdhc, + input clk_sys, + // link to user_io for io controller + output [31:0] sd_lba, + output reg sd_rd, + output reg sd_wr, + input sd_ack, + input sd_ack_conf, + output sd_conf, + output sd_sdhc, - // data coming in from io controller - input [7:0] io_din, - input io_din_strobe, + input img_mounted, + input [31:0] img_size, - // data going out to io controller - output [7:0] io_dout, - input io_dout_strobe, + output reg sd_busy = 0, + // data coming in from io controller + input [7:0] sd_buff_dout, + input sd_buff_wr, - input [8:0] io_buff_addr, + // data going out to io controller + output [7:0] sd_buff_din, - // configuration input - input allow_sdhc, + input [8:0] sd_buff_addr, - input sd_cs, - input sd_sck, - input sd_sdi, - output reg sd_sdo -); + // configuration input + input allow_sdhc, -// set io_rd once read_state machine starts waiting (rising edge of req_io_rd) -// and clear it once io controller uploads something (io_ack==1) -reg req_io_rd = 1'b0; // set when write_state is changed to RD_STATE_WAIT_IO + input sd_cs, + input sd_sck, + input sd_sdi, + output reg sd_sdo +); -reg req_io_wr = 1'b0; // set when write_state is changed to WR_STATE_BUSY - -always @(posedge clk) begin - reg old_io_ack; - reg req_io_rdD; - reg req_io_wrD; - - old_io_ack <= io_ack; - req_io_rdD <= req_io_rd; - req_io_wrD <= req_io_wr; - - if(~old_io_ack & io_ack) { io_rd, io_wr } <= 2'b00; - else begin - if (~req_io_rdD & req_io_rd) io_rd <= 1; - if (~req_io_wrD & req_io_wr) io_wr <= 1; - end -end - -wire [31:0] OCR = { 1'b0, io_sdhc, 30'h0 }; // bit30 = 1 -> high capaciry card (sdhc) +wire [31:0] OCR = { 1'b1, sd_sdhc, 6'h0, 9'h1f, 15'h0 }; // bit31 = finished powerup + // bit30 = 1 -> high capaciry card (sdhc) + // 15-23 supported voltage range wire [7:0] READ_DATA_TOKEN = 8'hfe; // number of bytes to wait after a command before sending the reply @@ -86,7 +69,7 @@ localparam RD_STATE_IDLE = 2'd0; localparam RD_STATE_WAIT_IO = 2'd1; localparam RD_STATE_SEND_TOKEN = 2'd2; localparam RD_STATE_SEND_DATA = 2'd3; -reg [1:0] read_state = RD_STATE_IDLE; +reg [1:0] read_state = RD_STATE_IDLE; localparam WR_STATE_IDLE = 3'd0; localparam WR_STATE_EXP_DTOKEN = 3'd1; @@ -95,46 +78,22 @@ localparam WR_STATE_RECV_CRC0 = 3'd3; localparam WR_STATE_RECV_CRC1 = 3'd4; localparam WR_STATE_SEND_DRESP = 3'd5; localparam WR_STATE_BUSY = 3'd6; -reg [2:0] write_state = WR_STATE_IDLE; +reg [2:0] write_state = WR_STATE_IDLE; reg card_is_reset = 1'b0; // flag that card has received a reset command -reg [6:0] sbuf; +reg [6:0] sbuf; reg cmd55; reg [7:0] cmd = 8'h00; reg [2:0] bit_cnt = 3'd0; // counts bits 0-7 0-7 ... reg [3:0] byte_cnt= 4'd15; // counts bytes -reg [31:0] lba; -assign io_lba = io_sdhc?lba:{9'd0, lba[31:9]}; +reg [39:0] args; +assign sd_lba = sd_sdhc?args[39:8]:{9'd0, args[39:17]}; reg [7:0] reply; reg [7:0] reply0, reply1, reply2, reply3; reg [3:0] reply_len; -// falling edge of io_ack signals that a sector to be read has been written into -// the sector buffer by the io controller. This signal is kept set as long -// as the read state machine is in the "wait for io controller" state (state 1) -wire rd_wait_io = (read_state != RD_STATE_IDLE); -reg rd_io_ack = 1'b0; - -wire wr_wait_io = (write_state == WR_STATE_BUSY); -reg wr_io_ack = 1'b0; - -always @(posedge clk) begin - reg old_io_ack; - old_io_ack <= io_ack; - - if(!wr_wait_io) wr_io_ack <= 1'b0; - else if (~io_ack & old_io_ack) begin - wr_io_ack <= 1'b1; - end - - if(!rd_wait_io) rd_io_ack <= 1'b0; - else if (~io_ack & old_io_ack) begin - rd_io_ack <= 1'b1; - end -end - // ------------------------- SECTOR BUFFER ----------------------- // the buffer itself. Can hold one sector @@ -145,357 +104,364 @@ reg buffer_write_strobe; sd_card_dpram #(8, 9) buffer_dpram ( - .clock_a (clk), - .address_a (io_buff_addr), - .data_a (io_din), - .wren_a (io_din_strobe & io_ack), - .q_a (io_dout), + .clock_a (clk_sys), + .address_a (sd_buff_addr), + .data_a (sd_buff_dout), + .wren_a (sd_buff_wr & sd_ack), + .q_a (sd_buff_din), - .clock_b (clk), - .address_b (buffer_ptr), - .data_b (buffer_din), - .wren_b (buffer_write_strobe), - .q_b (buffer_dout) + .clock_b (clk_sys), + .address_b (buffer_ptr), + .data_b (buffer_din), + .wren_b (buffer_write_strobe), + .q_b (buffer_dout) ); wire [7:0] WRITE_DATA_RESPONSE = 8'h05; // ------------------------- CSD/CID BUFFER ---------------------- reg [7:0] conf; -assign io_conf = io_configuring; +assign sd_conf = sd_configuring; -reg io_configuring = 1; +reg sd_configuring = 1; reg [4:0] conf_buff_ptr; -wire [7:0] conf_byte; - -sd_card_dpram #(8, 6) conf_dpram -( - .clock_a (clk), - .address_a (io_buff_addr), - .data_a (io_din), - .wren_a (io_din_strobe & io_ack_conf), - - .clock_b (clk), - .address_b (conf_buff_ptr), - .q_b (conf_byte) -); +reg [7:0] conf_byte; +reg[255:0] csdcid; // conf[0]==1 -> io controller is using an sdhc card -wire io_has_sdhc = conf[0]; -assign io_sdhc = allow_sdhc && io_has_sdhc; +wire sd_has_sdhc = conf[0]; +assign sd_sdhc = allow_sdhc && sd_has_sdhc; -always @(posedge clk) begin - if(io_din_strobe && io_ack_conf && io_buff_addr== 32) begin - conf <= io_din; - io_configuring <= 0; - end +always @(posedge clk_sys) begin + reg old_mounted; + + if (sd_buff_wr & sd_ack_conf) begin + if (sd_buff_addr == 32) begin + conf <= sd_buff_dout; + sd_configuring <= 0; + end + else csdcid[(31-sd_buff_addr) << 3 +:8] <= sd_buff_dout; + end + conf_byte <= csdcid[(31-conf_buff_ptr) << 3 +:8]; + + old_mounted <= img_mounted; + if (~old_mounted & img_mounted) begin + // update card size in case of a virtual SD image + if (sd_sdhc) + // CSD V1.0 size = (c_size + 1) * 512K + csdcid[69:48] <= {9'd0, img_size[31:19] }; + else begin + // CSD V2.0 no. of blocks = c_size ** (c_size_mult + 2) + csdcid[49:47] <= 3'd7; //c_size_mult + csdcid[73:62] <= img_size[29:18]; //c_size + end + end end -always@(posedge clk) begin +always@(posedge clk_sys) begin - reg illegal_write_state /* synthesis noprune */; - reg old_sd_sck; - old_sd_sck <= sd_sck; -// advance transmitter state machine on falling sck edge, so data is valid on the -// rising edge -// ----------------- spi transmitter -------------------- - if(sd_cs == 0 && old_sd_sck && ~sd_sck) begin + reg old_sd_sck; + reg [5:0] ack; - sd_sdo <= 1'b1; // default: send 1's (busy/wait) - req_io_rd <= 1'b0; - - if(byte_cnt == 5+NCR) begin - sd_sdo <= reply[~bit_cnt]; + ack <= {ack[4:0], sd_ack}; + if(ack[5:4] == 'b01) { sd_rd, sd_wr } <= 2'b00; + if(ack[5:4] == 'b10) sd_busy <= 0; - if(bit_cnt == 7) begin - // these three commands all have a reply_len of 0 and will thus - // not send more than a single reply byte - - // CMD9: SEND_CSD - // CMD10: SEND_CID - if((cmd == 8'h49)||(cmd == 8'h4a)) - read_state <= RD_STATE_SEND_TOKEN; // jump directly to data transmission - - // CMD17: READ_SINGLE_BLOCK - if(cmd == 8'h51) begin - read_state <= RD_STATE_WAIT_IO; // start waiting for data from io controller - req_io_rd <= 1'b1; // trigger request to io controller - end - end - end - else if((reply_len > 0) && (byte_cnt == 5+NCR+1)) - sd_sdo <= reply0[~bit_cnt]; - else if((reply_len > 1) && (byte_cnt == 5+NCR+2)) - sd_sdo <= reply1[~bit_cnt]; - else if((reply_len > 2) && (byte_cnt == 5+NCR+3)) - sd_sdo <= reply2[~bit_cnt]; - else if((reply_len > 3) && (byte_cnt == 5+NCR+4)) - sd_sdo <= reply3[~bit_cnt]; - else - sd_sdo <= 1'b1; + buffer_write_strobe <= 0; + if (buffer_write_strobe) buffer_ptr <= buffer_ptr + 1'd1; - // ---------- read state machine processing ------------- + old_sd_sck <= sd_sck; + // advance transmitter state machine on falling sck edge, so data is valid on the + // rising edge + // ----------------- spi transmitter -------------------- + if(sd_cs == 0 && old_sd_sck && ~sd_sck) begin - case(read_state) - RD_STATE_IDLE: ; - // don't do anything + sd_sdo <= 1'b1; // default: send 1's (busy/wait) - // waiting for io controller to return data - RD_STATE_WAIT_IO: begin - buffer_ptr <= 0; - if(rd_io_ack && (bit_cnt == 7)) - read_state <= RD_STATE_SEND_TOKEN; + if(byte_cnt == 5+NCR) begin + sd_sdo <= reply[~bit_cnt]; - end + if(bit_cnt == 7) begin + // these three commands all have a reply_len of 0 and will thus + // not send more than a single reply byte - // send data token - RD_STATE_SEND_TOKEN: begin - sd_sdo <= READ_DATA_TOKEN[~bit_cnt]; - - if(bit_cnt == 7) begin - read_state <= RD_STATE_SEND_DATA; // next: send data - conf_buff_ptr <= (cmd == 8'h4a) ? 5'h0 : 5'h10; - end - end - - // send data - RD_STATE_SEND_DATA: begin - if(cmd == 8'h51) // CMD17: READ_SINGLE_BLOCK - sd_sdo <= buffer_dout[~bit_cnt]; - else if(cmd == 8'h49) // CMD9: SEND_CSD - sd_sdo <= conf_byte[~bit_cnt]; - else if(cmd == 8'h4a) // CMD10: SEND_CID - sd_sdo <= conf_byte[~bit_cnt]; - else - sd_sdo <= 1'b1; + // CMD9: SEND_CSD + // CMD10: SEND_CID + if((cmd == 8'h49)||(cmd == 8'h4a)) + read_state <= RD_STATE_SEND_TOKEN; // jump directly to data transmission - if(bit_cnt == 7) begin - // sent 512 sector data bytes? - if((cmd == 8'h51) && &buffer_ptr) // (buffer_ptr ==511)) - read_state <= RD_STATE_IDLE; // next: send crc. It's ignored so return to idle state + // CMD17: READ_SINGLE_BLOCK + if(cmd == 8'h51) begin + read_state <= RD_STATE_WAIT_IO; // start waiting for data from io controller + sd_rd <= 1; // trigger request to io controller + sd_busy <= 1; + end + end + end + else if((reply_len > 0) && (byte_cnt == 5+NCR+1)) + sd_sdo <= reply0[~bit_cnt]; + else if((reply_len > 1) && (byte_cnt == 5+NCR+2)) + sd_sdo <= reply1[~bit_cnt]; + else if((reply_len > 2) && (byte_cnt == 5+NCR+3)) + sd_sdo <= reply2[~bit_cnt]; + else if((reply_len > 3) && (byte_cnt == 5+NCR+4)) + sd_sdo <= reply3[~bit_cnt]; + else + sd_sdo <= 1'b1; - // sent 16 cid/csd data bytes? - else if(((cmd == 8'h49)||(cmd == 8'h4a)) && conf_buff_ptr[3:0] == 4'h0f) // && (buffer_rptr == 16)) - read_state <= RD_STATE_IDLE; // return to idle state + // ---------- read state machine processing ------------- - else begin - buffer_ptr <= buffer_ptr + 1'd1; - conf_buff_ptr<= conf_buff_ptr+ 1'd1; - end - end - end - endcase + case(read_state) + RD_STATE_IDLE: ; + // don't do anything - // ------------------ write support ---------------------- - // send write data response - if(write_state == WR_STATE_SEND_DRESP) - sd_sdo <= WRITE_DATA_RESPONSE[~bit_cnt]; - - // busy after write until the io controller sends ack - if(write_state == WR_STATE_BUSY) - sd_sdo <= 1'b0; - end + // waiting for io controller to return data + RD_STATE_WAIT_IO: begin + buffer_ptr <= 0; + if(~sd_busy && (bit_cnt == 7)) + read_state <= RD_STATE_SEND_TOKEN; + end - if (buffer_write_strobe) begin - buffer_write_strobe <= 1'b0; - buffer_ptr <= buffer_ptr + 1'd1; - end + // send data token + RD_STATE_SEND_TOKEN: begin + sd_sdo <= READ_DATA_TOKEN[~bit_cnt]; - // spi receiver - // cs is active low - if(sd_cs == 1) begin - bit_cnt <= 3'd0; - end else if (~old_sd_sck & sd_sck) begin - illegal_write_state <= 1'b0; - req_io_wr <= 1'b0; - bit_cnt <= bit_cnt + 3'd1; - - // assemble byte - if(bit_cnt != 7) - sbuf[6:0] <= { sbuf[5:0], sd_sdi }; - else begin - // finished reading one byte - // byte counter runs against 15 byte boundary - if(byte_cnt != 15) - byte_cnt <= byte_cnt + 4'd1; + if(bit_cnt == 7) begin + read_state <= RD_STATE_SEND_DATA; // next: send data + conf_buff_ptr <= (cmd == 8'h4a) ? 5'h0 : 5'h10; + end + end - // byte_cnt > 6 -> complete command received - // first byte of valid command is 01xxxxxx - // don't accept new commands once a write or read command has been accepted - if((byte_cnt > 5) && (write_state == WR_STATE_IDLE) && - (read_state == RD_STATE_IDLE) && sbuf[6:5] == 2'b01) begin - byte_cnt <= 4'd0; - cmd <= { sbuf, sd_sdi}; + // send data + RD_STATE_SEND_DATA: begin + if(cmd == 8'h51) // CMD17: READ_SINGLE_BLOCK + sd_sdo <= buffer_dout[~bit_cnt]; + else if(cmd == 8'h49) begin // CMD9: SEND_CSD + sd_sdo <= conf_byte[~bit_cnt]; + end + else if(cmd == 8'h4a) // CMD10: SEND_CID + sd_sdo <= conf_byte[~bit_cnt]; + else + sd_sdo <= 1'b1; - // set cmd55 flag if previous command was 55 - cmd55 <= (cmd == 8'h77); - end + if(bit_cnt == 7) begin + // sent 512 sector data bytes? + if((cmd == 8'h51) && &buffer_ptr) // (buffer_ptr ==511)) + read_state <= RD_STATE_IDLE; // next: send crc. It's ignored so return to idle state - // parse additional command bytes - if(byte_cnt == 0) lba[31:24] <= { sbuf, sd_sdi}; - if(byte_cnt == 1) lba[23:16] <= { sbuf, sd_sdi}; - if(byte_cnt == 2) lba[15:8] <= { sbuf, sd_sdi}; - if(byte_cnt == 3) lba[7:0] <= { sbuf, sd_sdi}; + // sent 16 cid/csd data bytes? + else if(((cmd == 8'h49)||(cmd == 8'h4a)) && conf_buff_ptr[3:0] == 4'h0f) // && (buffer_rptr == 16)) + read_state <= RD_STATE_IDLE; // return to idle state - // last byte received, evaluate - if(byte_cnt == 4) begin - - // default: - reply <= 8'h04; // illegal command - reply_len <= 4'd0; // no extra reply bytes - - // CMD0: GO_IDLE_STATE - if(cmd == 8'h40) begin - card_is_reset <= 1'b1; - reply <= 8'h01; // ok, busy - end + else begin + buffer_ptr <= buffer_ptr + 1'd1; + conf_buff_ptr<= conf_buff_ptr+ 1'd1; + end + end + end + endcase - // every other command is only accepted after a reset - else if(card_is_reset) begin - // CMD1: SEND_OP_COND - if(cmd == 8'h41) - reply <= 8'h00; // ok, not busy - - // CMD8: SEND_IF_COND (V2 only) - else if(cmd == 8'h48) begin - reply <= 8'h01; // ok, busy - reply0 <= 8'h00; - reply1 <= 8'h00; - reply2 <= 8'h01; - reply3 <= 8'hAA; - reply_len <= 4'd4; - end - - // CMD9: SEND_CSD - else if(cmd == 8'h49) - reply <= 8'h00; // ok - - // CMD10: SEND_CID - else if(cmd == 8'h4a) - reply <= 8'h00; // ok - - // CMD16: SET_BLOCKLEN - else if(cmd == 8'h50) begin - // we only support a block size of 512 - if(lba == 32'd512) - reply <= 8'h00; // ok - else - reply <= 8'h40; // parmeter error - end + // ------------------ write support ---------------------- + // send write data response + if(write_state == WR_STATE_SEND_DRESP) + sd_sdo <= WRITE_DATA_RESPONSE[~bit_cnt]; - // CMD17: READ_SINGLE_BLOCK - else if(cmd == 8'h51) - reply <= 8'h00; // ok + // busy after write until the io controller sends ack + if(write_state == WR_STATE_BUSY) + sd_sdo <= 1'b0; + end - // CMD24: WRITE_BLOCK - else if(cmd == 8'h58) begin - reply <= 8'h00; // ok - write_state <= WR_STATE_EXP_DTOKEN; // expect data token - end + // spi receiver + // cs is active low + if(sd_cs == 1) begin + bit_cnt <= 3'd0; + end else if (~old_sd_sck & sd_sck) begin + bit_cnt <= bit_cnt + 3'd1; - // ACMD41: APP_SEND_OP_COND - else if(cmd55 && (cmd == 8'h69)) - reply <= 8'h00; // ok, not busy - - // CMD55: APP_COND - else if(cmd == 8'h77) - reply <= 8'h01; // ok, busy + // assemble byte + if(bit_cnt != 7) + sbuf[6:0] <= { sbuf[5:0], sd_sdi }; + else begin + // finished reading one byte + // byte counter runs against 15 byte boundary + if(byte_cnt != 15) + byte_cnt <= byte_cnt + 4'd1; - // CMD58: READ_OCR - else if(cmd == 8'h7a) begin - reply <= 8'h00; // ok - - reply0 <= OCR[31:24]; // bit 30 = 1 -> high capacity card - reply1 <= OCR[23:16]; - reply2 <= OCR[15:8]; - reply3 <= OCR[7:0]; - reply_len <= 4'd4; - end - end - end - - // ---------- handle write ----------- - case(write_state) - // don't do anything in idle state - WR_STATE_IDLE: ; - - // waiting for data token - WR_STATE_EXP_DTOKEN: - if({ sbuf, sd_sdi} == 8'hfe ) begin - write_state <= WR_STATE_RECV_DATA; - buffer_ptr <= 9'd0; - end + // byte_cnt > 6 -> complete command received + // first byte of valid command is 01xxxxxx + // don't accept new commands once a write or read command has been accepted + if((byte_cnt > 5) && (write_state == WR_STATE_IDLE) && + (read_state == RD_STATE_IDLE) && sbuf[6:5] == 2'b01) begin + byte_cnt <= 4'd0; + cmd <= { sbuf, sd_sdi}; - // transfer 512 bytes - WR_STATE_RECV_DATA: begin - // push one byte into local buffer - buffer_write_strobe <= 1'b1; - buffer_din <= { sbuf, sd_sdi }; + // set cmd55 flag if previous command was 55 + cmd55 <= (cmd == 8'h77); + end - // all bytes written? - if(&buffer_ptr) - write_state <= WR_STATE_RECV_CRC0; - end - - // transfer 1st crc byte - WR_STATE_RECV_CRC0: - write_state <= WR_STATE_RECV_CRC1; + // parse additional command bytes + if(byte_cnt == 0) args[39:32] <= { sbuf, sd_sdi}; + if(byte_cnt == 1) args[31:24] <= { sbuf, sd_sdi}; + if(byte_cnt == 2) args[23:16] <= { sbuf, sd_sdi}; + if(byte_cnt == 3) args[15:8] <= { sbuf, sd_sdi}; + if(byte_cnt == 4) args[7:0] <= { sbuf, sd_sdi}; - // transfer 2nd crc byte - WR_STATE_RECV_CRC1: - write_state <= WR_STATE_SEND_DRESP; - - // send data response - WR_STATE_SEND_DRESP: begin - write_state <= WR_STATE_BUSY; - req_io_wr <= 1'b1; // trigger write request to io ontroller - end - - // wait for io controller to accept data - WR_STATE_BUSY: - if(wr_io_ack) - write_state <= WR_STATE_IDLE; + // last byte received, evaluate + if(byte_cnt == 5) begin - default: - illegal_write_state <= 1'b1; - endcase - end - end + // default: + reply <= 8'h04; // illegal command + reply_len <= 4'd0; // no extra reply bytes + + // CMD0: GO_IDLE_STATE + if(cmd == 8'h40) begin + card_is_reset <= 1'b1; + reply <= 8'h01; // ok, busy + end + + // every other command is only accepted after a reset + else if(card_is_reset) begin + case(cmd) + // CMD1: SEND_OP_COND + 8'h41: reply <= 8'h00; // ok, not busy + + // CMD8: SEND_IF_COND (V2 only) + 8'h48: begin + reply <= 8'h01; // ok, busy + reply0 <= 8'h00; + reply1 <= 8'h00; + reply2 <= { 4'b0, args[19:16] }; + reply3 <= args[15:8]; + reply_len <= 4'd4; + end + + // CMD9: SEND_CSD + 8'h49: reply <= 8'h00; // ok + + // CMD10: SEND_CID + 8'h4a: reply <= 8'h00; // ok + + // CMD16: SET_BLOCKLEN + 8'h50: + // we only support a block size of 512 + if(args[39:8] == 32'd512) + reply <= 8'h00; // ok + else + reply <= 8'h40; // parmeter error + + // CMD17: READ_SINGLE_BLOCK + 8'h51: reply <= 8'h00; // ok + + // CMD24: WRITE_BLOCK + 8'h58: begin + reply <= 8'h00; // ok + write_state <= WR_STATE_EXP_DTOKEN; // expect data token + end + + // ACMD41: APP_SEND_OP_COND + 8'h69: if(cmd55) begin + reply <= 8'h00; // ok, not busy + end + + // CMD55: APP_COND + 8'h77: reply <= 8'h01; // ok, busy + + // CMD58: READ_OCR + 8'h7a: begin + reply <= 8'h00; // ok + + reply0 <= OCR[31:24]; // bit 30 = 1 -> high capacity card + reply1 <= OCR[23:16]; + reply2 <= OCR[15:8]; + reply3 <= OCR[7:0]; + reply_len <= 4'd4; + end + endcase + end + end + + // ---------- handle write ----------- + case(write_state) + // don't do anything in idle state + WR_STATE_IDLE: ; + + // waiting for data token + WR_STATE_EXP_DTOKEN: + if({ sbuf, sd_sdi} == 8'hfe ) begin + write_state <= WR_STATE_RECV_DATA; + buffer_ptr <= 9'd0; + end + + // transfer 512 bytes + WR_STATE_RECV_DATA: begin + // push one byte into local buffer + buffer_write_strobe <= 1'b1; + buffer_din <= { sbuf, sd_sdi }; + + // all bytes written? + if(&buffer_ptr) + write_state <= WR_STATE_RECV_CRC0; + end + + // transfer 1st crc byte + WR_STATE_RECV_CRC0: + write_state <= WR_STATE_RECV_CRC1; + + // transfer 2nd crc byte + WR_STATE_RECV_CRC1: + write_state <= WR_STATE_SEND_DRESP; + + // send data response + WR_STATE_SEND_DRESP: begin + write_state <= WR_STATE_BUSY; + sd_wr <= 1; // trigger write request to io ontroller + sd_busy <= 1; + end + + // wait for io controller to accept data + WR_STATE_BUSY: + if(~sd_busy) + write_state <= WR_STATE_IDLE; + + default: ; + endcase + end + end end endmodule module sd_card_dpram #(parameter DATAWIDTH=8, ADDRWIDTH=9) ( - input clock_a, - input [ADDRWIDTH-1:0] address_a, - input [DATAWIDTH-1:0] data_a, - input wren_a, - output reg [DATAWIDTH-1:0] q_a, + input clock_a, + input [ADDRWIDTH-1:0] address_a, + input [DATAWIDTH-1:0] data_a, + input wren_a, + output reg [DATAWIDTH-1:0] q_a, - input clock_b, - input [ADDRWIDTH-1:0] address_b, - input [DATAWIDTH-1:0] data_b, - input wren_b, - output reg [DATAWIDTH-1:0] q_b + input clock_b, + input [ADDRWIDTH-1:0] address_b, + input [DATAWIDTH-1:0] data_b, + input wren_b, + output reg [DATAWIDTH-1:0] q_b ); reg [DATAWIDTH-1:0] ram[0:(1<= 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; @@ -176,53 +192,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 @@ -245,7 +265,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 @@ -256,7 +276,7 @@ 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 @@ -266,9 +286,9 @@ end always@(posedge spi_sck or posedge SPI_SS_IO) begin if(SPI_SS_IO == 1) begin bit_cnt <= 0; - byte_cnt <= 0; + byte_cnt <= 0; end else begin - if((bit_cnt == 7)&&(byte_cnt != 8'd255)) + if((bit_cnt == 7)&&(~&byte_cnt)) byte_cnt <= byte_cnt + 8'd1; bit_cnt <= bit_cnt + 1'd1; @@ -288,7 +308,7 @@ 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 @@ -296,24 +316,24 @@ always@(posedge spi_sck or posedge SPI_SS_IO) begin 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]; + 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 + // 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]; + 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; + // 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 @@ -321,27 +341,25 @@ end // SPI receiver IO -> FPGA -reg spi_receiver_strobe_r; -reg spi_transfer_end_r; -reg [7:0] spi_byte_in_r; +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 - spi_receiver_strobe_r <= 0; spi_transfer_end_r <= 1; end else begin - spi_receiver_strobe_r <= 0; spi_transfer_end_r <= 0; if(bit_cnt != 7) sbuf[6:0] <= { sbuf[5:0], SPI_MOSI }; // finished reading a byte, prepare to transfer to clk_sys - if(bit_cnt == 7) begin - spi_byte_in_r <= { sbuf, SPI_MOSI}; - spi_receiver_strobe_r <= 1; + if(bit_cnt == 7) begin + spi_byte_in <= { sbuf, SPI_MOSI}; + spi_receiver_strobe_r <= ~spi_receiver_strobe_r; end end end @@ -351,10 +369,8 @@ always @(posedge clk_sys) begin reg spi_receiver_strobe; reg spi_transfer_end; - reg [7:0] spi_byte_in; reg spi_receiver_strobeD; reg spi_transfer_endD; - reg [7:0] spi_byte_inD; reg [7:0] acmd; reg [7:0] abyte_cnt; // counts bytes @@ -363,90 +379,39 @@ always @(posedge clk_sys) begin spi_receiver_strobe <= spi_receiver_strobeD; spi_transfer_endD <= spi_transfer_end_r; spi_transfer_end <= spi_transfer_endD; - spi_byte_inD <= spi_byte_in_r; - spi_byte_in <= spi_byte_inD; - - if(sd_dout_strobe) begin - sd_dout_strobe<= 0; - if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1; - end - - if(sd_din_strobe) begin - sd_din_strobe<= 0; - if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1; - end 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 + abyte_cnt <= 8'd0; + end else if (spi_receiver_strobeD ^ spi_receiver_strobe) begin - if(abyte_cnt != 8'd255) - abyte_cnt <= byte_cnt + 8'd1; - - if(abyte_cnt == 0) begin - acmd <= spi_byte_in; - - // fetch first byte when sectore FPGA->IO command has been seen - if(spi_byte_in == 8'h18) - sd_din_strobe <= 1'b1; - - if((spi_byte_in == 8'h17) || (spi_byte_in == 8'h18)) - sd_ack <= 1'b1; - - end else 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 - if(acmd == 8'h01) - but_sw <= spi_byte_in; - - if(acmd == 8'h02) - joystick_0 <= spi_byte_in; - - if(acmd == 8'h03) - joystick_1 <= spi_byte_in; - - if(acmd == 8'h04) begin + 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; + ps2_mouse_wptr <= ps2_mouse_wptr + 1'd1; end - - if(acmd == 8'h05) begin + 8'h05: begin // store incoming ps2 keyboard bytes ps2_kbd_fifo[ps2_kbd_wptr] <= spi_byte_in; - ps2_kbd_wptr <= ps2_kbd_wptr + 1; - end - - if(acmd == 8'h15) - status <= spi_byte_in; - - // send sector IO -> FPGA - if(acmd == 8'h17) begin - // flag that download begins - sd_dout_strobe <= 1'b1; - sd_dout <= spi_byte_in; - end - - // send sector FPGA -> IO - if(acmd == 8'h18) - sd_din_strobe <= 1'b1; - - // send SD config IO -> FPGA - if(acmd == 8'h19) begin - // flag that download begins - sd_dout_strobe <= 1'b1; - sd_ack_conf <= 1'b1; - sd_dout <= spi_byte_in; + ps2_kbd_wptr <= ps2_kbd_wptr + 1'd1; end // joystick analog - if(acmd == 8'h1a) begin - // first byte is joystick indes + 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 @@ -463,6 +428,101 @@ always @(posedge clk_sys) begin 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 diff --git a/cores/bbc/rtl/clocks.v b/cores/bbc/rtl/clocks.v index df7d741..30931f8 100755 --- a/cores/bbc/rtl/clocks.v +++ b/cores/bbc/rtl/clocks.v @@ -109,7 +109,7 @@ begin : ttxt_clk_gen if (reset_n === 1'b 0) begin ttxt_clken_counter <= {2{1'b 0}}; end else begin - ttxt_clken_counter <= ttxt_clken_counter + 1; + ttxt_clken_counter <= ttxt_clken_counter + 1'd1; end end