1
0
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:
gyurco
2019-01-29 23:46:06 +01:00
committed by GitHub
8 changed files with 926 additions and 887 deletions

11
.gitignore vendored
View File

@@ -1,3 +1,14 @@
out/
db/
incremental_db/
greybox_tmp
PLLJ_PLLSPE_INFO.txt
*.qws
*.bak
*.jdi
*.sof
*.done
*.pin
*.rpt
*.smsg
*.summary

View File

@@ -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[*]]

View File

@@ -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

View File

@@ -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
View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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