Floppy Support, Updated SYS (#6)

This commit is contained in:
Alan Steremberg
2022-01-23 23:02:32 -08:00
committed by GitHub
parent e467f353c3
commit c244ec1504
23 changed files with 12523 additions and 9084 deletions

View File

@@ -13,7 +13,7 @@ set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
set_global_assignment -name LAST_QUARTUS_VERSION "17.0.2 Standard Edition"
set_global_assignment -name LAST_QUARTUS_VERSION "17.0.2 Lite Edition"
set_global_assignment -name GENERATE_RBF_FILE ON
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
@@ -47,9 +47,19 @@ set_global_assignment -name ROUTER_CLOCKING_TOPOLOGY_ANALYSIS ON
set_global_assignment -name ECO_OPTIMIZE_TIMING ON
set_global_assignment -name PERIPHERY_TO_CORE_PLACEMENT_AND_ROUTING_OPTIMIZATION ON
set_global_assignment -name PHYSICAL_SYNTHESIS_ASYNCHRONOUS_SIGNAL_PIPELINING ON
set_global_assignment -name ALM_REGISTER_PACKING_EFFORT LOW
set_global_assignment -name ALM_REGISTER_PACKING_EFFORT MEDIUM
set_global_assignment -name SEED 1
#set_global_assignment -name VERILOG_MACRO "MISTER_FB=1"
#enable it only if 8bit indexed mode is used in core
#set_global_assignment -name VERILOG_MACRO "MISTER_FB_PALETTE=1"
#set_global_assignment -name VERILOG_MACRO "MISTER_DUAL_SDRAM=1"
#do not enable DEBUG_NOHDMI in release!
#set_global_assignment -name VERILOG_MACRO "MISTER_DEBUG_NOHDMI=1"
source sys/sys.tcl
source sys/sys_analog.tcl
source files.qip

View File

@@ -27,7 +27,7 @@ module emu
input RESET,
//Must be passed to hps_io module
inout [45:0] HPS_BUS,
inout [47:0] HPS_BUS,
//Base video clock. Usually equals to CLK_SYS.
output CLK_VIDEO,
@@ -37,9 +37,9 @@ module emu
output CE_PIXEL,
//Video aspect ratio for HDMI. Most retro systems have ratio 4:3.
//if VIDEO_ARX[12] or VIDEO_ARY[12] is set then [11:0] contains scaled size instead of aspect ratio.
output [12:0] VIDEO_ARX,
output [12:0] VIDEO_ARY,
//if VIDEO_ARX[12] or VIDEO_ARY[12] is set then [11:0] contains scaled size instead of aspect ratio.
output [12:0] VIDEO_ARX,
output [12:0] VIDEO_ARY,
output [7:0] VGA_R,
output [7:0] VGA_G,
@@ -50,11 +50,12 @@ module emu
output VGA_F1,
output [1:0] VGA_SL,
output VGA_SCALER, // Force VGA scaler
input [11:0] HDMI_WIDTH,
input [11:0] HDMI_HEIGHT,
`ifdef USE_FB
input [11:0] HDMI_WIDTH,
input [11:0] HDMI_HEIGHT,
output HDMI_FREEZE,
`ifdef MISTER_FB
// Use framebuffer in DDRAM (USE_FB=1 in qsf)
// FB_FORMAT:
// [2:0] : 011=8bpp(palette) 100=16bpp 101=24bpp 110=32bpp
@@ -72,6 +73,7 @@ module emu
input FB_LL,
output FB_FORCE_BLANK,
`ifdef MISTER_FB_PALETTE
// Palette control for 8bit modes.
// Ignored for other video modes.
output FB_PAL_CLK,
@@ -79,6 +81,7 @@ module emu
output [23:0] FB_PAL_DOUT,
input [23:0] FB_PAL_DIN,
output FB_PAL_WR,
`endif
`endif
output LED_USER, // 1 - ON, 0 - OFF.
@@ -110,7 +113,6 @@ module emu
output SD_CS,
input SD_CD,
`ifdef USE_DDRAM
//High latency DDR3 RAM interface
//Use for non-critical time purposes
output DDRAM_CLK,
@@ -123,9 +125,7 @@ module emu
output [63:0] DDRAM_DIN,
output [7:0] DDRAM_BE,
output DDRAM_WE,
`endif
`ifdef USE_SDRAM
//SDRAM interface with lower latency
output SDRAM_CLK,
output SDRAM_CKE,
@@ -138,10 +138,10 @@ module emu
output SDRAM_nCAS,
output SDRAM_nRAS,
output SDRAM_nWE,
`endif
`ifdef DUAL_SDRAM
`ifdef MISTER_DUAL_SDRAM
//Secondary SDRAM
//Set all output SDRAM_* signals to Z ASAP if SDRAM2_EN is 0
input SDRAM2_EN,
output SDRAM2_CLK,
output [12:0] SDRAM2_A,
@@ -170,7 +170,6 @@ module emu
input OSD_STATUS
);
assign ADC_BUS = 'Z;
assign USER_OUT = '1;
@@ -183,6 +182,7 @@ assign LED_DISK = {1'b1,~vsd_sel & sd_act};
assign LED_POWER = 0;
assign BUTTONS = 0;
assign VGA_SCALER= 0;
assign HDMI_FREEZE = 0;
wire [1:0] ar = status[14:13];
video_freak video_freak
@@ -201,8 +201,11 @@ video_freak video_freak
parameter CONF_STR = {
"BBCMicro;;",
"-;",
"S,VHD;",
"S0,VHD;",
"H0S1,SSDDSD;",
"H0S2,SSDDSD;",
"OC,Autostart,Yes,No;",
"H0OH,Dflt Boot,MMC (vhd),Floppy (SSD/DSD);",
"-;",
"ODE,Aspect ratio,Original,Full Screen,[ARC1],[ARC2];",
"O23,Scandoubler Fx,None,HQ2x,CRT 25%,CRT 50%;",
@@ -262,34 +265,32 @@ wire ioctl_download;
wire [7:0] ioctl_index;
wire ioctl_wr;
wire [24:0] ioctl_addr;
wire [15:0] ioctl_dout;
wire [7:0] ioctl_dout;
wire forced_scandoubler;
wire [21:0] gamma_bus;
wire [31:0] sd_lba;
wire sd_rd;
wire sd_wr;
wire sd_ack;
wire [7:0] sd_buff_addr;
wire [15:0] sd_buff_dout;
wire [15:0] sd_buff_din;
wire [31:0] sd_lba[3];
wire [2:0] sd_rd;
wire [2:0] sd_wr;
wire [2:0] sd_ack;
wire [12:0] sd_buff_addr;
wire [7:0] sd_buff_dout;
wire [7:0] sd_buff_din[3];
wire sd_buff_wr;
wire img_mounted;
wire [2:0] img_mounted;
wire img_readonly;
wire [63:0] img_size;
wire sd_ack_conf;
wire [64:0] RTC;
hps_io #(.STRLEN($size(CONF_STR)>>3), .WIDE(1)) hps_io
hps_io #(.CONF_STR(CONF_STR),.VDNUM(3),.BLKSZ(2)) hps_io
(
.clk_sys(clk_sys),
.HPS_BUS(HPS_BUS),
.conf_str(CONF_STR),
.buttons(buttons),
.status(status),
.status_menumask(~status[4]),
.forced_scandoubler(forced_scandoubler),
.gamma_bus(gamma_bus),
@@ -308,7 +309,6 @@ hps_io #(.STRLEN($size(CONF_STR)>>3), .WIDE(1)) hps_io
.sd_rd(sd_rd),
.sd_wr(sd_wr),
.sd_ack(sd_ack),
.sd_ack_conf(sd_ack_conf),
.sd_buff_addr(sd_buff_addr),
.sd_buff_dout(sd_buff_dout),
.sd_buff_din(sd_buff_din),
@@ -319,13 +319,13 @@ hps_io #(.STRLEN($size(CONF_STR)>>3), .WIDE(1)) hps_io
.joystick_0(joy1),
.joystick_1(joy2),
.joystick_analog_0({joy1_y,joy1_x}),
.joystick_analog_1({joy2_y,joy2_x})
.joystick_l_analog_0({joy1_y,joy1_x}),
.joystick_l_analog_1({joy2_y,joy2_x})
);
///////////////// RESET /////////////////////////
wire reset = RESET | status[0] | buttons[1] | (~status[12] & img_mounted);
wire reset = RESET | status[0] | buttons[1] | (~status[12] & img_mounted[0]);
//////////////// MEMORY /////////////////////////
@@ -333,16 +333,17 @@ reg m128 = 0;
always @(posedge clk_sys) if(reset_req) m128 <= status[4];
wire mem_we_n;
wire [18:0] mem_addr;
reg [18:0] mem_addr;
wire [18:0] mem_addr_w;
wire [7:0] mem_din;
reg [17:0] rom_addr;
reg [15:0] rom_dout;
reg [7:0] rom_dout;
reg [7:0] rom_data;
(* ram_init_file = "roms/rom.mif" *) reg [15:0] rom[114688];
always @(posedge clk_sys) if(!ioctl_index && ioctl_wr && reset) rom[reset ? ioctl_addr[17:1] : rom_addr[17:1]] <= {ioctl_dout[7:0], ioctl_dout[15:8]};
always @(posedge clk_sys) rom_dout <= rom[rom_addr[17:1]];
(* ram_init_file = "roms/rom.mif" *) reg [7:0] rom[229376];
always @(posedge clk_sys) if(!ioctl_index && ioctl_wr && reset) rom[reset ? ioctl_addr[17:0] : rom_addr[17:0]] <= ioctl_dout;
always @(posedge clk_sys) rom_dout <= rom[rom_addr[17:0]];
// Beeb ROM Images
@@ -419,7 +420,7 @@ always_comb begin
'b1_11_00,
'b1_11_01,
'b1_11_10,
'b1_11_11: rom_data = rom_addr[0] ? rom_dout[7:0] : rom_dout[15:8];
'b1_11_11: rom_data = rom_dout;
default: rom_data = 0;
endcase
end
@@ -468,6 +469,7 @@ wire ce_vid;
bbc_micro_core BBCMicro
(
.clksys(clk_sys),
.clock_32(clk_32),
.clock_24(clk_24),
@@ -506,7 +508,7 @@ bbc_micro_core BBCMicro
.RTC(RTC),
.keyb_dip({4'd0, ~status[12], ~status[9:7]}),
.keyb_dip({3'd0, ~status[17], ~status[12], ~status[9:7]}),
.joystick1_x( status[11] ? {joyb_x,joyb_x[7:4]} : {joya_x,joya_x[7:4]}),
.joystick1_y( status[11] ? {joyb_y,joyb_y[7:4]} : {joya_y,joya_y[7:4]}),
@@ -517,9 +519,37 @@ bbc_micro_core BBCMicro
.joystick2_fire(~status[11] ? ~joy2[4] : ~af),
.m128_mode(m128),
.copro_mode(|status[6:5])
.copro_mode(|status[6:5]),
.img_mounted ( img_mounted[2:1] ),
.img_size ( img_size ),
.sd_lba ( fd_sd_lba ),
.sd_rd ( sd_rd[2:1] ),
.sd_wr ( sd_wr[2:1] ),
.sd_ack ( sd_ack[2:1] ),
.sd_buff_addr ( sd_buff_addr[8:0] ),
.sd_dout ( sd_buff_dout ),
.sd_din ( fd_sd_buff_din ),
.sd_dout_strobe ( sd_buff_wr )
);
wire [31:0] fd_sd_lba;
wire [7:0] fd_sd_buff_din;
always @(posedge clk_32/*clk_sys*/)
begin
// ajs hack for now
sd_buff_din[1] <= fd_sd_buff_din;
sd_lba[1] <= fd_sd_lba;
sd_buff_din[2] <= fd_sd_buff_din;
sd_lba[2] <=fd_sd_lba;
end
wire [7:0] audio_sn;
assign AUDIO_L = {audio_sn, 8'd0};
@@ -557,6 +587,7 @@ wire [1:0] scale = status[3:2];
wire HSync, VSync, HBlank, VBlank, clk_sel;
wire r,g,b;
wire freeze_sync;
assign CLK_VIDEO = clk_sys;
video_mixer #(640, 1, 1) mixer
@@ -582,13 +613,23 @@ wire sdmiso = vsd_sel ? vsdmiso : SD_MISO;
wire sdss;
reg vsd_sel = 0;
always @(posedge clk_sys) if(img_mounted) vsd_sel <= |img_size;
always @(posedge clk_sys) if(img_mounted[0]) vsd_sel <= |img_size;
wire vsdmiso;
sd_card #(1) sd_card
sd_card #(.WIDE(0)) sd_card
(
.*,
.img_mounted(img_mounted[0]),
.sd_buff_addr(sd_buff_addr[8:0]),
.sd_rd(sd_rd[0]),
.sd_wr(sd_wr[0]),
.sd_ack(sd_ack[0]),
.sd_lba(sd_lba[0]),
.sd_buff_din(sd_buff_din[0]),
.clk_spi(clk_sys),
.sdhc(1),
.sck(sdclk),

View File

@@ -33,5 +33,7 @@ set_global_assignment -name VHDL_FILE rtl/mc6845.vhd
set_global_assignment -name VHDL_FILE rtl/vidproc.vhd
set_global_assignment -name VHDL_FILE rtl/keyboard.vhd
set_global_assignment -name VHDL_FILE rtl/bbc_micro_core.vhd -hdl_version VHDL_2008
set_global_assignment -name VERILOG_FILE rtl/fdc1772/fdc1772.v
set_global_assignment -name VERILOG_FILE rtl/fdc1772/floppy.v
set_global_assignment -name SDC_FILE BBCMicro.sdc
set_global_assignment -name SYSTEMVERILOG_FILE BBCMicro.sv

View File

@@ -58,6 +58,7 @@ rem cat m128/adfs.rom >> $IMAGE
rem cat m128/view.rom >> $IMAGE
rem cat m128/terminal.rom >> $IMAGE
copy /b bbcb\os12.rom +bbcb\swmmfs2.rom +bbcb\ram_master_v6.rom +bbcb\basic2.rom +m128\adfs1-57.rom +m128\mammfs2.rom +m128\mos.rom +m128\dfs.rom +m128\viewsht.rom +m128\edit.rom +m128\basic4.rom +m128\adfs.rom +m128\view.rom +m128\terminal.rom rom.bin
srec rom.bin -binary -o rom.mif -mif
copy /b bbcb\os12.rom +bbcb\swmmfs2.rom +bbcb\ram_master_v6.rom +bbcb\basic2.rom +m128\adfs1-57.rom +m128\mammfs2.rom +m128\mos.rom +m128\dfs.rom +m128\viewsht.rom +m128\edit.rom +m128\basic4.rom +m128\adfs.rom +m128\view.rom +m128\terminal.rom rom.bin
rem copy /b bbcb\os12.rom +bbcb\swmmfs2.rom +bbcb\ram_master_v6.rom +bbcb\basic2.rom +m128\adfs1-57.rom +m128\mammfs2.rom +m128\mos.rom +m128\dfs0.9.rom +m128\dfs0.9.rom +m128\viewsht.rom +m128\edit.rom +m128\basic4.rom +m128\adfs.rom +m128\view.rom +m128\terminal.rom rom.bin
srec rom.bin -binary -o rom.mif -mif 8
pause

17796
roms/rom.mif

File diff suppressed because it is too large Load Diff

View File

@@ -65,6 +65,8 @@ entity bbc_micro_core is
port
(
-- Clocks
--clock_48 : in std_logic;
clksys : in std_logic;
clock_32 : in std_logic;
clock_24 : in std_logic;
@@ -148,12 +150,70 @@ entity bbc_micro_core is
ext_tube_phi2 : out std_logic;
ext_tube_a : out std_logic_vector(6 downto 0);
ext_tube_di : out std_logic_vector(7 downto 0);
ext_tube_do : in std_logic_vector(7 downto 0) := x"FE"
ext_tube_do : in std_logic_vector(7 downto 0) := x"FE";
-- FDC signals
img_mounted : in std_logic_vector(1 downto 0);
img_size : in std_logic_vector(31 downto 0);
sd_lba : out std_logic_vector(31 downto 0);
sd_rd : out std_logic_vector(1 downto 0);
sd_wr : out std_logic_vector(1 downto 0);
sd_ack : in std_logic_vector(1 downto 0);
sd_buff_addr : in std_logic_vector(8 downto 0);
sd_dout : in std_logic_vector(7 downto 0);
sd_din : out std_logic_vector(7 downto 0);
sd_dout_strobe : in std_logic
);
end entity;
architecture rtl of bbc_micro_core is
component fdc1772 is
generic (
CLK_EN : integer := 4000; -- old values tried with different ram/success : 42666000 42800000 42680000 42856000
-- CLK_EN : integer := 2033;
EXT_MOTOR : integer := 1 -- 256 bytes/sector
);
port (
clksys : in std_logic;
clkcpu : in std_logic;
clk8m_en : in std_logic;
floppy_drive : in std_logic_vector( 1 downto 0);
floppy_side : in std_logic;
floppy_reset : in std_logic;
floppy_step : out std_logic;
floppy_motor : in std_logic;
floppy_ready : out std_logic;
irq : out std_logic;
drq : out std_logic;
cpu_addr : in std_logic_vector( 1 downto 0);
cpu_sel : in std_logic;
cpu_rw : in std_logic;
cpu_din : in std_logic_vector( 7 downto 0);
cpu_dout : out std_logic_vector( 7 downto 0);
img_mounted : in std_logic_vector( 1 downto 0);
img_wp : in std_logic_vector( 1 downto 0);
img_size : in std_logic_vector(31 downto 0); -- in bytes
sd_lba : out std_logic_vector(31 downto 0);
sd_rd : out std_logic_vector( 1 downto 0);
sd_wr : out std_logic_vector( 1 downto 0);
-- sd_ack : in std_logic_vector( 1 downto 0);
sd_ack : in std_logic;
sd_buff_addr : in std_logic_vector( 8 downto 0);
sd_dout : in std_logic_vector( 7 downto 0);
sd_din : out std_logic_vector( 7 downto 0);
sd_dout_strobe : in std_logic
-- drive_led : out std_logic
);
end component ;
-------------
-- Signals
-------------
@@ -182,6 +242,7 @@ signal ttxt_clken : std_logic;
-- CPU signals
signal cpu_irq_n : std_logic;
signal cpu_nmi_n : std_logic;
signal cpu_r_nw : std_logic;
signal cpu_sync : std_logic;
signal cpu_a_t65 : std_logic_vector(23 downto 0);
@@ -321,6 +382,12 @@ signal mouse_via_enable : std_logic; -- 0xFE60-FE7F
--signal adlc_enable : std_logic; -- 0xFEA0-FEBF (Econet)
signal tube_enable : std_logic; -- 0xFEE0-FEFF
signal fddc_enable: std_logic;
signal fdc_enable: std_logic;
signal fdcon_enable: std_logic;
signal adc_enable : std_logic; -- 0xFEC0-FEDF
signal adc_eoc_n : std_logic;
signal adc_do : std_logic_vector(7 downto 0);
@@ -344,6 +411,17 @@ signal rtc_r_nw : std_logic;
signal rtc_as : std_logic;
signal rtc_ds : std_logic;
-- FDC1770
signal fdc_irq : std_logic;
signal fdc_drq : std_logic;
signal fdc_do : std_logic_vector(7 downto 0);
signal floppy_drive : std_logic_vector(1 downto 0);
signal floppy_side : std_logic;
--signal floppy_density : std_logic;
signal floppy_motor : std_logic;
signal floppy_reset : std_logic;
-- 0xFE34 Access Control
signal acccon : std_logic_vector(7 downto 0);
signal acc_irr : std_logic;
@@ -369,27 +447,27 @@ begin
-------------------------
cpuT65 : entity work.T65
port map (
"00",
not m128_mode and reset_n,
cpu_clken,
clock_32,
'1',
'1',
cpu_irq_n,
'1',
'1',
cpu_r_nw_t65,
cpu_sync_t65,
open,
open,
open,
open,
open,
open,
open,
cpu_a_t65,
cpu_di,
cpu_do_t65
Mode =>"00",
Res_n =>not m128_mode and reset_n,
Enable => cpu_clken,
Clk => clock_32,
Rdy=> '1',
Abort_n => '1',
IRQ_n => cpu_irq_n,
NMI_n => cpu_nmi_n,
SO_n => '1',
R_W_n => cpu_r_nw_t65,
Sync => cpu_sync_t65,
EF => open,
MF => open,
XF => open,
ML_n => open,
VP_n => open,
VDA => open,
VPA => open,
A => cpu_a_t65,
DI=> cpu_di,
DO=> cpu_do_t65
);
cpuC02 : entity work.r65c02
@@ -397,7 +475,7 @@ begin
reset => m128_mode and reset_n,
clk => clock_32,
enable => cpu_clken,
nmi_n => '1',
nmi_n => cpu_nmi_n,
irq_n => cpu_irq_n,
di => unsigned(cpu_di),
do => cpu_dout_us,
@@ -898,6 +976,8 @@ begin
sys_via_enable <= '0';
user_via_enable <= '0';
mouse_via_enable <= '0';
fdc_enable<='0';
fdcon_enable<='0';
-- adlc_enable <= '0';
adc_enable <= '0';
tube_enable <= '0';
@@ -931,7 +1011,14 @@ begin
-- 0xFE20
if cpu_a(4) = '0' then
-- 0xFE20
vidproc_enable <= '1';
if (m128_mode = '0' or cpu_a(3 downto 2) = "00") then
vidproc_enable <= '1'; -- does this need master off?
end if;
if (m128_mode = '1' and cpu_a(3)='1') then -- AJS
fdc_enable<='1';
elsif (m128_mode = '1' and cpu_a(3)='0' and cpu_a(2)='1') then -- AJS
fdcon_enable<='1';
end if;
elsif m128_mode = '1' then
case cpu_a(3 downto 2) is
-- 0xFE30
@@ -1006,6 +1093,7 @@ begin
ext_tube_do when tube_enable = '1' and IncludeCoProExt else
-- Master 128 additions
romsel when romsel_enable = '1' and m128_mode = '1' else
fdc_do when fdc_enable = '1' else
acccon when acccon_enable = '1' and m128_mode = '1' else
"11111110" when io_sheila = '1' else
"11111111" when io_fred = '1' or io_jim = '1' else
@@ -1013,6 +1101,7 @@ begin
cpu_irq_n <= not (sys_via_irq or user_via_irq or mouse_via_irq or acc_irr) when m128_mode = '1' else
not (sys_via_irq or user_via_irq or mouse_via_irq);
cpu_nmi_n <= not fdc_irq and not fdc_drq;
-- Synchronous outputs to External Memory
@@ -1147,6 +1236,94 @@ begin
end if;
end process;
-- FDC (Master)
fdc : fdc1772
port map
(
clksys => clksys,
clkcpu => clock_32, -- 48?
clk8m_en => mhz4_clken,
cpu_sel => fdc_enable,
cpu_rw => cpu_r_nw,
cpu_addr => cpu_a(1 downto 0),
cpu_dout => fdc_do,
cpu_din => cpu_do,
irq => fdc_irq,
drq => fdc_drq,
-- The following signals are all passed in from the Top module
img_mounted => img_mounted,
img_size => img_size,
img_wp => "00",
sd_lba => sd_lba,
sd_rd => sd_rd,
sd_wr => sd_wr,
sd_ack => sd_ack(0) or sd_ack(1),
sd_buff_addr => sd_buff_addr,
sd_dout => sd_dout,
sd_din => sd_din,
sd_dout_strobe => sd_dout_strobe,
floppy_drive => floppy_drive,
floppy_motor => not floppy_motor,
floppy_side => floppy_side,
floppy_reset => floppy_reset
);
-- From MAME:
-- Master drive control:
-- Bit Meaning
-- -----------------
-- 7,6 Not used.
-- 5 Double density select (0 = double, 1 = single).
-- 4 Side select (0 = side 0, 1 = side 1).
-- 3 Drive select 2.
-- 2 Reset drive controller chip. (0 = reset controller, 1 = no reset)
-- 1 Drive select 1.
-- 0 Drive select 0.
-- FDC Control Register (Master)
process(clock_32,reset_n)
begin
if reset_n = '0' then
floppy_drive <= "11";
floppy_side <= '0';
floppy_reset <= '0';
-- floppy_density <= '0';
floppy_motor<='0';
elsif rising_edge(clock_32) then
if (cpu_clken) then
-- fe24-fe27 FDC Latch 1770 Control latch
if (fdcon_enable ='1' and cpu_r_nw='0') then
floppy_drive <= not cpu_do(1) & not cpu_do(0) ;
floppy_reset <= cpu_do(2);
floppy_side <= not cpu_do(4);
-- floppy_density <= cpu_do(5);
floppy_motor <= '0';
end if;
end if;
end if;
end process;
-- Address translation logic for calculation of display address
process(crtc_ma,crtc_ra,disp_addr_offs)
variable aa : unsigned(3 downto 0);

1080
rtl/fdc1772/fdc1772.v Normal file

File diff suppressed because it is too large Load Diff

286
rtl/fdc1772/floppy.v Normal file
View File

@@ -0,0 +1,286 @@
//
// floppy.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/>.
//
module floppy (
// main clock
input clk,
input clk8m_en,
input select,
input motor_on,
input step_in,
input step_out,
input [10:0] sector_len,
input sector_base, // number of first sector on track (archie 0, dos 1)
input [4:0] spt, // sectors/track
input [9:0] sector_gap_len, // gap len/sector
input hd,
input fm,
output dclk_en, // data clock enable
output [6:0] track, // number of track under head
output [4:0] sector, // number of sector under head, 0 = no sector
output sector_hdr, // valid sector header under head
output sector_data, // valid sector data under head
output ready, // drive is ready, data can be read
output reg index
);
// The sysclock is the value all floppy timings are derived from.
// Default: 8 MHz
parameter CLK_EN = 8000;
assign sector_hdr = (sec_state == SECTOR_STATE_HDR);
assign sector_data = (sec_state == SECTOR_STATE_DATA);
// a standard DD floppy has a data rate of 250kBit/s and rotates at 300RPM
localparam RATESD = 125000;
localparam RATEDD = 250000;
localparam RATEHD = 500000;
localparam RPM = 300;
localparam STEPBUSY = 18; // 18ms after step data can be read
localparam SPINUP = 500; // drive spins up in up to 800ms
localparam SPINDOWN = 300; // GUESSED: drive spins down in 300ms
localparam INDEX_PULSE_LEN = 5; // fd1036 data sheet says 1~8ms
localparam SECTOR_HDR_LEN = 6; // GUESSED: Sector header is 6 bytes
localparam TRACKS = 85; // max allowed track
// Archimedes specific values
//localparam SECTOR_LEN = 11'd1024 // Default sector size is 1024 on Archie
//localparam SECTOR_LEN = 11'd512; // Default sector size is 512 on ST ...
//localparam SPT = 4'd10; // ... with 5 sectors per track
//localparam SECTOR_BASE = 4'd1; // number of first sector on track (archie 0, dos 1)
// number of physical bytes per track
localparam BPTSD = RATESD*60/(8*RPM);
localparam BPTDD = RATEDD*60/(8*RPM);
localparam BPTHD = RATEHD*60/(8*RPM);
// report disk ready if it spins at full speed
assign ready = select && (rate == (fm ? RATESD : hd ? RATEHD : RATEDD));
// ================================================================
// ========================= INDEX PULSE ==========================
// ================================================================
// Index pulse generation. Pulse starts with the begin of index_pulse_start
// and lasts INDEX_PULSE_CYCLES system clock cycles
localparam INDEX_PULSE_CYCLES = INDEX_PULSE_LEN * CLK_EN;
reg [18:0] index_pulse_cnt;
always @(posedge clk) if(clk8m_en) begin
if(index_pulse_start && (index_pulse_cnt == INDEX_PULSE_CYCLES-1)) begin
index <= 1'b0;
index_pulse_cnt <= 19'd0;
end else if(index_pulse_cnt == INDEX_PULSE_CYCLES-1)
index <= 1'b1;
else
index_pulse_cnt <= index_pulse_cnt + 1'd1;
end
// ================================================================
// ======================= track handling =========================
// ================================================================
localparam STEP_BUSY_CLKS = CLK_EN*STEPBUSY; // steprate is in ms
assign track = current_track;
reg [6:0] current_track /* verilator public */ = 7'd0;
reg step_inD;
reg step_outD;
reg [19:0] step_busy /* verilator public */;
always @(posedge clk) begin
step_inD <= step_in;
step_outD <= step_out;
if(clk8m_en && step_busy != 0)
step_busy <= step_busy - 18'd1;
if(select) begin
// rising edge of step signal starts step
if(step_in && !step_inD) begin
if(current_track != 0) current_track <= current_track - 7'd1;
step_busy <= STEP_BUSY_CLKS[19:0];
end
if(step_out && !step_outD) begin
if(current_track != TRACKS-1) current_track <= current_track + 7'd1;
step_busy <= STEP_BUSY_CLKS[19:0];
end
end
end
// ================================================================
// ====================== sector handling =========================
// ================================================================
// track has BPT bytes
// SPT sectors are stored on the track
//localparam SECTOR_GAP_LEN = BPT/SPT - (SECTOR_LEN + SECTOR_HDR_LEN);
assign sector = current_sector;
localparam SECTOR_STATE_GAP = 2'd0;
localparam SECTOR_STATE_HDR = 2'd1;
localparam SECTOR_STATE_DATA = 2'd2;
// we simulate an interleave of 1
reg [4:0] start_sector = 4'd1;
reg [1:0] sec_state;
reg [9:0] sec_byte_cnt; // counting bytes within sectors
reg [4:0] current_sector = 4'd1;
always @(posedge clk) begin
if (byte_clk_en) begin
if(index_pulse_start) begin
sec_byte_cnt <= sector_gap_len-1'd1;
sec_state <= SECTOR_STATE_GAP; // track starts with gap
current_sector <= start_sector; // track starts with sector 1
end else begin
if(sec_byte_cnt == 0) begin
case(sec_state)
SECTOR_STATE_GAP: begin
sec_state <= SECTOR_STATE_HDR;
sec_byte_cnt <= SECTOR_HDR_LEN[9:0]-1'd1;
end
SECTOR_STATE_HDR: begin
sec_state <= SECTOR_STATE_DATA;
sec_byte_cnt <= sector_len[9:0]-1'd1;
end
SECTOR_STATE_DATA: begin
sec_state <= SECTOR_STATE_GAP;
sec_byte_cnt <= sector_gap_len-1'd1;
if(current_sector == sector_base+spt-1)
current_sector <= sector_base;
else
current_sector <= sector + 1'd1;
end
default:
sec_state <= SECTOR_STATE_GAP;
endcase
end else
sec_byte_cnt <= sec_byte_cnt - 10'd1;
end
end
end
// ================================================================
// ========================= BYTE CLOCK ===========================
// ================================================================
// An ed floppy at 300rpm with 1MBit/s has max 31.250 bytes/track
// thus we need to support up to 31250 events
reg [14:0] byte_cnt;
reg index_pulse_start;
always @(posedge clk) begin
if (byte_clk_en) begin
index_pulse_start <= 1'b0;
if(byte_cnt == ((fm ? BPTSD : hd ? BPTHD : BPTDD)-1'd1)) begin
byte_cnt <= 0;
index_pulse_start <= 1'b1;
end else
byte_cnt <= byte_cnt + 1'd1;
end
end
// Make byte clock from bit clock.
// When a DD disk spins at 300RPM every 32us a byte passes the disk head
assign dclk_en = byte_clk_en;
reg byte_clk_en;
reg [2:0] clk_cnt2;
always @(posedge clk) begin
byte_clk_en <= 0;
if (data_clk_en) begin
clk_cnt2 <= clk_cnt2 + 1'd1;
if (clk_cnt2 == 3'b011) byte_clk_en <= 1;
end
end
// ================================================================
// ===================== SPIN VIRTUAL DISK ========================
// ================================================================
// number of system clock cycles after which disk has reached
// full speed
localparam SPIN_UP_CLKS = CLK_EN*SPINUP;
localparam SPIN_DOWN_CLKS = CLK_EN*SPINDOWN;
reg [31:0] spin_up_counter;
// internal motor on signal that is only true if the drive is selected
wire motor_on_sel = motor_on && select;
// data rate determines rotation speed
reg [31:0] rate /* verilator public */ = 0;
reg motor_onD;
always @(posedge clk) begin
motor_onD <= motor_on_sel;
// reset spin_up counter whenever motor state changes
if(motor_onD != motor_on_sel)
spin_up_counter <= 32'd0;
else if(clk8m_en) begin
spin_up_counter <= spin_up_counter + (fm ? RATESD : hd ? RATEHD : RATEDD);
if(motor_on_sel) begin
// spinning up
if(spin_up_counter > SPIN_UP_CLKS) begin
if(rate < (fm ? RATESD : hd ? RATEHD : RATEDD))
rate <= rate + 32'd1;
spin_up_counter <= spin_up_counter - (SPIN_UP_CLKS - (fm ? RATESD : hd ? RATEHD : RATEDD));
end
end else begin
// spinning down
if(spin_up_counter > SPIN_DOWN_CLKS) begin
if(rate > 0)
rate <= rate - 32'd1;
spin_up_counter <= spin_up_counter - (SPIN_DOWN_CLKS - (fm ? RATESD : hd ? RATEHD : RATEDD));
end
end // else: !if(motor_on)
end // else: !if(motor_onD != motor_on)
end
// Generate a data clock from the system clock. This depends on motor
// speed and reaches the full rate when the disk rotates at 300RPM. No
// valid data can be read until the disk has reached it's full speed.
reg data_clk;
reg data_clk_en;
reg [31:0] clk_cnt;
always @(posedge clk) begin
data_clk_en <= 0;
if(clk8m_en) begin
if(clk_cnt + rate > CLK_EN*1000/2) begin
clk_cnt <= clk_cnt - (CLK_EN*1000/2 - rate);
data_clk <= !data_clk;
if (~data_clk) data_clk_en <= 1;
end else
clk_cnt <= clk_cnt + rate;
end
end
endmodule

View File

@@ -121,8 +121,9 @@ architecture rtl of rtc is
x"EB", -- CMOS 3 - Econet print server identity (lo)
x"00", -- CMOS 4 - Econet print server identity (hi)
x"C3", -- CMOS 5 - Default Filing System / Language (default file system MMFS)
-- x"C9", -- CMOS 5 - Default Filing System / Language (default file system MMFS)
x"FF", -- CMOS 6 - ROM frugal bits (*INSERT/*UNPLUG)
x"DD", -- CMOS 7 - ROM frugal bits (*INSERT/*UNPLUG) (disable ADFS)
x"FF", -- CMOS 7 - ROM frugal bits (*INSERT/*UNPLUG) (disable ADFS)
x"00", -- CMOS 8 - Edit startup settings
x"00", -- CMOS 9 - reserved for telecommunications applications
ini10, -- CMOS 10 - VDU mode and *TV settings
@@ -130,7 +131,7 @@ architecture rtl of rtc is
x"20", -- CMOS 12 - Keyboard auto-repeat delay
x"08", -- CMOS 13 - Keyboard auto-repeat rate
x"0A", -- CMOS 14 - Printer ignore character
x"2D", -- CMOS 15 - Default printer type, serial baud rate, ignore status and TUBE select
x"2C", -- CMOS 15 - Default printer type, serial baud rate, ignore status and TUBE select
ini16, -- CMOS 16 - Default serial data format, auto boot option, int/ext TUBE, bell amplitude
x"00", -- CMOS 17 - reserved for ANFS
x"00", -- CMOS 18 - reserved for ANFS
@@ -169,7 +170,7 @@ architecture rtl of rtc is
type RTC_STATE_TYPE is (
INIT, WRITE_10, WRITE_16, RUNNING
INIT, WRITE_5, WRITE_10, WRITE_16, RUNNING
);
signal rtc_state : RTC_STATE_TYPE := INIT;
@@ -229,6 +230,11 @@ begin
as_r <= '0';
ds_r <= '0';
do <= (others => '0');
rtc_state <= WRITE_5;
-- Copy the file mode from the DIP switches into CMOS on power up
when WRITE_5 =>
if (keyb_dip(4) ='1') then rtc_ram(19) <= x"C3"; else rtc_ram(19) <= x"C9"; end if;
rtc_state <= WRITE_10;
-- Copy the screen mode from the DIP switches into CMOS on power up

View File

@@ -174,15 +174,16 @@ module screen_rotate
input rotate_ccw,
input no_rotate,
input flip,
output FB_EN,
output [4:0] FB_FORMAT,
output [11:0] FB_WIDTH,
output [11:0] FB_HEIGHT,
output [31:0] FB_BASE,
output [13:0] FB_STRIDE,
input FB_VBL,
input FB_LL,
output FB_EN,
output [4:0] FB_FORMAT,
output reg [11:0] FB_WIDTH,
output reg [11:0] FB_HEIGHT,
output [31:0] FB_BASE,
output [13:0] FB_STRIDE,
input FB_VBL,
input FB_LL,
output DDRAM_CLK,
input DDRAM_BUSY,
@@ -196,6 +197,8 @@ module screen_rotate
parameter MEM_BASE = 7'b0010010; // buffer at 0x24000000, 3x8MB
reg do_flip;
assign DDRAM_CLK = CLK_VIDEO;
assign DDRAM_BURSTCNT = 1;
assign DDRAM_ADDR = {MEM_BASE, i_fb, ram_addr[22:3]};
@@ -207,8 +210,6 @@ assign DDRAM_RD = 0;
assign FB_EN = fb_en[2];
assign FB_FORMAT = 5'b00110;
assign FB_BASE = {MEM_BASE,o_fb,23'd0};
assign FB_WIDTH = vsz;
assign FB_HEIGHT = hsz;
assign FB_STRIDE = stride;
function [1:0] buf_next;
@@ -220,6 +221,17 @@ function [1:0] buf_next;
end
endfunction
always @(posedge CLK_VIDEO) begin
do_flip <= no_rotate && flip;
if( do_flip ) begin
FB_WIDTH <= hsz;
FB_HEIGHT <= vsz;
end else begin
FB_WIDTH <= vsz;
FB_HEIGHT <= hsz;
end
end
reg [1:0] i_fb,o_fb;
always @(posedge CLK_VIDEO) begin
reg old_vbl,old_vs;
@@ -251,20 +263,23 @@ always @(posedge CLK_VIDEO) begin
if(CE_PIXEL) begin
old_vs <= VGA_VS;
old_de <= VGA_DE;
hcnt <= hcnt + 1'd1;
if(~old_de & VGA_DE) begin
hcnt <= 1;
vcnt <= vcnt + 1'd1;
end
if(old_de & ~VGA_DE) hsz <= hcnt;
if(old_de & ~VGA_DE) begin
hsz <= hcnt;
if( do_flip ) bwidth <= hcnt + 2'd3;
end
if(~old_vs & VGA_VS) begin
vsz <= vcnt;
bwidth <= vcnt + 2'd3;
if( !do_flip ) bwidth <= vcnt + 2'd3;
vcnt <= 0;
fb_en <= {fb_en[1:0], ~no_rotate};
fb_en <= {fb_en[1:0], ~no_rotate | flip};
end
if(old_vs & ~VGA_VS) bufsize <= hsz * stride;
if(old_vs & ~VGA_VS) bufsize <= (do_flip ? vsz : hsz ) * stride;
end
end
@@ -278,21 +293,25 @@ always @(posedge CLK_VIDEO) begin
reg old_vs, old_de;
ram_wr <= 0;
if(CE_PIXEL) begin
if(CE_PIXEL && FB_EN) begin
old_vs <= VGA_VS;
old_de <= VGA_DE;
if(~old_vs & VGA_VS) begin
next_addr <= rotate_ccw ? (bufsize - stride) : {vsz-1'd1, 2'b00};
next_addr <=
do_flip ? bufsize-3'd4 :
rotate_ccw ? (bufsize - stride) : {vsz-1'd1, 2'b00};
hcnt <= rotate_ccw ? 3'd4 : {vsz-2'd2, 2'b00};
end
if(VGA_DE) begin
ram_wr <= 1;
ram_data <= {VGA_B,VGA_G,VGA_R};
ram_data <= {8'd0,VGA_B,VGA_G,VGA_R};
ram_addr <= next_addr;
next_addr <= rotate_ccw ? (next_addr - stride) : (next_addr + stride);
next_addr <=
do_flip ? next_addr-3'd4 :
rotate_ccw ? (next_addr - stride) : (next_addr + stride);
end
if(old_de & ~VGA_DE) begin
if(old_de & ~VGA_DE & ~do_flip) begin
next_addr <= rotate_ccw ? (bufsize - stride + hcnt) : hcnt;
hcnt <= rotate_ccw ? (hcnt + 3'd4) : (hcnt - 3'd4);
end

View File

@@ -151,6 +151,7 @@ ENTITY ascal IS
o_vs : OUT std_logic; -- V sync
o_de : OUT std_logic; -- Display Enable
o_vbl : OUT std_logic; -- V blank
o_brd : OUT std_logic; -- border enable
o_ce : IN std_logic; -- Clock Enable
o_clk : IN std_logic; -- Output clock
@@ -382,8 +383,9 @@ ARCHITECTURE rtl OF ascal IS
SIGNAL avl_o_vs_sync,avl_o_vs : std_logic;
SIGNAL avl_fb_ena : std_logic;
FUNCTION buf_next(a,b : natural RANGE 0 TO 2) RETURN natural IS
FUNCTION buf_next(a,b : natural RANGE 0 TO 2; freeze : std_logic := '0') RETURN natural IS
BEGIN
IF (freeze='1') THEN RETURN a; END IF;
IF (a=0 AND b=1) OR (a=1 AND b=0) THEN RETURN 2; END IF;
IF (a=1 AND b=2) OR (a=2 AND b=1) THEN RETURN 0; END IF;
RETURN 1;
@@ -400,6 +402,7 @@ ARCHITECTURE rtl OF ascal IS
----------------------------------------------------------
-- Output
SIGNAL o_run : std_logic;
SIGNAL o_freeze : std_logic;
SIGNAL o_mode,o_hmode,o_vmode : unsigned(4 DOWNTO 0);
SIGNAL o_format : unsigned(5 DOWNTO 0);
SIGNAL o_fb_pal_dr : unsigned(23 DOWNTO 0);
@@ -456,6 +459,7 @@ ARCHITECTURE rtl OF ascal IS
SIGNAL o_hacc,o_hacc_ini,o_hacc_next,o_vacc,o_vacc_next,o_vacc_ini : natural RANGE 0 TO 4*OHRES-1;
SIGNAL o_hsv,o_vsv,o_dev,o_pev,o_end : unsigned(0 TO 5);
SIGNAL o_hsp,o_vss : std_logic;
SIGNAL o_vcarrym,o_prim : boolean;
SIGNAL o_read,o_read_pre : std_logic;
SIGNAL o_readlev,o_copylev : natural RANGE 0 TO 2;
SIGNAL o_hburst,o_hbcpt : natural RANGE 0 TO 31;
@@ -483,6 +487,7 @@ ARCHITECTURE rtl OF ascal IS
SIGNAL o_divstart : std_logic;
SIGNAL o_divrun : std_logic;
SIGNAL o_hacpt,o_vacpt : unsigned(11 DOWNTO 0);
SIGNAL o_vacptl : unsigned(1 DOWNTO 0);
-----------------------------------------------------------------------------
FUNCTION shift_ishift(shift : unsigned(0 TO 119);
@@ -703,8 +708,10 @@ ARCHITECTURE rtl OF ascal IS
RETURN x;
END FUNCTION;
SIGNAL o_h_frac2,o_v_frac : unsigned(FRAC-1 DOWNTO 0);
SIGNAL o_h_near_frac,o_v_near_frac : unsigned(FRAC-1 DOWNTO 0);
SIGNAL o_h_bil_frac,o_v_bil_frac : unsigned(FRAC-1 DOWNTO 0);
SIGNAL o_h_bil_pix,o_v_bil_pix : type_pix;
SIGNAL o_h_near_pix,o_v_near_pix : type_pix;
-----------------------------------------------------------------------------
-- Nearest + Bilinear + Sharp Bilinear
@@ -716,6 +723,7 @@ ARCHITECTURE rtl OF ascal IS
TYPE type_bil_t IS RECORD
r,g,b : unsigned(8+FRAC DOWNTO 0);
END RECORD;
FUNCTION bil_calc(f : unsigned(FRAC-1 DOWNTO 0);
p : arr_pix(0 TO 3)) RETURN type_bil_t IS
VARIABLE fp,fn : unsigned(FRAC DOWNTO 0);
@@ -723,7 +731,7 @@ ARCHITECTURE rtl OF ascal IS
VARIABLE x : type_bil_t;
CONSTANT Z : unsigned(FRAC-1 DOWNTO 0):=(OTHERS =>'0');
BEGIN
fp:='0' & f;
fp:=('0' & f) + (Z & f(FRAC-1));
fn:=('1' & Z) - fp;
u:=p(2).r * fp + p(1).r * fn;
x.r:=u;
@@ -733,7 +741,27 @@ ARCHITECTURE rtl OF ascal IS
x.b:=u;
RETURN x;
END FUNCTION;
FUNCTION near_calc(f : unsigned(FRAC-1 DOWNTO 0);
p : arr_pix(0 TO 3)) RETURN type_bil_t IS
VARIABLE fp,fn : unsigned(FRAC DOWNTO 0);
VARIABLE u : unsigned(8+FRAC DOWNTO 0);
VARIABLE x : type_bil_t;
CONSTANT Z : unsigned(FRAC-1 DOWNTO 0):=(OTHERS =>'0');
BEGIN
IF f(FRAC-1)='0' THEN
x.r := '0' & p(1).r & Z;
x.g := '0' & p(1).g & Z;
x.b := '0' & p(1).b & Z;
ELSE
x.r := '0' & p(2).r & Z;
x.g := '0' & p(2).g & Z;
x.b := '0' & p(2).b & Z;
END IF;
RETURN x;
END FUNCTION;
SIGNAL o_h_bil_t,o_v_bil_t : type_bil_t;
SIGNAL o_h_near_t,o_v_near_t : type_bil_t;
SIGNAL i_h_bil_t : type_bil_t;
-----------------------------------------------------------------------------
@@ -1730,28 +1758,61 @@ BEGIN
-- Triple buffering.
-- For intelaced video, half frames are updated independently
-- Input : Toggle buffer at end of input frame
o_freeze <= freeze;
o_inter <=i_inter; -- <ASYNC>
o_iendframe0<=i_endframe0; -- <ASYNC>
o_iendframe02<=o_iendframe0;
IF o_iendframe0='1' AND o_iendframe02='0' THEN
o_ibuf0<=buf_next(o_ibuf0,o_obuf0);
o_ibuf0<=buf_next(o_ibuf0,o_obuf0,o_freeze);
o_bufup0<='1';
END IF;
o_iendframe1<=i_endframe1; -- <ASYNC>
o_iendframe12<=o_iendframe1;
IF o_iendframe1='1' AND o_iendframe12='0' THEN
o_ibuf1<=buf_next(o_ibuf1,o_obuf1);
o_ibuf1<=buf_next(o_ibuf1,o_obuf1,o_freeze);
o_bufup1<='1';
END IF;
-- Output : Change framebuffer, and image properties, at VS falling edge
IF o_vsv(1)='1' AND o_vsv(0)='0' AND o_bufup0='1' THEN
o_obuf0<=buf_next(o_obuf0,o_ibuf0,o_freeze);
o_bufup0<='0';
END IF;
IF o_vsv(1)='1' AND o_vsv(0)='0' AND o_bufup1='1' THEN
o_obuf1<=buf_next(o_obuf1,o_ibuf1);
o_obuf1<=buf_next(o_obuf1,o_ibuf1,o_freeze);
o_bufup1<='0';
o_ihsize<=i_hrsize; -- <ASYNC>
o_ivsize<=i_vrsize; -- <ASYNC>
o_hdown<=i_hdown; -- <ASYNC>
o_vdown<=i_vdown; -- <ASYNC>
END IF;
-- Simultaneous change of input and output framebuffers
IF o_vsv(1)='1' AND o_vsv(0)='0' AND
o_iendframe0='1' AND o_iendframe02='0' THEN
o_bufup0<='0';
o_obuf0<=o_ibuf0;
END IF;
IF o_vsv(1)='1' AND o_vsv(0)='0' AND
o_iendframe1='1' AND o_iendframe12='0' THEN
o_bufup1<='0';
o_obuf1<=o_ibuf1;
END IF;
-- Non-interlaced, use same buffer for even and odd lines
IF o_inter='0' THEN
o_ibuf1<=o_ibuf0;
o_obuf1<=o_obuf0;
END IF;
-- Triple buffer disabled
IF o_mode(3)='0' THEN
o_obuf0<=0;
o_obuf1<=0;
o_ibuf0<=0;
o_ibuf1<=0;
END IF;
-- Framebuffer mode.
IF o_fb_ena='1' THEN
o_ihsize<=o_fb_hsize;
@@ -1771,25 +1832,6 @@ BEGIN
o_stride<=to_unsigned(o_ihsize_temp2,14);
o_stride(NB_BURST-1 DOWNTO 0)<=(OTHERS =>'0');
END IF;
IF o_vsv(1)='1' AND o_vsv(0)='0' AND o_bufup0='1' THEN
o_obuf0<=buf_next(o_obuf0,o_ibuf0);
o_bufup0<='0';
END IF;
IF o_inter='0' THEN
o_ibuf1<=o_ibuf0;
o_obuf1<=o_obuf0;
END IF;
-- Triple buffer disabled
IF o_mode(3)='0' THEN
o_obuf0<=0;
o_obuf1<=0;
o_ibuf0<=0;
o_ibuf1<=0;
END IF;
------------------------------------------------------
o_hmode<=o_mode;
IF o_hdown='1' AND DOWNSCALE THEN
@@ -1848,35 +1890,51 @@ BEGIN
o_state<=sHSYNC;
o_hsp<='0';
END IF;
o_prim<=true;
o_vcarrym<=false;
--------------------------------------------------
WHEN sHSYNC =>
dif_v:=(o_vacc_next - 2*o_vsize + 16384) MOD 16384;
dif_v :=(o_vacc_next - 2*o_vsize + 16384) MOD 16384;
IF o_prim THEN
IF dif_v>=8192 THEN
o_vacc <=o_vacc_next;
ELSE
o_vacc <=dif_v;
END IF;
END IF;
IF dif_v>=8192 THEN
o_vacc <=o_vacc_next;
o_vacc_next<=(o_vacc_next + 2*o_ivsize) MOD 8192;
vcarry_v:=false;
ELSE
o_vacc <=dif_v;
o_vacc_next<=(dif_v + 2*o_ivsize + 8192) MOD 8192;
o_vacc_next<=dif_v;
vcarry_v:=true;
END IF;
o_divstart<='1';
IF o_vcpt_pre2=o_vmin THEN
o_vacc <=o_vacc_ini;
o_vacc_next<=o_vacc_ini + 2*o_ivsize;
o_vacpt<=x"001";
o_vacpt <=x"001";
o_vacptl<="01";
vcarry_v:=false;
END IF;
IF vcarry_v THEN
o_vacpt<=o_vacpt+1;
END IF;
IF vcarry_v AND o_prim THEN
o_vacptl<=o_vacptl+1;
END IF;
o_vcarrym <= o_vcarrym OR vcarry_v;
o_prim <= false;
o_hbcpt<=0; -- Clear burst counter on line
IF (o_vpe='1' AND vcarry_v) OR o_fload>0 THEN
o_state<=sREAD;
ELSE
o_state<=sDISP;
o_divstart<=to_std_logic(NOT vcarry_v);
IF NOT vcarry_v OR o_fload>0 THEN
IF (o_vpe='1' AND o_vcarrym) OR o_fload>0 THEN
o_state<=sREAD;
ELSE
o_state<=sDISP;
END IF;
END IF;
WHEN sREAD =>
@@ -1926,7 +1984,7 @@ BEGIN
o_alt<="0100";
ELSE
o_adrs<=to_unsigned(o_adrs_pre + (o_hbcpt * N_BURST),32);
o_alt<=altx(o_vacpt(1 DOWNTO 0) + 1);
o_alt<=altx(o_vacptl + 1);
END IF;
END IF;
@@ -2260,33 +2318,38 @@ BEGIN
o_hpixq<=(o_hpix3,o_hpix2,o_hpix1,o_hpix0);
-- NEAREST / BILINEAR / SHARP BILINEAR ---------------
-- NEAREST -------------------------------------------
-- C2
o_h_near_frac<=near_frac(o_hfrac2);
-- C3
o_h_near_t<=near_calc(o_h_near_frac,o_hpixq);
-- C4 : Nearest
o_h_near_pix.r<=o_h_near_t.r(7+FRAC DOWNTO FRAC);
o_h_near_pix.g<=o_h_near_t.g(7+FRAC DOWNTO FRAC);
o_h_near_pix.b<=o_h_near_t.b(7+FRAC DOWNTO FRAC);
-- BILINEAR / SHARP BILINEAR ---------------
-- C1 : Pre-calc Sharp Bilinear
o_h_sbil_t<=sbil_frac1(o_hfrac1);
-- C2 : Select
o_h_frac2<=(OTHERS =>'0');
CASE o_hmode(1 DOWNTO 0) IS
WHEN "00" => -- Nearest
IF MASK(MASK_NEAREST)='1' THEN
o_h_frac2<=near_frac(o_hfrac2);
END IF;
WHEN "01" => -- Bilinear
IF MASK(MASK_BILINEAR)='1' THEN
o_h_frac2<=bil_frac(o_hfrac2);
END IF;
WHEN "10" => -- Sharp Bilinear
IF MASK(MASK_SHARP_BILINEAR)='1' THEN
o_h_frac2<=sbil_frac2(o_hfrac2,o_h_sbil_t);
END IF;
WHEN OTHERS =>
NULL;
END CASE;
o_h_bil_frac<=(OTHERS =>'0');
IF o_hmode(0)='1' THEN -- Bilinear
IF MASK(MASK_BILINEAR)='1' THEN
o_h_bil_frac<=bil_frac(o_hfrac2);
END IF;
ELSE -- Sharp Bilinear
IF MASK(MASK_SHARP_BILINEAR)='1' THEN
o_h_bil_frac<=sbil_frac2(o_hfrac2,o_h_sbil_t);
END IF;
END IF;
-- C3 : Opposite frac
o_h_bil_t<=bil_calc(o_h_frac2,o_hpixq);
o_h_bil_t<=bil_calc(o_h_bil_frac,o_hpixq);
-- C4 : Nearest / Bilinear / Sharp Bilinear
-- C4 : Bilinear / Sharp Bilinear
o_h_bil_pix.r<=bound(o_h_bil_t.r,8+FRAC);
o_h_bil_pix.g<=bound(o_h_bil_t.g,8+FRAC);
o_h_bil_pix.b<=bound(o_h_bil_t.b,8+FRAC);
@@ -2324,9 +2387,12 @@ BEGIN
o_ldw<=(x"00",x"00",x"00");
CASE o_hmode(2 DOWNTO 0) IS
WHEN "000" | "001" | "010" => -- Nearest | Bilinear | Sharp Bilinear
IF MASK(MASK_NEAREST)='1' OR
MASK(MASK_BILINEAR)='1' OR
WHEN "000" => -- Nearest
IF MASK(MASK_NEAREST)='1' THEN
o_ldw<=o_h_near_pix;
END IF;
WHEN "001" | "010" => -- Bilinear | Sharp Bilinear
IF MASK(MASK_BILINEAR)='1' OR
MASK(MASK_SHARP_BILINEAR)='1' THEN
o_ldw<=o_h_bil_pix;
END IF;
@@ -2425,7 +2491,7 @@ BEGIN
-- CYCLE 2 -----------------------------------------
-- Lines reordering
CASE o_vacpt(1 DOWNTO 0) IS
CASE o_vacptl IS
WHEN "10" => pixq_v:=(o_ldr0,o_ldr1,o_ldr2,o_ldr3);
WHEN "11" => pixq_v:=(o_ldr1,o_ldr2,o_ldr3,o_ldr0);
WHEN "00" => pixq_v:=(o_ldr2,o_ldr3,o_ldr0,o_ldr1);
@@ -2445,31 +2511,37 @@ BEGIN
o_vpixq1<=o_vpixq;
-- NEAREST / BILINEAR / SHARP BILINEAR -------------
-- NEAREST -----------------------------------------
-- C4
o_v_near_frac<=near_frac(o_vfrac);
-- C5
o_v_near_t<=near_calc(o_v_near_frac,o_vpixq1);
-- C6 : Nearest
o_v_near_pix.r<=o_v_near_t.r(7+FRAC DOWNTO FRAC);
o_v_near_pix.g<=o_v_near_t.g(7+FRAC DOWNTO FRAC);
o_v_near_pix.b<=o_v_near_t.b(7+FRAC DOWNTO FRAC);
-- BILINEAR / SHARP BILINEAR -----------------------
-- C3 : Pre-calc Sharp Bilinear
o_v_sbil_t<=sbil_frac1(o_vfrac);
-- C4 : Select
o_v_frac<=(OTHERS =>'0');
CASE o_vmode(1 DOWNTO 0) IS
WHEN "00" => -- Nearest
IF MASK(MASK_NEAREST)='1' THEN
o_v_frac<=near_frac(o_vfrac);
END IF;
WHEN "01" => -- Bilinear
IF MASK(MASK_BILINEAR)='1' THEN
o_v_frac<=bil_frac(o_vfrac);
END IF;
WHEN "10" => -- Sharp Bilinear
IF MASK(MASK_SHARP_BILINEAR)='1' THEN
o_v_frac<=sbil_frac2(o_vfrac,o_v_sbil_t);
END IF;
WHEN OTHERS => NULL;
END CASE;
o_v_bil_frac<=(OTHERS =>'0');
IF o_vmode(0)='1' THEN -- Bilinear
IF MASK(MASK_BILINEAR)='1' THEN
o_v_bil_frac<=bil_frac(o_vfrac);
END IF;
ELSE -- Sharp Bilinear
IF MASK(MASK_SHARP_BILINEAR)='1' THEN
o_v_bil_frac<=sbil_frac2(o_vfrac,o_v_sbil_t);
END IF;
END IF;
o_v_bil_t<=bil_calc(o_v_frac,o_vpixq1);
o_v_bil_t<=bil_calc(o_v_bil_frac,o_vpixq1);
-- C6 : Nearest / Bilinear / Sharp Bilinear
-- C6 : Bilinear / Sharp Bilinear
o_v_bil_pix.r<=bound(o_v_bil_t.r,8+FRAC);
o_v_bil_pix.g<=bound(o_v_bil_t.g,8+FRAC);
o_v_bil_pix.b<=bound(o_v_bil_t.b,8+FRAC);
@@ -2508,11 +2580,17 @@ BEGIN
o_r<=x"00";
o_g<=x"00";
o_b<=x"00";
o_brd<= not o_pev(5);
CASE o_vmode(2 DOWNTO 0) IS
WHEN "000" | "001" | "010" => -- Nearest | Bilinear | Sharp Bilinear
IF MASK(MASK_NEAREST)='1' OR
MASK(MASK_BILINEAR)='1' OR
WHEN "000" => -- Nearest
IF MASK(MASK_NEAREST)='1' THEN
o_r<=o_v_near_pix.r;
o_g<=o_v_near_pix.g;
o_b<=o_v_near_pix.b;
END IF;
WHEN "001" | "010" => -- Bilinear | Sharp Bilinear
IF MASK(MASK_BILINEAR)='1' OR
MASK(MASK_SHARP_BILINEAR)='1' THEN
o_r<=o_v_bil_pix.r;
o_g<=o_v_bil_pix.g;

View File

@@ -32,8 +32,10 @@ always @(posedge clk_vid) begin
reg [7:0] R_gamma, G_gamma;
reg hs,vs,hb,vb;
reg [1:0] ctr = 0;
reg old_ce;
if(ce_pix) begin
old_ce <= ce_pix;
if(~old_ce & ce_pix) begin
{R_in,G_in,B_in} <= RGB_in;
hs <= HSync; vs <= VSync;
hb <= HBlank; vb <= VBlank;

View File

@@ -24,14 +24,13 @@
// Use buffer to access SD card. It's time-critical part.
//
// WIDE=1 for 16 bit file I/O
// VDNUM 1-4
module hps_io #(parameter STRLEN=0, PS2DIV=0, WIDE=0, VDNUM=1, PS2WE=0)
// VDNUM 1..10
// BLKSZ 0..7: 0 = 128, 1 = 256, 2 = 512(default), .. 7 = 16384
//
module hps_io #(parameter CONF_STR, CONF_STR_BRAM=1, PS2DIV=0, WIDE=0, VDNUM=1, BLKSZ=2, PS2WE=0)
(
input clk_sys,
inout [45:0] HPS_BUS,
// parameter STRLEN and the actual length of conf_str have to match
input [(8*STRLEN)-1:0] conf_str,
inout [47:0] HPS_BUS,
// buttons up to 32
output reg [31:0] joystick_0,
@@ -42,12 +41,19 @@ module hps_io #(parameter STRLEN=0, PS2DIV=0, WIDE=0, VDNUM=1, PS2WE=0)
output reg [31:0] joystick_5,
// analog -127..+127, Y: [15:8], X: [7:0]
output reg [15:0] joystick_analog_0,
output reg [15:0] joystick_analog_1,
output reg [15:0] joystick_analog_2,
output reg [15:0] joystick_analog_3,
output reg [15:0] joystick_analog_4,
output reg [15:0] joystick_analog_5,
output reg [15:0] joystick_l_analog_0,
output reg [15:0] joystick_l_analog_1,
output reg [15:0] joystick_l_analog_2,
output reg [15:0] joystick_l_analog_3,
output reg [15:0] joystick_l_analog_4,
output reg [15:0] joystick_l_analog_5,
output reg [15:0] joystick_r_analog_0,
output reg [15:0] joystick_r_analog_1,
output reg [15:0] joystick_r_analog_2,
output reg [15:0] joystick_r_analog_3,
output reg [15:0] joystick_r_analog_4,
output reg [15:0] joystick_r_analog_5,
// paddle 0..255
output reg [7:0] paddle_0,
@@ -86,22 +92,17 @@ module hps_io #(parameter STRLEN=0, PS2DIV=0, WIDE=0, VDNUM=1, PS2WE=0)
output reg [63:0] img_size, // size of image in bytes. valid only for active bit in img_mounted
// SD block level access
input [31:0] sd_lba,
input [VD:0] sd_rd, // only single sd_rd can be active at any given time
input [VD:0] sd_wr, // only single sd_wr can be active at any given time
output reg sd_ack,
// do not use in new projects.
// CID and CSD are fake except CSD image size field.
input sd_conf,
output reg sd_ack_conf,
input [31:0] sd_lba[VDNUM],
input [5:0] sd_blk_cnt[VDNUM], // number of blocks-1, total size ((sd_blk_cnt+1)*(1<<(BLKSZ+7))) must be <= 16384!
input [VD:0] sd_rd,
input [VD:0] sd_wr,
output reg [VD:0] sd_ack,
// SD byte level access. Signals for 2-PORT altsyncram.
output reg [AW:0] sd_buff_addr,
output reg [DW:0] sd_buff_dout,
input [DW:0] sd_buff_din,
input [DW:0] sd_buff_din[VDNUM],
output reg sd_buff_wr,
input [15:0] sd_req_type,
// ARM -> FPGA download
output reg ioctl_download = 0, // signal indicating an active download
@@ -110,6 +111,7 @@ module hps_io #(parameter STRLEN=0, PS2DIV=0, WIDE=0, VDNUM=1, PS2WE=0)
output reg [26:0] ioctl_addr, // in WIDE mode address will be incremented by 2
output reg [DW:0] ioctl_dout,
output reg ioctl_upload = 0, // signal indicating an active upload
input ioctl_upload_req,
input [DW:0] ioctl_din,
output reg ioctl_rd,
output reg [31:0] ioctl_file_ext,
@@ -161,10 +163,8 @@ module hps_io #(parameter STRLEN=0, PS2DIV=0, WIDE=0, VDNUM=1, PS2WE=0)
assign EXT_BUS[31:16] = HPS_BUS[31:16];
assign EXT_BUS[35:33] = HPS_BUS[35:33];
localparam MAX_W = $clog2((512 > (STRLEN+1)) ? 512 : (STRLEN+1))-1;
localparam DW = (WIDE) ? 15 : 7;
localparam AW = (WIDE) ? 7 : 8;
localparam AW = (WIDE) ? 12 : 13;
localparam VD = VDNUM-1;
wire io_strobe= HPS_BUS[33];
@@ -187,22 +187,18 @@ assign forced_scandoubler = cfg[4];
//cfg[5] - ypbpr handled in sys_top
assign direct_video = cfg[10];
// command byte read by the io controller
wire [15:0] sd_cmd =
{
2'b00,
(VDNUM>=4) ? sd_wr[3] : 1'b0,
(VDNUM>=3) ? sd_wr[2] : 1'b0,
(VDNUM>=2) ? sd_wr[1] : 1'b0,
reg [3:0] sdn;
reg [3:0] sd_rrb = 0;
always_comb begin
int n, i;
(VDNUM>=4) ? sd_rd[3] : 1'b0,
(VDNUM>=3) ? sd_rd[2] : 1'b0,
(VDNUM>=2) ? sd_rd[1] : 1'b0,
4'h5, sd_conf, 1'b1,
sd_wr[0],
sd_rd[0]
};
sdn = 0;
for(i = VDNUM - 1; i >= 0; i = i - 1) begin
n = i + sd_rrb;
if(n >= VDNUM) n = n - VDNUM;
if(sd_wr[n] | sd_rd[n]) sdn = n[3:0];
end
end
/////////////////////////////////////////////////////////
@@ -226,6 +222,19 @@ video_calc video_calc
/////////////////////////////////////////////////////////
localparam STRLEN = $size(CONF_STR)>>3;
localparam MAX_W = $clog2((32 > (STRLEN+2)) ? 32 : (STRLEN+2))-1;
wire [7:0] conf_byte;
generate
if(CONF_STR_BRAM) begin
confstr_rom #(CONF_STR, STRLEN) confstr_rom(.*, .conf_addr(byte_cnt - 1'd1));
end
else begin
assign conf_byte = CONF_STR[{(STRLEN - byte_cnt),3'b000} +:8];
end
endgenerate
assign gamma_bus[20:0] = {clk_sys, gamma_en, gamma_wr, gamma_wr_addr, gamma_value};
reg gamma_en;
reg gamma_wr;
@@ -237,6 +246,8 @@ wire pressed = (ps2_key_raw[15:8] != 8'hf0);
wire extended = (~pressed ? (ps2_key_raw[23:16] == 8'he0) : (ps2_key_raw[15:8] == 8'he0));
reg [MAX_W:0] byte_cnt;
reg [3:0] sdn_ack;
wire [15:0] disk = 16'd1 << io_din[11:8];
always@(posedge clk_sys) begin : uio_block
reg [15:0] cmd;
@@ -247,16 +258,22 @@ always@(posedge clk_sys) begin : uio_block
reg [3:0] stflg = 0;
reg [63:0] status_req;
reg old_status_set = 0;
reg old_upload_req = 0;
reg upload_req = 0;
reg old_info = 0;
reg [7:0] info_n = 0;
reg [15:0] tmp1;
reg [7:0] tmp2;
reg [3:0] sdn_r;
old_status_set <= status_set;
if(~old_status_set & status_set) begin
stflg <= stflg + 1'd1;
status_req <= status_in;
end
old_upload_req <= ioctl_upload_req;
if(~old_upload_req & ioctl_upload_req) upload_req <= 1;
old_info <= info_req;
if(~old_info & info_req) info_n <= info;
@@ -282,7 +299,6 @@ always@(posedge clk_sys) begin : uio_block
cmd <= 0;
byte_cnt <= 0;
sd_ack <= 0;
sd_ack_conf <= 0;
io_dout <= 0;
ps2skip <= 0;
img_mounted <= 0;
@@ -295,23 +311,25 @@ always@(posedge clk_sys) begin : uio_block
if(byte_cnt == 0) begin
cmd <= io_din;
case(io_din)
'h19: sd_ack_conf <= 1;
'h17,
'h18: sd_ack <= 1;
'h29: io_dout <= {4'hA, stflg};
'h2B: io_dout <= 1;
'h2F: io_dout <= 1;
'h32: io_dout <= gamma_bus[21];
'h36: begin io_dout <= info_n; info_n <= 0; end
'h39: io_dout <= 1;
casex(io_din)
'h16: begin io_dout <= {1'b1, sd_blk_cnt[sdn], BLKSZ[2:0], sdn, sd_wr[sdn], sd_rd[sdn]}; sdn_r <= sdn; end
'h0X17,
'h0X18: begin sd_ack <= disk[VD:0]; sdn_ack <= io_din[11:8]; end
'h29: io_dout <= {4'hA, stflg};
'h2B: io_dout <= {HPS_BUS[47:46],4'b0010};
'h2F: io_dout <= 1;
'h32: io_dout <= gamma_bus[21];
'h36: begin io_dout <= info_n; info_n <= 0; end
'h39: io_dout <= 1;
'h3C: if(upload_req) begin io_dout <= 1; upload_req <= 0; end
'h3E: io_dout <= 1; // shadow mask
endcase
sd_buff_addr <= 0;
if(io_din == 5) ps2_key_raw <= 0;
end else begin
case(cmd)
casex(cmd)
// buttons and switches
'h01: cfg <= io_din;
'h02: if(byte_cnt==1) joystick_0[15:0] <= io_din; else joystick_0[31:16] <= io_din;
@@ -353,47 +371,41 @@ always@(posedge clk_sys) begin : uio_block
end
// reading config string, returning a byte from string
'h14: if(byte_cnt < STRLEN + 1) io_dout[7:0] <= conf_str[(STRLEN - byte_cnt)<<3 +:8];
'h14: if(byte_cnt <= STRLEN) io_dout[7:0] <= conf_byte;
// reading sd card status
'h16: if(!byte_cnt[MAX_W:3]) begin
case(byte_cnt[2:0])
1: io_dout <= sd_cmd;
2: io_dout <= sd_lba[15:0];
3: io_dout <= sd_lba[31:16];
4: io_dout <= sd_req_type;
'h16: if(!byte_cnt[MAX_W:2]) begin
case(byte_cnt[1:0])
1: sd_rrb <= (sd_rrb == VD) ? 4'd0 : (sd_rrb + 1'd1);
2: io_dout <= sd_lba[sdn_r][15:0];
3: io_dout <= sd_lba[sdn_r][31:16];
endcase
end
// send SD config IO -> FPGA
// flag that download begins
// sd card knows data is config if sd_dout_strobe is asserted
// with sd_ack still being inactive (low)
'h19,
// send sector IO -> FPGA
// flag that download begins
'h17: begin
'h0X17: begin
sd_buff_dout <= io_din[DW:0];
b_wr <= 1;
end
// reading sd card write data
'h18: begin
'h0X18: begin
if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1;
io_dout <= sd_buff_din;
io_dout <= sd_buff_din[sdn_ack];
end
// joystick analog
// joystick left analog
'h1a: if(!byte_cnt[MAX_W:2]) begin
case(byte_cnt[1:0])
1: {pdsp_idx,stick_idx} <= io_din[7:0]; // first byte is joystick index
2: case(stick_idx)
0: joystick_analog_0 <= io_din;
1: joystick_analog_1 <= io_din;
2: joystick_analog_2 <= io_din;
3: joystick_analog_3 <= io_din;
4: joystick_analog_4 <= io_din;
5: joystick_analog_5 <= io_din;
0: joystick_l_analog_0 <= io_din;
1: joystick_l_analog_1 <= io_din;
2: joystick_l_analog_2 <= io_din;
3: joystick_l_analog_3 <= io_din;
4: joystick_l_analog_4 <= io_din;
5: joystick_l_analog_5 <= io_din;
15: case(pdsp_idx)
0: paddle_0 <= io_din[7:0];
1: paddle_1 <= io_din[7:0];
@@ -412,6 +424,21 @@ always@(posedge clk_sys) begin : uio_block
endcase
end
// joystick right analog
'h3d: if(!byte_cnt[MAX_W:2]) begin
case(byte_cnt[1:0])
1: stick_idx <= io_din[3:0]; // first byte is joystick index
2: case(stick_idx)
0: joystick_r_analog_0 <= io_din;
1: joystick_r_analog_1 <= io_din;
2: joystick_r_analog_2 <= io_din;
3: joystick_r_analog_3 <= io_din;
4: joystick_r_analog_4 <= io_din;
5: joystick_r_analog_5 <= io_din;
endcase
endcase
end
// notify image selection
'h1c: begin
img_mounted <= io_din[VD:0] ? io_din[VD:0] : 1'b1;
@@ -936,3 +963,16 @@ always @(posedge clk_100) begin
end
endmodule
module confstr_rom #(parameter CONF_STR, STRLEN)
(
input clk_sys,
input [$clog2(STRLEN+1)-1:0] conf_addr,
output reg [7:0] conf_byte
);
wire [7:0] rom[STRLEN];
initial for(int i = 0; i < STRLEN; i++) rom[i] = CONF_STR[((STRLEN-i)*8)-1 -:8];
always @ (posedge clk_sys) conf_byte <= rom[conf_addr];
endmodule

View File

@@ -72,7 +72,7 @@ always@(posedge clk_sys) begin
// command 0x40: OSDCMDENABLE, OSDCMDDISABLE
if(io_din[7:4] == 4) begin
if(!io_din[0]) {osd_status,highres} <= 0;
else {osd_status,info} <= {~io_din[2],io_din[2]};
else {osd_status,info} <= {~io_din[2] & ~io_din[3],io_din[2]};
bcnt <= 0;
end
// command 0x20: OSDCMDWRITE

View File

@@ -23,52 +23,55 @@
//
// Made module syncrhronous. Total code refactoring. (Sorgelig)
// clk_spi must be at least 4 x sck for proper work.
// clk_spi must be at least 2 x sck for proper work.
module sd_card #(parameter WIDE = 0)
module sd_card #(parameter WIDE = 0, OCTAL=0)
(
input clk_sys,
input reset,
input clk_sys,
input reset,
input sdhc,
output [31:0] sd_lba,
output reg sd_rd,
output reg sd_wr,
input sd_ack,
input sd_ack_conf,
input sdhc,
input img_mounted,
input [63:0] img_size,
input [AW:0] sd_buff_addr,
input [DW:0] sd_buff_dout,
output [DW:0] sd_buff_din,
input sd_buff_wr,
output reg [31:0] sd_lba,
output reg sd_rd,
output reg sd_wr,
input sd_ack,
input [AW:0] sd_buff_addr,
input [DW:0] sd_buff_dout,
output [DW:0] sd_buff_din,
input sd_buff_wr,
// SPI interface
input clk_spi,
input clk_spi,
input ss,
input sck,
input mosi,
output reg miso
input ss,
input sck,
input [SW:0] mosi,
output reg [SW:0] miso
);
localparam AW = WIDE ? 7 : 8;
localparam DW = WIDE ? 15 : 7;
localparam AW = WIDE ? 7 : 8;
localparam DW = WIDE ? 15 : 7;
localparam SZ = OCTAL ? 8 : 1;
localparam SW = SZ-1;
assign sd_lba = sdhc ? lba : {9'd0, lba[31:9]};
wire[31:0] OCR = { 1'b1, sdhc, 30'd0 }; // bit30 = 1 -> high capaciry card (sdhc) // bit31 = 0 -> card power up finished
wire [7:0] READ_DATA_TOKEN = 8'hfe;
wire [7:0] DATA_TOKEN_CMD25 = 8'hfc;
wire [7:0] STOP_TRAN = 8'hfd;
wire [7:0] DATA_TOKEN = 8'hfe;
wire [7:0] WRITE_DATA_RESPONSE = 8'h05;
// number of bytes to wait after a command before sending the reply
localparam NCR=3;
localparam NCR = 5+3; // 5 bytes are required (command length)
localparam RD_STATE_IDLE = 0;
localparam RD_STATE_WAIT_IO = 1;
localparam RD_STATE_SEND_TOKEN = 2;
localparam RD_STATE_SEND_DATA = 3;
localparam RD_STATE_WAIT_M = 4;
localparam RD_STATE_START = 1;
localparam RD_STATE_WAIT_IO = 2;
localparam RD_STATE_SEND_TOKEN = 3;
localparam RD_STATE_SEND_DATA = 4;
localparam RD_STATE_WAIT_M = 5;
localparam WR_STATE_IDLE = 0;
localparam WR_STATE_EXP_DTOKEN = 1;
@@ -78,460 +81,383 @@ localparam WR_STATE_RECV_CRC1 = 4;
localparam WR_STATE_SEND_DRESP = 5;
localparam WR_STATE_BUSY = 6;
sdbuf #(WIDE) buffer
localparam PREF_STATE_IDLE = 0;
localparam PREF_STATE_RD = 1;
localparam PREF_STATE_FINISH = 2;
altsyncram sdbuf
(
.clock_a(clk_sys),
.address_a(sd_buff_addr),
.data_a(sd_buff_dout),
.wren_a(sd_ack & sd_buff_wr),
.q_a(sd_buff_din),
.clock0 (clk_sys),
.address_a ({sd_buf,sd_buff_addr}),
.data_a (sd_buff_dout),
.wren_a (sd_ack & sd_buff_wr),
.q_a (sd_buff_din),
.clock_b(clk_spi),
.address_b(buffer_ptr),
.data_b(buffer_din),
.wren_b(buffer_wr),
.q_b(buffer_dout)
.clock1 (clk_spi),
.address_b ({spi_buf,buffer_ptr}),
.data_b (buffer_din),
.wren_b (buffer_wr),
.q_b (buffer_dout),
.aclr0(1'b0),
.aclr1(1'b0),
.addressstall_a(1'b0),
.addressstall_b(1'b0),
.byteena_a(1'b1),
.byteena_b(1'b1),
.clocken0(1'b1),
.clocken1(1'b1),
.clocken2(1'b1),
.clocken3(1'b1),
.eccstatus(),
.rden_a(1'b1),
.rden_b(1'b1)
);
defparam
sdbuf.numwords_a = 1<<(AW+3),
sdbuf.widthad_a = AW+3,
sdbuf.width_a = DW+1,
sdbuf.numwords_b = 2048,
sdbuf.widthad_b = 11,
sdbuf.width_b = 8,
sdbuf.address_reg_b = "CLOCK1",
sdbuf.clock_enable_input_a = "BYPASS",
sdbuf.clock_enable_input_b = "BYPASS",
sdbuf.clock_enable_output_a = "BYPASS",
sdbuf.clock_enable_output_b = "BYPASS",
sdbuf.indata_reg_b = "CLOCK1",
sdbuf.intended_device_family = "Cyclone V",
sdbuf.lpm_type = "altsyncram",
sdbuf.operation_mode = "BIDIR_DUAL_PORT",
sdbuf.outdata_aclr_a = "NONE",
sdbuf.outdata_aclr_b = "NONE",
sdbuf.outdata_reg_a = "UNREGISTERED",
sdbuf.outdata_reg_b = "UNREGISTERED",
sdbuf.power_up_uninitialized = "FALSE",
sdbuf.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ",
sdbuf.read_during_write_mode_port_b = "NEW_DATA_NO_NBE_READ",
sdbuf.width_byteena_a = 1,
sdbuf.width_byteena_b = 1,
sdbuf.wrcontrol_wraddress_reg_b = "CLOCK1";
sdbuf #(WIDE) conf
(
.clock_a(clk_sys),
.address_a(sd_buff_addr),
.data_a(sd_buff_dout),
.wren_a(sd_ack_conf & sd_buff_wr),
reg [26:0] csd_size;
reg csd_sdhc;
always @(posedge clk_sys) begin
if (img_mounted) begin
csd_sdhc <= sdhc;
if (sdhc) begin
csd_size[0] <= 0;
csd_size[22:1] <= img_size[40:19]; // in 512K units
csd_size[26:23] <= 0;
end
else begin
csd_size[2:0] <= 7; // C_SIZE_MULT
csd_size[14:3] <= 12'b101101101101;
csd_size[26:15] <= img_size[29:18]; // in 256K units ((2**(C_SIZE_MULT+2))*512)
end
end
end
.clock_b(clk_spi),
.address_b(buffer_ptr),
.q_b(config_dout)
);
wire [127:0] CSD = {1'b0,csd_sdhc,6'h00,8'h0e,8'h00,8'h32,8'h5b,8'h59,6'h00,csd_size,7'h7f,8'h80,8'h0a,8'h40,8'h40,8'hf1};
wire [127:0] CID = {8'hcd,8'hc7,8'h00,8'h93,8'h6f,8'h2f,8'h73,8'h00,8'h00,8'h44,8'h32,8'h38,8'h34,8'h00,8'h00,8'h3e};
reg [31:0] lba, new_lba;
reg [8:0] buffer_ptr;
reg [7:0] buffer_din;
wire [7:0] buffer_dout;
wire [7:0] config_dout;
reg buffer_wr;
always @(posedge clk_spi) begin
reg [2:0] read_state;
reg [2:0] write_state;
reg [6:0] sbuf;
reg cmd55;
reg [7:0] cmd;
reg [2:0] bit_cnt;
reg [3:0] byte_cnt;
reg [7:0] reply;
reg [7:0] reply0, reply1, reply2, reply3;
reg [3:0] reply_len;
reg tx_finish;
reg rx_finish;
reg old_sck;
reg synced;
reg [5:0] ack;
reg io_ack;
reg [4:0] idle_cnt = 0;
reg [2:0] wait_m_cnt;
reg [1:0] sd_buf, spi_buf;
reg [6:0] sbuf;
reg [2:0] bit_cnt;
wire last_bit = &bit_cnt || OCTAL;
wire [7:0] ibuf = OCTAL ? mosi : {sbuf,mosi[0]};
always @(posedge clk_spi) begin
reg [2:0] read_state;
reg [2:0] write_state;
reg [1:0] pref_state;
reg [5:0] cmd;
reg cmd55;
reg [39:0] reply;
reg [3:0] byte_cnt;
reg old_sck;
reg [2:0] ack;
reg [2:0] wait_m_cnt;
reg [31:0] arg;
ack[1:0] <= {ack[0],sd_ack};
if(ack[1] == ack[0]) ack[2] <= ack[1];
if(~ack[2] & ack[1]) {sd_rd,sd_wr} <= 0;
if( ack[2] & ~ack[1]) begin
sd_buf <= sd_buf + 1'd1;
sd_lba <= sd_lba + 1;
end
if(buffer_wr & ~&buffer_ptr) buffer_ptr <= buffer_ptr + 1'd1;
buffer_wr <= 0;
ack <= {ack[4:0], sd_ack};
if(ack[5:4] == 2'b10) io_ack <= 1;
if(ack[5:4] == 2'b01) {sd_rd,sd_wr} <= 0;
old_sck <= sck;
if(~ss) idle_cnt <= 31;
else if(~old_sck && sck && idle_cnt) idle_cnt <= idle_cnt - 1'd1;
if(reset || !idle_cnt) begin
if(reset) begin
bit_cnt <= 0;
byte_cnt <= 15;
synced <= 0;
miso <= 1;
sbuf <= 7'b1111111;
tx_finish <= 0;
rx_finish <= 0;
byte_cnt <= '1;
miso <= '1;
cmd <= 0;
sd_wr <= 0;
sd_rd <= 0;
read_state <= RD_STATE_IDLE;
write_state <= WR_STATE_IDLE;
pref_state <= PREF_STATE_IDLE;
end
else begin
if(old_sck & ~sck & ~ss) begin
tx_finish <= 0;
miso <= 1; // default: send 1's (busy/wait)
if(byte_cnt == 5+NCR) begin
miso <= reply[~bit_cnt];
if(bit_cnt == 7) begin
// these three commands all have a reply_len of 0 and will thus
// not send more than a single reply byte
// CMD9: SEND_CSD
// CMD10: SEND_CID
if((cmd == 'h49) | (cmd == 'h4a))
read_state <= RD_STATE_SEND_TOKEN; // jump directly to data transmission
// CMD17/CMD18
if((cmd == 'h51) | (cmd == 'h52)) begin
io_ack <= 0;
read_state <= RD_STATE_WAIT_IO; // start waiting for data from io controller
lba <= new_lba;
sd_rd <= 1; // trigger request to io controller
end
if(buffer_wr) begin
if(~&buffer_ptr) buffer_ptr <= buffer_ptr + 1'd1;
else begin
spi_buf <= spi_buf + 1'd1;
sd_wr <= 1;
end
end
else if((reply_len > 0) && (byte_cnt == 5+NCR+1)) miso <= reply0[~bit_cnt];
else if((reply_len > 1) && (byte_cnt == 5+NCR+2)) miso <= reply1[~bit_cnt];
else if((reply_len > 2) && (byte_cnt == 5+NCR+3)) miso <= reply2[~bit_cnt];
else if((reply_len > 3) && (byte_cnt == 5+NCR+4)) miso <= reply3[~bit_cnt];
else begin
if(byte_cnt > 5+NCR && read_state==RD_STATE_IDLE && write_state==WR_STATE_IDLE) tx_finish <= 1;
end
// ---------- read state machine processing -------------
case(read_state)
RD_STATE_IDLE: ; // do nothing
// waiting for io controller to return data
RD_STATE_WAIT_IO: begin
if(io_ack & (bit_cnt == 7)) read_state <= RD_STATE_SEND_TOKEN;
end
// send data token
RD_STATE_SEND_TOKEN: begin
miso <= READ_DATA_TOKEN[~bit_cnt];
if(bit_cnt == 7) begin
read_state <= RD_STATE_SEND_DATA; // next: send data
buffer_ptr <= 0;
if(cmd == 'h49) buffer_ptr <= 16;
case(pref_state)
PREF_STATE_IDLE:
if(((sd_buf - spi_buf) <= 1) && (read_state != RD_STATE_IDLE) && (cmd == 17 || cmd == 18)) begin
sd_rd <= 1;
pref_state <= PREF_STATE_RD;
end
end
// send data
RD_STATE_SEND_DATA: begin
miso <= ((cmd == 'h49) | (cmd == 'h4A)) ? config_dout[~bit_cnt] : buffer_dout[~bit_cnt];
if(bit_cnt == 7) begin
// sent 512 sector data bytes?
if((cmd == 'h51) & &buffer_ptr) read_state <= RD_STATE_IDLE;
else if((cmd == 'h52) & &buffer_ptr) begin
read_state <= RD_STATE_WAIT_M;
wait_m_cnt <= 0;
end
// sent 16 cid/csd data bytes?
else if(((cmd == 'h49) | (cmd == 'h4a)) & (&buffer_ptr[3:0])) read_state <= RD_STATE_IDLE;
// not done yet -> trigger read of next data byte
else buffer_ptr <= buffer_ptr + 1'd1;
PREF_STATE_RD:
if(read_state == RD_STATE_IDLE) begin
pref_state <= PREF_STATE_IDLE;
end
end
RD_STATE_WAIT_M: begin
if(bit_cnt == 7) begin
wait_m_cnt <= wait_m_cnt + 1'd1;
if(&wait_m_cnt) begin
lba <= lba + 1;
io_ack <= 0;
sd_rd <= 1;
read_state <= RD_STATE_WAIT_IO;
end
else if(ack[2] & ~ack[1]) begin
pref_state <= (cmd == 18) ? PREF_STATE_IDLE : PREF_STATE_FINISH;
end
PREF_STATE_FINISH:
if(read_state == RD_STATE_IDLE) begin
pref_state <= PREF_STATE_IDLE;
end
end
endcase
// ------------------ write support ----------------------
// send write data response
if(write_state == WR_STATE_SEND_DRESP) miso <= WRITE_DATA_RESPONSE[~bit_cnt];
// busy after write until the io controller sends ack
if(write_state == WR_STATE_BUSY) miso <= 0;
end
if(~old_sck & sck & ~ss) begin
if(synced) bit_cnt <= bit_cnt + 1'd1;
// assemble byte
if(bit_cnt != 7) begin
sbuf[6:0] <= { sbuf[5:0], mosi };
// resync while waiting for token
if(write_state==WR_STATE_EXP_DTOKEN) begin
if(cmd == 'h58) begin
if({sbuf,mosi} == 8'hfe) begin
write_state <= WR_STATE_RECV_DATA;
buffer_ptr <= 0;
bit_cnt <= 0;
end
end
else begin
if({sbuf,mosi} == 8'hfc) begin
write_state <= WR_STATE_RECV_DATA;
buffer_ptr <= 0;
bit_cnt <= 0;
end
if({sbuf,mosi} == 8'hfd) begin
write_state <= WR_STATE_IDLE;
rx_finish <= 1;
bit_cnt <= 0;
end
end
end
old_sck <= sck;
if(ss) begin
bit_cnt <= 0;
byte_cnt <= '1;
miso <= '1;
end
else begin
// finished reading one byte
// byte counter runs against 15 byte boundary
if(byte_cnt != 15) byte_cnt <= byte_cnt + 1'd1;
else if(old_sck & ~sck) begin
miso <= '1; // default: send 1's (busy/wait)
if(byte_cnt >= NCR) {miso,reply} <= {reply, {SZ{1'b1}}};
// byte_cnt > 6 -> complete command received
// first byte of valid command is 01xxxxxx
// don't accept new commands once a write or read command has been accepted
if((byte_cnt > 5) & (write_state == WR_STATE_IDLE) & (read_state == RD_STATE_IDLE) && !rx_finish) begin
byte_cnt <= 0;
cmd <= { sbuf, mosi};
// ---------- read state machine processing -------------
case(read_state)
RD_STATE_IDLE: ;
// set cmd55 flag if previous command was 55
cmd55 <= (cmd == 'h77);
end
RD_STATE_START: begin
if(byte_cnt == NCR && last_bit) read_state <= (cmd == 9 || cmd == 10) ? RD_STATE_SEND_TOKEN : RD_STATE_WAIT_IO;
end
if((byte_cnt > 5) & (read_state == RD_STATE_WAIT_M) && ({sbuf, mosi} == 8'h4c)) begin
byte_cnt <= 0;
rx_finish <= 0;
cmd <= {sbuf, mosi};
read_state <= RD_STATE_IDLE;
end
// waiting for io controller to return data
RD_STATE_WAIT_IO: begin
if(sd_buf != spi_buf && last_bit) read_state <= RD_STATE_SEND_TOKEN;
end
// parse additional command bytes
if(byte_cnt == 0) new_lba[31:24] <= { sbuf, mosi};
if(byte_cnt == 1) new_lba[23:16] <= { sbuf, mosi};
if(byte_cnt == 2) new_lba[15:8] <= { sbuf, mosi};
if(byte_cnt == 3) new_lba[7:0] <= { sbuf, mosi};
// last byte (crc) received, evaluate
if(byte_cnt == 4) begin
// default:
reply <= 4; // illegal command
reply_len <= 0; // no extra reply bytes
rx_finish <= 1;
case(cmd)
// CMD0: GO_IDLE_STATE
'h40: reply <= 1; // ok, busy
// CMD1: SEND_OP_COND
'h41: reply <= 0; // ok, not busy
// CMD8: SEND_IF_COND (V2 only)
'h48: begin
reply <= 1; // ok, busy
reply0 <= 'h00;
reply1 <= 'h00;
reply2 <= 'h01;
reply3 <= 'hAA;
reply_len <= 4;
end
// CMD9: SEND_CSD
'h49: reply <= 0; // ok
// CMD10: SEND_CID
'h4a: reply <= 0; // ok
// CMD12: STOP_TRANSMISSION
'h4c: reply <= 0; // ok
// CMD13: SEND_STATUS
'h4d: begin
reply <= 'h00; // ok
reply0 <='h00;
reply_len <= 1;
end
// CMD16: SET_BLOCKLEN
'h50: begin
// we only support a block size of 512
if(new_lba == 512) reply <= 0; // ok
else reply <= 'h40; // parmeter error
end
// CMD17: READ_SINGLE_BLOCK
'h51: reply <= 0; // ok
// CMD18: READ_MULTIPLE
'h52: reply <= 0; // ok
// ACMD23: SET_WR_BLK_ERASE_COUNT
'h57: reply <= 0; //ok
// CMD24: WRITE_BLOCK
'h58,
// CMD25: WRITE_MULTIPLE
'h59: begin
reply <= 0; // ok
write_state <= WR_STATE_EXP_DTOKEN; // expect data token
rx_finish <=0;
lba <= new_lba;
end
// ACMD41: APP_SEND_OP_COND
'h69: if(cmd55) reply <= 0; // ok, not busy
// CMD55: APP_COND
'h77: reply <= 1; // ok, busy
// CMD58: READ_OCR
'h7a: begin
reply <= 0; // ok
reply0 <= OCR[31:24]; // bit 30 = 1 -> high capacity card
reply1 <= OCR[23:16];
reply2 <= OCR[15:8];
reply3 <= OCR[7:0];
reply_len <= 4;
end
// CMD59: CRC_ON_OFF
'h7b: reply <= 0; // ok
endcase
end
// ---------- handle write -----------
case(write_state)
// do nothing in idle state
WR_STATE_IDLE: ;
// waiting for data token
WR_STATE_EXP_DTOKEN: begin
buffer_ptr <= 0;
if(cmd == 'h58) begin
if({sbuf,mosi} == 8'hfe) write_state <= WR_STATE_RECV_DATA;
end
else begin
if({sbuf,mosi} == 8'hfc) write_state <= WR_STATE_RECV_DATA;
if({sbuf,mosi} == 8'hfd) begin
write_state <= WR_STATE_IDLE;
rx_finish <= 1;
end
// send data token
RD_STATE_SEND_TOKEN: begin
miso <= DATA_TOKEN[~bit_cnt -:SZ];
if(last_bit) begin
read_state <= RD_STATE_SEND_DATA; // next: send data
buffer_ptr <= 0;
end
end
// transfer 512 bytes
WR_STATE_RECV_DATA: begin
// push one byte into local buffer
buffer_wr <= 1;
buffer_din <= {sbuf, mosi};
// send data
RD_STATE_SEND_DATA: begin
// all bytes written?
if(&buffer_ptr) write_state <= WR_STATE_RECV_CRC0;
miso <= (cmd == 9) ? CSD[{buffer_ptr[3:0],~bit_cnt} -:SZ] : (cmd == 10) ? CID[{buffer_ptr[3:0],~bit_cnt} -:SZ] : buffer_dout[~bit_cnt -:SZ];
if(last_bit) begin
// sent 512 sector data bytes?
if(cmd == 17 && &buffer_ptr) read_state <= RD_STATE_IDLE;
else if(cmd == 18 && &buffer_ptr) begin
read_state <= RD_STATE_WAIT_M;
wait_m_cnt <= 0;
end
// sent 16 cid/csd data bytes?
else if((cmd == 9 || cmd == 10) && &buffer_ptr[3:0]) read_state <= RD_STATE_IDLE;
// not done yet -> trigger read of next data byte
else buffer_ptr <= buffer_ptr + 1'd1;
end
end
// transfer 1st crc byte
WR_STATE_RECV_CRC0:
write_state <= WR_STATE_RECV_CRC1;
RD_STATE_WAIT_M: begin
if(last_bit) begin
wait_m_cnt <= wait_m_cnt + 1'd1;
if(&wait_m_cnt) begin
spi_buf <= spi_buf + 1'd1;
read_state <= RD_STATE_WAIT_IO;
end
end
end
endcase
// transfer 2nd crc byte
WR_STATE_RECV_CRC1:
write_state <= WR_STATE_SEND_DRESP;
// ------------------ write support ----------------------
// send write data response
if(write_state == WR_STATE_SEND_DRESP) miso <= WRITE_DATA_RESPONSE[~bit_cnt -:SZ];
// send data response
WR_STATE_SEND_DRESP: begin
write_state <= WR_STATE_BUSY;
io_ack <= 0;
sd_wr <= 1;
// busy after write until the io controller sends ack
if(write_state == WR_STATE_BUSY) miso <= 0;
end
else if(~old_sck & sck) begin
sbuf[6:0] <= {sbuf[5:0],mosi[0]};
bit_cnt <= bit_cnt + SZ[2:0];
if(last_bit) begin
// finished reading one byte
// byte counter runs against 15 byte boundary
if(~&byte_cnt) byte_cnt <= byte_cnt + 1'd1;
// byte_cnt > 6 -> complete command received
// first byte of valid command is 01xxxxxx
// don't accept new commands once a write or read command has been accepted
if(byte_cnt > 5 &&
((write_state == WR_STATE_IDLE && read_state == RD_STATE_IDLE && ibuf[7:6] == 1) ||
(read_state != RD_STATE_IDLE && ibuf == 8'h4c))) begin
byte_cnt <= 0;
cmd <= ibuf[5:0];
cmd55 <= (cmd == 55); // set cmd55 flag if previous command was 55
if(ibuf[5:0] == 12) read_state <= RD_STATE_IDLE;
end
// wait for io controller to accept data
WR_STATE_BUSY:
if(io_ack) begin
if(cmd == 'h59) begin
write_state <= WR_STATE_EXP_DTOKEN;
lba <= lba + 1;
// parse additional command bytes
if(byte_cnt == 0) arg[31:24] <= ibuf;
if(byte_cnt == 1) arg[23:16] <= ibuf;
if(byte_cnt == 2) arg[15:8] <= ibuf;
if(byte_cnt == 3) arg[7:0] <= ibuf;
// last byte (crc) received, evaluate
if(byte_cnt == 4) begin
// default:
reply <= 40'h04FFFFFFFF; // illegal command
case(cmd)
// CMD0: GO_IDLE_STATE
0: reply[39:32] <= 1; // ok, busy
// CMD1: SEND_OP_COND
1: reply[39:32] <= 0;
// CMD8: SEND_IF_COND (V2 only)
8: reply <= 40'h01000001AA; // ok, busy
// CMD9: SEND_CSD
9,
// CMD10: SEND_CID
10: begin
reply[39:32] <= 0;
read_state <= RD_STATE_START;
end
// CMD12: STOP_TRANSMISSION
12: reply[39:32] <= 0;
// CMD13: SEND_STATUS
13: reply[39:24] <= 16'h0000;
// CMD16: SET_BLOCKLEN
16: reply[39:32] <= (arg == 512) ? 8'h00 : 8'h40; // we only support a block size of 512
// CMD17: READ_SINGLE_BLOCK
17,
// CMD18: READ_MULTIPLE
18: begin
reply[39:32] <= 0;
read_state <= RD_STATE_START;
spi_buf <= 0;
sd_buf <= 0;
sd_lba <= csd_sdhc ? arg : {9'd0, arg[31:9]};
end
// ACMD23: SET_WR_BLK_ERASE_COUNT
23: reply[39:32] <= 0;
// CMD24: WRITE_BLOCK
24,
// CMD25: WRITE_MULTIPLE
25: begin
reply[39:32] <= 0;
write_state <= WR_STATE_EXP_DTOKEN; // expect data token
spi_buf <= 0;
sd_buf <= 0;
sd_lba <= csd_sdhc ? arg : {9'd0, arg[31:9]};
end
// ACMD41: APP_SEND_OP_COND
41: if(cmd55) reply[39:32] <= 0; // ok, not busy
// CMD55: APP_COND
55: reply[39:32] <= 1; // ok, busy
// CMD58: READ_OCR
58: reply <= { 8'h00, 1'b1, csd_sdhc, 30'd0 }; // bit 30 = 1 -> high capacity card
// CMD59: CRC_ON_OFF
59: reply[39:32] <= 0;
endcase
end
// ---------- handle write -----------
case(write_state)
// do nothing in idle state
WR_STATE_IDLE: ;
// waiting for data token
WR_STATE_EXP_DTOKEN: begin
buffer_ptr <= 0;
if(cmd == 24) begin
if(ibuf == DATA_TOKEN) write_state <= WR_STATE_RECV_DATA;
end
else begin
write_state <= WR_STATE_IDLE;
rx_finish <= 1;
if(ibuf == DATA_TOKEN_CMD25) write_state <= WR_STATE_RECV_DATA;
if(ibuf == STOP_TRAN) write_state <= WR_STATE_IDLE;
end
end
endcase
end
// wait for first 0 bit until start counting bits
if(!synced && !mosi) begin
synced <= 1;
bit_cnt <= 1; // byte assembly prepare for next time loop
sbuf <= 7'b1111110; // byte assembly prepare for next time loop
rx_finish<= 0;
end else if (synced && tx_finish && rx_finish ) begin
synced <= 0;
bit_cnt <= 0;
rx_finish<= 0;
// transfer 512 bytes
WR_STATE_RECV_DATA: begin
// push one byte into local buffer
buffer_wr <= 1;
buffer_din <= ibuf;
// all bytes written?
if(&buffer_ptr) write_state <= WR_STATE_RECV_CRC0;
end
// transfer 1st crc byte
WR_STATE_RECV_CRC0:
write_state <= WR_STATE_RECV_CRC1;
// transfer 2nd crc byte
WR_STATE_RECV_CRC1:
write_state <= WR_STATE_SEND_DRESP;
// send data response
WR_STATE_SEND_DRESP:
write_state <= WR_STATE_BUSY;
// wait for io controller to accept data
WR_STATE_BUSY:
if(spi_buf == sd_buf) write_state <= (cmd == 25) ? WR_STATE_EXP_DTOKEN : WR_STATE_IDLE;
endcase
end
end
end
end
endmodule
module sdbuf #(parameter WIDE)
(
input clock_a,
input [AW:0] address_a,
input [DW:0] data_a,
input wren_a,
output reg [DW:0] q_a,
input clock_b,
input [8:0] address_b,
input [7:0] data_b,
input wren_b,
output reg [7:0] q_b
);
localparam AW = WIDE ? 7 : 8;
localparam DW = WIDE ? 15 : 7;
always@(posedge clock_a) begin
if(wren_a) begin
ram[address_a] <= data_a;
q_a <= data_a;
end
else begin
q_a <= ram[address_a];
end
end
generate
if(WIDE) begin
reg [1:0][7:0] ram[1<<8];
always@(posedge clock_b) begin
if(wren_b) begin
ram[address_b[8:1]][address_b[0]] <= data_b;
q_b <= data_b;
end
else begin
q_b <= ram[address_b[8:1]][address_b[0]];
end
end
end
else begin
reg [7:0] ram[1<<9];
always@(posedge clock_b) begin
if(wren_b) begin
ram[address_b] <= data_b;
q_b <= data_b;
end
else begin
q_b <= ram[address_b];
end
end
end
endgenerate
endmodule

136
sys/shadowmask.sv Normal file
View File

@@ -0,0 +1,136 @@
module shadowmask
(
input clk,
input clk_sys,
input cmd_wr,
input [15:0] cmd_in,
input [23:0] din,
input hs_in,vs_in,
input de_in,
input brd_in,
input enable,
output reg [23:0] dout,
output reg hs_out,vs_out,
output reg de_out
);
reg [4:0] hmax;
reg [4:0] vmax;
reg [7:0] mask_idx;
reg mask_2x;
reg mask_rotate;
reg mask_enable;
reg [10:0] mask_lut[256];
always @(posedge clk) begin
reg [4:0] hcount;
reg [4:0] vcount;
reg [3:0] hindex;
reg [3:0] vindex;
reg [4:0] hmax2;
reg [4:0] vmax2;
reg [11:0] pcnt,pde;
reg old_hs, old_vs, old_brd;
reg next_v;
old_hs <= hs_in;
old_vs <= vs_in;
old_brd<= brd_in;
// hcount and vcount counts pixel rows and columns
// hindex and vindex half the value of the counters for double size patterns
// hindex2, vindex2 swap the h and v counters for drawing rotated masks
hindex <= mask_2x ? hcount[4:1] : hcount[3:0];
vindex <= mask_2x ? vcount[4:1] : vcount[3:0];
mask_idx <= mask_rotate ? {hindex,vindex} : {vindex,hindex};
// hmax and vmax store these sizes
// hmax2 and vmax2 swap the values to handle rotation
hmax2 <= ((mask_rotate ? vmax : hmax) << mask_2x) | mask_2x;
vmax2 <= ((mask_rotate ? hmax : vmax) << mask_2x) | mask_2x;
pcnt <= pcnt+1'd1;
if(old_brd && ~brd_in) pde <= pcnt-4'd3;
hcount <= hcount+1'b1;
if(hcount == hmax2 || pde == pcnt) hcount <= 0;
if(~old_brd && brd_in) next_v <= 1;
if(old_vs && ~vs_in) vcount <= 0;
if(old_hs && ~hs_in) begin
vcount <= vcount + next_v;
next_v <= 0;
pcnt <= 0;
if (vcount == vmax2) vcount <= 0;
end
end
reg [4:0] r_mul, g_mul, b_mul; // 1.4 fixed point multipliers
always @(posedge clk) begin
reg [10:0] lut;
lut <= mask_lut[mask_idx];
r_mul <= 5'b10000; g_mul <= 5'b10000; b_mul <= 5'b10000; // default 100% to all channels
if (mask_enable) begin
r_mul <= lut[10] ? {1'b1,lut[7:4]} : {1'b0,lut[3:0]};
g_mul <= lut[9] ? {1'b1,lut[7:4]} : {1'b0,lut[3:0]};
b_mul <= lut[8] ? {1'b1,lut[7:4]} : {1'b0,lut[3:0]};
end
end
always @(posedge clk) begin
reg [11:0] vid;
reg [7:0] r1, g1, b1;
reg [7:0] r2, g2, b2;
reg [7:0] r3_x, g3_x, b3_x; // 6.25% + 12.5%
reg [8:0] r3_y, g3_y, b3_y; // 25% + 50% + 100%
reg [8:0] r4, g4, b4;
// C1 - data input
{r1,g1,b1} <= din;
vid <= {vid[8:0],vs_in, hs_in, de_in};
// C2 - relax timings
{r2,g2,b2} <= {r1,g1,b1};
// C3 - perform multiplications
r3_x <= ({4{r_mul[0]}} & r2[7:4]) + ({8{r_mul[1]}} & r2[7:3]);
r3_y <= ({6{r_mul[2]}} & r2[7:2]) + ({7{r_mul[3]}} & r2[7:1]) + ({9{r_mul[4]}} & r2[7:0]);
g3_x <= ({4{g_mul[0]}} & g2[7:4]) + ({8{g_mul[1]}} & g2[7:3]);
g3_y <= ({6{g_mul[2]}} & g2[7:2]) + ({7{g_mul[3]}} & g2[7:1]) + ({9{g_mul[4]}} & g2[7:0]);
b3_x <= ({4{b_mul[0]}} & b2[7:4]) + ({8{b_mul[1]}} & b2[7:3]);
b3_y <= ({6{b_mul[2]}} & b2[7:2]) + ({7{b_mul[3]}} & b2[7:1]) + ({9{b_mul[4]}} & b2[7:0]);
// C4 - combine results
r4 <= r3_x + r3_y;
g4 <= g3_x + g3_y;
b4 <= b3_x + b3_y;
// C5 - clamp and output
dout <= {{8{r4[8]}} | r4[7:0], {8{g4[8]}} | g4[7:0], {8{b4[8]}} | b4[7:0]};
{vs_out,hs_out,de_out} <= vid[11:9];
end
// clock in mask commands
always @(posedge clk_sys) begin
reg m_enable;
reg [7:0] idx;
if (cmd_wr) begin
case(cmd_in[15:13])
3'b000: begin {m_enable, mask_rotate, mask_2x} <= cmd_in[3:1]; idx <= 0; end
3'b001: vmax <= cmd_in[3:0];
3'b010: hmax <= cmd_in[3:0];
3'b011: begin mask_lut[idx] <= cmd_in[10:0]; idx <= idx + 1'd1; end
endcase
end
mask_enable <= m_enable & enable;
end
endmodule

View File

@@ -7,10 +7,12 @@ set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) m
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) hq2x.sv ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) scandoubler.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) scanlines.v ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) shadowmask.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_cleaner.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) gamma_corr.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_mixer.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_freak.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_freezer.sv ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) arcade_video.v ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) osd.v ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) vga_out.sv ]
@@ -29,4 +31,4 @@ set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) f
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) ddr_svc.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) sysmem.sv ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) sd_card.sv ]
set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) hps_io.v ]
set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) hps_io.sv ]

View File

@@ -67,3 +67,5 @@ set_false_path -from {ascal|o_hdisp* ascal|o_vdisp*}
set_false_path -from {ascal|o_htotal* ascal|o_vtotal*}
set_false_path -from {ascal|o_hsstart* ascal|o_vsstart* ascal|o_hsend* ascal|o_vsend*}
set_false_path -from {ascal|o_hsize* ascal|o_vsize*}
set_false_path -from {mcp23009|sd_cd}

View File

@@ -19,18 +19,6 @@
//
//============================================================================
`ifndef ARCADE_SYS
`define USE_DDRAM
`define USE_SDRAM
`endif
`ifndef USE_DDRAM
`ifdef USE_FB
`define USE_DDRAM
`endif
`endif
module sys_top
(
/////////// CLOCK //////////
@@ -68,7 +56,7 @@ module sys_top
output SDRAM_CLK,
output SDRAM_CKE,
`ifdef DUAL_SDRAM
`ifdef MISTER_DUAL_SDRAM
////////// SDR #2 //////////
output [12:0] SDRAM2_A,
inout [15:0] SDRAM2_DQ,
@@ -139,20 +127,14 @@ module sys_top
////////////////////// Secondary SD ///////////////////////////////////
wire SD_CS, SD_CLK, SD_MOSI;
`ifdef ARCADE_SYS
assign SD_CS = 1'bZ;
assign SD_CLK = 1'bZ;
assign SD_MOSI = 1'bZ;
`ifndef MISTER_DUAL_SDRAM
wire sd_miso = SW[3] | SDIO_DAT[0];
`else
`ifndef DUAL_SDRAM
wire sd_miso = SW[3] | SDIO_DAT[0];
`else
wire sd_miso = 1;
`endif
wire SD_MISO = mcp_sdcd ? sd_miso : SD_SPI_MISO;
wire sd_miso = 1;
`endif
wire SD_MISO = mcp_sdcd ? sd_miso : SD_SPI_MISO;
`ifndef DUAL_SDRAM
`ifndef MISTER_DUAL_SDRAM
assign SDIO_DAT[2:1]= 2'bZZ;
assign SDIO_DAT[3] = SW[3] ? 1'bZ : SD_CS;
assign SDIO_CLK = SW[3] ? 1'bZ : SD_CLK;
@@ -175,7 +157,7 @@ wire led_d = led_disk[1] ? ~led_disk[0] : ~(led_disk[0] | gp_out[29]);
wire led_u = ~led_user;
wire led_locked;
`ifndef DUAL_SDRAM
`ifndef MISTER_DUAL_SDRAM
assign LED_POWER = (SW[3] | led_p) ? 1'bZ : 1'b0;
assign LED_HDD = (SW[3] | led_d) ? 1'bZ : 1'b0;
assign LED_USER = (SW[3] | led_u) ? 1'bZ : 1'b0;
@@ -185,7 +167,7 @@ wire led_locked;
assign LED = (led_overtake & led_state) | (~led_overtake & {1'b0,led_locked,1'b0, ~led_p, 1'b0, ~led_d, 1'b0, ~led_u});
wire btn_r, btn_o, btn_u;
`ifdef DUAL_SDRAM
`ifdef MISTER_DUAL_SDRAM
assign {btn_r,btn_o,btn_u} = {mcp_btn[1],mcp_btn[2],mcp_btn[0]};
`else
assign {btn_r,btn_o,btn_u} = ~{BTN_RESET,BTN_OSD,BTN_USER} | {mcp_btn[1],mcp_btn[2],mcp_btn[0]};
@@ -233,7 +215,7 @@ end
wire [31:0] gp_in = {1'b0, btn_user | btn[1], btn_osd | btn[0], SW[3], 8'd0, io_ver, io_ack, io_wide, io_dout};
wire [31:0] gp_out;
wire [1:0] io_ver = 1; // 0 - standard MiST I/O (for quick porting of complex MiST cores). 1 - optimized HPS I/O. 2,3 - reserved for future.
wire [1:0] io_ver = 1; // 0 - obsolete. 1 - optimized HPS I/O. 2,3 - reserved for future.
wire io_wait;
wire io_wide;
wire [15:0] io_dout;
@@ -243,7 +225,7 @@ wire io_ss0 = gp_outr[18];
wire io_ss1 = gp_outr[19];
wire io_ss2 = gp_outr[20];
`ifndef DEBUG_NOHDMI
`ifndef MISTER_DEBUG_NOHDMI
wire io_osd_hdmi = io_ss1 & ~io_ss0;
`endif
@@ -268,7 +250,7 @@ always @(posedge clk_sys) begin
gp_outd <= gp_out;
end
`ifdef DUAL_SDRAM
`ifdef MISTER_DUAL_SDRAM
wire [7:0] core_type = 'hA8; // generic core, dual SDRAM.
`else
wire [7:0] core_type = 'hA4; // generic core.
@@ -290,7 +272,7 @@ reg cfg_set = 0;
wire vga_fb = cfg[12] | vga_force_scaler;
wire [1:0] hdmi_limited = {cfg[11],cfg[8]};
`ifdef DEBUG_NOHDMI
`ifdef MISTER_DEBUG_NOHDMI
wire direct_video = 1;
`else
wire direct_video = cfg[10];
@@ -301,7 +283,7 @@ wire audio_96k = cfg[6];
wire csync_en = cfg[3];
wire ypbpr_en = cfg[5];
wire io_osd_vga = io_ss1 & ~io_ss2;
`ifndef DUAL_SDRAM
`ifndef MISTER_DUAL_SDRAM
wire sog = cfg[9];
wire vga_scaler = cfg[2] | vga_force_scaler;
`endif
@@ -310,9 +292,10 @@ reg cfg_custom_t = 0;
reg [5:0] cfg_custom_p1;
reg [31:0] cfg_custom_p2;
reg [4:0] vol_att = 0;
reg [4:0] vol_att;
initial vol_att = 5'b11111;
reg [6:0] coef_addr;
reg [8:0] coef_addr;
reg [8:0] coef_data;
reg coef_wr = 0;
@@ -353,6 +336,10 @@ always@(posedge clk_sys) begin
old_strobe <= io_strobe;
coef_wr <= 0;
`ifndef MISTER_DEBUG_NOHDMI
shadowmask_wr <= 0;
`endif
if(~io_uio) begin
has_cmd <= 0;
cmd <= 0;
@@ -380,6 +367,7 @@ always@(posedge clk_sys) begin
end
end
else begin
cnt <= cnt + 1'd1;
if(cmd == 1) begin
cfg <= io_din;
cfg_set <= 1;
@@ -387,7 +375,6 @@ always@(posedge clk_sys) begin
end
if(cmd == 'h20) begin
cfg_set <= 0;
cnt <= cnt + 1'd1;
if(cnt<8) begin
case(cnt[2:0])
0: if(WIDTH != io_din[11:0]) WIDTH <= io_din[11:0];
@@ -399,7 +386,7 @@ always@(posedge clk_sys) begin
6: if(VS != io_din[11:0]) VS <= io_din[11:0];
7: if(VBP != io_din[11:0]) VBP <= io_din[11:0];
endcase
`ifndef DEBUG_NOHDMI
`ifndef MISTER_DEBUG_NOHDMI
if(cnt == 1) begin
cfg_custom_p1 <= 0;
cfg_custom_p2 <= 0;
@@ -419,7 +406,6 @@ always@(posedge clk_sys) begin
end
end
if(cmd == 'h2F) begin
cnt <= cnt + 1'd1;
case(cnt[3:0])
0: {LFB_EN,LFB_FLT,LFB_FMT} <= {io_din[15], io_din[14], io_din[5:0]};
1: LFB_BASE[15:0] <= io_din[15:0];
@@ -436,12 +422,14 @@ always@(posedge clk_sys) begin
if(cmd == 'h25) {led_overtake, led_state} <= io_din;
if(cmd == 'h26) vol_att <= io_din[4:0];
if(cmd == 'h27) VSET <= io_din[11:0];
if(cmd == 'h2A) {coef_wr,coef_addr,coef_data} <= {1'b1,io_din};
if(cmd == 'h2A) begin
if(cnt[0]) {coef_wr,coef_data} <= {1'b1,io_din[8:0]};
else coef_addr <= io_din[8:0];
end
if(cmd == 'h2B) scaler_flt <= io_din[2:0];
if(cmd == 'h37) {FREESCALE,HSET} <= {io_din[15],io_din[11:0]};
if(cmd == 'h38) vs_line <= io_din[11:0];
if(cmd == 'h39) begin
cnt <= cnt + 1'd1;
case(cnt[3:0])
0: acx_att <= io_din[4:0];
1: aflt_rate[15:0] <= io_din;
@@ -461,7 +449,6 @@ always@(posedge clk_sys) begin
endcase
end
if(cmd == 'h3A) begin
cnt <= cnt + 1'd1;
case(cnt[3:0])
0: arc1x <= io_din[12:0];
1: arc1y <= io_din[12:0];
@@ -469,6 +456,9 @@ always@(posedge clk_sys) begin
3: arc2y <= io_din[12:0];
endcase
end
`ifndef MISTER_DEBUG_NOHDMI
if(cmd == 'h3E) {shadowmask_wr,shadowmask_data} <= {1'b1, io_din};
`endif
end
end
@@ -481,9 +471,7 @@ end
cyclonev_hps_interface_peripheral_uart uart
(
.ri(0)
`ifndef ARCADE_SYS
,
.ri(0),
.dsr(uart_dsr),
.dcd(uart_dsr),
.dtr(uart_dtr),
@@ -492,7 +480,6 @@ cyclonev_hps_interface_peripheral_uart uart
.rts(uart_rts),
.rxd(uart_rxd),
.txd(uart_txd)
`endif
);
wire aspi_sck,aspi_mosi,aspi_ss,aspi_miso;
@@ -547,7 +534,6 @@ sysmem_lite sysmem
//DE10-nano has no reset signal on GPIO, so core has to emulate cold reset button.
.reset_hps_cold_req(btn_r),
`ifdef USE_DDRAM
//64-bit DDR3 RAM access
.ram1_clk(ram_clk),
.ram1_address(ram_address),
@@ -559,7 +545,6 @@ sysmem_lite sysmem
.ram1_writedata(ram_writedata),
.ram1_byteenable(ram_byteenable),
.ram1_write(ram_write),
`endif
//64-bit DDR3 RAM access
.ram2_clk(clk_audio),
@@ -640,17 +625,23 @@ wire [15:0] vbuf_byteenable;
wire vbuf_write;
wire [23:0] hdmi_data;
wire hdmi_vs, hdmi_hs, hdmi_de, hdmi_vbl;
wire hdmi_vs, hdmi_hs, hdmi_de, hdmi_vbl, hdmi_brd;
wire freeze;
`ifndef DEBUG_NOHDMI
`ifndef MISTER_DEBUG_NOHDMI
wire clk_hdmi = hdmi_clk_out;
ascal
#(
.RAMBASE(32'h20000000),
`ifndef USE_FB
`ifndef MISTER_FB
.PALETTE2("false"),
`else
`ifndef MISTER_FB_PALETTE
.PALETTE2("false"),
`endif
`endif
.FRAC(6),
.N_DW(128),
.N_AW(28)
)
@@ -658,7 +649,7 @@ ascal
(
.reset_na (~reset_req),
.run (1),
.freeze (0),
.freeze (freeze),
.i_clk (clk_ihdmi),
.i_ce (ce_hpix),
@@ -684,6 +675,7 @@ ascal
.o_vs (hdmi_vs),
.o_de (hdmi_de),
.o_vbl (hdmi_vbl),
.o_brd (hdmi_brd),
.o_lltune (lltune),
.htotal (WIDTH + HFP + HBP + HS),
.hsstart (WIDTH + HFP),
@@ -709,13 +701,15 @@ ascal
.pal1_a (pal_a),
.pal1_wr (pal_wr),
`ifdef USE_FB
.pal2_clk (fb_pal_clk),
.pal2_dw (fb_pal_d),
.pal2_dr (fb_pal_q),
.pal2_a (fb_pal_a),
.pal2_wr (fb_pal_wr),
.pal_n (fb_en),
`ifdef MISTER_FB
`ifdef MISTER_FB_PALETTE
.pal2_clk (fb_pal_clk),
.pal2_dw (fb_pal_d),
.pal2_dr (fb_pal_q),
.pal2_a (fb_pal_a),
.pal2_wr (fb_pal_wr),
.pal_n (fb_en),
`endif
`endif
.o_fb_ena (FB_EN),
@@ -775,7 +769,7 @@ always @(posedge clk_sys) begin
end
end
`ifdef USE_FB
`ifdef MISTER_FB
reg fb_vbl;
always @(posedge clk_vid) fb_vbl <= hdmi_vbl;
`endif
@@ -899,7 +893,7 @@ always @(posedge clk_vid) begin
vmax <= vmaxi;
end
`ifndef DEBUG_NOHDMI
`ifndef MISTER_DEBUG_NOHDMI
wire [15:0] lltune;
pll_hdmi_adj pll_hdmi_adj
(
@@ -942,7 +936,7 @@ end
///////////////////////// HDMI output /////////////////////////////////
`ifndef DEBUG_NOHDMI
`ifndef MISTER_DEBUG_NOHDMI
wire hdmi_clk_out;
pll_hdmi pll_hdmi
(
@@ -974,7 +968,7 @@ reg adj_write;
reg [5:0] adj_address;
reg [31:0] adj_data;
`ifndef DEBUG_NOHDMI
`ifndef MISTER_DEBUG_NOHDMI
pll_cfg pll_cfg
(
.mgmt_clk(FPGA_CLK1_50),
@@ -1063,35 +1057,44 @@ cyclonev_hps_interface_peripheral_i2c hdmi_i2c
.sda(HDMI_I2C_SDA)
);
`ifndef DEBUG_NOHDMI
wire [23:0] hdmi_data_sl;
wire hdmi_de_sl, hdmi_vs_sl, hdmi_hs_sl;
`ifndef MISTER_DEBUG_NOHDMI
`ifdef USE_FB
`ifdef MISTER_FB
reg dis_output;
always @(posedge clk_hdmi) begin
reg dis;
dis <= fb_force_blank;
dis <= fb_force_blank & ~LFB_EN;
dis_output <= dis;
end
`else
wire dis_output = 0;
`endif
scanlines #(1) HDMI_scanlines
wire [23:0] hdmi_data_mask;
wire hdmi_de_mask, hdmi_vs_mask, hdmi_hs_mask;
reg [15:0] shadowmask_data;
reg shadowmask_wr = 0;
shadowmask HDMI_shadowmask
(
.clk(clk_hdmi),
.clk_sys(clk_sys),
.cmd_wr(shadowmask_wr),
.cmd_in(shadowmask_data),
.scanlines(scanlines),
.din(dis_output ? 24'd0 : hdmi_data),
.hs_in(hdmi_hs),
.vs_in(hdmi_vs),
.de_in(hdmi_de),
.dout(hdmi_data_sl),
.hs_out(hdmi_hs_sl),
.vs_out(hdmi_vs_sl),
.de_out(hdmi_de_sl)
.brd_in(hdmi_brd),
.enable(~LFB_EN),
.dout(hdmi_data_mask),
.hs_out(hdmi_hs_mask),
.vs_out(hdmi_vs_mask),
.de_out(hdmi_de_mask)
);
wire [23:0] hdmi_data_osd;
@@ -1106,19 +1109,15 @@ osd hdmi_osd
.io_din(io_din),
.clk_video(clk_hdmi),
.din(hdmi_data_sl),
.hs_in(hdmi_hs_sl),
.vs_in(hdmi_vs_sl),
.de_in(hdmi_de_sl),
.din(hdmi_data_mask),
.hs_in(hdmi_hs_mask),
.vs_in(hdmi_vs_mask),
.de_in(hdmi_de_mask),
.dout(hdmi_data_osd),
.hs_out(hdmi_hs_osd),
.vs_out(hdmi_vs_osd),
.de_out(hdmi_de_osd)
`ifndef ARCADE_SYS
,
.osd_status(osd_status)
`endif
);
`endif
@@ -1167,7 +1166,7 @@ always @(posedge clk_vid) begin
end
wire hdmi_tx_clk;
`ifndef DEBUG_NOHDMI
`ifndef MISTER_DEBUG_NOHDMI
cyclonev_clkselect hdmi_clk_sw
(
.clkselect({1'b1, ~vga_fb & direct_video}),
@@ -1257,6 +1256,7 @@ osd vga_osd
.io_osd(io_osd_vga),
.io_strobe(io_strobe),
.io_din(io_din),
.osd_status(osd_status),
.clk_video(clk_vid),
.din(vga_data_sl),
@@ -1272,7 +1272,7 @@ osd vga_osd
wire vga_cs_osd;
csync csync_vga(clk_vid, vga_hs_osd, vga_vs_osd, vga_cs_osd);
`ifndef DUAL_SDRAM
`ifndef MISTER_DUAL_SDRAM
wire [23:0] vgas_o;
wire vgas_hs, vgas_vs, vgas_cs;
vga_out vga_scaler_out
@@ -1343,7 +1343,7 @@ end
assign SDCD_SPDIF =(SW[3] & ~spdif) ? 1'b0 : 1'bZ;
`ifndef DUAL_SDRAM
`ifndef MISTER_DUAL_SDRAM
wire analog_l, analog_r;
assign AUDIO_SPDIF = SW[3] ? 1'bZ : SW[0] ? HDMI_LRCLK : spdif;
@@ -1390,7 +1390,7 @@ audio_out audio_out
.i2s_bclk(HDMI_SCLK),
.i2s_lrclk(HDMI_LRCLK),
.i2s_data(HDMI_I2S),
`ifndef DUAL_SDRAM
`ifndef MISTER_DUAL_SDRAM
.dac_l(analog_l),
.dac_r(analog_r),
`endif
@@ -1457,18 +1457,16 @@ wire hvs_fix, hhs_fix, hde_emu;
wire clk_vid, ce_pix, clk_ihdmi, ce_hpix;
wire vga_force_scaler;
`ifdef USE_DDRAM
wire ram_clk;
wire [28:0] ram_address;
wire [7:0] ram_burstcount;
wire ram_waitrequest;
wire [63:0] ram_readdata;
wire ram_readdatavalid;
wire ram_read;
wire [63:0] ram_writedata;
wire [7:0] ram_byteenable;
wire ram_write;
`endif
wire ram_clk;
wire [28:0] ram_address;
wire [7:0] ram_burstcount;
wire ram_waitrequest;
wire [63:0] ram_readdata;
wire ram_readdatavalid;
wire ram_read;
wire [63:0] ram_writedata;
wire [7:0] ram_byteenable;
wire ram_write;
wire led_user;
wire [1:0] led_power;
@@ -1480,32 +1478,23 @@ sync_fix sync_h(clk_vid, hs_emu, hs_fix);
wire [6:0] user_out, user_in;
`ifndef USE_SDRAM
assign {SDRAM_DQ, SDRAM_A, SDRAM_BA, SDRAM_CLK, SDRAM_CKE, SDRAM_DQML, SDRAM_DQMH, SDRAM_nWE, SDRAM_nCAS, SDRAM_nRAS, SDRAM_nCS} = {39'bZ};
`endif
assign clk_ihdmi= clk_vid;
assign ce_hpix = ce_pix;
assign hr_out = r_out;
assign hg_out = g_out;
assign hb_out = b_out;
assign hhs_fix = hs_fix;
assign hvs_fix = vs_fix;
assign hde_emu = de_emu;
assign hr_out = vga_data_sl[23:16];
assign hg_out = vga_data_sl[15:8];
assign hb_out = vga_data_sl[7:0];
assign hhs_fix = vga_hs_sl;
assign hvs_fix = vga_vs_sl;
assign hde_emu = vga_de_sl;
`ifdef ARCADE_SYS
assign audio_mix = 0;
assign {ADC_SCK, ADC_SDI, ADC_CONVST} = 0;
assign btn = 0;
`else
wire uart_dtr;
wire uart_dsr;
wire uart_cts;
wire uart_rts;
wire uart_rxd;
wire uart_txd;
wire osd_status;
`endif
wire uart_dtr;
wire uart_dsr;
wire uart_cts;
wire uart_rts;
wire uart_rxd;
wire uart_txd;
wire osd_status;
wire fb_en;
wire [4:0] fb_fmt;
@@ -1514,13 +1503,16 @@ wire [11:0] fb_height;
wire [31:0] fb_base;
wire [13:0] fb_stride;
`ifdef USE_FB
wire fb_pal_clk;
wire [7:0] fb_pal_a;
wire [23:0] fb_pal_d;
wire [23:0] fb_pal_q;
wire fb_pal_wr;
wire fb_force_blank;
`ifdef MISTER_FB
`ifdef MISTER_FB_PALETTE
wire fb_pal_clk;
wire [7:0] fb_pal_a;
wire [23:0] fb_pal_d;
wire [23:0] fb_pal_q;
wire fb_pal_wr;
`endif
wire fb_force_blank;
`else
assign fb_en = 0;
assign fb_fmt = 0;
@@ -1534,7 +1526,7 @@ emu emu
(
.CLK_50M(FPGA_CLK2_50),
.RESET(reset),
.HPS_BUS({f1, HDMI_TX_VS,
.HPS_BUS({scanlines,f1, HDMI_TX_VS,
clk_100m, clk_ihdmi,
ce_hpix, hde_emu, hhs_fix, hvs_fix,
io_wait, clk_sys, io_fpga, io_uio, io_strobe, io_wide, io_din, io_dout}),
@@ -1550,6 +1542,7 @@ emu emu
.HDMI_WIDTH(direct_video ? 12'd0 : hdmi_width),
.HDMI_HEIGHT(direct_video ? 12'd0 : hdmi_height),
.HDMI_FREEZE(freeze),
.CLK_VIDEO(clk_vid),
.CE_PIXEL(ce_pix),
@@ -1557,7 +1550,7 @@ emu emu
.VIDEO_ARX(ARX),
.VIDEO_ARY(ARY),
`ifdef USE_FB
`ifdef MISTER_FB
.FB_EN(fb_en),
.FB_FORMAT(fb_fmt),
.FB_WIDTH(fb_width),
@@ -1568,11 +1561,14 @@ emu emu
.FB_LL(lowlat),
.FB_FORCE_BLANK(fb_force_blank),
`ifdef MISTER_FB_PALETTE
.FB_PAL_CLK (fb_pal_clk),
.FB_PAL_ADDR(fb_pal_a),
.FB_PAL_DOUT(fb_pal_d),
.FB_PAL_DIN (fb_pal_q),
.FB_PAL_WR (fb_pal_wr),
`endif
`endif
.LED_USER(led_user),
@@ -1583,13 +1579,10 @@ emu emu
.AUDIO_L(audio_l),
.AUDIO_R(audio_r),
.AUDIO_S(audio_s),
`ifndef ARCADE_SYS
.AUDIO_MIX(audio_mix),
.ADC_BUS({ADC_SCK,ADC_SDO,ADC_SDI,ADC_CONVST}),
`endif
`ifdef USE_DDRAM
.ADC_BUS({ADC_SCK,ADC_SDO,ADC_SDI,ADC_CONVST}),
.DDRAM_CLK(ram_clk),
.DDRAM_ADDR(ram_address),
.DDRAM_BURSTCNT(ram_burstcount),
@@ -1600,9 +1593,7 @@ emu emu
.DDRAM_DIN(ram_writedata),
.DDRAM_BE(ram_byteenable),
.DDRAM_WE(ram_write),
`endif
`ifdef USE_SDRAM
.SDRAM_DQ(SDRAM_DQ),
.SDRAM_A(SDRAM_A),
.SDRAM_DQML(SDRAM_DQML),
@@ -1614,9 +1605,8 @@ emu emu
.SDRAM_nCAS(SDRAM_nCAS),
.SDRAM_CLK(SDRAM_CLK),
.SDRAM_CKE(SDRAM_CKE),
`endif
`ifdef DUAL_SDRAM
`ifdef MISTER_DUAL_SDRAM
.SDRAM2_DQ(SDRAM2_DQ),
.SDRAM2_A(SDRAM2_A),
.SDRAM2_BA(SDRAM2_BA),
@@ -1628,14 +1618,14 @@ emu emu
.SDRAM2_EN(SW[3]),
`endif
`ifndef ARCADE_SYS
.BUTTONS(btn),
.OSD_STATUS(osd_status),
.SD_SCK(SD_CLK),
.SD_MOSI(SD_MOSI),
.SD_MISO(SD_MISO),
.SD_CS(SD_CS),
`ifdef DUAL_SDRAM
`ifdef MISTER_DUAL_SDRAM
.SD_CD(mcp_sdcd),
`else
.SD_CD(mcp_sdcd & (SW[0] ? VGA_HS : (SW[3] | SDCD_SPDIF))),
@@ -1647,7 +1637,6 @@ emu emu
.UART_TXD(uart_rxd),
.UART_DTR(uart_dsr),
.UART_DSR(uart_dtr),
`endif
.USER_OUT(user_out),
.USER_IN(user_in)

View File

@@ -25,27 +25,44 @@ wire [5:0] blue = din[7:2];
// 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)
reg [18:0] y_2, pb_2, pr_2;
reg [7:0] y, pb, pr;
reg [23:0] din2, din3;
reg hsync2, vsync2, csync2;
reg [23:0] rgb;
always @(posedge clk) begin
y_2 <= 19'd04096 + ({red, 8'd0} + {red, 3'd0}) + ({green, 9'd0} + {green, 2'd0}) + ({blue, 6'd0} + {blue, 5'd0} + {blue, 2'd0});
pb_2 <= 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});
pr_2 <= 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});
reg [18:0] y_1r, pb_1r, pr_1r;
reg [18:0] y_1g, pb_1g, pr_1g;
reg [18:0] y_1b, pb_1b, pr_1b;
reg [18:0] y_2, pb_2, pr_2;
reg [23:0] din1, din2;
reg hsync2, vsync2, csync2;
reg hsync1, vsync1, csync1;
y_1r <= 19'd04096 + ({red, 8'd0} + {red, 3'd0});
pb_1r <= 19'd32768 - ({red, 7'd0} + {red, 4'd0} + {red, 3'd0});
pr_1r <= 19'd32768 + ({red, 8'd0} + {red, 7'd0} + {red, 6'd0});
y_1g <= {green, 9'd0} + {green, 2'd0};
pb_1g <= {green, 8'd0} + {green, 5'd0} + {green, 3'd0};
pr_1g <= {green, 8'd0} + {green, 6'd0} + {green, 5'd0} + {green, 4'd0} + {green, 3'd0};
y_1b <= {blue, 6'd0} + {blue, 5'd0} + {blue, 2'd0};
pb_1b <= {blue, 8'd0} + {blue, 7'd0} + {blue, 6'd0};
pr_1b <= {blue, 6'd0} + {blue, 3'd0};
y_2 <= y_1r + y_1g + y_1b;
pb_2 <= pb_1r - pb_1g + pb_1b;
pr_2 <= pr_1r - pr_1g - pr_1b;
y <= ( y_2[18] || !y_2[17:12]) ? 8'd16 : (y_2[17:8] > 235) ? 8'd235 : y_2[15:8];
pb <= (pb_2[18] || !pb_2[17:12]) ? 8'd16 : (&pb_2[17:12]) ? 8'd240 : pb_2[15:8];
pr <= (pr_2[18] || !pr_2[17:12]) ? 8'd16 : (&pr_2[17:12]) ? 8'd240 : pr_2[15:8];
hsync_o <= hsync2; hsync2 <= hsync;
vsync_o <= vsync2; vsync2 <= vsync;
csync_o <= csync2; csync2 <= csync;
hsync_o <= hsync2; hsync2 <= hsync1; hsync1 <= hsync;
vsync_o <= vsync2; vsync2 <= vsync1; vsync1 <= vsync;
csync_o <= csync2; csync2 <= csync1; csync1 <= csync;
din2 <= din;
din3 <= din2;
rgb <= din2; din2 <= din1; din1 <= din;
end
assign dout = ypbpr_en ? {pr, y, pb} : din3;
assign dout = ypbpr_en ? {pr, y, pb} : rgb;
endmodule

View File

@@ -28,21 +28,29 @@ module video_freak
input [11:0] ARX,
input [11:0] ARY,
input [11:0] CROP_SIZE,
input [4:0] CROP_OFF,
input [1:0] SCALE
input [4:0] CROP_OFF, // -16...+15
input [2:0] SCALE //0 - normal, 1 - V-integer, 2 - HV-Integer-, 3 - HV-Integer+, 4 - HV-Integer
);
reg mul_start;
wire mul_run;
reg [11:0] mul_arg1, mul_arg2;
wire [23:0] mul_res;
sys_umul #(12,12) mul(CLK_VIDEO,mul_start,mul_run, mul_arg1,mul_arg2,mul_res);
reg vde;
reg [11:0] arxo,aryo;
reg [11:0] vsize;
reg [11:0] hsize;
always @(posedge CLK_VIDEO) begin
reg old_de, old_vs,vcalc,ovde;
reg old_de, old_vs,ovde;
reg [11:0] vtot,vcpt,vcrop,voff;
reg [11:0] hcpt;
reg [11:0] vadj;
reg [23:0] ARXG,ARYG,arx,ary;
reg [23:0] ARXG,ARYG;
reg [11:0] arx,ary;
reg [1:0] vcalc;
if (CE_PIXEL) begin
old_de <= VGA_DE_IN;
@@ -51,7 +59,7 @@ always @(posedge CLK_VIDEO) begin
vcpt <= 0;
vtot <= vcpt;
vcalc <= 1;
vcrop <= ((CROP_SIZE >= vcpt) || !CROP_SIZE) ? 12'd0 : CROP_SIZE;
vcrop <= (CROP_SIZE >= vcpt) ? 12'd0 : CROP_SIZE;
end
if (VGA_DE_IN) hcpt <= hcpt + 1'd1;
@@ -65,17 +73,36 @@ always @(posedge CLK_VIDEO) begin
arx <= ARX;
ary <= ARY;
vsize <= vcrop;
vsize <= vcrop ? vcrop : vtot;
mul_start <= 0;
if(!vcrop || !ary || !arx) begin
arxo <= arx[11:0];
aryo <= ary[11:0];
vsize <= vtot;
arxo <= arx;
aryo <= ary;
end
else if (vcalc) begin
ARXG <= arx * vtot;
ARYG <= ary * vcrop;
vcalc <= 0;
if(~mul_start & ~mul_run) begin
vcalc <= vcalc + 1'd1;
case(vcalc)
1: begin
mul_arg1 <= arx;
mul_arg2 <= vtot;
mul_start <= 1;
end
2: begin
ARXG <= mul_res;
mul_arg1 <= ary;
mul_arg2 <= vcrop;
mul_start <= 1;
end
3: begin
ARYG <= mul_res;
end
endcase
end
end
else if (ARXG[23] | ARYG[23]) begin
arxo <= ARXG[23:12];
@@ -99,11 +126,11 @@ video_scale_int scale
.CLK_VIDEO(CLK_VIDEO),
.HDMI_WIDTH(HDMI_WIDTH),
.HDMI_HEIGHT(HDMI_HEIGHT),
.SCALE(SCALE),
.hsize(hsize),
.vsize(vsize),
.arx_i(arxo),
.ary_i(aryo),
.scale(SCALE),
.arx_o(VIDEO_ARX),
.ary_o(VIDEO_ARY)
);
@@ -113,18 +140,18 @@ endmodule
module video_scale_int
(
input CLK_VIDEO,
input CLK_VIDEO,
input [11:0] HDMI_WIDTH,
input [11:0] HDMI_HEIGHT,
input [11:0] HDMI_WIDTH,
input [11:0] HDMI_HEIGHT,
input [11:0] hsize,
input [11:0] vsize,
input [2:0] SCALE,
input [11:0] arx_i,
input [11:0] ary_i,
input [11:0] hsize,
input [11:0] vsize,
input [1:0] scale,
input [11:0] arx_i,
input [11:0] ary_i,
output reg [12:0] arx_o,
output reg [12:0] ary_o
@@ -144,16 +171,17 @@ wire [23:0] mul_res;
sys_umul #(12,12) mul(CLK_VIDEO,mul_start,mul_run, mul_arg1,mul_arg2,mul_res);
wire [11:0] wideres = mul_res[11:0] + hsize;
reg [12:0] arxf,aryf;
always @(posedge CLK_VIDEO) begin
reg [11:0] oheight;
reg [11:0] oheight,wres;
reg [12:0] arxf,aryf;
reg [3:0] cnt;
reg narrow;
div_start <= 0;
mul_start <= 0;
if (!scale || !ary_i || !arx_i) begin
if (!SCALE || (!ary_i && arx_i)) begin
arxf <= arx_i;
aryf <= ary_i;
end
@@ -181,44 +209,63 @@ always @(posedge CLK_VIDEO) begin
2: begin
oheight <= mul_res[11:0];
if(!ary_i) begin
cnt <= 8;
end
end
3: begin
mul_arg1 <= mul_res[11:0];
mul_arg2 <= arx_i;
mul_start <= 1;
end
3: begin
4: begin
div_num <= mul_res;
div_den <= ary_i;
div_start <= 1;
end
4: begin
5: begin
div_num <= div_res;
div_den <= hsize;
div_start <= 1;
end
5: begin
6: begin
mul_arg1 <= hsize;
mul_arg2 <= div_res[11:0] ? div_res[11:0] : 12'd1;
mul_start <= 1;
end
6: if(mul_res <= HDMI_WIDTH) cnt <= 8;
else begin
7: if(mul_res <= HDMI_WIDTH) begin
cnt <= 10;
end
8: begin
div_num <= HDMI_WIDTH;
div_den <= hsize;
div_start <= 1;
end
7: begin
9: begin
mul_arg1 <= hsize;
mul_arg2 <= div_res[11:0] ? div_res[11:0] : 12'd1;
mul_start <= 1;
end
8: begin
arxf <= {1'b1, ~scale[1] ? div_num[11:0] : (scale[0] && (wideres <= HDMI_WIDTH)) ? wideres : mul_res[11:0]};
10: begin
narrow <= ((div_num[11:0] - mul_res[11:0]) <= (wideres - div_num[11:0])) || (wideres > HDMI_WIDTH);
wres <= wideres;
end
11: begin
case(SCALE)
2: arxf <= {1'b1, mul_res[11:0]};
3: arxf <= {1'b1, (wres > HDMI_WIDTH) ? mul_res[11:0] : wres};
4: arxf <= {1'b1, narrow ? mul_res[11:0] : wres};
default: arxf <= {1'b1, div_num[11:0]};
endcase
aryf <= {1'b1, oheight};
end
endcase

143
sys/video_freezer.sv Normal file
View File

@@ -0,0 +1,143 @@
//
// video freeze with sync
// (C) Alexey Melnikov
//
//
// This program 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 2 of the License, or (at your option)
// any later version.
//
// This program 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, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
module video_freezer
(
input clk,
output sync,
input freeze,
input hs_in,
input vs_in,
input hbl_in,
input vbl_in,
output hs_out,
output vs_out,
output hbl_out,
output vbl_out
);
sync_lock #(33) vs_lock
(
.clk(clk),
.sync_in(vs_in),
.sync_out(vs_out),
.de_in(vbl_in),
.de_out(vbl_out),
.freeze(freeze)
);
wire sync_pt;
sync_lock #(21) hs_lock
(
.clk(clk),
.sync_in(hs_in),
.sync_out(hs_out),
.de_in(hbl_in),
.de_out(hbl_out),
.freeze(freeze),
.sync_pt(sync_pt)
);
reg sync_o;
always @(posedge clk) begin
reg old_hs, old_vs;
reg vs_sync;
old_vs <= vs_out;
if(~old_vs & vs_out) vs_sync <= 1;
if(sync_pt & vs_sync) begin
vs_sync <= 0;
sync_o <= ~sync_o;
end
end
assign sync = sync_o;
endmodule
module sync_lock #(parameter WIDTH)
(
input clk,
input sync_in,
input de_in,
output sync_out,
output de_out,
input freeze,
output sync_pt,
output valid
);
reg [WIDTH-1:0] f_len, s_len, de_start, de_end;
reg sync_valid;
reg old_sync;
always @(posedge clk) old_sync <= sync_in;
always @(posedge clk) begin
reg [WIDTH-1:0] cnti;
reg f_valid;
reg old_de;
cnti <= cnti + 1'd1;
if(~old_sync & sync_in) begin
if(sync_valid) f_len <= cnti;
f_valid <= 1;
sync_valid <= f_valid;
cnti <= 0;
end
if(old_sync & ~sync_in & sync_valid) s_len <= cnti;
old_de <= de_in;
if(~old_de & de_in & sync_valid) de_start <= cnti;
if(old_de & ~de_in & sync_valid) de_end <= cnti;
if(freeze) {f_valid, sync_valid} <= 0;
end
reg sync_o, de_o, sync_o_pre;
always @(posedge clk) begin
reg [WIDTH-1:0] cnto;
cnto <= cnto + 1'd1;
if(old_sync & ~sync_in & sync_valid) cnto <= s_len + 2'd2;
if(cnto == f_len) cnto <= 0;
sync_o_pre <= (cnto == (s_len>>1)); // middle in sync
if(cnto == f_len) sync_o <= 1;
if(cnto == s_len) sync_o <= 0;
if(cnto == de_start) de_o <= 1;
if(cnto == de_end) de_o <= 0;
end
assign sync_out = freeze ? sync_o : sync_in;
assign valid = sync_valid;
assign sync_pt = sync_o_pre;
assign de_out = freeze ? de_o : de_in;
endmodule

View File

@@ -10,10 +10,7 @@
`timescale 1ns / 1ps
//
// LINE_LENGTH: Length of display line in pixels
// Usually it's length from HSync to HSync.
// May be less if line_start is used.
//
// LINE_LENGTH: Length of display line in pixels when HBlank = 0;
// HALF_DEPTH: If =1 then color dept is 4 bits per component
//
// altera message_off 10720
@@ -47,6 +44,12 @@ module video_mixer
input HBlank,
input VBlank,
// Freeze engine
// HDMI: displays last frame
// VGA: black screen with HSync and VSync
input HDMI_FREEZE,
output freeze_sync,
// video output signals
output reg [7:0] VGA_R,
output reg [7:0] VGA_G,
@@ -60,19 +63,43 @@ localparam DWIDTH = HALF_DEPTH ? 3 : 7;
localparam DWIDTH_SD = GAMMA ? 7 : DWIDTH;
localparam HALF_DEPTH_SD = GAMMA ? 0 : HALF_DEPTH;
wire frz_hs, frz_vs;
wire frz_hbl, frz_vbl;
video_freezer freezer
(
.clk(CLK_VIDEO),
.freeze(HDMI_FREEZE),
.hs_in(HSync),
.vs_in(VSync),
.hbl_in(HBlank),
.vbl_in(VBlank),
.sync(freeze_sync),
.hs_out(frz_hs),
.vs_out(frz_vs),
.hbl_out(frz_hbl),
.vbl_out(frz_vbl)
);
reg frz;
always @(posedge CLK_VIDEO) begin
reg frz1;
frz1 <= HDMI_FREEZE;
frz <= frz1;
end
generate
if(GAMMA && HALF_DEPTH) begin
wire [7:0] R_in = {R,R};
wire [7:0] G_in = {G,G};
wire [7:0] B_in = {B,B};
wire [7:0] R_in = frz ? 8'd0 : {R,R};
wire [7:0] G_in = frz ? 8'd0 : {G,G};
wire [7:0] B_in = frz ? 8'd0 : {B,B};
end else begin
wire [DWIDTH:0] R_in = R;
wire [DWIDTH:0] G_in = G;
wire [DWIDTH:0] B_in = B;
wire [DWIDTH:0] R_in = frz ? 1'd0 : R;
wire [DWIDTH:0] G_in = frz ? 1'd0 : G;
wire [DWIDTH:0] B_in = frz ? 1'd0 : B;
end
endgenerate
wire hs_g, vs_g;
wire hb_g, vb_g;
wire [DWIDTH_SD:0] R_gamma, G_gamma, B_gamma;
@@ -90,10 +117,10 @@ generate
.gamma_wr_addr(gamma_bus[17:8]),
.gamma_value(gamma_bus[7:0]),
.HSync(HSync),
.VSync(VSync),
.HBlank(HBlank),
.VBlank(VBlank),
.HSync(frz_hs),
.VSync(frz_vs),
.HBlank(frz_hbl),
.VBlank(frz_vbl),
.RGB_in({R_in,G_in,B_in}),
.HSync_out(hs_g),
@@ -105,7 +132,7 @@ generate
end else begin
assign gamma_bus[21] = 0;
assign {R_gamma,G_gamma,B_gamma} = {R_in,G_in,B_in};
assign {hs_g, vs_g, hb_g, vb_g} = {HSync, VSync, HBlank, VBlank};
assign {hs_g, vs_g, hb_g, vb_g} = {frz_hs, frz_vs, frz_hbl, frz_vbl};
end
endgenerate