mirror of
https://github.com/mist-devel/mist-board.git
synced 2026-02-05 07:34:41 +00:00
Archie: use common mist-video
This commit is contained in:
@@ -136,7 +136,7 @@ set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_*
|
||||
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to DRAM_*
|
||||
|
||||
set_global_assignment -name ENABLE_SIGNALTAP OFF
|
||||
set_global_assignment -name USE_SIGNALTAP_FILE output_files/ide.stp
|
||||
set_global_assignment -name USE_SIGNALTAP_FILE output_files/dio.stp
|
||||
set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "3.3-V LVTTL"
|
||||
set_global_assignment -name ENABLE_CONFIGURATION_PINS OFF
|
||||
set_global_assignment -name ENABLE_NCE_PIN OFF
|
||||
@@ -181,13 +181,15 @@ set_global_assignment -name PHYSICAL_SYNTHESIS_EFFORT EXTRA
|
||||
set_global_assignment -name PRE_MAPPING_RESYNTHESIS ON
|
||||
set_global_assignment -name REMOVE_REDUNDANT_LOGIC_CELLS ON
|
||||
set_global_assignment -name VERILOG_FILE archimedes_mist_top.v
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE rgb2ypbpr.sv
|
||||
set_global_assignment -name VERILOG_FILE scandoubler.v
|
||||
set_global_assignment -name VERILOG_FILE "../../../../mist-modules/mist_video.v"
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE "../../../../mist-modules/cofi.sv"
|
||||
set_global_assignment -name VERILOG_FILE "../../../../mist-modules/scandoubler.v"
|
||||
set_global_assignment -name SYSTEMVERILOG_FILE "../../../../mist-modules/rgb2ypbpr.sv"
|
||||
set_global_assignment -name VERILOG_FILE "../../../../mist-modules/osd.v"
|
||||
set_global_assignment -name VERILOG_FILE sigma_delta_dac.v
|
||||
set_global_assignment -name VERILOG_FILE audio.v
|
||||
set_global_assignment -name VERILOG_FILE data_io.v
|
||||
set_global_assignment -name VERILOG_FILE user_io.v
|
||||
set_global_assignment -name VERILOG_FILE osd.v
|
||||
set_global_assignment -name VERILOG_FILE sram_line_en.v
|
||||
set_global_assignment -name VERILOG_FILE sram_byte_en.v
|
||||
set_global_assignment -name QIP_FILE clockgen.qip
|
||||
@@ -229,6 +231,4 @@ set_global_assignment -name QIP_FILE rom_reconfig_25.qip
|
||||
set_global_assignment -name QIP_FILE pll_reconfig.qip
|
||||
set_global_assignment -name QIP_FILE rom_reconfig_36.qip
|
||||
set_global_assignment -name QIP_FILE pll_vidc.qip
|
||||
set_global_assignment -name SIGNALTAP_FILE output_files/vidc.stp
|
||||
set_global_assignment -name SIGNALTAP_FILE output_files/sd.stp
|
||||
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
|
||||
@@ -103,6 +103,7 @@ wire [1:0] buttons;
|
||||
wire [1:0] switches;
|
||||
wire scandoubler_disable;
|
||||
wire ypbpr;
|
||||
wire no_csync;
|
||||
|
||||
// the top file should generate the correct clocks for the machine
|
||||
|
||||
@@ -258,74 +259,48 @@ always @(posedge clk_pix) begin
|
||||
{ r_adj, g_adj, b_adj } <= 12'h0;
|
||||
end
|
||||
|
||||
wire [5:0] sd_r, sd_g, sd_b;
|
||||
wire sd_hs;
|
||||
wire sd_vs;
|
||||
|
||||
scandoubler #(11, 4) scandoubler
|
||||
(
|
||||
.clk_sys ( clk_pix ),
|
||||
.scanlines ( 2'b00 ),
|
||||
.ce_divider ( 1'b1 ),
|
||||
.hs_in ( hs_adj ),
|
||||
.vs_in ( vs_adj ),
|
||||
.r_in ( r_adj ),
|
||||
.g_in ( g_adj ),
|
||||
.b_in ( b_adj ),
|
||||
.hs_out ( sd_hs ),
|
||||
.vs_out ( sd_vs ),
|
||||
.r_out ( sd_r ),
|
||||
.g_out ( sd_g ),
|
||||
.b_out ( sd_b )
|
||||
);
|
||||
|
||||
wire vs = scandoubler_en ? sd_vs : core_vs;
|
||||
wire hs = scandoubler_en ? sd_hs : core_hs;
|
||||
wire [5:0] r = scandoubler_en ? sd_r : { r_adj, r_adj[3:2] };
|
||||
wire [5:0] g = scandoubler_en ? sd_g : { g_adj, g_adj[3:2] };
|
||||
wire [5:0] b = scandoubler_en ? sd_b : { b_adj, b_adj[3:2] };
|
||||
|
||||
wire [5:0] osd_r_o, osd_g_o, osd_b_o;
|
||||
|
||||
osd #(10'd0,10'd0,4) OSD (
|
||||
.clk_sys ( clk_pix ),
|
||||
|
||||
// spi for OSD
|
||||
.SPI_DI ( SPI_DI ),
|
||||
.SPI_SCK ( SPI_SCK ),
|
||||
.SPI_SS3 ( SPI_SS3 ),
|
||||
|
||||
.R_in ( r ),
|
||||
.G_in ( g ),
|
||||
.B_in ( b ),
|
||||
.HSync ( hs ),
|
||||
.VSync ( vs ),
|
||||
|
||||
.R_out ( osd_r_o ),
|
||||
.G_out ( osd_g_o ),
|
||||
.B_out ( osd_b_o )
|
||||
);
|
||||
|
||||
wire [5:0] Y, Pb, Pr;
|
||||
|
||||
rgb2ypbpr rgb2ypbpr
|
||||
(
|
||||
.red ( osd_r_o ),
|
||||
.green ( osd_g_o ),
|
||||
.blue ( osd_b_o ),
|
||||
.y ( Y ),
|
||||
.pb ( Pb ),
|
||||
.pr ( Pr )
|
||||
);
|
||||
|
||||
wire scandoubler_en = ~scandoubler_disable && pixbaseclk_select[0] == pixbaseclk_select[1];
|
||||
assign VGA_R = ypbpr?Pr:osd_r_o;
|
||||
assign VGA_G = ypbpr? Y:osd_g_o;
|
||||
assign VGA_B = ypbpr?Pb:osd_b_o;
|
||||
wire CSync = ~(hs ^ vs);
|
||||
//24 MHz modes get composite sync automatically
|
||||
assign VGA_HS = ((pixbaseclk_select[0] == pixbaseclk_select[1] && scandoubler_disable) | ypbpr) ? CSync : hs;
|
||||
assign VGA_VS = ((pixbaseclk_select[0] == pixbaseclk_select[1] && scandoubler_disable) | ypbpr) ? 1'b1 : vs;
|
||||
|
||||
mist_video #(.COLOR_DEPTH(4), .SD_HCNT_WIDTH(10)) mist_video (
|
||||
.clk_sys ( clk_pix ),
|
||||
|
||||
// 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 ( 2'b00 ),
|
||||
|
||||
// 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_en ),
|
||||
// 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 ( r_adj ),
|
||||
.G ( g_adj ),
|
||||
.B ( b_adj ),
|
||||
|
||||
.HSync ( hs_adj ),
|
||||
.VSync ( vs_adj ),
|
||||
|
||||
// MiST video output signals
|
||||
.VGA_R ( VGA_R ),
|
||||
.VGA_G ( VGA_G ),
|
||||
.VGA_B ( VGA_B ),
|
||||
.VGA_VS ( VGA_VS ),
|
||||
.VGA_HS ( VGA_HS )
|
||||
);
|
||||
|
||||
wire [31:0] sd_lba;
|
||||
wire [1:0] sd_rd;
|
||||
@@ -358,6 +333,7 @@ user_io user_io(
|
||||
.BUTTONS ( buttons ),
|
||||
.scandoubler_disable(scandoubler_disable),
|
||||
.ypbpr ( ypbpr ),
|
||||
.no_csync ( no_csync ),
|
||||
|
||||
.JOY0 ( joyA ),
|
||||
.JOY1 ( joyB ),
|
||||
|
||||
@@ -1,179 +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 clk_sys,
|
||||
|
||||
// SPI interface
|
||||
input SPI_SCK,
|
||||
input SPI_SS3,
|
||||
input SPI_DI,
|
||||
|
||||
// VGA signals coming from core
|
||||
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] 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;
|
||||
|
||||
// *********************************************************************************
|
||||
// spi client
|
||||
// *********************************************************************************
|
||||
|
||||
// this core supports only the display related OSD commands
|
||||
// of the minimig
|
||||
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 SPI_SCK, posedge SPI_SS3) begin
|
||||
reg [4:0] cnt;
|
||||
reg [10:0] bcnt;
|
||||
reg [7:0] sbuf;
|
||||
reg [7:0] cmd;
|
||||
|
||||
if(SPI_SS3) begin
|
||||
cnt <= 0;
|
||||
bcnt <= 0;
|
||||
end else begin
|
||||
sbuf <= {sbuf[6:0], SPI_DI};
|
||||
|
||||
// 0:7 is command, rest payload
|
||||
if(cnt < 15) cnt <= cnt + 1'd1;
|
||||
else cnt <= 8;
|
||||
|
||||
if(cnt == 7) begin
|
||||
cmd <= {sbuf[6:0], SPI_DI};
|
||||
|
||||
// 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
|
||||
|
||||
// *********************************************************************************
|
||||
// video timing and sync polarity anaylsis
|
||||
// *********************************************************************************
|
||||
|
||||
// horizontal counter
|
||||
reg [9:0] h_cnt;
|
||||
reg [9:0] hs_low, hs_high;
|
||||
wire hs_pol = hs_high < hs_low;
|
||||
wire [9:0] dsp_width = hs_pol ? hs_low : hs_high;
|
||||
|
||||
// vertical counter
|
||||
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;
|
||||
|
||||
wire doublescan = (dsp_height>350);
|
||||
|
||||
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
|
||||
|
||||
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 = ((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;
|
||||
|
||||
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);
|
||||
|
||||
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 osd_pixel = osd_byte[doublescan ? osd_vcnt[4:2] : 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]};
|
||||
|
||||
endmodule
|
||||
@@ -1,55 +0,0 @@
|
||||
module rgb2ypbpr (
|
||||
input [5:0] red,
|
||||
input [5:0] green,
|
||||
input [5:0] blue,
|
||||
|
||||
output [5:0] y,
|
||||
output [5:0] pb,
|
||||
output [5:0] pr
|
||||
);
|
||||
|
||||
wire [5:0] yuv_full[225] = '{
|
||||
6'd0, 6'd0, 6'd0, 6'd0, 6'd1, 6'd1, 6'd1, 6'd1,
|
||||
6'd2, 6'd2, 6'd2, 6'd3, 6'd3, 6'd3, 6'd3, 6'd4,
|
||||
6'd4, 6'd4, 6'd5, 6'd5, 6'd5, 6'd5, 6'd6, 6'd6,
|
||||
6'd6, 6'd7, 6'd7, 6'd7, 6'd7, 6'd8, 6'd8, 6'd8,
|
||||
6'd9, 6'd9, 6'd9, 6'd9, 6'd10, 6'd10, 6'd10, 6'd11,
|
||||
6'd11, 6'd11, 6'd11, 6'd12, 6'd12, 6'd12, 6'd13, 6'd13,
|
||||
6'd13, 6'd13, 6'd14, 6'd14, 6'd14, 6'd15, 6'd15, 6'd15,
|
||||
6'd15, 6'd16, 6'd16, 6'd16, 6'd17, 6'd17, 6'd17, 6'd17,
|
||||
6'd18, 6'd18, 6'd18, 6'd19, 6'd19, 6'd19, 6'd19, 6'd20,
|
||||
6'd20, 6'd20, 6'd21, 6'd21, 6'd21, 6'd21, 6'd22, 6'd22,
|
||||
6'd22, 6'd23, 6'd23, 6'd23, 6'd23, 6'd24, 6'd24, 6'd24,
|
||||
6'd25, 6'd25, 6'd25, 6'd25, 6'd26, 6'd26, 6'd26, 6'd27,
|
||||
6'd27, 6'd27, 6'd27, 6'd28, 6'd28, 6'd28, 6'd29, 6'd29,
|
||||
6'd29, 6'd29, 6'd30, 6'd30, 6'd30, 6'd31, 6'd31, 6'd31,
|
||||
6'd31, 6'd32, 6'd32, 6'd32, 6'd33, 6'd33, 6'd33, 6'd33,
|
||||
6'd34, 6'd34, 6'd34, 6'd35, 6'd35, 6'd35, 6'd35, 6'd36,
|
||||
6'd36, 6'd36, 6'd36, 6'd37, 6'd37, 6'd37, 6'd38, 6'd38,
|
||||
6'd38, 6'd38, 6'd39, 6'd39, 6'd39, 6'd40, 6'd40, 6'd40,
|
||||
6'd40, 6'd41, 6'd41, 6'd41, 6'd42, 6'd42, 6'd42, 6'd42,
|
||||
6'd43, 6'd43, 6'd43, 6'd44, 6'd44, 6'd44, 6'd44, 6'd45,
|
||||
6'd45, 6'd45, 6'd46, 6'd46, 6'd46, 6'd46, 6'd47, 6'd47,
|
||||
6'd47, 6'd48, 6'd48, 6'd48, 6'd48, 6'd49, 6'd49, 6'd49,
|
||||
6'd50, 6'd50, 6'd50, 6'd50, 6'd51, 6'd51, 6'd51, 6'd52,
|
||||
6'd52, 6'd52, 6'd52, 6'd53, 6'd53, 6'd53, 6'd54, 6'd54,
|
||||
6'd54, 6'd54, 6'd55, 6'd55, 6'd55, 6'd56, 6'd56, 6'd56,
|
||||
6'd56, 6'd57, 6'd57, 6'd57, 6'd58, 6'd58, 6'd58, 6'd58,
|
||||
6'd59, 6'd59, 6'd59, 6'd60, 6'd60, 6'd60, 6'd60, 6'd61,
|
||||
6'd61, 6'd61, 6'd62, 6'd62, 6'd62, 6'd62, 6'd63, 6'd63,
|
||||
6'd63
|
||||
};
|
||||
|
||||
wire [18:0] y_8 = 19'd04096 + ({red, 8'd0} + {red, 3'd0}) + ({green, 9'd0} + {green, 2'd0}) + ({blue, 6'd0} + {blue, 5'd0} + {blue, 2'd0});
|
||||
wire [18:0] pb_8 = 19'd32768 - ({red, 7'd0} + {red, 4'd0} + {red, 3'd0}) - ({green, 8'd0} + {green, 5'd0} + {green, 3'd0}) + ({blue, 8'd0} + {blue, 7'd0} + {blue, 6'd0});
|
||||
wire [18:0] pr_8 = 19'd32768 + ({red, 8'd0} + {red, 7'd0} + {red, 6'd0}) - ({green, 8'd0} + {green, 6'd0} + {green, 5'd0} + {green, 4'd0} + {green, 3'd0}) - ({blue, 6'd0} + {blue , 3'd0});
|
||||
|
||||
wire [7:0] y_i = ( y_8[17:8] < 16) ? 8'd16 : ( y_8[17:8] > 235) ? 8'd235 : y_8[15:8];
|
||||
wire [7:0] pb_i = (pb_8[17:8] < 16) ? 8'd16 : (pb_8[17:8] > 240) ? 8'd240 : pb_8[15:8];
|
||||
wire [7:0] pr_i = (pr_8[17:8] < 16) ? 8'd16 : (pr_8[17:8] > 240) ? 8'd240 : pr_8[15:8];
|
||||
|
||||
assign pr = yuv_full[pr_i - 8'd16];
|
||||
assign y = yuv_full[y_i - 8'd16];
|
||||
assign pb = yuv_full[pb_i - 8'd16];
|
||||
|
||||
endmodule
|
||||
@@ -1,216 +0,0 @@
|
||||
//
|
||||
// scandoubler.v
|
||||
//
|
||||
// Copyright (c) 2015 Till Harbaum <till@harbaum.org>
|
||||
//
|
||||
// This source file is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published
|
||||
// by the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This source file is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// TODO: Delay vsync one line
|
||||
|
||||
module scandoubler
|
||||
(
|
||||
// system interface
|
||||
input clk_sys,
|
||||
|
||||
// scanlines (00-none 01-25% 10-50% 11-75%)
|
||||
input [1:0] scanlines,
|
||||
input ce_divider, // 0 - 4, 1 - 2
|
||||
|
||||
// shifter video interface
|
||||
input hs_in,
|
||||
input vs_in,
|
||||
input [COLOR_DEPTH-1:0] r_in,
|
||||
input [COLOR_DEPTH-1:0] g_in,
|
||||
input [COLOR_DEPTH-1:0] b_in,
|
||||
|
||||
// output interface
|
||||
output reg hs_out,
|
||||
output reg vs_out,
|
||||
output reg [5:0] r_out,
|
||||
output reg [5:0] g_out,
|
||||
output reg [5:0] b_out
|
||||
);
|
||||
|
||||
parameter HCNT_WIDTH = 9;
|
||||
parameter COLOR_DEPTH = 6;
|
||||
|
||||
// try to detect changes in input signal and lock input clock gate
|
||||
// it
|
||||
|
||||
reg [1:0] i_div;
|
||||
|
||||
reg ce_x1, ce_x2;
|
||||
|
||||
always @(*) begin
|
||||
if (!ce_divider) begin
|
||||
ce_x1 = (i_div == 2'b01);
|
||||
ce_x2 = i_div[0];
|
||||
end else begin
|
||||
ce_x1 = ~i_div[0];
|
||||
ce_x2 = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk_sys) begin
|
||||
reg last_hs_in;
|
||||
last_hs_in <= hs_in;
|
||||
if(last_hs_in & !hs_in) begin
|
||||
i_div <= 2'b00;
|
||||
end else begin
|
||||
i_div <= i_div + 2'd1;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// --------------------- create output signals -----------------
|
||||
// latch everything once more to make it glitch free and apply scanline effect
|
||||
reg scanline;
|
||||
reg [5:0] r;
|
||||
reg [5:0] g;
|
||||
reg [5:0] b;
|
||||
|
||||
always @(*) begin
|
||||
if (COLOR_DEPTH == 6) begin
|
||||
b = sd_out[5:0];
|
||||
g = sd_out[11:6];
|
||||
r = sd_out[17:12];
|
||||
end else if (COLOR_DEPTH == 2) begin
|
||||
b = {3{sd_out[1:0]}};
|
||||
g = {3{sd_out[3:2]}};
|
||||
r = {3{sd_out[5:4]}};
|
||||
end else if (COLOR_DEPTH == 1) begin
|
||||
b = {6{sd_out[0]}};
|
||||
g = {6{sd_out[1]}};
|
||||
r = {6{sd_out[2]}};
|
||||
end else begin
|
||||
b = { sd_out[COLOR_DEPTH-1:0], sd_out[COLOR_DEPTH-1 -:(6-COLOR_DEPTH)] };
|
||||
g = { sd_out[COLOR_DEPTH*2-1:COLOR_DEPTH], sd_out[COLOR_DEPTH*2-1 -:(6-COLOR_DEPTH)] };
|
||||
r = { sd_out[COLOR_DEPTH*3-1:COLOR_DEPTH*2], sd_out[COLOR_DEPTH*3-1 -:(6-COLOR_DEPTH)] };
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk_sys) begin
|
||||
if(ce_x2) begin
|
||||
hs_out <= hs_sd;
|
||||
vs_out <= vs_in;
|
||||
|
||||
// reset scanlines at every new screen
|
||||
if(vs_out != vs_in) scanline <= 0;
|
||||
|
||||
// toggle scanlines at begin of every hsync
|
||||
if(hs_out && !hs_sd) scanline <= !scanline;
|
||||
|
||||
// if no scanlines or not a scanline
|
||||
if(!scanline || !scanlines) begin
|
||||
r_out <= r;
|
||||
g_out <= g;
|
||||
b_out <= b;
|
||||
end else begin
|
||||
case(scanlines)
|
||||
1: begin // reduce 25% = 1/2 + 1/4
|
||||
r_out <= {1'b0, r[5:1]} + {2'b00, r[5:2] };
|
||||
g_out <= {1'b0, g[5:1]} + {2'b00, g[5:2] };
|
||||
b_out <= {1'b0, b[5:1]} + {2'b00, b[5:2] };
|
||||
end
|
||||
|
||||
2: begin // reduce 50% = 1/2
|
||||
r_out <= {1'b0, r[5:1]};
|
||||
g_out <= {1'b0, g[5:1]};
|
||||
b_out <= {1'b0, b[5:1]};
|
||||
end
|
||||
|
||||
3: begin // reduce 75% = 1/4
|
||||
r_out <= {2'b00, r[5:2]};
|
||||
g_out <= {2'b00, g[5:2]};
|
||||
b_out <= {2'b00, b[5:2]};
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// scan doubler output register
|
||||
reg [COLOR_DEPTH*3-1:0] sd_out;
|
||||
|
||||
// ==================================================================
|
||||
// ======================== the line buffers ========================
|
||||
// ==================================================================
|
||||
|
||||
// 2 lines of 2**HCNT_WIDTH pixels 3*COLOR_DEPTH bit RGB
|
||||
(* ramstyle = "no_rw_check" *) reg [COLOR_DEPTH*3-1:0] sd_buffer[2*2**HCNT_WIDTH];
|
||||
|
||||
// use alternating sd_buffers when storing/reading data
|
||||
reg line_toggle;
|
||||
|
||||
// total hsync time (in 16MHz cycles), hs_total reaches 1024
|
||||
reg [HCNT_WIDTH-1:0] hs_max;
|
||||
reg [HCNT_WIDTH-1:0] hs_rise;
|
||||
reg [HCNT_WIDTH-1:0] hcnt;
|
||||
|
||||
always @(posedge clk_sys) begin
|
||||
reg hsD, vsD;
|
||||
|
||||
if(ce_x1) begin
|
||||
hsD <= hs_in;
|
||||
|
||||
// falling edge of hsync indicates start of line
|
||||
if(hsD && !hs_in) begin
|
||||
hs_max <= hcnt;
|
||||
hcnt <= 0;
|
||||
end else begin
|
||||
hcnt <= hcnt + 1'd1;
|
||||
end
|
||||
|
||||
// save position of rising edge
|
||||
if(!hsD && hs_in) hs_rise <= hcnt;
|
||||
|
||||
vsD <= vs_in;
|
||||
if(vsD != vs_in) line_toggle <= 0;
|
||||
|
||||
// begin of incoming hsync
|
||||
if(hsD && !hs_in) line_toggle <= !line_toggle;
|
||||
|
||||
sd_buffer[{line_toggle, hcnt}] <= {r_in, g_in, b_in};
|
||||
end
|
||||
end
|
||||
|
||||
// ==================================================================
|
||||
// ==================== output timing generation ====================
|
||||
// ==================================================================
|
||||
|
||||
reg [HCNT_WIDTH-1:0] sd_hcnt;
|
||||
reg hs_sd;
|
||||
|
||||
// timing generation runs 32 MHz (twice the input signal analysis speed)
|
||||
always @(posedge clk_sys) begin
|
||||
reg hsD;
|
||||
|
||||
if(ce_x2) begin
|
||||
hsD <= hs_in;
|
||||
|
||||
// output counter synchronous to input and at twice the rate
|
||||
sd_hcnt <= sd_hcnt + 1'd1;
|
||||
if(hsD && !hs_in) sd_hcnt <= hs_max;
|
||||
if(sd_hcnt == hs_max) sd_hcnt <= 0;
|
||||
|
||||
// replicate horizontal sync at twice the speed
|
||||
if(sd_hcnt == hs_max) hs_sd <= 0;
|
||||
if(sd_hcnt == hs_rise) hs_sd <= 1;
|
||||
|
||||
// read data from line sd_buffer
|
||||
sd_out <= sd_buffer[{~line_toggle, sd_hcnt}];
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -33,6 +33,7 @@ module user_io (
|
||||
output [7:0] JOY1,
|
||||
output scandoubler_disable,
|
||||
output ypbpr,
|
||||
output no_csync,
|
||||
|
||||
input [7:0] kbd_out_data,
|
||||
input kbd_out_strobe,
|
||||
@@ -80,6 +81,7 @@ assign BUTTONS = but_sw[1:0];
|
||||
assign SWITCHES = but_sw[3:2];
|
||||
assign scandoubler_disable = but_sw[4];
|
||||
assign ypbpr = but_sw[5];
|
||||
assign no_csync = but_sw[6];
|
||||
|
||||
// this variant of user_io is for the achie core (type == a6) only
|
||||
wire [7:0] core_type = 8'ha6;
|
||||
|
||||
Reference in New Issue
Block a user