mirror of
https://github.com/mist-devel/mist-board.git
synced 2026-02-06 16:14:42 +00:00
Merge pull request #71 from gyurco/bbc
BBC updates, fix IO Voltage, add YPbPr
This commit is contained in:
11
.gitignore
vendored
11
.gitignore
vendored
@@ -1,3 +1,14 @@
|
||||
out/
|
||||
db/
|
||||
incremental_db/
|
||||
greybox_tmp
|
||||
PLLJ_PLLSPE_INFO.txt
|
||||
*.qws
|
||||
*.bak
|
||||
*.jdi
|
||||
*.sof
|
||||
*.done
|
||||
*.pin
|
||||
*.rpt
|
||||
*.smsg
|
||||
*.summary
|
||||
|
||||
@@ -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[*]]
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
423
cores/bbc/fpga/mist/osd.v
Executable file → Normal file
423
cores/bbc/fpga/mist/osd.v
Executable file → Normal file
@@ -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 <till@harbaum.org>
|
||||
//
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
// 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 <till@harbaum.org>
|
||||
//
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
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
|
||||
|
||||
@@ -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<<ADDRWIDTH)-1];
|
||||
|
||||
always @(posedge clock_a) begin
|
||||
q_a <= ram[address_a];
|
||||
if(wren_a) begin
|
||||
q_a <= data_a;
|
||||
ram[address_a] <= data_a;
|
||||
end
|
||||
q_a <= ram[address_a];
|
||||
if(wren_a) begin
|
||||
q_a <= data_a;
|
||||
ram[address_a] <= data_a;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clock_b) begin
|
||||
q_b <= ram[address_b];
|
||||
if(wren_b) begin
|
||||
q_b <= data_b;
|
||||
ram[address_b] <= data_b;
|
||||
end
|
||||
q_b <= ram[address_b];
|
||||
if(wren_b) begin
|
||||
q_b <= data_b;
|
||||
ram[address_b] <= data_b;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -22,63 +22,69 @@
|
||||
|
||||
// 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 clk_sys,
|
||||
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,
|
||||
output scandoubler_disable,
|
||||
|
||||
output reg [7:0] status,
|
||||
input clk_sys, // clock for system-related messages (kbd, joy, etc...)
|
||||
input clk_sd, // clock for SD-card related messages
|
||||
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
|
||||
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 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 ps2_kbd_clk,
|
||||
output reg ps2_kbd_data,
|
||||
output ps2_mouse_clk,
|
||||
output reg ps2_mouse_data,
|
||||
|
||||
// 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 [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 [4:0] but_sw;
|
||||
reg [2:0] stick_idx;
|
||||
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 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;
|
||||
@@ -86,16 +92,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);
|
||||
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;
|
||||
@@ -111,56 +123,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;
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user