mirror of
https://github.com/mist-devel/mist-board.git
synced 2026-02-05 15:44:40 +00:00
NES: use common MiST modules, fix PAL video
This commit is contained in:
@@ -71,7 +71,7 @@ module GameLoader(input clk, input reset,
|
||||
// Read 16 bytes of ines header
|
||||
0: if (indata_clk) begin
|
||||
error <= 0;
|
||||
ctr <= ctr + 1;
|
||||
ctr <= ctr + 1'd1;
|
||||
ines[ctr] <= indata;
|
||||
bytes_left <= {prgrom, 14'b0};
|
||||
if (ctr == 4'b1111)
|
||||
@@ -81,8 +81,8 @@ module GameLoader(input clk, input reset,
|
||||
1, 2: begin // Read the next |bytes_left| bytes into |mem_addr|
|
||||
if (bytes_left != 0) begin
|
||||
if (indata_clk) begin
|
||||
bytes_left <= bytes_left - 1;
|
||||
mem_addr <= mem_addr + 1;
|
||||
bytes_left <= bytes_left - 1'd1;
|
||||
mem_addr <= mem_addr + 1'd1;
|
||||
end
|
||||
end else if (state == 1) begin
|
||||
state <= 2;
|
||||
@@ -150,8 +150,7 @@ module NES_mist(
|
||||
parameter CONF_STR = {
|
||||
"NES;NES;",
|
||||
"O12,System Type,NTSC,PAL,Dendy;",
|
||||
"O3,HQ2X(VGA-Only),OFF,ON;",
|
||||
"O4,Scanlines,OFF,ON;",
|
||||
"O34,Scanlines,OFF,25%,50%,75%;",
|
||||
"O5,Joystick swap,OFF,ON;",
|
||||
"O6,Invert mirroring,OFF,ON;",
|
||||
"O7,Hide overscan,OFF,ON;",
|
||||
@@ -164,8 +163,8 @@ wire [31:0] status;
|
||||
|
||||
wire arm_reset = status[0];
|
||||
wire [1:0] system_type = status[2:1];
|
||||
wire smoothing_osd = status[3];
|
||||
wire scanlines_osd = status[4];
|
||||
wire pal_video = |system_type;
|
||||
wire [1:0] scanlines = status[4:3];
|
||||
wire joy_swap = status[5];
|
||||
wire mirroring_osd = status[6];
|
||||
wire overscan_osd = status[7];
|
||||
@@ -174,6 +173,7 @@ wire reset_osd = status[9];
|
||||
|
||||
wire scandoubler_disable;
|
||||
wire ypbpr;
|
||||
wire no_csync;
|
||||
wire ps2_kbd_clk, ps2_kbd_data;
|
||||
|
||||
wire [7:0] core_joy_A;
|
||||
@@ -195,6 +195,7 @@ user_io #(.STRLEN($size(CONF_STR)>>3)) user_io(
|
||||
.buttons(buttons),
|
||||
.scandoubler_disable(scandoubler_disable),
|
||||
.ypbpr(ypbpr),
|
||||
.no_csync(no_csync),
|
||||
|
||||
.joystick_0(core_joy_A),
|
||||
.joystick_1(core_joy_B),
|
||||
@@ -208,10 +209,8 @@ user_io #(.STRLEN($size(CONF_STR)>>3)) user_io(
|
||||
wire [7:0] joyA = joy_swap ? core_joy_B : core_joy_A;
|
||||
wire [7:0] joyB = joy_swap ? core_joy_A : core_joy_B;
|
||||
|
||||
wire [7:0] nes_joy_A = (reset_nes || osd_visible) ? 8'd0 :
|
||||
{ joyA[0], joyA[1], joyA[2], joyA[3], joyA[7], joyA[6], joyA[5], joyA[4] } | kbd_joy0;
|
||||
wire [7:0] nes_joy_B = (reset_nes || osd_visible) ? 8'd0 :
|
||||
{ joyB[0], joyB[1], joyB[2], joyB[3], joyB[7], joyB[6], joyB[5], joyB[4] } | kbd_joy1;
|
||||
wire [7:0] nes_joy_A = { joyA[0], joyA[1], joyA[2], joyA[3], joyA[7], joyA[6], joyA[5], joyA[4] } | kbd_joy0;
|
||||
wire [7:0] nes_joy_B = { joyB[0], joyB[1], joyB[2], joyB[3], joyB[7], joyB[6], joyB[5], joyB[4] } | kbd_joy1;
|
||||
|
||||
wire clock_locked;
|
||||
wire clk85;
|
||||
@@ -306,8 +305,6 @@ wire [7:0] nes_joy_B = (reset_nes || osd_visible) ? 8'd0 :
|
||||
|
||||
assign LED = downloading ? 1'b0 : loader_fail ? led_blink[23] : 1'b1;
|
||||
|
||||
wire osd_visible;
|
||||
|
||||
wire reset_nes = (init_reset || buttons[1] || arm_reset || reset_osd || download_reset || loader_fail);
|
||||
|
||||
wire ext_audio = 1;
|
||||
@@ -407,43 +404,79 @@ sdram sdram (
|
||||
wire downloading;
|
||||
|
||||
data_io data_io (
|
||||
.sck ( SPI_SCK ),
|
||||
.ss ( SPI_SS2 ),
|
||||
.sdi ( SPI_DI ),
|
||||
.clk_sys ( clk ),
|
||||
|
||||
.downloading ( downloading ),
|
||||
.size ( ),
|
||||
.SPI_SCK ( SPI_SCK ),
|
||||
.SPI_SS2 ( SPI_SS2 ),
|
||||
.SPI_DI ( SPI_DI ),
|
||||
|
||||
.ioctl_download ( downloading ),
|
||||
|
||||
// ram interface
|
||||
.clk ( clk ),
|
||||
.wr ( loader_clk ),
|
||||
.a ( ),
|
||||
.d ( loader_input )
|
||||
.ioctl_wr ( loader_clk ),
|
||||
.ioctl_dout ( loader_input )
|
||||
);
|
||||
|
||||
wire nes_hs, nes_vs;
|
||||
wire [4:0] nes_r;
|
||||
wire [4:0] nes_g;
|
||||
wire [4:0] nes_b;
|
||||
|
||||
video video (
|
||||
.clk(clk),
|
||||
.sdi(SPI_DI),
|
||||
.sck(SPI_SCK),
|
||||
.ss(SPI_SS3),
|
||||
|
||||
.color(color),
|
||||
.count_v(scanline),
|
||||
.count_h(cycle),
|
||||
.mode(scandoubler_disable),
|
||||
.ypbpr(ypbpr),
|
||||
.smoothing(!smoothing_osd),
|
||||
.scanlines(scanlines_osd),
|
||||
.pal_video(pal_video),
|
||||
.overscan(overscan_osd),
|
||||
.palette(palette2_osd),
|
||||
|
||||
.VGA_HS(VGA_HS),
|
||||
.VGA_VS(VGA_VS),
|
||||
.VGA_R(VGA_R),
|
||||
.VGA_G(VGA_G),
|
||||
.VGA_B(VGA_B),
|
||||
|
||||
.osd_visible(osd_visible)
|
||||
|
||||
.sync_h(nes_hs),
|
||||
.sync_v(nes_vs),
|
||||
.r(nes_r),
|
||||
.g(nes_g),
|
||||
.b(nes_b)
|
||||
);
|
||||
|
||||
mist_video #(.COLOR_DEPTH(5), .OSD_COLOR(3'd5), .SD_HCNT_WIDTH(10)) mist_video (
|
||||
.clk_sys ( clk ),
|
||||
|
||||
// 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 ( nes_r ),
|
||||
.G ( nes_g ),
|
||||
.B ( nes_b ),
|
||||
|
||||
.HSync ( ~nes_hs ),
|
||||
.VSync ( ~nes_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 )
|
||||
);
|
||||
|
||||
assign AUDIO_R = audio;
|
||||
|
||||
11
cores/nes/mist/clk.ppf
Normal file
11
cores/nes/mist/clk.ppf
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE pinplan>
|
||||
<pinplan intended_family="Cyclone III" variation_name="clk" 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>
|
||||
4
cores/nes/mist/clk.qip
Normal file
4
cores/nes/mist/clk.qip
Normal file
@@ -0,0 +1,4 @@
|
||||
set_global_assignment -name IP_TOOL_NAME "ALTPLL"
|
||||
set_global_assignment -name IP_TOOL_VERSION "13.1"
|
||||
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "clk.v"]
|
||||
set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "clk.ppf"]
|
||||
@@ -62,19 +62,16 @@ derive_clock_uncertainty;
|
||||
# Set Input Delay
|
||||
#**************************************************************
|
||||
|
||||
# SDRAM is clocked from sd1clk_pin, but the SDRAM controller uses memclk
|
||||
set_input_delay -clock [get_clocks {clock_21mhz|altpll_component|auto_generated|pll1|clk[0]}] -max 6.4 [get_ports SDRAM_DQ[*]]
|
||||
set_input_delay -clock [get_clocks {clock_21mhz|altpll_component|auto_generated|pll1|clk[0]}] -min 3.2 [get_ports SDRAM_DQ[*]]
|
||||
set_input_delay -clock [get_clocks {clock_21mhz|altpll_component|auto_generated|pll1|clk[0]}] -reference_pin [get_ports SDRAM_CLK] -max 6.4 [get_ports SDRAM_DQ[*]]
|
||||
set_input_delay -clock [get_clocks {clock_21mhz|altpll_component|auto_generated|pll1|clk[0]}] -reference_pin [get_ports SDRAM_CLK] -min 3.2 [get_ports SDRAM_DQ[*]]
|
||||
|
||||
|
||||
#**************************************************************
|
||||
# Set Output Delay
|
||||
#**************************************************************
|
||||
|
||||
set_output_delay -clock [get_clocks {clock_21mhz|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 {clock_21mhz|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 {clock_21mhz|altpll_component|auto_generated|pll1|clk[0]}] -max 1.5 [get_ports SDRAM_CLK]
|
||||
set_output_delay -clock [get_clocks {clock_21mhz|altpll_component|auto_generated|pll1|clk[0]}] -min -0.8 [get_ports SDRAM_CLK]
|
||||
set_output_delay -clock [get_clocks {clock_21mhz|altpll_component|auto_generated|pll1|clk[0]}] -reference_pin [get_ports SDRAM_CLK] -max 1.5 [get_ports {SDRAM_D* SDRAM_A* SDRAM_BA* SDRAM_n* SDRAM_CKE}]
|
||||
set_output_delay -clock [get_clocks {clock_21mhz|altpll_component|auto_generated|pll1|clk[0]}] -reference_pin [get_ports SDRAM_CLK] -min -0.8 [get_ports {SDRAM_D* SDRAM_A* SDRAM_BA* SDRAM_n* SDRAM_CKE}]
|
||||
|
||||
set_output_delay -clock [get_clocks {clock_21mhz|altpll_component|auto_generated|pll1|clk[1]}] -max 0 [get_ports {VGA_*}]
|
||||
set_output_delay -clock [get_clocks {clock_21mhz|altpll_component|auto_generated|pll1|clk[1]}] -min -5 [get_ports {VGA_*}]
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
//
|
||||
// data_io.v
|
||||
//
|
||||
// io controller writable ram 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/>.
|
||||
//
|
||||
|
||||
module data_io #(parameter ADDR_WIDTH=16, START_ADDR = 0) (
|
||||
// io controller spi interface
|
||||
input sck,
|
||||
input ss,
|
||||
input sdi,
|
||||
|
||||
output downloading, // signal indicating an active download
|
||||
output [ADDR_WIDTH-1:0] size, // number of bytes in input buffer
|
||||
|
||||
// external ram interface
|
||||
input clk,
|
||||
output reg wr,
|
||||
output reg [ADDR_WIDTH-1:0] a,
|
||||
output [7:0] d
|
||||
);
|
||||
|
||||
assign d = data;
|
||||
assign size = addr - START_ADDR;
|
||||
|
||||
// *********************************************************************************
|
||||
// spi client
|
||||
// *********************************************************************************
|
||||
|
||||
// this core supports only the display related OSD commands
|
||||
// of the minimig
|
||||
reg [6:0] sbuf;
|
||||
reg [7:0] cmd;
|
||||
reg [7:0] data;
|
||||
reg [4:0] cnt;
|
||||
|
||||
reg [ADDR_WIDTH-1:0] addr;
|
||||
reg rclk;
|
||||
|
||||
localparam UIO_FILE_TX = 8'h53;
|
||||
localparam UIO_FILE_TX_DAT = 8'h54;
|
||||
|
||||
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 <= 5'd0;
|
||||
else begin
|
||||
rclk <= 1'b0;
|
||||
|
||||
// don't shift in last bit. It is evaluated directly
|
||||
// when writing to ram
|
||||
if(cnt != 15)
|
||||
sbuf <= { sbuf[5:0], sdi};
|
||||
|
||||
// increase target address after write
|
||||
if(rclk)
|
||||
addr <= addr + 1;
|
||||
|
||||
// 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};
|
||||
|
||||
// prepare/end transmission
|
||||
if((cmd == UIO_FILE_TX) && (cnt == 15)) begin
|
||||
// prepare
|
||||
if(sdi) begin
|
||||
addr <= START_ADDR;
|
||||
downloading_reg <= 1'b1;
|
||||
end else
|
||||
downloading_reg <= 1'b0;
|
||||
end
|
||||
|
||||
// command 0x54: UIO_FILE_TX
|
||||
if((cmd == UIO_FILE_TX_DAT) && (cnt == 15)) begin
|
||||
data <= {sbuf, sdi};
|
||||
rclk <= 1'b1;
|
||||
a <= addr;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
reg rclkD, rclkD2;
|
||||
always@(posedge clk) begin
|
||||
// bring rclk from spi clock domain into c64 clock domain
|
||||
rclkD <= rclk;
|
||||
rclkD2 <= rclkD;
|
||||
wr <= 1'b0;
|
||||
|
||||
if(rclkD && !rclkD2)
|
||||
wr <= 1'b1;
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -1,161 +0,0 @@
|
||||
// A simple OSD implementation. Can be hooked up between a cores
|
||||
// VGA output and the physical VGA pins
|
||||
|
||||
module osd (
|
||||
// OSDs pixel clock, should be synchronous to cores pixel clock to
|
||||
// avoid jitter.
|
||||
input pclk,
|
||||
|
||||
// SPI interface
|
||||
input sck,
|
||||
input ss,
|
||||
input sdi,
|
||||
|
||||
// VGA signals coming from core
|
||||
input [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 reg osd_enable
|
||||
|
||||
);
|
||||
|
||||
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 [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 hsD, hsD2;
|
||||
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] dsp_height = vs_pol?vs_low:vs_high;
|
||||
|
||||
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;
|
||||
|
||||
v_cnt <= v_cnt + 10'd1;
|
||||
end
|
||||
|
||||
else
|
||||
h_cnt <= h_cnt + 10'd1;
|
||||
|
||||
vsD <= vs_in;
|
||||
vsD2 <= vsD;
|
||||
|
||||
// falling edge of vs_in
|
||||
if(!vsD && vsD2) begin
|
||||
v_cnt <= 10'd0;
|
||||
vs_high <= v_cnt;
|
||||
end
|
||||
|
||||
// rising edge of vs_in
|
||||
else if(vsD && !vsD2) begin
|
||||
v_cnt <= 10'd0;
|
||||
vs_low <= v_cnt;
|
||||
end
|
||||
end
|
||||
|
||||
// area in which OSD is being displayed
|
||||
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)>> 1) + OSD_Y_OFFSET;
|
||||
wire [9:0] v_osd_end = v_osd_start + OSD_HEIGHT;
|
||||
wire [9:0] osd_hcnt = h_cnt - h_osd_start + 7'd1; // one pixel offset for osd_byte register
|
||||
wire [9:0] osd_vcnt = v_cnt - v_osd_start;
|
||||
|
||||
wire osd_de = osd_enable &&
|
||||
(hs_in != hs_pol) && (h_cnt >= h_osd_start) && (h_cnt < h_osd_end) &&
|
||||
(vs_in != vs_pol) && (v_cnt >= v_osd_start) && (v_cnt < v_osd_end);
|
||||
|
||||
reg [7:0] osd_byte;
|
||||
always @(posedge pclk) osd_byte <= osd_buffer[{osd_vcnt[6:4], osd_hcnt[7:0]}];
|
||||
|
||||
wire osd_pixel = osd_byte[osd_vcnt[3:1]];
|
||||
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] };
|
||||
|
||||
endmodule
|
||||
@@ -1,522 +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 [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
|
||||
|
||||
if(sd_din_strobe) begin
|
||||
sd_din_strobe<= 0;
|
||||
if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1;
|
||||
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;
|
||||
|
||||
// fetch first byte when sectore FPGA->IO command has been seen
|
||||
if(spi_byte_in == 8'h18)
|
||||
sd_din_strobe <= 1'b1;
|
||||
|
||||
if((spi_byte_in == 8'h17) || (spi_byte_in == 8'h18))
|
||||
sd_ack <= 1'b1;
|
||||
|
||||
end else begin
|
||||
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: sd_din_strobe <= 1'b1;
|
||||
|
||||
// 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
|
||||
@@ -291,14 +291,12 @@ set_location_assignment PLL_1 -to clock_21mhz|altpll_component|auto_generated|pl
|
||||
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 QIP_FILE "../../mist-modules/mist.qip"
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE mist/NES_mist.sv
|
||||
set_global_assignment -name VERILOG_FILE mist/ps2_intf.v
|
||||
set_global_assignment -name VERILOG_FILE mist/keyboard.v
|
||||
set_global_assignment -name VERILOG_FILE mist/sigma_delta_dac.v
|
||||
set_global_assignment -name VERILOG_FILE mist/data_io.v
|
||||
set_global_assignment -name VERILOG_FILE mist/sdram.v
|
||||
set_global_assignment -name VERILOG_FILE mist/user_io.v
|
||||
set_global_assignment -name VERILOG_FILE mist/osd.v
|
||||
set_global_assignment -name VERILOG_FILE mist/clk.v
|
||||
set_global_assignment -name SDC_FILE mist/constraints.sdc
|
||||
set_global_assignment -name VERILOG_FILE src/nes.v
|
||||
@@ -306,9 +304,7 @@ set_global_assignment -name SYSTEMVERILOG_FILE src/cart.sv
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE src/apu.sv
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE src/ppu.sv
|
||||
set_global_assignment -name VERILOG_FILE src/compat.v
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE src/video_mixer.sv
|
||||
set_global_assignment -name VERILOG_FILE src/video.v
|
||||
set_global_assignment -name VERILOG_FILE src/hq2x.v
|
||||
set_global_assignment -name VERILOG_FILE src/dsp.v
|
||||
set_global_assignment -name VHDL_FILE src/dpram.vhd
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE src/EEPROM_24C0x.sv
|
||||
|
||||
@@ -1,268 +0,0 @@
|
||||
// Copyright (c) 2012-2013 Ludvig Strigeus
|
||||
// This program is GPL Licensed. See COPYING for the full license.
|
||||
|
||||
module DiffCheck(input [14:0] rgb1, input [14:0] rgb2, output result);
|
||||
wire [5:0] r = rgb1[4:0] - rgb2[4:0];
|
||||
wire [5:0] g = rgb1[9:5] - rgb2[9:5];
|
||||
wire [5:0] b = rgb1[14:10] - rgb2[14:10];
|
||||
wire [6:0] t = $signed(r) + $signed(b);
|
||||
wire [6:0] gx = {g[5], g};
|
||||
wire [7:0] y = $signed(t) + $signed(gx);
|
||||
wire [6:0] u = $signed(r) - $signed(b);
|
||||
wire [7:0] v = $signed({g, 1'b0}) - $signed(t);
|
||||
// if y is inside (-24..24)
|
||||
wire y_inside = (y < 8'h18 || y >= 8'he8);
|
||||
// if u is inside (-4, 4)
|
||||
wire u_inside = (u < 7'h4 || u >= 7'h7c);
|
||||
// if v is inside (-6, 6)
|
||||
wire v_inside = (v < 8'h6 || v >= 8'hfA);
|
||||
assign result = !(y_inside && u_inside && v_inside);
|
||||
endmodule
|
||||
|
||||
module InnerBlend(input [8:0] Op, input [4:0] A, input [4:0] B, input [4:0] C, output [4:0] O);
|
||||
wire OpOnes = Op[4];
|
||||
wire [7:0] Amul = A * Op[7:5];
|
||||
wire [6:0] Bmul = B * Op[3:2];
|
||||
wire [6:0] Cmul = C * Op[1:0];
|
||||
wire [7:0] At = Amul;
|
||||
wire [7:0] Bt = (OpOnes == 0) ? {Bmul, 1'b0} : {3'b0, B};
|
||||
wire [7:0] Ct = (OpOnes == 0) ? {Cmul, 1'b0} : {3'b0, C};
|
||||
wire [8:0] Res = {At, 1'b0} + Bt + Ct;
|
||||
assign O = Op[8] ? A : Res[8:4];
|
||||
endmodule
|
||||
|
||||
module Blend(input [5:0] rule, input disable_hq2x,
|
||||
input [14:0] E, input [14:0] A, input [14:0] B, input [14:0] D, input [14:0] F, input [14:0] H, output [14:0] Result);
|
||||
reg [1:0] input_ctrl;
|
||||
reg [8:0] op;
|
||||
localparam BLEND0 = 9'b1_xxx_x_xx_xx; // 0: A
|
||||
localparam BLEND1 = 9'b0_110_0_10_00; // 1: (A * 12 + B * 4) >> 4
|
||||
localparam BLEND2 = 9'b0_100_0_10_10; // 2: (A * 8 + B * 4 + C * 4) >> 4
|
||||
localparam BLEND3 = 9'b0_101_0_10_01; // 3: (A * 10 + B * 4 + C * 2) >> 4
|
||||
localparam BLEND4 = 9'b0_110_0_01_01; // 4: (A * 12 + B * 2 + C * 2) >> 4
|
||||
localparam BLEND5 = 9'b0_010_0_11_11; // 5: (A * 4 + (B + C) * 6) >> 4
|
||||
localparam BLEND6 = 9'b0_111_1_xx_xx; // 6: (A * 14 + B + C) >> 4
|
||||
localparam AB = 2'b00;
|
||||
localparam AD = 2'b01;
|
||||
localparam DB = 2'b10;
|
||||
localparam BD = 2'b11;
|
||||
wire is_diff;
|
||||
DiffCheck diff_checker(rule[1] ? B : H,
|
||||
rule[0] ? D : F,
|
||||
is_diff);
|
||||
always @* begin
|
||||
case({!is_diff, rule[5:2]})
|
||||
1,17: {op, input_ctrl} = {BLEND1, AB};
|
||||
2,18: {op, input_ctrl} = {BLEND1, DB};
|
||||
3,19: {op, input_ctrl} = {BLEND1, BD};
|
||||
4,20: {op, input_ctrl} = {BLEND2, DB};
|
||||
5,21: {op, input_ctrl} = {BLEND2, AB};
|
||||
6,22: {op, input_ctrl} = {BLEND2, AD};
|
||||
|
||||
8: {op, input_ctrl} = {BLEND0, 2'bxx};
|
||||
9: {op, input_ctrl} = {BLEND0, 2'bxx};
|
||||
10: {op, input_ctrl} = {BLEND0, 2'bxx};
|
||||
11: {op, input_ctrl} = {BLEND1, AB};
|
||||
12: {op, input_ctrl} = {BLEND1, AB};
|
||||
13: {op, input_ctrl} = {BLEND1, AB};
|
||||
14: {op, input_ctrl} = {BLEND1, DB};
|
||||
15: {op, input_ctrl} = {BLEND1, BD};
|
||||
|
||||
24: {op, input_ctrl} = {BLEND2, DB};
|
||||
25: {op, input_ctrl} = {BLEND5, DB};
|
||||
26: {op, input_ctrl} = {BLEND6, DB};
|
||||
27: {op, input_ctrl} = {BLEND2, DB};
|
||||
28: {op, input_ctrl} = {BLEND4, DB};
|
||||
29: {op, input_ctrl} = {BLEND5, DB};
|
||||
30: {op, input_ctrl} = {BLEND3, BD};
|
||||
31: {op, input_ctrl} = {BLEND3, DB};
|
||||
default: {op, input_ctrl} = 11'bx;
|
||||
endcase
|
||||
|
||||
// Setting op[8] effectively disables HQ2X because blend will always return E.
|
||||
if (disable_hq2x)
|
||||
op[8] = 1;
|
||||
end
|
||||
// Generate inputs to the inner blender. Valid combinations.
|
||||
// 00: E A B
|
||||
// 01: E A D
|
||||
// 10: E D B
|
||||
// 11: E B D
|
||||
wire [14:0] Input1 = E;
|
||||
wire [14:0] Input2 = !input_ctrl[1] ? A :
|
||||
!input_ctrl[0] ? D : B;
|
||||
wire [14:0] Input3 = !input_ctrl[0] ? B : D;
|
||||
InnerBlend inner_blend1(op, Input1[4:0], Input2[4:0], Input3[4:0], Result[4:0]);
|
||||
InnerBlend inner_blend2(op, Input1[9:5], Input2[9:5], Input3[9:5], Result[9:5]);
|
||||
InnerBlend inner_blend3(op, Input1[14:10], Input2[14:10], Input3[14:10], Result[14:10]);
|
||||
endmodule
|
||||
|
||||
module Hq2x(input clk,
|
||||
input [14:0] inputpixel,
|
||||
input disable_hq2x,
|
||||
input reset_frame,
|
||||
input reset_line,
|
||||
input [9:0] read_x,
|
||||
output frame_available,
|
||||
output reg [14:0] outpixel);
|
||||
reg [5:0] hqTable[0:255];
|
||||
initial begin
|
||||
hqTable[0] = 19; hqTable[1] = 19; hqTable[2] = 26; hqTable[3] = 11;
|
||||
hqTable[4] = 19; hqTable[5] = 19; hqTable[6] = 26; hqTable[7] = 11;
|
||||
hqTable[8] = 23; hqTable[9] = 15; hqTable[10] = 47; hqTable[11] = 35;
|
||||
hqTable[12] = 23; hqTable[13] = 15; hqTable[14] = 55; hqTable[15] = 39;
|
||||
hqTable[16] = 19; hqTable[17] = 19; hqTable[18] = 26; hqTable[19] = 58;
|
||||
hqTable[20] = 19; hqTable[21] = 19; hqTable[22] = 26; hqTable[23] = 58;
|
||||
hqTable[24] = 23; hqTable[25] = 15; hqTable[26] = 35; hqTable[27] = 35;
|
||||
hqTable[28] = 23; hqTable[29] = 15; hqTable[30] = 7; hqTable[31] = 35;
|
||||
hqTable[32] = 19; hqTable[33] = 19; hqTable[34] = 26; hqTable[35] = 11;
|
||||
hqTable[36] = 19; hqTable[37] = 19; hqTable[38] = 26; hqTable[39] = 11;
|
||||
hqTable[40] = 23; hqTable[41] = 15; hqTable[42] = 55; hqTable[43] = 39;
|
||||
hqTable[44] = 23; hqTable[45] = 15; hqTable[46] = 51; hqTable[47] = 43;
|
||||
hqTable[48] = 19; hqTable[49] = 19; hqTable[50] = 26; hqTable[51] = 58;
|
||||
hqTable[52] = 19; hqTable[53] = 19; hqTable[54] = 26; hqTable[55] = 58;
|
||||
hqTable[56] = 23; hqTable[57] = 15; hqTable[58] = 51; hqTable[59] = 35;
|
||||
hqTable[60] = 23; hqTable[61] = 15; hqTable[62] = 7; hqTable[63] = 43;
|
||||
hqTable[64] = 19; hqTable[65] = 19; hqTable[66] = 26; hqTable[67] = 11;
|
||||
hqTable[68] = 19; hqTable[69] = 19; hqTable[70] = 26; hqTable[71] = 11;
|
||||
hqTable[72] = 23; hqTable[73] = 61; hqTable[74] = 35; hqTable[75] = 35;
|
||||
hqTable[76] = 23; hqTable[77] = 61; hqTable[78] = 51; hqTable[79] = 35;
|
||||
hqTable[80] = 19; hqTable[81] = 19; hqTable[82] = 26; hqTable[83] = 11;
|
||||
hqTable[84] = 19; hqTable[85] = 19; hqTable[86] = 26; hqTable[87] = 11;
|
||||
hqTable[88] = 23; hqTable[89] = 15; hqTable[90] = 51; hqTable[91] = 35;
|
||||
hqTable[92] = 23; hqTable[93] = 15; hqTable[94] = 51; hqTable[95] = 35;
|
||||
hqTable[96] = 19; hqTable[97] = 19; hqTable[98] = 26; hqTable[99] = 11;
|
||||
hqTable[100] = 19; hqTable[101] = 19; hqTable[102] = 26; hqTable[103] = 11;
|
||||
hqTable[104] = 23; hqTable[105] = 61; hqTable[106] = 7; hqTable[107] = 35;
|
||||
hqTable[108] = 23; hqTable[109] = 61; hqTable[110] = 7; hqTable[111] = 43;
|
||||
hqTable[112] = 19; hqTable[113] = 19; hqTable[114] = 26; hqTable[115] = 11;
|
||||
hqTable[116] = 19; hqTable[117] = 19; hqTable[118] = 26; hqTable[119] = 58;
|
||||
hqTable[120] = 23; hqTable[121] = 15; hqTable[122] = 51; hqTable[123] = 35;
|
||||
hqTable[124] = 23; hqTable[125] = 61; hqTable[126] = 7; hqTable[127] = 43;
|
||||
hqTable[128] = 19; hqTable[129] = 19; hqTable[130] = 26; hqTable[131] = 11;
|
||||
hqTable[132] = 19; hqTable[133] = 19; hqTable[134] = 26; hqTable[135] = 11;
|
||||
hqTable[136] = 23; hqTable[137] = 15; hqTable[138] = 47; hqTable[139] = 35;
|
||||
hqTable[140] = 23; hqTable[141] = 15; hqTable[142] = 55; hqTable[143] = 39;
|
||||
hqTable[144] = 19; hqTable[145] = 19; hqTable[146] = 26; hqTable[147] = 11;
|
||||
hqTable[148] = 19; hqTable[149] = 19; hqTable[150] = 26; hqTable[151] = 11;
|
||||
hqTable[152] = 23; hqTable[153] = 15; hqTable[154] = 51; hqTable[155] = 35;
|
||||
hqTable[156] = 23; hqTable[157] = 15; hqTable[158] = 51; hqTable[159] = 35;
|
||||
hqTable[160] = 19; hqTable[161] = 19; hqTable[162] = 26; hqTable[163] = 11;
|
||||
hqTable[164] = 19; hqTable[165] = 19; hqTable[166] = 26; hqTable[167] = 11;
|
||||
hqTable[168] = 23; hqTable[169] = 15; hqTable[170] = 55; hqTable[171] = 39;
|
||||
hqTable[172] = 23; hqTable[173] = 15; hqTable[174] = 51; hqTable[175] = 43;
|
||||
hqTable[176] = 19; hqTable[177] = 19; hqTable[178] = 26; hqTable[179] = 11;
|
||||
hqTable[180] = 19; hqTable[181] = 19; hqTable[182] = 26; hqTable[183] = 11;
|
||||
hqTable[184] = 23; hqTable[185] = 15; hqTable[186] = 51; hqTable[187] = 39;
|
||||
hqTable[188] = 23; hqTable[189] = 15; hqTable[190] = 7; hqTable[191] = 43;
|
||||
hqTable[192] = 19; hqTable[193] = 19; hqTable[194] = 26; hqTable[195] = 11;
|
||||
hqTable[196] = 19; hqTable[197] = 19; hqTable[198] = 26; hqTable[199] = 11;
|
||||
hqTable[200] = 23; hqTable[201] = 15; hqTable[202] = 51; hqTable[203] = 35;
|
||||
hqTable[204] = 23; hqTable[205] = 15; hqTable[206] = 51; hqTable[207] = 39;
|
||||
hqTable[208] = 19; hqTable[209] = 19; hqTable[210] = 26; hqTable[211] = 11;
|
||||
hqTable[212] = 19; hqTable[213] = 19; hqTable[214] = 26; hqTable[215] = 11;
|
||||
hqTable[216] = 23; hqTable[217] = 15; hqTable[218] = 51; hqTable[219] = 35;
|
||||
hqTable[220] = 23; hqTable[221] = 15; hqTable[222] = 7; hqTable[223] = 35;
|
||||
hqTable[224] = 19; hqTable[225] = 19; hqTable[226] = 26; hqTable[227] = 11;
|
||||
hqTable[228] = 19; hqTable[229] = 19; hqTable[230] = 26; hqTable[231] = 11;
|
||||
hqTable[232] = 23; hqTable[233] = 15; hqTable[234] = 51; hqTable[235] = 35;
|
||||
hqTable[236] = 23; hqTable[237] = 15; hqTable[238] = 7; hqTable[239] = 43;
|
||||
hqTable[240] = 19; hqTable[241] = 19; hqTable[242] = 26; hqTable[243] = 11;
|
||||
hqTable[244] = 19; hqTable[245] = 19; hqTable[246] = 26; hqTable[247] = 11;
|
||||
hqTable[248] = 23; hqTable[249] = 15; hqTable[250] = 7; hqTable[251] = 35;
|
||||
hqTable[252] = 23; hqTable[253] = 15; hqTable[254] = 7; hqTable[255] = 43;
|
||||
end
|
||||
|
||||
reg [14:0] Prev0, Prev1, Prev2, Curr0, Curr1, Curr2, Next0, Next1, Next2;
|
||||
reg [14:0] A, B, D, F, G, H;
|
||||
reg [7:0] pattern, nextpatt;
|
||||
reg [1:0] i;
|
||||
reg [7:0] y;
|
||||
reg [1:0] yshort; // counts only lines 0-3, then stays on 3.
|
||||
reg [8:0] offs;
|
||||
reg first_pixel;
|
||||
reg [14:0] inbuf[0:511]; // 2 lines of input pixels
|
||||
reg [14:0] outbuf[0:2047]; // 4 lines of output pixels
|
||||
|
||||
|
||||
wire curbuf = y[0];
|
||||
reg last_line;
|
||||
wire prevbuf = (yshort <= 1) ? curbuf : !curbuf;
|
||||
wire writebuf = !curbuf;
|
||||
reg writestep;
|
||||
|
||||
wire diff0, diff1;
|
||||
DiffCheck diffcheck0(Curr1, (i == 0) ? Prev0 : (i == 1) ? Curr0 : (i == 2) ? Prev2 : Next1, diff0);
|
||||
DiffCheck diffcheck1(Curr1, (i == 0) ? Prev1 : (i == 1) ? Next0 : (i == 2) ? Curr2 : Next2, diff1);
|
||||
wire [7:0] new_pattern = {diff1, diff0, pattern[7:2]};
|
||||
always @(posedge clk)
|
||||
pattern <= new_pattern;
|
||||
|
||||
wire less_254 = (offs >= 510) || (offs < 254);
|
||||
wire [8:0] inbuf_rd_addr = {i[0] == 0 ? prevbuf : curbuf, offs[7:0]};
|
||||
|
||||
always @(posedge clk) begin
|
||||
if ((i == 0 || i ==1) && less_254) Curr2 <= inbuf[inbuf_rd_addr];
|
||||
if (i == 1 && less_254) begin
|
||||
Prev2 <= Curr2;
|
||||
end
|
||||
if (i == 2 && less_254) begin
|
||||
Next2 <= last_line ? Curr2 : inputpixel;
|
||||
inbuf[{writebuf, offs[7:0]}] <= inputpixel;
|
||||
end
|
||||
end
|
||||
|
||||
wire [14:0] X = (i == 0) ? A : (i == 1) ? Prev1 : (i == 2) ? Next1 : G;
|
||||
wire [14:0] blend_result;
|
||||
Blend blender(hqTable[nextpatt], disable_hq2x, Curr0, X, B, D, F, H, blend_result);
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (!offs[8])
|
||||
outbuf[{curbuf, i[1], offs[7:0], i[1]^i[0]}] <= blend_result;
|
||||
if (!writestep) begin
|
||||
nextpatt <= {nextpatt[5], nextpatt[3], nextpatt[0], nextpatt[6], nextpatt[1], nextpatt[7], nextpatt[4], nextpatt[2]};
|
||||
{B, F, H, D} <= {F, H, D, B};
|
||||
end else begin
|
||||
nextpatt <= {new_pattern[7:6], new_pattern[3], new_pattern[5], new_pattern[2], new_pattern[4], new_pattern[1:0]};
|
||||
{A, G} <= {Prev0, Next0};
|
||||
{B, F, H, D} <= {Prev1, Curr2, Next1, Curr0};
|
||||
{Prev0, Prev1} <= {first_pixel ? Prev2 : Prev1, Prev2};
|
||||
{Curr0, Curr1} <= {first_pixel ? Curr2 : Curr1, Curr2};
|
||||
{Next0, Next1} <= {first_pixel ? Next2 : Next1, Next2};
|
||||
end
|
||||
end
|
||||
|
||||
reg last_reset_line;
|
||||
initial last_reset_line = 0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
outpixel <= outbuf[{!curbuf, read_x}];
|
||||
if (writestep) begin
|
||||
offs <= offs + 9'b1;
|
||||
first_pixel <= 0;
|
||||
end
|
||||
i <= i + 2'b1;
|
||||
writestep <= (i == 2);
|
||||
if (reset_line) begin
|
||||
offs <= -2;
|
||||
first_pixel <= 1;
|
||||
i <= 0;
|
||||
writestep <= 0;
|
||||
// Increment Y only once.
|
||||
if (!last_reset_line) begin
|
||||
y <= y + 8'b1;
|
||||
yshort <= (yshort == 3) ? yshort : (yshort + 2'b1);
|
||||
last_line <= ((y + 8'b1) >= 240);
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
if (reset_frame) begin
|
||||
y <= 0;
|
||||
yshort <= 0;
|
||||
last_line <= 0;
|
||||
end
|
||||
last_reset_line <= reset_line;
|
||||
end
|
||||
assign frame_available = (i == 0) && first_pixel && (yshort == 2) && !reset_line;
|
||||
endmodule // Hq2x
|
||||
@@ -6,51 +6,19 @@ module video(
|
||||
input [5:0] color,
|
||||
input [8:0] count_h,
|
||||
input [8:0] count_v,
|
||||
input mode,
|
||||
input ypbpr,
|
||||
input smoothing,
|
||||
input scanlines,
|
||||
input pal_video,
|
||||
input overscan,
|
||||
input palette,
|
||||
|
||||
input sck,
|
||||
input ss,
|
||||
input sdi,
|
||||
|
||||
output VGA_HS,
|
||||
output VGA_VS,
|
||||
output [5:0] VGA_R,
|
||||
output [5:0] VGA_G,
|
||||
output [5:0] VGA_B,
|
||||
|
||||
output osd_visible
|
||||
output reg sync_h,
|
||||
output reg sync_v,
|
||||
output [4:0] r,
|
||||
output [4:0] g,
|
||||
output [4:0] b
|
||||
);
|
||||
|
||||
reg clk2 = 1'b0;
|
||||
always @(posedge clk) clk2 <= ~clk2;
|
||||
wire clkv = mode ? clk2 : clk;
|
||||
|
||||
wire [5:0] R_out, G_out, B_out;
|
||||
|
||||
osd #(10'd0, 10'd0, 3'd4) osd (
|
||||
.pclk(clkv),
|
||||
|
||||
.sck(sck),
|
||||
.sdi(sdi),
|
||||
.ss(ss),
|
||||
|
||||
.red_in ({vga_r, vga_r[4]}),
|
||||
.green_in({vga_g, vga_g[4]}),
|
||||
.blue_in ({vga_b, vga_b[4]}),
|
||||
.hs_in(sync_h),
|
||||
.vs_in(sync_v),
|
||||
|
||||
.red_out(R_out),
|
||||
.green_out(G_out),
|
||||
.blue_out(B_out),
|
||||
|
||||
.osd_enable(osd_visible)
|
||||
);
|
||||
reg vidclk_en;
|
||||
always @(posedge clk) vidclk_en <= ~vidclk_en;
|
||||
|
||||
// NTSC UnsaturatedV6 palette
|
||||
//see: http://www.firebrandx.com/nespalette.html
|
||||
@@ -65,77 +33,51 @@ wire [14:0] pixel = palette ? pixel_unsat[14:0] : pixel_fce[14:0];
|
||||
reg [15:0] pixel_unsat, pixel_fce;
|
||||
|
||||
always @(posedge clk) begin
|
||||
pixel_unsat <= pal_unsat_lut[color];
|
||||
pixel_fce <= pal_fcelut[color];
|
||||
pixel_unsat <= pal_unsat_lut[color];
|
||||
pixel_fce <= pal_fcelut[color];
|
||||
end
|
||||
|
||||
|
||||
// Horizontal and vertical counters
|
||||
reg [9:0] h, v;
|
||||
wire hpicture = (h < 512); // 512 lines of picture
|
||||
wire hend = (h == 681); // End of line, 682 pixels.
|
||||
wire vpicture = (v < (480 >> mode)); // 480 lines of picture
|
||||
wire vend = (v == (523 >> mode)); // End of picture, 524 lines. (Should really be 525 according to NTSC spec)
|
||||
|
||||
wire [14:0] doubler_pixel;
|
||||
wire doubler_sync;
|
||||
|
||||
Hq2x hq2x(clk, pixel, smoothing, // enabled
|
||||
count_v[8], // reset_frame
|
||||
(count_h[8:3] == 42), // reset_line
|
||||
{v[0], h[9] ? 9'd0 : h[8:0] + 9'd1}, // 0-511 for line 1, or 512-1023 for line 2.
|
||||
doubler_sync, // new frame has just started
|
||||
doubler_pixel); // pixel is outputted
|
||||
wire vpicture = (v < 240); // 240 lines of picture
|
||||
wire vend = (v == (pal_video ? 311 : 261)); // End of picture, 262/312 lines.
|
||||
|
||||
reg [8:0] old_count_v;
|
||||
wire sync_frame = (old_count_v == 9'd511) && (count_v == 9'd0);
|
||||
always @(posedge clkv) begin
|
||||
h <= (hend || (mode ? sync_frame : doubler_sync)) ? 10'd0 : h + 10'd1;
|
||||
if(mode ? sync_frame : doubler_sync) v <= 0;
|
||||
else if (hend) v <= vend ? 10'd0 : v + 10'd1;
|
||||
always @(posedge clk) begin
|
||||
if (vidclk_en) begin
|
||||
h <= (hend || sync_frame) ? 10'd0 : h + 10'd1;
|
||||
if(sync_frame) v <= 0;
|
||||
else if (hend) v <= vend ? 10'd0 : v + 10'd1;
|
||||
|
||||
old_count_v <= count_v;
|
||||
old_count_v <= count_v;
|
||||
end
|
||||
end
|
||||
|
||||
wire [14:0] pixel_v = (!hpicture || !vpicture) ? 15'd0 : mode ? pixel : doubler_pixel;
|
||||
wire darker = !mode && v[0] && scanlines;
|
||||
wire [14:0] pixel_v = (!hpicture || !vpicture) ? 15'd0 : pixel;
|
||||
|
||||
// display overlay to hide overscan area
|
||||
// based on Mario3, DoubleDragon2, Shadow of the Ninja
|
||||
wire ol = overscan && ( (h > 512-16) ||
|
||||
(h < 20) ||
|
||||
(v < (mode ? 6 : 12)) ||
|
||||
(v > (mode ? 240-10 : 480-20))
|
||||
wire ol = overscan && ( (h > 512-16) ||
|
||||
(h < 20) ||
|
||||
(v < 6 ) ||
|
||||
(v > (240-10))
|
||||
);
|
||||
|
||||
wire [4:0] vga_r = ol ? {4'b0, pixel_v[4:4]} : (darker ? {1'b0, pixel_v[4:1]} : pixel_v[4:0]);
|
||||
wire [4:0] vga_g = ol ? {4'b0, pixel_v[9:9]} : (darker ? {1'b0, pixel_v[9:6]} : pixel_v[9:5]);
|
||||
wire [4:0] vga_b = ol ? {4'b0, pixel_v[14:14]} : (darker ? {1'b0, pixel_v[14:11]} : pixel_v[14:10]);
|
||||
wire sync_h = ((h >= (512 + 23 + (mode ? 18 : 35))) && (h < (512 + 23 + (mode ? 18 : 35) + 82)));
|
||||
wire sync_v = ((v >= (mode ? 240 + 5 : 480 + 10)) && (v < (mode ? 240 + 14 : 480 + 12)));
|
||||
assign r = ol ? {4'b0, pixel_v[4:4]} : pixel_v[4:0];
|
||||
assign g = ol ? {4'b0, pixel_v[9:9]} : pixel_v[9:5];
|
||||
assign b = ol ? {4'b0, pixel_v[14:14]} : pixel_v[14:10];
|
||||
|
||||
video_mixer video_mixer
|
||||
(
|
||||
.scandoubler_disable(mode),
|
||||
.ypbpr(ypbpr),
|
||||
.ypbpr_full(1),
|
||||
|
||||
.r_i({R_out, R_out[5:4]}),
|
||||
.g_i({G_out, G_out[5:4]}),
|
||||
.b_i({B_out, B_out[5:4]}),
|
||||
.hsync_i(sync_h),
|
||||
.vsync_i(sync_v),
|
||||
|
||||
.r_p({R_out, R_out[5:4]}),
|
||||
.g_p({G_out, G_out[5:4]}),
|
||||
.b_p({B_out, B_out[5:4]}),
|
||||
.hsync_p(sync_h),
|
||||
.vsync_p(sync_v),
|
||||
|
||||
.VGA_HS(VGA_HS),
|
||||
.VGA_VS(VGA_VS),
|
||||
.VGA_R(VGA_R),
|
||||
.VGA_G(VGA_G),
|
||||
.VGA_B(VGA_B)
|
||||
);
|
||||
always @(posedge clk) begin
|
||||
if (vidclk_en) begin
|
||||
if (h == 556) begin
|
||||
sync_h <= 1;
|
||||
sync_v <= (v >= (pal_video ? 270 : 243) && (v < ((pal_video ? 270 : 243) + 3)));
|
||||
end
|
||||
if (h == 606) sync_h <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
`timescale 1ns / 1ps
|
||||
|
||||
// Core should provide as much color resolution as possible with normalized 0-255 range
|
||||
// this module will reduce color resolution to 6 bits only at final stage.
|
||||
|
||||
module video_mixer
|
||||
(
|
||||
// 0 = HVSync 31KHz, 1 = CSync 15KHz
|
||||
input scandoubler_disable,
|
||||
|
||||
// YPbPr always uses composite sync
|
||||
input ypbpr,
|
||||
|
||||
// 0 = 16-240 range. 1 = 0-255 range. (only for YPbPr color space)
|
||||
input ypbpr_full,
|
||||
|
||||
// interlace (15khz) color
|
||||
input [7:0] r_i,
|
||||
input [7:0] g_i,
|
||||
input [7:0] b_i,
|
||||
|
||||
// interlace sync. Positive pulses.
|
||||
input hsync_i,
|
||||
input vsync_i,
|
||||
|
||||
// progressive (31khz) color
|
||||
input [7:0] r_p,
|
||||
input [7:0] g_p,
|
||||
input [7:0] b_p,
|
||||
|
||||
// progressive sync. Positive pulses.
|
||||
input hsync_p,
|
||||
input vsync_p,
|
||||
|
||||
// MiST video output signals
|
||||
output [5:0] VGA_R,
|
||||
output [5:0] VGA_G,
|
||||
output [5:0] VGA_B,
|
||||
output VGA_VS,
|
||||
output VGA_HS
|
||||
);
|
||||
|
||||
wire [7:0] red = scandoubler_disable ? r_i : r_p;
|
||||
wire [7:0] green = scandoubler_disable ? g_i : g_p;
|
||||
wire [7:0] blue = scandoubler_disable ? b_i : b_p;
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
// http://marsee101.blog19.fc2.com/blog-entry-2311.html
|
||||
// Y = 16 + 0.257*R + 0.504*G + 0.098*B (Y = 0.299*R + 0.587*G + 0.114*B)
|
||||
// Pb = 128 - 0.148*R - 0.291*G + 0.439*B (Pb = -0.169*R - 0.331*G + 0.500*B)
|
||||
// Pr = 128 + 0.439*R - 0.368*G - 0.071*B (Pr = 0.500*R - 0.419*G - 0.081*B)
|
||||
|
||||
wire [18:0] y_8 = 19'd04096 + ({red, 6'd0} + {red, 1'd0}) + ({green, 7'd0} + {green}) + ({blue, 4'd0} + {blue, 3'd0} + {blue});
|
||||
wire [18:0] pb_8 = 19'd32768 - ({red, 5'd0} + {red, 2'd0} + {red, 1'd0}) - ({green, 6'd0} + {green, 3'd0} + {green, 1'd0}) + ({blue, 6'd0} + {blue, 5'd0} + {blue, 4'd0});
|
||||
wire [18:0] pr_8 = 19'd32768 + ({red, 6'd0} + {red, 5'd0} + {red, 4'd0}) - ({green, 6'd0} + {green, 4'd0} + {green, 3'd0} + {green, 2'd0} + {green, 1'd0}) - ({blue, 4'd0} + {blue , 1'd0});
|
||||
|
||||
wire [7:0] y = ( y_8[17:8] < 16) ? 8'd16 : ( y_8[17:8] > 235) ? 8'd235 : y_8[15:8];
|
||||
wire [7:0] pb = (pb_8[17:8] < 16) ? 8'd16 : (pb_8[17:8] > 240) ? 8'd240 : pb_8[15:8];
|
||||
wire [7:0] pr = (pr_8[17:8] < 16) ? 8'd16 : (pr_8[17:8] > 240) ? 8'd240 : pr_8[15:8];
|
||||
|
||||
assign VGA_R = ypbpr ? (ypbpr_full ? yuv_full[pr-8'd16] : pr[7:2]) : red[7:2];
|
||||
assign VGA_G = ypbpr ? (ypbpr_full ? yuv_full[y -8'd16] : y[7:2]) : green[7:2];
|
||||
assign VGA_B = ypbpr ? (ypbpr_full ? yuv_full[pb-8'd16] : pb[7:2]) : blue[7:2];
|
||||
assign VGA_VS = (scandoubler_disable | ypbpr) ? 1'b1 : ~vsync_p;
|
||||
assign VGA_HS = scandoubler_disable ? ~(hsync_i ^ vsync_i) : ypbpr ? ~(hsync_p ^ vsync_p) : ~hsync_p;
|
||||
|
||||
endmodule
|
||||
Reference in New Issue
Block a user