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