1
0
mirror of https://github.com/mist-devel/mist-board.git synced 2026-02-05 07:34:41 +00:00

BBC: use common MiST modules

This commit is contained in:
Gyorgy Szombathelyi
2020-02-18 16:00:35 +01:00
parent 8a028f21e2
commit 8d1826bd5f
8 changed files with 474 additions and 1906 deletions

View File

@@ -41,7 +41,7 @@ set_global_assignment -name DEVICE EP3C25E144C8
set_global_assignment -name TOP_LEVEL_ENTITY bbc_mist_top
set_global_assignment -name ORIGINAL_QUARTUS_VERSION 13.1
set_global_assignment -name PROJECT_CREATION_TIME_DATE "13:11:51 AUGUST 27, 2015"
set_global_assignment -name LAST_QUARTUS_VERSION 13.1
set_global_assignment -name LAST_QUARTUS_VERSION "13.1 SP4.26"
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0
set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85
@@ -55,10 +55,6 @@ set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "23 MM HEAT SINK WITH 200 LFPM AIRFLOW"
set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)"
set_location_assignment PIN_22 -to CLOCK_50[0]
set_location_assignment PIN_23 -to CLOCK_50[1]
set_location_assignment PIN_128 -to CLOCK_32[0]
set_location_assignment PIN_129 -to CLOCK_32[1]
set_location_assignment PIN_54 -to CLOCK_27[0]
set_location_assignment PIN_55 -to CLOCK_27[1]
set_location_assignment PIN_144 -to VGA_R[5]
@@ -133,7 +129,7 @@ set_location_assignment PIN_65 -to AUDIO_L
set_location_assignment PIN_80 -to AUDIO_R
set_global_assignment -name ENABLE_SIGNALTAP OFF
set_global_assignment -name USE_SIGNALTAP_FILE output_files/stp2.stp
set_global_assignment -name USE_SIGNALTAP_FILE output_files/dio.stp
set_global_assignment -name ENABLE_CONFIGURATION_PINS OFF
set_global_assignment -name ENABLE_NCE_PIN OFF
set_global_assignment -name ENABLE_BOOT_SEL_PIN OFF
@@ -165,17 +161,9 @@ set_global_assignment -name PHYSICAL_SYNTHESIS_ASYNCHRONOUS_SIGNAL_PIPELINING ON
set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_DUPLICATION ON
set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC_FOR_AREA ON
set_global_assignment -name PHYSICAL_SYNTHESIS_MAP_LOGIC_TO_MEMORY_FOR_AREA ON
set_global_assignment -name VERILOG_FILE bbc_mist_top.v
set_global_assignment -name SYSTEMVERILOG_FILE rgb2ypbpr.sv
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_location_assignment PLL_1 -to CLOCKS|altpll_component|auto_generated|pll1
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
@@ -206,4 +194,9 @@ 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 SYSTEMVERILOG_FILE bbc_mist_top.sv
set_global_assignment -name VERILOG_FILE sdram.v
set_global_assignment -name VERILOG_FILE clockgen.v
set_global_assignment -name QIP_FILE "../../../../mist-modules/mist.qip"
set_global_assignment -name VERILOG_FILE "../../../../mist-modules/sd_card.v"
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

View File

@@ -0,0 +1,466 @@
`timescale 1ns / 1ps
// bbc_mist_top.v
module bbc_mist_top(
// clock inputs
input wire [1:0] CLOCK_27, // 27 MHz
// LED outputs
output wire LED, // LED Yellow
// VGA
output wire VGA_HS, // VGA H_SYNC
output wire VGA_VS, // VGA V_SYNC
output wire [5:0] VGA_R, // VGA Red[5:0]
output wire [5:0] VGA_G, // VGA Green[5:0]
output wire [5:0] VGA_B, // VGA Blue[5:0];
// AUDIO
output wire AUDIO_L, // sigma-delta DAC output left
output wire AUDIO_R, // sigma-delta DAC output right
// SDRAM
inout [15:0] SDRAM_DQ, // SDRAM Data bus 16 Bits
output [12:0] SDRAM_A, // SDRAM Address bus 13 Bits
output SDRAM_DQML, // SDRAM Low-byte Data Mask
output SDRAM_DQMH, // SDRAM High-byte Data Mask
output SDRAM_nWE, // SDRAM Write Enable
output SDRAM_nCAS, // SDRAM Column Address Strobe
output SDRAM_nRAS, // SDRAM Row Address Strobe
output SDRAM_nCS, // SDRAM Chip Select
output [1:0] SDRAM_BA, // SDRAM Bank Address
output SDRAM_CLK, // SDRAM Clock
output SDRAM_CKE, // SDRAM Clock Enable
// SPI
output SPI_DO,
input SPI_DI,
input SPI_SCK,
input SPI_SS2, // data_io
input SPI_SS3, // OSD
input CONF_DATA0 // SPI_SS for user_io
);
assign LED = 1'b0;
// the configuration string is returned to the io controller to allow
// it to control the menu on the OSD
parameter CONF_STR = {
"BBC;ROM;",
"O12,Scanlines,Off,25%,50%,75%;",
"O3,Joystick Swap,Off,On;",
"O4,ROM mapping,High,Low;",
"O5,Auto boot,Off,On;",
"T0,Reset;"
};
wire [1:0] scanlines = status[2:1];
wire joyswap = status[3];
wire rommap = status[4];
wire autoboot = status[5];
// generated clocks
wire clk_32m /* synthesis keep */ ;
wire clk_24m /* synthesis keep */ ;
wire pll_ready;
// core's raw video
wire core_r, core_g, core_b, core_hs, core_vs;
wire core_clken;
// memory bus signals.
wire [14:0] vid_adr;
wire [7:0] vid_data;
wire [15:0] mem_adr;
wire [3:0] mem_romsel;
wire [7:0] mem_di;
wire [7:0] rom_do;
wire [7:0] ram_do;
wire [7:0] mem_do;
wire mem_we;
wire mem_sync;
// core's raw audio
wire [15:0] coreaud_l, coreaud_r;
// user io
wire [7:0] status;
wire [1:0] buttons;
wire [1:0] switches;
wire ps2_clk;
wire ps2_dat;
// the top file should generate the correct clocks for the machine
assign SDRAM_CLK = clk_32m;
clockgen CLOCKS(
.inclk0 (CLOCK_27[0]),
.c0 (clk_32m),
.c1 (clk_24m),
.locked (pll_ready) // pll locked output
);
// conections between user_io (implementing the SPI communication
// to the io controller) and the legacy
wire [31:0] sd_lba;
wire sd_rd;
wire sd_wr;
wire sd_ack;
wire sd_conf;
wire sd_sdhc;
wire [7:0] sd_dout;
wire sd_dout_strobe;
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;
wire [15:0] joystick_analog_0;
wire [15:0] joystick_analog_1;
wire scandoubler_disable;
wire ypbpr;
wire no_csync;
user_io #(.STRLEN($size(CONF_STR)>>3)) user_io(
.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 ),
.joystick_0 ( joystick_0 ),
.joystick_1 ( joystick_1 ),
.joystick_analog_0 ( joystick_analog_0 ),
.joystick_analog_1 ( joystick_analog_1 ),
.status ( status ),
.switches ( switches ),
.buttons ( buttons ),
.scandoubler_disable ( scandoubler_disable ),
.ypbpr ( ypbpr ),
.no_csync ( no_csync ),
// 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 ),
.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
wire sd_sck;
wire sd_cs;
wire sd_sdi;
wire sd_sdo;
sd_card sd_card (
// connection to io controller
.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 ),
.sd_sck ( sd_sck ),
.sd_sdi ( sd_sdi ),
.sd_sdo ( sd_sdo )
);
// data loading
wire loader_active;
wire loader_we, ioctl_we;
wire [24:0] loader_addr, ioctl_addr;
wire [7:0] loader_data, ioctl_data;
always @(posedge clk_32m) begin
reg we_int = 0;
if (mem_sync) begin
we_int <= 0;
loader_we <= we_int;
if (we_int) begin
loader_addr <= ioctl_addr;
loader_data <= ioctl_data;
end
end
if (ioctl_we) we_int <= 1;
end
data_io #(.START_ADDR({ 7'b0000001, 4'ha, 14'h0 })) DATA_IO (
.clk_sys ( clk_32m ),
.SPI_SCK ( SPI_SCK ),
.SPI_SS2 ( SPI_SS2 ),
.SPI_DI ( SPI_DI ),
.ioctl_download ( loader_active ),
// ram interface
.ioctl_wr ( ioctl_we ),
.ioctl_addr ( ioctl_addr ),
.ioctl_dout ( ioctl_data )
);
wire [7:0] user_via_pb_out;
wire user_via_cb1_in;
wire user_via_cb2_in;
// reset core whenever the user changes the rom mapping
reg last_rom_map;
reg [11:0] rom_map_counter = 12'h0;
always @(posedge clk_32m) begin
last_rom_map <= rommap;
if(last_rom_map != rommap)
rom_map_counter <= 12'hfff;
else if(rom_map_counter != 0)
rom_map_counter <= rom_map_counter - 12'd1;
end
wire rom_remap_reset = (rom_map_counter != 0);
// the bbc is being reset of the pll isn't stable, if the ram isn't ready,
// of the arm boots or if the user selects reset from the osd or of the user
// presses the "core" button or the io controller uploads a rom
wire reset_in = ~pll_ready || ~sdram_ready || status[0] ||
buttons[1] || loader_active || rom_remap_reset;
// synchronize reset with memory state machine
reg reset;
always @(posedge mem_sync)
reset <= reset_in;
// the autoboot feature simply works by pressing shift for 2 seconds after
// the bbc has been reset
wire autoboot_shift = autoboot && (autoboot_counter != 0 );
reg [24:0] autoboot_counter;
always @(posedge clk_32m) begin
if(reset)
autoboot_counter <= 25'd32000000;
else if(autoboot_counter != 0)
autoboot_counter <= autoboot_counter - 25'd1;
end
bbc BBC(
.CLK32M_I ( clk_32m ),
.CLK24M_I ( clk_24m ),
.RESET_I ( reset ),
.HSYNC ( core_hs ),
.VSYNC ( core_vs ),
.VIDEO_CLKEN( core_clken ),
.VIDEO_R ( core_r ),
.VIDEO_G ( core_g ),
.VIDEO_B ( core_b ),
.MEM_ADR ( mem_adr ),
.MEM_WE ( mem_we ),
.MEM_DO ( mem_do ),
.MEM_DI ( mem_di ),
.MEM_SYNC ( mem_sync ),
.ROMSEL ( mem_romsel ),
.VID_ADR ( vid_adr ),
.VID_DI ( vid_data ),
.SHIFT ( autoboot_shift ),
.SDCLK (sd_sck ),
.SDSS (sd_cs ),
.SDMISO (sd_sdo ),
.SDMOSI (sd_sdi ),
.joy_but ( { joystick_1[4], joystick_0[4] } ),
.joy0_axis0 ( joyswap ? joystick_analog_1[15:8] : joystick_analog_0[15:8] ),
.joy0_axis1 ( joyswap ? joystick_analog_1[ 7:0] : joystick_analog_0[ 7:0] ),
.joy1_axis0 ( joyswap ? joystick_analog_0[15:8] : joystick_analog_1[15:8] ),
.joy1_axis1 ( joyswap ? joystick_analog_0[15:8] : joystick_analog_1[ 7:0] ),
.DIP_SWITCH ( 8'b00000000 ),
.PS2_CLK ( ps2_clk ),
.PS2_DAT ( ps2_dat ),
.AUDIO_L ( coreaud_l ),
.AUDIO_R ( coreaud_r )
);
assign SDRAM_CKE = 1'b1;
wire sdram_ready;
// cpu is accessing built-in core rom (mos or basic)
wire cpu_ram = (mem_adr[15] == 1'b0);
wire mos_rom = (mem_adr[15:14] == 2'b11);
wire [24:0] sdram_adr =
loader_active?loader_addr:
cpu_ram?{ 9'b000000000, mem_adr }: // ordinary ram access
{ 7'b0000001, mem_romsel, mem_adr[13:0] }; // sideways ram/rom access
wire sdram_we = loader_active?loader_we:(mem_we && (cpu_ram || sideways_ram));
wire [7:0] sdram_di =
loader_active?loader_data:mem_do;
sdram sdram (
// interface to the MT48LC16M16 chip
.sd_data ( SDRAM_DQ ),
.sd_addr ( SDRAM_A ),
.sd_dqm ( {SDRAM_DQMH, SDRAM_DQML} ),
.sd_cs ( SDRAM_nCS ),
.sd_ba ( SDRAM_BA ),
.sd_we ( SDRAM_nWE ),
.sd_ras ( SDRAM_nRAS ),
.sd_cas ( SDRAM_nCAS ),
// system interface
.clk ( clk_32m ),
.sync ( mem_sync ),
.init ( !pll_ready ),
.ready ( sdram_ready ),
// cpu/video interface
.cpu_di ( sdram_di ),
.cpu_adr ( sdram_adr ),
.cpu_we ( sdram_we ),
.cpu_do ( ram_do ),
.vid_blnk ( loader_active ),
.vid_adr ( { 9'd0, vid_adr } ),
.vid_do ( vid_data )
);
wire [7:0] os_do;
os12 os12 (
.clock ( clk_32m ),
.address ( mem_adr[13:0] ),
.q ( os_do )
);
wire [7:0] basic_do;
basic2 basic2 (
.clock ( clk_32m ),
.address ( mem_adr[13:0] ),
.q ( basic_do )
);
wire [7:0] mmfs_do;
mmfs mmfs (
.clock ( clk_32m ),
.address ( mem_adr[13:0] ),
.q ( mmfs_do )
);
// 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);
// rommap is '1' of low mapping is selected in the menu
wire basic_map = rommap?(mem_romsel == 4'h0):(mem_romsel == 4'he);
wire mmfs_map = rommap?(mem_romsel == 4'h2):(mem_romsel == 4'hc);
assign mem_di =
((mem_adr[15:14] == 2'b10) && basic_map) ? basic_do :
((mem_adr[15:14] == 2'b10) && mmfs_map) ? mmfs_do :
((mem_adr[15:14] == 2'b10) && (mem_romsel == 4'ha)) ? ram_do :
mos_rom ? os_do :
cpu_ram ? ram_do :
sideways_ram ? ram_do :
8'hff;
audio AUDIO (
.clk ( clk_24m ),
.rst ( ~pll_ready ),
.audio_data_l( coreaud_l ),
.audio_data_r( coreaud_r ),
.audio_l ( AUDIO_L ),
.audio_r ( AUDIO_R )
);
mist_video #(.COLOR_DEPTH(1), .SD_HCNT_WIDTH(10)) mist_video (
.clk_sys ( clk_32m ),
// OSD SPI interface
.SPI_SCK ( SPI_SCK ),
.SPI_SS3 ( SPI_SS3 ),
.SPI_DI ( SPI_DI ),
// scanlines (00-none 01-25% 10-50% 11-75%)
.scanlines ( scanlines ),
// non-scandoubled pixel clock divider 0 - clk_sys/4, 1 - clk_sys/2
.ce_divider ( 1'b0 ),
// 0 = HVSync 31KHz, 1 = CSync 15KHz
.scandoubler_disable ( scandoubler_disable ),
// disable csync without scandoubler
.no_csync ( no_csync ),
// YPbPr always uses composite sync
.ypbpr ( ypbpr ),
// Rotate OSD [0] - rotate [1] - left or right
.rotate ( 2'b00 ),
// composite-like blending
.blend ( 1'b0 ),
// video in
.R ( core_r ),
.G ( core_g ),
.B ( core_b ),
.HSync ( core_hs ),
.VSync ( core_vs ),
// MiST video output signals
.VGA_R ( VGA_R ),
.VGA_G ( VGA_G ),
.VGA_B ( VGA_B ),
.VGA_VS ( VGA_VS ),
.VGA_HS ( VGA_HS )
);
endmodule // bbc_mist_top

View File

@@ -1,496 +0,0 @@
`timescale 1ns / 1ps
// bbc_mist_top.v
module bbc_mist_top(
// clock inputs
input wire [1:0] CLOCK_27, // 27 MHz
// LED outputs
output wire LED, // LED Yellow
// VGA
output wire VGA_HS, // VGA H_SYNC
output wire VGA_VS, // VGA V_SYNC
output wire [5:0] VGA_R, // VGA Red[5:0]
output wire [5:0] VGA_G, // VGA Green[5:0]
output wire [5:0] VGA_B, // VGA Blue[5:0];
// AUDIO
output wire AUDIO_L, // sigma-delta DAC output left
output wire AUDIO_R, // sigma-delta DAC output right
// SDRAM
inout [15:0] SDRAM_DQ, // SDRAM Data bus 16 Bits
output [12:0] SDRAM_A, // SDRAM Address bus 13 Bits
output SDRAM_DQML, // SDRAM Low-byte Data Mask
output SDRAM_DQMH, // SDRAM High-byte Data Mask
output SDRAM_nWE, // SDRAM Write Enable
output SDRAM_nCAS, // SDRAM Column Address Strobe
output SDRAM_nRAS, // SDRAM Row Address Strobe
output SDRAM_nCS, // SDRAM Chip Select
output [1:0] SDRAM_BA, // SDRAM Bank Address
output SDRAM_CLK, // SDRAM Clock
output SDRAM_CKE, // SDRAM Clock Enable
// SPI
output SPI_DO,
input SPI_DI,
input SPI_SCK,
input SPI_SS2, // data_io
input SPI_SS3, // OSD
input CONF_DATA0 // SPI_SS for user_io
);
assign LED = 1'b0;
// the configuration string is returned to the io controller to allow
// it to control the menu on the OSD
parameter CONF_STR = {
"BBC;ROM;",
"O1,Scanlines,Off,On;",
"O2,ROM mapping,High,Low;",
"O3,Auto boot,Off,On;",
"T4,Reset;"
};
parameter CONF_STR_LEN = 8+20+24+20+9;
// generated clocks
wire clk_32m /* synthesis keep */ ;
wire clk_24m /* synthesis keep */ ;
wire pll_ready;
// core's raw video
wire core_r, core_g, core_b, core_hs, core_vs;
wire core_clken;
// memory bus signals.
wire [14:0] vid_adr;
wire [7:0] vid_data;
wire [15:0] mem_adr;
wire [3:0] mem_romsel;
wire [7:0] mem_di;
wire [7:0] rom_do;
wire [7:0] ram_do;
wire [7:0] mem_do;
wire mem_we;
wire mem_sync;
// core's raw audio
wire [15:0] coreaud_l, coreaud_r;
// user io
wire [7:0] status;
wire [1:0] buttons;
wire [1:0] switches;
wire ps2_clk;
wire ps2_dat;
// the top file should generate the correct clocks for the machine
assign SDRAM_CLK = !clk_32m;
clockgen CLOCKS(
.inclk0 (CLOCK_27[0]),
.c0 (clk_32m),
.c1 (clk_24m),
.locked (pll_ready) // pll locked output
);
// without scan doubler only half the pixel clock is used
reg clk_12m;
always @(posedge clk_24m)
clk_12m <= !clk_12m;
wire ce_pix = scandoubler_disable?clk_12m:1'd1;
wire [5:0] osd_r_o, osd_g_o, osd_b_o;
osd #(0,0,4) OSD (
.clk_sys ( clk_24m ),
.ce_pix ( ce_pix ),
// spi for OSD
.sdi ( SPI_DI ),
.sck ( SPI_SCK ),
.ss ( SPI_SS3 ),
.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 ),
.red_out ( osd_r_o ),
.green_out ( osd_g_o ),
.blue_out ( osd_b_o ),
.hs_out ( v_hs ),
.vs_out ( v_vs )
);
wire [5:0] Y, Pb, Pr;
rgb2ypbpr rgb2ypbpr
(
.red ( osd_r_o ),
.green ( osd_g_o ),
.blue ( osd_b_o ),
.y ( Y ),
.pb ( Pb ),
.pr ( Pr )
);
wire v_hs, v_vs;
// create composite sync for 15khz
wire csync = !(v_vs ^ v_hs);
assign VGA_HS = (scandoubler_disable || ypbpr) ?csync:v_hs;
assign VGA_VS = (scandoubler_disable || ypbpr) ?1'b1:v_vs;
assign VGA_R = ypbpr?Pr:osd_r_o;
assign VGA_G = ypbpr? Y:osd_g_o;
assign VGA_B = ypbpr?Pb:osd_b_o;
// conections between user_io (implementing the SPIU communication
// to the io controller) and the legacy
wire [31:0] sd_lba;
wire sd_rd;
wire sd_wr;
wire sd_ack;
wire sd_conf;
wire sd_sdhc;
wire [7:0] sd_dout;
wire sd_dout_strobe;
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;
wire [15:0] joystick_analog_0;
wire [15:0] joystick_analog_1;
wire scandoubler_disable;
wire ypbpr;
user_io #(.STRLEN(CONF_STR_LEN)) user_io(
.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 ),
// use mist joystick 1 as bbc primary joystick
.joystick_0 ( joystick_1 ),
.joystick_1 ( joystick_0 ),
.joystick_analog_0 ( joystick_analog_1 ),
.joystick_analog_1 ( joystick_analog_0 ),
.status ( status ),
.switches ( switches ),
.buttons ( buttons ),
.scandoubler_disable ( scandoubler_disable ),
.ypbpr ( ypbpr ),
// 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 ),
.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
wire sd_sck;
wire sd_cs;
wire sd_sdi;
wire sd_sdo;
sd_card sd_card (
// connection to io controller
.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 ),
.sd_sck ( sd_sck ),
.sd_sdi ( sd_sdi ),
.sd_sdo ( sd_sdo )
);
// data loading
wire loader_active;
wire loader_we;
wire [24:0] loader_addr;
wire [7:0] loader_data;
data_io DATA_IO (
.sck ( SPI_SCK ),
.ss ( SPI_SS2 ),
.sdi ( SPI_DI ),
.downloading ( loader_active ),
.index ( ),
// ram interface
.clk ( mem_sync ),
.wr ( loader_we ),
.addr ( loader_addr ),
.data ( loader_data )
);
wire [7:0] user_via_pb_out;
wire user_via_cb1_in;
wire user_via_cb2_in;
// reset core whenever the user changes the rom mapping
reg last_rom_map;
reg [11:0] rom_map_counter = 12'h0;
always @(posedge clk_32m) begin
last_rom_map <= status[2];
if(last_rom_map != status[2])
rom_map_counter <= 12'hfff;
else if(rom_map_counter != 0)
rom_map_counter <= rom_map_counter - 12'd1;
end
wire rom_remap_reset = (rom_map_counter != 0);
// the bbc is being reset of the pll isn't stable, if the ram isn't ready,
// of the arm boots or if the user selects reset from the osd or of the user
// presses the "core" button or the io controller uploads a rom
wire reset_in = ~pll_ready || ~sdram_ready || status[0] || status[4] ||
buttons[1] || loader_active || rom_remap_reset;
// synchronize reset with memory state machine
reg reset;
always @(posedge mem_sync)
reset <= reset_in;
// the autoboot feature simply works by pressing shift for 2 seconds after
// the bbc has been reset
wire autoboot_shift = status[3] && (autoboot_counter != 0 );
reg [24:0] autoboot_counter;
always @(posedge clk_32m) begin
if(reset)
autoboot_counter <= 25'd32000000;
else if(autoboot_counter != 0)
autoboot_counter <= autoboot_counter - 25'd1;
end
bbc BBC(
.CLK32M_I ( clk_32m ),
.CLK24M_I ( clk_24m ),
.RESET_I ( reset ),
.HSYNC ( core_hs ),
.VSYNC ( core_vs ),
.VIDEO_CLKEN ( core_clken ),
.VIDEO_R ( core_r ),
.VIDEO_G ( core_g ),
.VIDEO_B ( core_b ),
.MEM_ADR ( mem_adr ),
.MEM_WE ( mem_we ),
.MEM_DO ( mem_do ),
.MEM_DI ( mem_di ),
.MEM_SYNC ( mem_sync ),
.ROMSEL ( mem_romsel ),
.VID_ADR ( vid_adr ),
.VID_DI ( vid_data ),
.SHIFT ( autoboot_shift ),
.SDCLK (sd_sck ),
.SDSS (sd_cs ),
.SDMISO (sd_sdo ),
.SDMOSI (sd_sdi ),
.joy_but ( { joystick_1[4], joystick_0[4] } ),
.joy0_axis0 ( joystick_analog_0[15:8] ),
.joy0_axis1 ( joystick_analog_0[7:0] ),
.joy1_axis0 ( joystick_analog_1[15:8] ),
.joy1_axis1 ( joystick_analog_1[7:0] ),
.DIP_SWITCH ( 8'b00000000 ),
.PS2_CLK ( ps2_clk ),
.PS2_DAT ( ps2_dat ),
.AUDIO_L ( coreaud_l ),
.AUDIO_R ( coreaud_r )
);
assign SDRAM_CKE = 1'b1;
wire sdram_ready;
// cpu is accessing built-in core rom (mos or basic)
wire cpu_ram = (mem_adr[15] == 1'b0);
wire mos_rom = (mem_adr[15:14] == 2'b11);
wire [24:0] sdram_adr =
loader_active?loader_addr:
cpu_ram?{ 9'b000000000, mem_adr }: // ordinary ram access
{ 7'b0000001, mem_romsel, mem_adr[13:0] }; // sideways ram/rom access
wire sdram_we = loader_active?loader_we:(mem_we && (cpu_ram || sideways_ram));
wire [7:0] sdram_di =
loader_active?loader_data:mem_do;
sdram sdram (
// interface to the MT48LC16M16 chip
.sd_data ( SDRAM_DQ ),
.sd_addr ( SDRAM_A ),
.sd_dqm ( {SDRAM_DQMH, SDRAM_DQML} ),
.sd_cs ( SDRAM_nCS ),
.sd_ba ( SDRAM_BA ),
.sd_we ( SDRAM_nWE ),
.sd_ras ( SDRAM_nRAS ),
.sd_cas ( SDRAM_nCAS ),
// system interface
.clk ( clk_32m ),
.sync ( mem_sync ),
.init ( !pll_ready ),
.ready ( sdram_ready ),
// cpu/video interface
.cpu_di ( sdram_di ),
.cpu_adr ( sdram_adr ),
.cpu_we ( sdram_we ),
.cpu_do ( ram_do ),
.vid_blnk ( loader_active ),
.vid_adr ( { 9'd0, vid_adr } ),
.vid_do ( vid_data )
);
wire [7:0] os_do;
os12 os12 (
.clock ( clk_32m ),
.address ( mem_adr[13:0] ),
.q ( os_do )
);
wire [7:0] basic_do;
basic2 basic2 (
.clock ( clk_32m ),
.address ( mem_adr[13:0] ),
.q ( basic_do )
);
wire [7:0] mmfs_do;
mmfs mmfs (
.clock ( clk_32m ),
.address ( mem_adr[13:0] ),
.q ( mmfs_do )
);
audio AUDIO (
.clk ( clk_24m ),
.rst ( ~pll_ready ),
.audio_data_l ( coreaud_l ),
.audio_data_r ( coreaud_r ),
.audio_l ( AUDIO_L ),
.audio_r ( AUDIO_R )
);
wire sd_hs, sd_vs;
wire [1:0] sd_r;
wire [1:0] sd_g;
wire [1:0] sd_b;
scandoubler SCANDOUBLE(
.clk_16 ( clk_32m ),
.clk_16_en ( core_clken ),
.scanlines ( status[1] ),
.vs_in ( core_vs ),
.hs_in ( core_hs ),
.r_in ( core_r ),
.g_in ( core_g ),
.b_in ( core_b ),
.clk ( clk_32m ),
.vs_out ( sd_vs ),
.hs_out ( sd_hs ),
.r_out ( sd_r ),
.g_out ( sd_g ),
.b_out ( sd_b )
);
// switch between doubled and non-doubled video
wire [1:0] video_r = scandoubler_disable?core_r:sd_r;
wire [1:0] video_g = scandoubler_disable?core_g:sd_g;
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;
// 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);
// status[2] is '1' of low mapping is selected in the menu
wire basic_map = status[2]?(mem_romsel == 4'h0):(mem_romsel == 4'he);
wire mmfs_map = status[2]?(mem_romsel == 4'h2):(mem_romsel == 4'hc);
assign mem_di =
((mem_adr[15:14] == 2'b10) && basic_map) ? basic_do :
((mem_adr[15:14] == 2'b10) && mmfs_map) ? mmfs_do :
((mem_adr[15:14] == 2'b10) && (mem_romsel == 4'ha)) ? ram_do :
mos_rom ? os_do :
cpu_ram ? ram_do :
sideways_ram ? ram_do :
8'hff;
endmodule // bbc_mist_top

View File

@@ -1,134 +0,0 @@
//
// data_io.v
//
// io controller writable ram for the MiST board
// 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 data_io (
// io controller spi interface
input sck,
input ss,
input sdi,
output downloading, // signal indicating an active download
output reg [4:0] index, // menu index used to upload the file
// external ram interface
input clk,
output reg wr,
output reg [24:0] addr,
output reg [7:0] data
);
// *********************************************************************************
// spi client
// *********************************************************************************
// this core supports only the display related OSD commands
// of the minimig
reg [6:0] sbuf;
reg [7:0] cmd;
reg [3:0] cnt;
reg rclk;
reg [24:0] laddr;
reg [7:0] ldata;
localparam UIO_FILE_TX = 8'h53;
localparam UIO_FILE_TX_DAT = 8'h54;
localparam UIO_FILE_INDEX = 8'h55;
assign downloading = downloading_reg;
reg downloading_reg = 1'b0;
// filter spi clock. the 8 bit gate delay is ~2.5ns in total
wire [7:0] spi_sck_D = { spi_sck_D[6:0], sck } /* synthesis keep */;
wire spi_sck = (spi_sck && spi_sck_D != 8'h00) || (!spi_sck && spi_sck_D == 8'hff);
// data_io has its own SPI interface to the io controller
always@(posedge spi_sck, posedge ss) begin
if(ss == 1'b1)
cnt <= 4'd0;
else begin
rclk <= 1'b0;
// don't shift in last bit. It is evaluated directly
// when writing to ram
if(cnt[2:0] != 3'd7)
sbuf <= { sbuf[5:0], sdi};
// count 0-7 8-15 8-15 ...
if(cnt != 15) cnt <= cnt + 4'd1;
else cnt <= 4'd8;
// finished command byte
if(cnt == 7)
cmd <= {sbuf, sdi};
if(cnt == 15) begin
// prepare/end transmission
if(cmd == UIO_FILE_TX) begin
// prepare
if(sdi) begin
// download rom into sideways rom slot e
laddr <= { 7'b0000001, 4'ha, 14'h0 } - 25'd1;
downloading_reg <= 1'b1;
end else
downloading_reg <= 1'b0;
end
// command 0x54: UIO_FILE_TX
if(cmd == UIO_FILE_TX_DAT) begin
ldata <= {sbuf, sdi};
laddr <= laddr + 25'd1;
rclk <= 1'b1;
end
// expose file (menu) index
if(cmd == UIO_FILE_INDEX)
index <= {sbuf[3:0], sdi};
end
end
end
reg mem_req;
always @(posedge rclk or posedge wr) begin
if(wr) mem_req <= 1'b0;
else mem_req <= 1'b1;
end
// memory request needs to be valid on the rising
// edge so data and address are sure stable in it's
// falling edge
reg mem_reqD;
always@(posedge clk)
mem_reqD <= mem_req;
always@(negedge clk) begin
wr <= 1'b0;
if(mem_reqD) begin
addr <= laddr;
data <= ldata;
wr <= 1'b1;
end
end
endmodule

View File

@@ -1,209 +0,0 @@
//
// 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,55 +0,0 @@
module rgb2ypbpr (
input [5:0] red,
input [5:0] green,
input [5:0] blue,
output [5:0] y,
output [5:0] pb,
output [5:0] pr
);
wire [5:0] yuv_full[225] = '{
6'd0, 6'd0, 6'd0, 6'd0, 6'd1, 6'd1, 6'd1, 6'd1,
6'd2, 6'd2, 6'd2, 6'd3, 6'd3, 6'd3, 6'd3, 6'd4,
6'd4, 6'd4, 6'd5, 6'd5, 6'd5, 6'd5, 6'd6, 6'd6,
6'd6, 6'd7, 6'd7, 6'd7, 6'd7, 6'd8, 6'd8, 6'd8,
6'd9, 6'd9, 6'd9, 6'd9, 6'd10, 6'd10, 6'd10, 6'd11,
6'd11, 6'd11, 6'd11, 6'd12, 6'd12, 6'd12, 6'd13, 6'd13,
6'd13, 6'd13, 6'd14, 6'd14, 6'd14, 6'd15, 6'd15, 6'd15,
6'd15, 6'd16, 6'd16, 6'd16, 6'd17, 6'd17, 6'd17, 6'd17,
6'd18, 6'd18, 6'd18, 6'd19, 6'd19, 6'd19, 6'd19, 6'd20,
6'd20, 6'd20, 6'd21, 6'd21, 6'd21, 6'd21, 6'd22, 6'd22,
6'd22, 6'd23, 6'd23, 6'd23, 6'd23, 6'd24, 6'd24, 6'd24,
6'd25, 6'd25, 6'd25, 6'd25, 6'd26, 6'd26, 6'd26, 6'd27,
6'd27, 6'd27, 6'd27, 6'd28, 6'd28, 6'd28, 6'd29, 6'd29,
6'd29, 6'd29, 6'd30, 6'd30, 6'd30, 6'd31, 6'd31, 6'd31,
6'd31, 6'd32, 6'd32, 6'd32, 6'd33, 6'd33, 6'd33, 6'd33,
6'd34, 6'd34, 6'd34, 6'd35, 6'd35, 6'd35, 6'd35, 6'd36,
6'd36, 6'd36, 6'd36, 6'd37, 6'd37, 6'd37, 6'd38, 6'd38,
6'd38, 6'd38, 6'd39, 6'd39, 6'd39, 6'd40, 6'd40, 6'd40,
6'd40, 6'd41, 6'd41, 6'd41, 6'd42, 6'd42, 6'd42, 6'd42,
6'd43, 6'd43, 6'd43, 6'd44, 6'd44, 6'd44, 6'd44, 6'd45,
6'd45, 6'd45, 6'd46, 6'd46, 6'd46, 6'd46, 6'd47, 6'd47,
6'd47, 6'd48, 6'd48, 6'd48, 6'd48, 6'd49, 6'd49, 6'd49,
6'd50, 6'd50, 6'd50, 6'd50, 6'd51, 6'd51, 6'd51, 6'd52,
6'd52, 6'd52, 6'd52, 6'd53, 6'd53, 6'd53, 6'd54, 6'd54,
6'd54, 6'd54, 6'd55, 6'd55, 6'd55, 6'd56, 6'd56, 6'd56,
6'd56, 6'd57, 6'd57, 6'd57, 6'd58, 6'd58, 6'd58, 6'd58,
6'd59, 6'd59, 6'd59, 6'd60, 6'd60, 6'd60, 6'd60, 6'd61,
6'd61, 6'd61, 6'd62, 6'd62, 6'd62, 6'd62, 6'd63, 6'd63,
6'd63
};
wire [18:0] y_8 = 19'd04096 + ({red, 8'd0} + {red, 3'd0}) + ({green, 9'd0} + {green, 2'd0}) + ({blue, 6'd0} + {blue, 5'd0} + {blue, 2'd0});
wire [18:0] pb_8 = 19'd32768 - ({red, 7'd0} + {red, 4'd0} + {red, 3'd0}) - ({green, 8'd0} + {green, 5'd0} + {green, 3'd0}) + ({blue, 8'd0} + {blue, 7'd0} + {blue, 6'd0});
wire [18:0] pr_8 = 19'd32768 + ({red, 8'd0} + {red, 7'd0} + {red, 6'd0}) - ({green, 8'd0} + {green, 6'd0} + {green, 5'd0} + {green, 4'd0} + {green, 3'd0}) - ({blue, 6'd0} + {blue , 3'd0});
wire [7:0] y_i = ( y_8[17:8] < 16) ? 8'd16 : ( y_8[17:8] > 235) ? 8'd235 : y_8[15:8];
wire [7:0] pb_i = (pb_8[17:8] < 16) ? 8'd16 : (pb_8[17:8] > 240) ? 8'd240 : pb_8[15:8];
wire [7:0] pr_i = (pr_8[17:8] < 16) ? 8'd16 : (pr_8[17:8] > 240) ? 8'd240 : pr_8[15:8];
assign pr = yuv_full[pr_i - 8'd16];
assign y = yuv_full[y_i - 8'd16];
assign pb = yuv_full[pb_i - 8'd16];
endmodule

View File

@@ -1,467 +0,0 @@
//
// sd_card.v
//
// This file implelents a sd card for the MIST board since on the board
// the SD card is connected to the ARM IO controller and the FPGA has no
// direct connection to the SD card. This file provides a SD card like
// interface to the IO controller easing porting of cores that expect
// a direct interface to the SD card.
//
// Copyright (c) 2014 Till Harbaum <till@harbaum.org>
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the Lesser 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/>.
//
// http://elm-chan.org/docs/mmc/mmc_e.html
module sd_card (
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,
input img_mounted,
input [31:0] img_size,
output reg sd_busy = 0,
// data coming in from io controller
input [7:0] sd_buff_dout,
input sd_buff_wr,
// data going out to io controller
output [7:0] sd_buff_din,
input [8:0] sd_buff_addr,
// configuration input
input allow_sdhc,
input sd_cs,
input sd_sck,
input sd_sdi,
output reg sd_sdo
);
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
localparam NCR=4;
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;
localparam WR_STATE_IDLE = 3'd0;
localparam WR_STATE_EXP_DTOKEN = 3'd1;
localparam WR_STATE_RECV_DATA = 3'd2;
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 card_is_reset = 1'b0; // flag that card has received a reset command
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 [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;
// ------------------------- SECTOR BUFFER -----------------------
// the buffer itself. Can hold one sector
reg [8:0] buffer_ptr;
wire [7:0] buffer_dout;
reg [7:0] buffer_din;
reg buffer_write_strobe;
sd_card_dpram #(8, 9) buffer_dpram
(
.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_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 sd_conf = sd_configuring;
reg sd_configuring = 1;
reg [4:0] conf_buff_ptr;
reg [7:0] conf_byte;
reg[255:0] csdcid;
// conf[0]==1 -> io controller is using an sdhc card
wire sd_has_sdhc = conf[0];
assign sd_sdhc = allow_sdhc && sd_has_sdhc;
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_sys) begin
reg old_sd_sck;
reg [5:0] ack;
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;
buffer_write_strobe <= 0;
if (buffer_write_strobe) buffer_ptr <= buffer_ptr + 1'd1;
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
sd_sdo <= 1'b1; // default: send 1's (busy/wait)
if(byte_cnt == 5+NCR) begin
sd_sdo <= reply[~bit_cnt];
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
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;
// ---------- read state machine processing -------------
case(read_state)
RD_STATE_IDLE: ;
// don't do anything
// 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
// 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) 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;
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
// 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
else begin
buffer_ptr <= buffer_ptr + 1'd1;
conf_buff_ptr<= conf_buff_ptr+ 1'd1;
end
end
end
endcase
// ------------------ 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
// 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;
// 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;
// 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};
// set cmd55 flag if previous command was 55
cmd55 <= (cmd == 8'h77);
end
// 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};
// last byte received, evaluate
if(byte_cnt == 5) 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
// 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_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
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
end
endmodule

View File

@@ -1,530 +0,0 @@
//
// user_io.v
//
// user_io for the MiST board
// http://code.google.com/p/mist-board/
//
// Copyright (c) 2014 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/>.
//
// parameter STRLEN and the actual length of conf_str have to match
module user_io #(parameter STRLEN=0, parameter PS2DIV=100) (
input [(8*STRLEN)-1:0] conf_str,
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,
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
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
);
reg [6:0] sbuf;
reg [7:0] cmd;
reg [2:0] bit_cnt; // counts bits 0-7 0-7 ...
reg [9:0] byte_cnt; // counts bytes
reg [7:0] but_sw;
reg [2:0] stick_idx;
assign buttons = but_sw[1:0];
assign switches = but_sw[3:2];
assign 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;
// command byte read by the io controller
wire [7:0] sd_cmd = { 4'h5, sd_conf, sd_sdhc, sd_wr, sd_rd };
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;
reg [PS2_FIFO_BITS-1:0] ps2_kbd_rptr;
// ps2 transmitter state machine
reg [3:0] ps2_kbd_tx_state;
reg [7:0] ps2_kbd_tx_byte;
reg ps2_kbd_parity;
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 clk_sys) begin
reg ps2_clkD;
ps2_clkD <= ps2_clk;
if (~ps2_clkD & ps2_clk) begin
ps2_kbd_r_inc <= 1'b0;
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
end
// mouse
reg [7:0] ps2_mouse_fifo [(2**PS2_FIFO_BITS)-1:0];
reg [PS2_FIFO_BITS-1:0] ps2_mouse_wptr;
reg [PS2_FIFO_BITS-1:0] ps2_mouse_rptr;
// ps2 transmitter state machine
reg [3:0] ps2_mouse_tx_state;
reg [7:0] ps2_mouse_tx_byte;
reg ps2_mouse_parity;
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 clk_sys) begin
reg ps2_clkD;
ps2_clkD <= ps2_clk;
if (~ps2_clkD & ps2_clk) begin
ps2_mouse_r_inc <= 1'b0;
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
end
// fifo to receive serial data from core to be forwarded to io controller
// 16 byte fifo to store serial bytes
localparam SERIAL_OUT_FIFO_BITS = 6;
reg [7:0] serial_out_fifo [(2**SERIAL_OUT_FIFO_BITS)-1:0];
reg [SERIAL_OUT_FIFO_BITS-1:0] serial_out_wptr;
reg [SERIAL_OUT_FIFO_BITS-1:0] serial_out_rptr;
wire serial_out_data_available = serial_out_wptr != serial_out_rptr;
wire [7:0] serial_out_byte = serial_out_fifo[serial_out_rptr] /* synthesis keep */;
wire [7:0] serial_out_status = { 7'b1000000, serial_out_data_available};
// status[0] is reset signal from io controller and is thus used to flush
// the fifo
always @(posedge serial_strobe or posedge status[0]) begin
if(status[0] == 1) begin
serial_out_wptr <= 0;
end else begin
serial_out_fifo[serial_out_wptr] <= serial_data;
serial_out_wptr <= serial_out_wptr + 1'd1;
end
end
always@(negedge spi_sck or posedge status[0]) begin
if(status[0] == 1) begin
serial_out_rptr <= 0;
end else 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'd1;
end
end
end
// SPI bit and byte counters
always@(posedge spi_sck or posedge SPI_SS_IO) begin
if(SPI_SS_IO == 1) begin
bit_cnt <= 0;
byte_cnt <= 0;
end else begin
if((bit_cnt == 7)&&(~&byte_cnt))
byte_cnt <= byte_cnt + 8'd1;
bit_cnt <= bit_cnt + 1'd1;
end
end
// SPI transmitter FPGA -> IO
reg [7:0] spi_byte_out;
always@(negedge spi_sck or posedge SPI_SS_IO) begin
if(SPI_SS_IO == 1) begin
SPI_MISO <= 1'bZ;
end else begin
SPI_MISO <= spi_byte_out[~bit_cnt];
end
end
always@(posedge spi_sck or posedge SPI_SS_IO) begin
reg [31:0] sd_lba_r;
if(SPI_SS_IO == 1) begin
spi_byte_out <= core_type;
end else begin
// read the command byte to choose the response
if(bit_cnt == 7) begin
if(!byte_cnt) cmd <= {sbuf, SPI_MOSI};
spi_byte_out <= 0;
case({(!byte_cnt) ? {sbuf, SPI_MOSI} : cmd})
// reading config string
8'h14: if(byte_cnt < STRLEN) spi_byte_out <= conf_str[(STRLEN - byte_cnt - 1)<<3 +:8];
// reading sd card status
8'h16: if(byte_cnt == 0) begin
spi_byte_out <= sd_cmd;
sd_lba_r <= sd_lba;
end
else if(byte_cnt < 5) spi_byte_out <= sd_lba_r[(4-byte_cnt)<<3 +:8];
// reading sd card write data
8'h18: spi_byte_out <= sd_din;
8'h1b:
// send alternating flag byte and data
if(byte_cnt[0]) spi_byte_out <= serial_out_status;
else spi_byte_out <= serial_out_byte;
endcase
end
end
end
// SPI receiver IO -> FPGA
reg spi_receiver_strobe_r = 0;
reg spi_transfer_end_r = 1;
reg [7:0] spi_byte_in;
// Read at spi_sck clock domain, assemble bytes for transferring to clk_sys
always@(posedge spi_sck or posedge SPI_SS_IO) begin
if(SPI_SS_IO == 1) begin
spi_transfer_end_r <= 1;
end else begin
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 <= { sbuf, SPI_MOSI};
spi_receiver_strobe_r <= ~spi_receiver_strobe_r;
end
end
end
// Process bytes from SPI at the clk_sys domain
always @(posedge clk_sys) begin
reg spi_receiver_strobe;
reg spi_transfer_end;
reg spi_receiver_strobeD;
reg spi_transfer_endD;
reg [7:0] acmd;
reg [7:0] abyte_cnt; // counts bytes
//synchronize between SPI and sys clock domains
spi_receiver_strobeD <= spi_receiver_strobe_r;
spi_receiver_strobe <= spi_receiver_strobeD;
spi_transfer_endD <= spi_transfer_end_r;
spi_transfer_end <= spi_transfer_endD;
if (~spi_transfer_endD & spi_transfer_end) begin
abyte_cnt <= 8'd0;
end else if (spi_receiver_strobeD ^ spi_receiver_strobe) begin
if(~&abyte_cnt)
abyte_cnt <= abyte_cnt + 8'd1;
if(abyte_cnt == 0) begin
acmd <= spi_byte_in;
end else begin
case(acmd)
// buttons and switches
8'h01: but_sw <= spi_byte_in;
8'h60: if (abyte_cnt < 5) joystick_0[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
8'h61: if (abyte_cnt < 5) joystick_1[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
8'h62: if (abyte_cnt < 5) joystick_2[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
8'h63: if (abyte_cnt < 5) joystick_3[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
8'h64: if (abyte_cnt < 5) joystick_4[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
8'h04: begin
// store incoming ps2 mouse bytes
ps2_mouse_fifo[ps2_mouse_wptr] <= spi_byte_in;
ps2_mouse_wptr <= ps2_mouse_wptr + 1'd1;
end
8'h05: begin
// store incoming ps2 keyboard bytes
ps2_kbd_fifo[ps2_kbd_wptr] <= spi_byte_in;
ps2_kbd_wptr <= ps2_kbd_wptr + 1'd1;
end
// joystick analog
8'h1a: begin
// first byte is joystick index
if(abyte_cnt == 1)
stick_idx <= spi_byte_in[2:0];
else if(abyte_cnt == 2) begin
// second byte is x axis
if(stick_idx == 0)
joystick_analog_0[15:8] <= spi_byte_in;
else if(stick_idx == 1)
joystick_analog_1[15:8] <= spi_byte_in;
end else if(abyte_cnt == 3) begin
// third byte is y axis
if(stick_idx == 0)
joystick_analog_0[7:0] <= spi_byte_in;
else if(stick_idx == 1)
joystick_analog_1[7:0] <= spi_byte_in;
end
end
8'h15: status <= spi_byte_in;
// status, 32bit version
8'h1e: if(abyte_cnt<5) status[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
endcase
end
end
end
// Process SD-card related bytes from SPI at the clk_sd domain
always @(posedge clk_sd) begin
reg spi_receiver_strobe;
reg spi_transfer_end;
reg spi_receiver_strobeD;
reg spi_transfer_endD;
reg sd_wrD;
reg [7:0] acmd;
reg [7:0] abyte_cnt; // counts bytes
//synchronize between SPI and sd clock domains
spi_receiver_strobeD <= spi_receiver_strobe_r;
spi_receiver_strobe <= spi_receiver_strobeD;
spi_transfer_endD <= spi_transfer_end_r;
spi_transfer_end <= spi_transfer_endD;
if(sd_dout_strobe) begin
sd_dout_strobe<= 0;
if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1;
end
sd_din_strobe<= 0;
sd_wrD <= sd_wr;
// fetch the first byte immediately after the write command seen
if (~sd_wrD & sd_wr) begin
sd_buff_addr <= 0;
sd_din_strobe <= 1;
end
img_mounted <= 0;
if (~spi_transfer_endD & spi_transfer_end) begin
abyte_cnt <= 8'd0;
sd_ack <= 1'b0;
sd_ack_conf <= 1'b0;
sd_dout_strobe <= 1'b0;
sd_din_strobe <= 1'b0;
sd_buff_addr <= 0;
end else if (spi_receiver_strobeD ^ spi_receiver_strobe) begin
if(~&abyte_cnt)
abyte_cnt <= abyte_cnt + 8'd1;
if(abyte_cnt == 0) begin
acmd <= spi_byte_in;
if(spi_byte_in == 8'h18) begin
sd_din_strobe <= 1'b1;
if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1;
end
if((spi_byte_in == 8'h17) || (spi_byte_in == 8'h18))
sd_ack <= 1'b1;
end else begin
case(acmd)
// send sector IO -> FPGA
8'h17: begin
// flag that download begins
sd_dout_strobe <= 1'b1;
sd_dout <= spi_byte_in;
end
// send sector FPGA -> IO
8'h18: begin
sd_din_strobe <= 1'b1;
if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1;
end
// send SD config IO -> FPGA
8'h19: begin
// flag that download begins
sd_dout_strobe <= 1'b1;
sd_ack_conf <= 1'b1;
sd_dout <= spi_byte_in;
end
8'h1c: img_mounted <= 1;
// send image info
8'h1d: if(abyte_cnt<5) img_size[(abyte_cnt-1)<<3 +:8] <= spi_byte_in;
endcase
end
end
end
endmodule