├── EDSAC.qpf ├── img ├── osd.png ├── adpcm.png ├── edsac.jpg ├── font.png ├── panel.jpg ├── charset.jpg ├── edsac2.gif ├── scope3.jpg ├── teletype.jpg ├── wwg-book.jpg ├── first-output.png └── rle-diagram.png ├── releases ├── EDSAC_20200511.rbf ├── EDSAC_20200513.rbf └── EDSAC_20250904.rbf ├── rtl ├── lfsr.v ├── pll │ ├── pll_0002.qip │ ├── pll_0002_q13.qip │ └── pll_0002.v ├── mycore.v ├── rle_framebuffer.sv ├── cos.sv ├── adpcm_decoder.v ├── util.sv └── edsac_cpu.sv ├── sys ├── pll_hdmi │ ├── pll_hdmi_0002.qip │ └── pll_hdmi_0002.v ├── pll_q17.qip ├── pll_q13.qip ├── pll_audio │ ├── pll_audio_0002.qip │ └── pll_audio_0002.v ├── pll_cfg.qip ├── i2s.v ├── sigma_delta_dac.v ├── pll.13.qip ├── pll_hdmi.13.qip ├── pll_audio.13.qip ├── scanlines.v ├── vga_out.sv ├── mcp23009.sv ├── video_cleaner.sv ├── build_id.tcl ├── math.sv ├── sys_dual_sdram.tcl ├── i2c.v ├── ddr_svc.sv ├── sys.qip ├── sys_analog.tcl ├── video_freezer.sv ├── gamma_corr.sv ├── sys_top.sdc ├── shadowmask.sv ├── ltc2308.sv ├── alsa.sv ├── pll_cfg │ └── pll_cfg.v ├── scandoubler.v ├── video_mixer.sv ├── audio_out.v ├── iir_filter.v ├── mt32pi.sv ├── osd.v └── f2sdram_safe_terminator.sv ├── files.qip ├── .gitignore ├── clean.bat ├── clean.sh ├── roms └── initial_v2.mif ├── LICENSE ├── EDSAC.qsf ├── software ├── oxo.tap ├── pg51b.tap ├── conway.tap ├── cubes.tap ├── mandelbrot.tap ├── sieve.tap ├── squares_e0.tap ├── wada.tap ├── airy.tap ├── chapmanxsinx.tap └── doddglennie.tap ├── util.sv └── EDSAC.srf /EDSAC.qpf: -------------------------------------------------------------------------------- 1 | QUARTUS_VERSION = "17.0" 2 | PROJECT_REVISION = "EDSAC" 3 | -------------------------------------------------------------------------------- /img/osd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiSTer-devel/EDSAC_MiSTer/HEAD/img/osd.png -------------------------------------------------------------------------------- /img/adpcm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiSTer-devel/EDSAC_MiSTer/HEAD/img/adpcm.png -------------------------------------------------------------------------------- /img/edsac.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiSTer-devel/EDSAC_MiSTer/HEAD/img/edsac.jpg -------------------------------------------------------------------------------- /img/font.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiSTer-devel/EDSAC_MiSTer/HEAD/img/font.png -------------------------------------------------------------------------------- /img/panel.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiSTer-devel/EDSAC_MiSTer/HEAD/img/panel.jpg -------------------------------------------------------------------------------- /img/charset.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiSTer-devel/EDSAC_MiSTer/HEAD/img/charset.jpg -------------------------------------------------------------------------------- /img/edsac2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiSTer-devel/EDSAC_MiSTer/HEAD/img/edsac2.gif -------------------------------------------------------------------------------- /img/scope3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiSTer-devel/EDSAC_MiSTer/HEAD/img/scope3.jpg -------------------------------------------------------------------------------- /img/teletype.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiSTer-devel/EDSAC_MiSTer/HEAD/img/teletype.jpg -------------------------------------------------------------------------------- /img/wwg-book.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiSTer-devel/EDSAC_MiSTer/HEAD/img/wwg-book.jpg -------------------------------------------------------------------------------- /img/first-output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiSTer-devel/EDSAC_MiSTer/HEAD/img/first-output.png -------------------------------------------------------------------------------- /img/rle-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiSTer-devel/EDSAC_MiSTer/HEAD/img/rle-diagram.png -------------------------------------------------------------------------------- /releases/EDSAC_20200511.rbf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiSTer-devel/EDSAC_MiSTer/HEAD/releases/EDSAC_20200511.rbf -------------------------------------------------------------------------------- /releases/EDSAC_20200513.rbf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiSTer-devel/EDSAC_MiSTer/HEAD/releases/EDSAC_20200513.rbf -------------------------------------------------------------------------------- /releases/EDSAC_20250904.rbf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiSTer-devel/EDSAC_MiSTer/HEAD/releases/EDSAC_20250904.rbf -------------------------------------------------------------------------------- /rtl/lfsr.v: -------------------------------------------------------------------------------- 1 | module random ( 2 | input clock, 3 | output reg [30:0] lfsr 4 | ); 5 | 6 | always @(posedge clock) begin 7 | lfsr <= {lfsr[29:0], lfsr[30] ^~ lfsr[27]}; 8 | end 9 | 10 | endmodule 11 | -------------------------------------------------------------------------------- /sys/pll_hdmi/pll_hdmi_0002.qip: -------------------------------------------------------------------------------- 1 | set_instance_assignment -name PLL_COMPENSATION_MODE DIRECT -to "*pll_hdmi_0002*|altera_pll:altera_pll_i*|*" 2 | set_instance_assignment -name UNFORCE_MERGE_PLL_OUTPUT_COUNTER ON -to "*pll_hdmi_0002*|altera_pll:altera_pll_i*|*" 3 | -------------------------------------------------------------------------------- /rtl/pll/pll_0002.qip: -------------------------------------------------------------------------------- 1 | set_instance_assignment -name PLL_COMPENSATION_MODE DIRECT -to "*pll_0002*|altera_pll:altera_pll_i*|*" 2 | 3 | set_instance_assignment -name PLL_AUTO_RESET ON -to "*pll_0002*|altera_pll:altera_pll_i*|*" 4 | set_instance_assignment -name PLL_BANDWIDTH_PRESET AUTO -to "*pll_0002*|altera_pll:altera_pll_i*|*" 5 | -------------------------------------------------------------------------------- /sys/pll_q17.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name QIP_FILE rtl/pll.qip 2 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) pll_hdmi.qip ] 3 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) pll_audio.qip ] 4 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) pll_cfg.qip ] 5 | -------------------------------------------------------------------------------- /sys/pll_q13.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) pll.13.qip ] 2 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) pll_hdmi.13.qip ] 3 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) pll_audio.13.qip ] 4 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) pll_cfg.qip ] 5 | -------------------------------------------------------------------------------- /rtl/pll/pll_0002_q13.qip: -------------------------------------------------------------------------------- 1 | set_instance_assignment -name PLL_COMPENSATION_MODE DIRECT -to "*pll_0002*|altera_pll:altera_pll_i*|*" 2 | set_instance_assignment -name PLL_CHANNEL_SPACING "0.0 KHz" -to "*pll_0002*|altera_pll:altera_pll_i*|*" 3 | set_instance_assignment -name PLL_AUTO_RESET ON -to "*pll_0002*|altera_pll:altera_pll_i*|*" 4 | set_instance_assignment -name PLL_BANDWIDTH_PRESET AUTO -to "*pll_0002*|altera_pll:altera_pll_i*|*" 5 | -------------------------------------------------------------------------------- /sys/pll_audio/pll_audio_0002.qip: -------------------------------------------------------------------------------- 1 | set_instance_assignment -name PLL_COMPENSATION_MODE DIRECT -to "*pll_audio_0002*|altera_pll:altera_pll_i*|*" 2 | set_instance_assignment -name PLL_CHANNEL_SPACING "0.0 KHz" -to "*pll_audio_0002*|altera_pll:altera_pll_i*|*" 3 | set_instance_assignment -name PLL_AUTO_RESET ON -to "*pll_audio_0002*|altera_pll:altera_pll_i*|*" 4 | set_instance_assignment -name PLL_BANDWIDTH_PRESET AUTO -to "*pll_audio_0002*|altera_pll:altera_pll_i*|*" 5 | -------------------------------------------------------------------------------- /files.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name VERILOG_FILE rtl/adpcm_decoder.v 2 | set_global_assignment -name VERILOG_FILE rtl/teletype.v 3 | set_global_assignment -name SYSTEMVERILOG_FILE rtl/rle_framebuffer.sv 4 | set_global_assignment -name VERILOG_FILE rtl/memory.v 5 | set_global_assignment -name VERILOG_FILE rtl/lfsr.v 6 | set_global_assignment -name SYSTEMVERILOG_FILE rtl/util.sv 7 | set_global_assignment -name SYSTEMVERILOG_FILE rtl/edsac_cpu.sv 8 | set_global_assignment -name SYSTEMVERILOG_FILE EDSAC.sv 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | db 2 | greybox_tmp 3 | incremental_db 4 | output_files 5 | simulation 6 | hc_output 7 | scaler 8 | hps_isw_handoff 9 | vip 10 | *_sim 11 | .qsys_edit 12 | PLLJ_PLLSPE_INFO.txt 13 | *.bak 14 | *.orig 15 | *.rej 16 | *.qdf 17 | *.rpt 18 | *.smsg 19 | *.summary 20 | *.done 21 | *.jdi 22 | *.pin 23 | *.sof 24 | *.qws 25 | *.ppf 26 | *.ddb 27 | build_id.v 28 | c5_pin_model_dump.txt 29 | *.sopcinfo 30 | *.csv 31 | *.f 32 | *.cmp 33 | *.sip 34 | *.spd 35 | *.bsf 36 | *~ 37 | *.xml 38 | *_netlist 39 | *.cdf 40 | -------------------------------------------------------------------------------- /sys/pll_cfg.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name SYNTHESIS_ONLY_QIP ON 2 | set_global_assignment -library "pll_cfg" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_cfg/pll_cfg.v"] 3 | set_global_assignment -library "pll_cfg" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_cfg/pll_cfg_hdmi.v"] 4 | set_global_assignment -library "pll_cfg" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_cfg/altera_pll_reconfig_top.v"] 5 | set_global_assignment -library "pll_cfg" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_cfg/altera_pll_reconfig_core.v"] 6 | -------------------------------------------------------------------------------- /clean.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | del /s *.bak 3 | del /s *.orig 4 | del /s *.rej 5 | del /s *~ 6 | rmdir /s /q db 7 | rmdir /s /q incremental_db 8 | rmdir /s /q output_files 9 | rmdir /s /q simulation 10 | rmdir /s /q greybox_tmp 11 | rmdir /s /q hc_output 12 | rmdir /s /q .qsys_edit 13 | rmdir /s /q hps_isw_handoff 14 | rmdir /s /q sys\.qsys_edit 15 | rmdir /s /q sys\vip 16 | for /d %%i in (sys\*_sim) do rmdir /s /q "%%i" 17 | for /d %%i in (rtl\*_sim) do rmdir /s /q "%%i" 18 | del build_id.v 19 | del c5_pin_model_dump.txt 20 | del PLLJ_PLLSPE_INFO.txt 21 | del /s *.qws 22 | del /s *.ppf 23 | del /s *.ddb 24 | del /s *.csv 25 | del /s *.cmp 26 | del /s *.sip 27 | del /s *.spd 28 | del /s *.bsf 29 | del /s *.f 30 | del /s *.sopcinfo 31 | del /s *.xml 32 | del *.cdf 33 | del *.rpt 34 | del /s new_rtl_netlist 35 | del /s old_rtl_netlist 36 | pause 37 | -------------------------------------------------------------------------------- /clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | find -name "*.bak" -delete 4 | find -name "*.orig" -delete 5 | find -name "*.rej" -delete 6 | 7 | rm -rf db 8 | rm -rf incremental_db 9 | rm -rf output_files 10 | rm -rf output 11 | rm -rf simulation 12 | rm -rf greybox_tmp 13 | rm -rf hc_output 14 | rm -rf .qsys_edit 15 | rm -rf hps_isw_handoff 16 | rm -rf sys/.qsys_edit 17 | rm -rf sys/vip 18 | 19 | rm -rf sys/pll_sim/ 20 | 21 | find -name "*_sim" -print0 | xargs -0 rm 22 | find -name "*_sim" -delete 23 | 24 | find -name build_id.v -delete 25 | find -name c5_pin_morm_dump.txt -delete 26 | find -name PLLJ_PLLSPE_INFO.txt -delete 27 | 28 | find -iregex '.*\.\(qws\|ppf\|ddb\|cmp\|sip\|spd\|bsf\|f\|sopcinfo\|xml\|cdf\|csv\)$' -delete 29 | 30 | find -name "new_rtl_netlist" -delete 31 | find -name "old_rtl_netlist" -delete 32 | 33 | rm *.cdf 34 | rm sys/vip.qip 35 | rm sys/sysmem.qip 36 | -------------------------------------------------------------------------------- /roms/initial_v2.mif: -------------------------------------------------------------------------------- 1 | WIDTH=36; 2 | DEPTH=512; 3 | 4 | ADDRESS_RADIX=DEC; 5 | DATA_RADIX=BIN; 6 | 7 | CONTENT BEGIN 8 | 9 | 0 : 00011000000101000000101000000000000; 10 | 1 : 00111000000000100000000000000000010; 11 | 2 : 00100000000001000011100000001001110; 12 | 3 : 11001000000010000011111000000000000; 13 | 4 : 01000000000000010000101000000000000; 14 | 5 : 01100000001001110011100000000000010; 15 | 6 : 11001000000000001011011000000001000; 16 | 7 : 00011000000100010001100000001001110; 17 | 8 : 11100000001000110001100000000001110; 18 | 9 : 11100000000000000000101000000101000; 19 | 10: 11100000001010000010101000000010000; 20 | 11: 11100000000101100000101000001010110; 21 | 12: 00101000000101100011100000000000100; 22 | 13: 11100000001010110000011000001000100; 23 | 14: 11100000001010100000011000000010000; 24 | 15: 00011000000110010011100000001010000; 25 | 16: 00101000001010100011100000000101100; 26 | 17: 11100000001010001001000000001010001; 27 | 18: 00101000001010001000100000000100000; 28 | 19: 00000000000001011000011000000010000; 29 | 20: 00000000000000000000000000000000001; 30 | 31 | END; 32 | -------------------------------------------------------------------------------- /sys/i2s.v: -------------------------------------------------------------------------------- 1 | 2 | module i2s 3 | #( 4 | parameter AUDIO_DW = 16 5 | ) 6 | ( 7 | input reset, 8 | input clk, 9 | input ce, 10 | 11 | output reg sclk, 12 | output reg lrclk, 13 | output reg sdata, 14 | 15 | input [AUDIO_DW-1:0] left_chan, 16 | input [AUDIO_DW-1:0] right_chan 17 | ); 18 | 19 | always @(posedge clk) begin 20 | reg [7:0] bit_cnt; 21 | reg msclk; 22 | 23 | reg [AUDIO_DW-1:0] left; 24 | reg [AUDIO_DW-1:0] right; 25 | 26 | if (reset) begin 27 | bit_cnt <= 1; 28 | lrclk <= 1; 29 | sclk <= 1; 30 | msclk <= 1; 31 | end 32 | else begin 33 | sclk <= msclk; 34 | if(ce) begin 35 | msclk <= ~msclk; 36 | if(msclk) begin 37 | if(bit_cnt >= AUDIO_DW) begin 38 | bit_cnt <= 1; 39 | lrclk <= ~lrclk; 40 | if(lrclk) begin 41 | left <= left_chan; 42 | right <= right_chan; 43 | end 44 | end 45 | else begin 46 | bit_cnt <= bit_cnt + 1'd1; 47 | end 48 | sdata <= lrclk ? right[AUDIO_DW - bit_cnt] : left[AUDIO_DW - bit_cnt]; 49 | end 50 | end 51 | end 52 | end 53 | 54 | endmodule 55 | -------------------------------------------------------------------------------- /sys/sigma_delta_dac.v: -------------------------------------------------------------------------------- 1 | // 2 | // PWM DAC 3 | // 4 | // MSBI is the highest bit number. NOT amount of bits! 5 | // 6 | module sigma_delta_dac #(parameter MSBI=7, parameter INV=1'b1) 7 | ( 8 | output reg DACout, //Average Output feeding analog lowpass 9 | input [MSBI:0] DACin, //DAC input (excess 2**MSBI) 10 | input CLK, 11 | input RESET 12 | ); 13 | 14 | reg [MSBI+2:0] DeltaAdder; //Output of Delta Adder 15 | reg [MSBI+2:0] SigmaAdder; //Output of Sigma Adder 16 | reg [MSBI+2:0] SigmaLatch; //Latches output of Sigma Adder 17 | reg [MSBI+2:0] DeltaB; //B input of Delta Adder 18 | 19 | always @(*) DeltaB = {SigmaLatch[MSBI+2], SigmaLatch[MSBI+2]} << (MSBI+1); 20 | always @(*) DeltaAdder = DACin + DeltaB; 21 | always @(*) SigmaAdder = DeltaAdder + SigmaLatch; 22 | 23 | always @(posedge CLK or posedge RESET) begin 24 | if(RESET) begin 25 | SigmaLatch <= 1'b1 << (MSBI+1); 26 | DACout <= INV; 27 | end else begin 28 | SigmaLatch <= SigmaAdder; 29 | DACout <= SigmaLatch[MSBI+2] ^ INV; 30 | end 31 | end 32 | 33 | endmodule 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 MiSTer-devel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /sys/pll.13.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -entity "pll" -library "pll" -name IP_TOOL_NAME "altera_pll" 2 | set_global_assignment -entity "pll" -library "pll" -name IP_TOOL_VERSION "13.1" 3 | set_global_assignment -entity "pll" -library "pll" -name IP_TOOL_ENV "mwpim" 4 | set_global_assignment -library "pll" -name MISC_FILE [file join $::quartus(qip_path) "pll.cmp"] 5 | set_global_assignment -name SYNTHESIS_ONLY_QIP ON 6 | 7 | set_global_assignment -library "pll" -name VERILOG_FILE rtl/pll.v 8 | set_global_assignment -library "pll" -name VERILOG_FILE rtl/pll/pll_0002.v 9 | 10 | set_instance_assignment -name PLL_COMPENSATION_MODE DIRECT -to "*pll_0002*|altera_pll:altera_pll_i*|*" 11 | set_instance_assignment -name PLL_CHANNEL_SPACING "0.0 KHz" -to "*pll_0002*|altera_pll:altera_pll_i*|*" 12 | set_instance_assignment -name PLL_AUTO_RESET ON -to "*pll_0002*|altera_pll:altera_pll_i*|*" 13 | set_instance_assignment -name PLL_BANDWIDTH_PRESET AUTO -to "*pll_0002*|altera_pll:altera_pll_i*|*" 14 | 15 | set_global_assignment -entity "pll_0002" -library "pll" -name IP_TOOL_NAME "altera_pll" 16 | set_global_assignment -entity "pll_0002" -library "pll" -name IP_TOOL_VERSION "13.1" 17 | set_global_assignment -entity "pll_0002" -library "pll" -name IP_TOOL_ENV "mwpim" 18 | -------------------------------------------------------------------------------- /sys/pll_hdmi.13.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -entity "pll_hdmi" -library "pll_hdmi" -name IP_TOOL_NAME "altera_pll" 2 | set_global_assignment -entity "pll_hdmi" -library "pll_hdmi" -name IP_TOOL_VERSION "13.1" 3 | set_global_assignment -entity "pll_hdmi" -library "pll_hdmi" -name IP_TOOL_ENV "mwpim" 4 | set_global_assignment -library "pll_hdmi" -name MISC_FILE [file join $::quartus(qip_path) "pll_hdmi.cmp"] 5 | set_global_assignment -name SYNTHESIS_ONLY_QIP ON 6 | 7 | set_global_assignment -library "pll_hdmi" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_hdmi.v"] 8 | set_global_assignment -library "pll_hdmi" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_hdmi/pll_hdmi_0002.v"] 9 | 10 | set_instance_assignment -name PLL_COMPENSATION_MODE DIRECT -to "*pll_hdmi_0002*|altera_pll:altera_pll_i*|*" 11 | set_instance_assignment -name PLL_CHANNEL_SPACING "0.0 KHz" -to "*pll_hdmi_0002*|altera_pll:altera_pll_i*|*" 12 | set_instance_assignment -name PLL_AUTO_RESET ON -to "*pll_hdmi_0002*|altera_pll:altera_pll_i*|*" 13 | set_instance_assignment -name PLL_BANDWIDTH_PRESET AUTO -to "*pll_hdmi_0002*|altera_pll:altera_pll_i*|*" 14 | 15 | set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_TOOL_NAME "altera_pll" 16 | set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_TOOL_VERSION "13.1" 17 | set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_TOOL_ENV "mwpim" 18 | -------------------------------------------------------------------------------- /sys/pll_audio.13.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -entity "pll_audio" -library "pll_audio" -name IP_TOOL_NAME "altera_pll" 2 | set_global_assignment -entity "pll_audio" -library "pll_audio" -name IP_TOOL_VERSION "13.1" 3 | set_global_assignment -entity "pll_audio" -library "pll_audio" -name IP_TOOL_ENV "mwpim" 4 | set_global_assignment -library "pll_audio" -name MISC_FILE [file join $::quartus(qip_path) "pll_audio.cmp"] 5 | set_global_assignment -name SYNTHESIS_ONLY_QIP ON 6 | 7 | set_global_assignment -library "pll_audio" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_audio.v"] 8 | set_global_assignment -library "pll_audio" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_audio/pll_audio_0002.v"] 9 | 10 | set_instance_assignment -name PLL_COMPENSATION_MODE DIRECT -to "*pll_audio_0002*|altera_pll:altera_pll_i*|*" 11 | set_instance_assignment -name PLL_CHANNEL_SPACING "0.0 KHz" -to "*pll_audio_0002*|altera_pll:altera_pll_i*|*" 12 | set_instance_assignment -name PLL_AUTO_RESET ON -to "*pll_audio_0002*|altera_pll:altera_pll_i*|*" 13 | set_instance_assignment -name PLL_BANDWIDTH_PRESET AUTO -to "*pll_audio_0002*|altera_pll:altera_pll_i*|*" 14 | 15 | set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_TOOL_NAME "altera_pll" 16 | set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_TOOL_VERSION "13.1" 17 | set_global_assignment -entity "pll_audio_0002" -library "pll_audio" -name IP_TOOL_ENV "mwpim" 18 | -------------------------------------------------------------------------------- /sys/scanlines.v: -------------------------------------------------------------------------------- 1 | module scanlines #(parameter v2=0) 2 | ( 3 | input clk, 4 | 5 | input [1:0] scanlines, 6 | input [23:0] din, 7 | input hs_in,vs_in, 8 | input de_in,ce_in, 9 | 10 | output reg [23:0] dout, 11 | output reg hs_out,vs_out, 12 | output reg de_out,ce_out 13 | ); 14 | 15 | reg [1:0] scanline; 16 | always @(posedge clk) begin 17 | reg old_hs, old_vs; 18 | 19 | old_hs <= hs_in; 20 | old_vs <= vs_in; 21 | 22 | if(old_hs && ~hs_in) begin 23 | if(v2) begin 24 | scanline <= scanline + 1'd1; 25 | if (scanline == scanlines) scanline <= 0; 26 | end 27 | else scanline <= scanline ^ scanlines; 28 | end 29 | if(old_vs && ~vs_in) scanline <= 0; 30 | end 31 | 32 | wire [7:0] r,g,b; 33 | assign {r,g,b} = din; 34 | 35 | reg [23:0] d; 36 | always @(*) begin 37 | case(scanline) 38 | 1: // reduce 25% = 1/2 + 1/4 39 | d = {{1'b0, r[7:1]} + {2'b00, r[7:2]}, 40 | {1'b0, g[7:1]} + {2'b00, g[7:2]}, 41 | {1'b0, b[7:1]} + {2'b00, b[7:2]}}; 42 | 43 | 2: // reduce 50% = 1/2 44 | d = {{1'b0, r[7:1]}, 45 | {1'b0, g[7:1]}, 46 | {1'b0, b[7:1]}}; 47 | 48 | 3: // reduce 75% = 1/4 49 | d = {{2'b00, r[7:2]}, 50 | {2'b00, g[7:2]}, 51 | {2'b00, b[7:2]}}; 52 | 53 | default: d = {r,g,b}; 54 | endcase 55 | end 56 | 57 | always @(posedge clk) begin 58 | reg [23:0] dout1, dout2; 59 | reg de1,de2,vs1,vs2,hs1,hs2,ce1,ce2; 60 | 61 | dout <= dout2; dout2 <= dout1; dout1 <= d; 62 | vs_out <= vs2; vs2 <= vs1; vs1 <= vs_in; 63 | hs_out <= hs2; hs2 <= hs1; hs1 <= hs_in; 64 | de_out <= de2; de2 <= de1; de1 <= de_in; 65 | ce_out <= ce2; ce2 <= ce1; ce1 <= ce_in; 66 | end 67 | 68 | endmodule 69 | -------------------------------------------------------------------------------- /rtl/mycore.v: -------------------------------------------------------------------------------- 1 | 2 | module mycore 3 | ( 4 | input clk, 5 | input reset, 6 | 7 | input pal, 8 | input scandouble, 9 | 10 | output reg ce_pix, 11 | 12 | output reg HBlank, 13 | output reg HSync, 14 | output reg VBlank, 15 | output reg VSync, 16 | 17 | output [7:0] video 18 | ); 19 | 20 | reg [9:0] hc; 21 | reg [9:0] vc; 22 | reg [9:0] vvc; 23 | reg [63:0] rnd_reg; 24 | 25 | wire [5:0] rnd_c = {rnd_reg[0],rnd_reg[1],rnd_reg[2],rnd_reg[2],rnd_reg[2],rnd_reg[2]}; 26 | wire [63:0] rnd; 27 | 28 | lfsr random(rnd); 29 | 30 | always @(posedge clk) begin 31 | if(scandouble) ce_pix <= 1; 32 | else ce_pix <= ~ce_pix; 33 | 34 | if(reset) begin 35 | hc <= 0; 36 | vc <= 0; 37 | end 38 | else if(ce_pix) begin 39 | if(hc == 637) begin 40 | hc <= 0; 41 | if(vc == (pal ? (scandouble ? 623 : 311) : (scandouble ? 523 : 261))) begin 42 | vc <= 0; 43 | vvc <= vvc + 9'd6; 44 | end else begin 45 | vc <= vc + 1'd1; 46 | end 47 | end else begin 48 | hc <= hc + 1'd1; 49 | end 50 | 51 | rnd_reg <= rnd; 52 | end 53 | end 54 | 55 | always @(posedge clk) begin 56 | if (hc == 529) HBlank <= 1; 57 | else if (hc == 0) HBlank <= 0; 58 | 59 | if (hc == 544) begin 60 | HSync <= 1; 61 | 62 | if(pal) begin 63 | if(vc == (scandouble ? 609 : 304)) VSync <= 1; 64 | else if (vc == (scandouble ? 617 : 308)) VSync <= 0; 65 | 66 | if(vc == (scandouble ? 601 : 300)) VBlank <= 1; 67 | else if (vc == 0) VBlank <= 0; 68 | end 69 | else begin 70 | if(vc == (scandouble ? 490 : 245)) VSync <= 1; 71 | else if (vc == (scandouble ? 496 : 248)) VSync <= 0; 72 | 73 | if(vc == (scandouble ? 480 : 240)) VBlank <= 1; 74 | else if (vc == 0) VBlank <= 0; 75 | end 76 | end 77 | 78 | if (hc == 590) HSync <= 0; 79 | end 80 | 81 | reg [7:0] cos_out; 82 | wire [5:0] cos_g = cos_out[7:3]+6'd32; 83 | cos cos(vvc + {vc>>scandouble, 2'b00}, cos_out); 84 | 85 | assign video = (cos_g >= rnd_c) ? {cos_g - rnd_c, 2'b00} : 8'd0; 86 | 87 | endmodule 88 | -------------------------------------------------------------------------------- /sys/vga_out.sv: -------------------------------------------------------------------------------- 1 | 2 | module vga_out 3 | ( 4 | input clk, 5 | input ypbpr_en, 6 | 7 | input hsync, 8 | input vsync, 9 | input csync, 10 | input de, 11 | 12 | input [23:0] din, 13 | output [23:0] dout, 14 | 15 | output reg hsync_o, 16 | output reg vsync_o, 17 | output reg csync_o, 18 | output reg de_o 19 | ); 20 | 21 | wire [7:0] red = din[23:16]; 22 | wire [7:0] green = din[15:8]; 23 | wire [7:0] blue = din[7:0]; 24 | 25 | // http://marsee101.blog19.fc2.com/blog-entry-2311.html 26 | 27 | 28 | // Y = 0.301*R + 0.586*G + 0.113*B (Y = 0.299*R + 0.587*G + 0.114*B) 29 | // Pb = 128 - 0.168*R - 0.332*G + 0.500*B (Pb = -0.169*R - 0.331*G + 0.500*B) 30 | // Pr = 128 + 0.500*R - 0.418*G - 0.082*B (Pr = 0.500*R - 0.419*G - 0.081*B) 31 | 32 | reg [7:0] y, pb, pr; 33 | reg [23:0] rgb; 34 | always @(posedge clk) begin 35 | reg [18:0] y_1r, pb_1r, pr_1r; 36 | reg [18:0] y_1g, pb_1g, pr_1g; 37 | reg [18:0] y_1b, pb_1b, pr_1b; 38 | reg [18:0] y_2, pb_2, pr_2; 39 | reg [23:0] din1, din2; 40 | reg hsync2, vsync2, csync2, de2; 41 | reg hsync1, vsync1, csync1, de1; 42 | 43 | y_1r <= {red, 6'd0} + {red, 3'd0} + {red, 2'd0} + red; 44 | pb_1r <= 19'd32768 - ({red, 5'd0} + {red, 3'd0} + {red, 1'd0}); 45 | pr_1r <= 19'd32768 + {red, 7'd0}; 46 | 47 | y_1g <= {green, 7'd0} + {green, 4'd0} + {green, 2'd0} + {green, 1'd0}; 48 | pb_1g <= {green, 6'd0} + {green, 4'd0} + {green, 2'd0} + green; 49 | pr_1g <= {green, 6'd0} + {green, 5'd0} + {green, 3'd0} + {green, 1'd0}; 50 | 51 | y_1b <= {blue, 4'd0} + {blue, 3'd0} + {blue, 2'd0} + blue; 52 | pb_1b <= {blue, 7'd0}; 53 | pr_1b <= {blue, 4'd0} + {blue, 2'd0} + blue; 54 | 55 | y_2 <= y_1r + y_1g + y_1b; 56 | pb_2 <= pb_1r - pb_1g + pb_1b; 57 | pr_2 <= pr_1r - pr_1g - pr_1b; 58 | 59 | y <= y_2[18] ? 8'd0 : y_2[16] ? 8'd255 : y_2[15:8]; 60 | pb <= pb_2[18] ? 8'd0 : pb_2[16] ? 8'd255 : pb_2[15:8]; 61 | pr <= pr_2[18] ? 8'd0 : pr_2[16] ? 8'd255 : pr_2[15:8]; 62 | 63 | hsync_o <= hsync2; hsync2 <= hsync1; hsync1 <= hsync; 64 | vsync_o <= vsync2; vsync2 <= vsync1; vsync1 <= vsync; 65 | csync_o <= csync2; csync2 <= csync1; csync1 <= csync; 66 | de_o <= de2; de2 <= de1; de1 <= de; 67 | 68 | rgb <= din2; din2 <= din1; din1 <= din; 69 | end 70 | 71 | assign dout = ypbpr_en ? {pr, y, pb} : rgb; 72 | 73 | endmodule 74 | -------------------------------------------------------------------------------- /rtl/pll/pll_0002.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/10ps 2 | module pll_0002( 3 | 4 | // interface 'refclk' 5 | input wire refclk, 6 | 7 | // interface 'reset' 8 | input wire rst, 9 | 10 | // interface 'outclk0' 11 | output wire outclk_0, 12 | 13 | // interface 'locked' 14 | output wire locked 15 | ); 16 | 17 | altera_pll #( 18 | .fractional_vco_multiplier("false"), 19 | .reference_clock_frequency("50.0 MHz"), 20 | .operation_mode("direct"), 21 | .number_of_clocks(1), 22 | .output_clock_frequency0("20.000000 MHz"), 23 | .phase_shift0("0 ps"), 24 | .duty_cycle0(50), 25 | .output_clock_frequency1("0 MHz"), 26 | .phase_shift1("0 ps"), 27 | .duty_cycle1(50), 28 | .output_clock_frequency2("0 MHz"), 29 | .phase_shift2("0 ps"), 30 | .duty_cycle2(50), 31 | .output_clock_frequency3("0 MHz"), 32 | .phase_shift3("0 ps"), 33 | .duty_cycle3(50), 34 | .output_clock_frequency4("0 MHz"), 35 | .phase_shift4("0 ps"), 36 | .duty_cycle4(50), 37 | .output_clock_frequency5("0 MHz"), 38 | .phase_shift5("0 ps"), 39 | .duty_cycle5(50), 40 | .output_clock_frequency6("0 MHz"), 41 | .phase_shift6("0 ps"), 42 | .duty_cycle6(50), 43 | .output_clock_frequency7("0 MHz"), 44 | .phase_shift7("0 ps"), 45 | .duty_cycle7(50), 46 | .output_clock_frequency8("0 MHz"), 47 | .phase_shift8("0 ps"), 48 | .duty_cycle8(50), 49 | .output_clock_frequency9("0 MHz"), 50 | .phase_shift9("0 ps"), 51 | .duty_cycle9(50), 52 | .output_clock_frequency10("0 MHz"), 53 | .phase_shift10("0 ps"), 54 | .duty_cycle10(50), 55 | .output_clock_frequency11("0 MHz"), 56 | .phase_shift11("0 ps"), 57 | .duty_cycle11(50), 58 | .output_clock_frequency12("0 MHz"), 59 | .phase_shift12("0 ps"), 60 | .duty_cycle12(50), 61 | .output_clock_frequency13("0 MHz"), 62 | .phase_shift13("0 ps"), 63 | .duty_cycle13(50), 64 | .output_clock_frequency14("0 MHz"), 65 | .phase_shift14("0 ps"), 66 | .duty_cycle14(50), 67 | .output_clock_frequency15("0 MHz"), 68 | .phase_shift15("0 ps"), 69 | .duty_cycle15(50), 70 | .output_clock_frequency16("0 MHz"), 71 | .phase_shift16("0 ps"), 72 | .duty_cycle16(50), 73 | .output_clock_frequency17("0 MHz"), 74 | .phase_shift17("0 ps"), 75 | .duty_cycle17(50), 76 | .pll_type("General"), 77 | .pll_subtype("General") 78 | ) altera_pll_i ( 79 | .rst (rst), 80 | .outclk ({outclk_0}), 81 | .locked (locked), 82 | .fboutclk ( ), 83 | .fbclk (1'b0), 84 | .refclk (refclk) 85 | ); 86 | endmodule 87 | 88 | -------------------------------------------------------------------------------- /sys/pll_audio/pll_audio_0002.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/10ps 2 | module pll_audio_0002( 3 | 4 | // interface 'refclk' 5 | input wire refclk, 6 | 7 | // interface 'reset' 8 | input wire rst, 9 | 10 | // interface 'outclk0' 11 | output wire outclk_0, 12 | 13 | // interface 'locked' 14 | output wire locked 15 | ); 16 | 17 | altera_pll #( 18 | .fractional_vco_multiplier("true"), 19 | .reference_clock_frequency("50.0 MHz"), 20 | .operation_mode("direct"), 21 | .number_of_clocks(1), 22 | .output_clock_frequency0("24.576000 MHz"), 23 | .phase_shift0("0 ps"), 24 | .duty_cycle0(50), 25 | .output_clock_frequency1("0 MHz"), 26 | .phase_shift1("0 ps"), 27 | .duty_cycle1(50), 28 | .output_clock_frequency2("0 MHz"), 29 | .phase_shift2("0 ps"), 30 | .duty_cycle2(50), 31 | .output_clock_frequency3("0 MHz"), 32 | .phase_shift3("0 ps"), 33 | .duty_cycle3(50), 34 | .output_clock_frequency4("0 MHz"), 35 | .phase_shift4("0 ps"), 36 | .duty_cycle4(50), 37 | .output_clock_frequency5("0 MHz"), 38 | .phase_shift5("0 ps"), 39 | .duty_cycle5(50), 40 | .output_clock_frequency6("0 MHz"), 41 | .phase_shift6("0 ps"), 42 | .duty_cycle6(50), 43 | .output_clock_frequency7("0 MHz"), 44 | .phase_shift7("0 ps"), 45 | .duty_cycle7(50), 46 | .output_clock_frequency8("0 MHz"), 47 | .phase_shift8("0 ps"), 48 | .duty_cycle8(50), 49 | .output_clock_frequency9("0 MHz"), 50 | .phase_shift9("0 ps"), 51 | .duty_cycle9(50), 52 | .output_clock_frequency10("0 MHz"), 53 | .phase_shift10("0 ps"), 54 | .duty_cycle10(50), 55 | .output_clock_frequency11("0 MHz"), 56 | .phase_shift11("0 ps"), 57 | .duty_cycle11(50), 58 | .output_clock_frequency12("0 MHz"), 59 | .phase_shift12("0 ps"), 60 | .duty_cycle12(50), 61 | .output_clock_frequency13("0 MHz"), 62 | .phase_shift13("0 ps"), 63 | .duty_cycle13(50), 64 | .output_clock_frequency14("0 MHz"), 65 | .phase_shift14("0 ps"), 66 | .duty_cycle14(50), 67 | .output_clock_frequency15("0 MHz"), 68 | .phase_shift15("0 ps"), 69 | .duty_cycle15(50), 70 | .output_clock_frequency16("0 MHz"), 71 | .phase_shift16("0 ps"), 72 | .duty_cycle16(50), 73 | .output_clock_frequency17("0 MHz"), 74 | .phase_shift17("0 ps"), 75 | .duty_cycle17(50), 76 | .pll_type("General"), 77 | .pll_subtype("General") 78 | ) altera_pll_i ( 79 | .rst (rst), 80 | .outclk ({outclk_0}), 81 | .locked (locked), 82 | .fboutclk ( ), 83 | .fbclk (1'b0), 84 | .refclk (refclk) 85 | ); 86 | endmodule 87 | 88 | -------------------------------------------------------------------------------- /sys/mcp23009.sv: -------------------------------------------------------------------------------- 1 | // 2 | // MCP23009 3 | // (C) 2019 Alexey Melnikov 4 | // 5 | module mcp23009 6 | ( 7 | input clk, 8 | 9 | output reg [2:0] btn, 10 | input [2:0] led, 11 | output reg flg_sd_cd, 12 | output reg flg_present, 13 | output reg flg_mode, 14 | 15 | output scl, 16 | inout sda 17 | ); 18 | 19 | 20 | reg start = 0; 21 | wire ready; 22 | wire error; 23 | reg rw; 24 | wire [7:0] dout; 25 | reg [15:0] din; 26 | 27 | i2c #(50_000_000, 500_000) i2c 28 | ( 29 | .CLK(clk), 30 | .START(start), 31 | .READ(rw), 32 | .I2C_ADDR('h20), 33 | .I2C_WLEN(1), 34 | .I2C_WDATA1(din[15:8]), 35 | .I2C_WDATA2(din[7:0]), 36 | .I2C_RDATA(dout), 37 | .END(ready), 38 | .ACK(error), 39 | .I2C_SCL(scl), 40 | .I2C_SDA(sda) 41 | ); 42 | 43 | always@(posedge clk) begin 44 | reg [3:0] idx = 0; 45 | reg [1:0] state = 0; 46 | reg [15:0] timeout = 0; 47 | 48 | if(~&timeout) begin 49 | timeout <= timeout + 1'd1; 50 | start <= 0; 51 | state <= 0; 52 | idx <= 0; 53 | btn <= 0; 54 | rw <= 0; 55 | flg_sd_cd <= 1; 56 | flg_present <= 0; 57 | flg_mode <= 1; 58 | end 59 | else begin 60 | if(~&init_data[idx]) begin 61 | case(state) 62 | 0: begin 63 | start <= 1; 64 | state <= 1; 65 | din <= init_data[idx]; 66 | end 67 | 1: if(~ready) state <= 2; 68 | 2: begin 69 | start <= 0; 70 | if(ready) begin 71 | state <= 0; 72 | if(!error) idx <= idx + 1'd1; 73 | end 74 | end 75 | endcase 76 | end 77 | else begin 78 | case(state) 79 | 0: begin 80 | start <= 1; 81 | state <= 1; 82 | din <= {8'h09,5'b00000,led}; 83 | end 84 | 1: if(~ready) state <= 2; 85 | 2: begin 86 | start <= 0; 87 | if(ready) begin 88 | state <= 0; 89 | rw <= 0; 90 | if(!error) begin 91 | if(rw) begin 92 | {flg_sd_cd, flg_mode, btn} <= {dout[7:3]}; 93 | flg_present <= 1; 94 | end 95 | rw <= ~rw; 96 | end 97 | end 98 | end 99 | endcase 100 | end 101 | end 102 | end 103 | 104 | wire [15:0] init_data[12] = 105 | '{ 106 | 16'h00F8, 107 | 16'h0138, 108 | 16'h0200, 109 | 16'h0300, 110 | 16'h0400, 111 | 16'h0524, 112 | 16'h06FF, 113 | 16'h0700, 114 | 16'h0800, 115 | 16'h0900, 116 | 16'h0A00, 117 | 16'hFFFF 118 | }; 119 | 120 | endmodule 121 | -------------------------------------------------------------------------------- /sys/video_cleaner.sv: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // Copyright (c) 2018 Sorgelig 4 | // 5 | // This program is GPL Licensed. See COPYING for the full license. 6 | // 7 | // 8 | //////////////////////////////////////////////////////////////////////////////////////////////////////// 9 | 10 | `timescale 1ns / 1ps 11 | 12 | module video_cleaner 13 | ( 14 | input clk_vid, 15 | input ce_pix, 16 | 17 | input [7:0] R, 18 | input [7:0] G, 19 | input [7:0] B, 20 | 21 | input HSync, 22 | input VSync, 23 | input HBlank, 24 | input VBlank, 25 | 26 | //optional de 27 | input DE_in, 28 | 29 | //optional interlace support 30 | input interlace, 31 | input f1, 32 | 33 | // video output signals 34 | output reg [7:0] VGA_R, 35 | output reg [7:0] VGA_G, 36 | output reg [7:0] VGA_B, 37 | output reg VGA_VS, 38 | output reg VGA_HS, 39 | output VGA_DE, 40 | 41 | // optional aligned blank 42 | output reg HBlank_out, 43 | output reg VBlank_out, 44 | 45 | // optional aligned de 46 | output reg DE_out 47 | ); 48 | 49 | wire hs, vs; 50 | s_fix sync_v(clk_vid, HSync, hs); 51 | s_fix sync_h(clk_vid, VSync, vs); 52 | 53 | wire hbl = hs | HBlank; 54 | wire vbl = vs | VBlank; 55 | 56 | assign VGA_DE = ~(HBlank_out | VBlank_out); 57 | 58 | always @(posedge clk_vid) begin 59 | if(ce_pix) begin 60 | HBlank_out <= hbl; 61 | 62 | VGA_HS <= hs; 63 | 64 | VGA_R <= R; 65 | VGA_G <= G; 66 | VGA_B <= B; 67 | DE_out <= DE_in; 68 | 69 | if (interlace & f1) begin 70 | VGA_VS <= vs; 71 | VBlank_out <= vbl; 72 | end else begin 73 | if(~VGA_HS & hs) VGA_VS <= vs; 74 | if(HBlank_out & ~hbl) VBlank_out <= vbl; 75 | end 76 | end 77 | end 78 | 79 | endmodule 80 | 81 | module s_fix 82 | ( 83 | input clk, 84 | 85 | input sync_in, 86 | output sync_out 87 | ); 88 | 89 | assign sync_out = sync_in ^ pol; 90 | 91 | reg pol; 92 | always @(posedge clk) begin 93 | integer pos = 0, neg = 0, cnt = 0; 94 | reg s1,s2; 95 | 96 | s1 <= sync_in; 97 | s2 <= s1; 98 | 99 | if(~s2 & s1) neg <= cnt; 100 | if(s2 & ~s1) pos <= cnt; 101 | 102 | cnt <= cnt + 1; 103 | if(s2 != s1) cnt <= 0; 104 | 105 | pol <= pos > neg; 106 | end 107 | 108 | endmodule 109 | -------------------------------------------------------------------------------- /sys/build_id.tcl: -------------------------------------------------------------------------------- 1 | 2 | # Build TimeStamp Verilog Module 3 | # Jeff Wiencrot - 8/1/2011 4 | # Sorgelig - 02/11/2019 5 | proc generateBuildID_Verilog {} { 6 | 7 | # Get the timestamp (see: http://www.altera.com/support/examples/tcl/tcl-date-time-stamp.html) 8 | set buildDate "`define BUILD_DATE \"[clock format [ clock seconds ] -format %y%m%d]\"" 9 | 10 | # Create a Verilog file for output 11 | set outputFileName "build_id.v" 12 | 13 | set fileData "" 14 | if { [file exists $outputFileName]} { 15 | set outputFile [open $outputFileName "r"] 16 | set fileData [read $outputFile] 17 | close $outputFile 18 | } 19 | 20 | if {$buildDate ne $fileData} { 21 | set outputFile [open $outputFileName "w"] 22 | puts -nonewline $outputFile $buildDate 23 | close $outputFile 24 | # Send confirmation message to the Messages window 25 | post_message "Generated: [pwd]/$outputFileName: $buildDate" 26 | } 27 | } 28 | 29 | # Build CDF file 30 | # Sorgelig - 17/2/2018 31 | proc generateCDF {revision device outpath} { 32 | 33 | set outputFileName "jtag.cdf" 34 | set outputFile [open $outputFileName "w"] 35 | 36 | puts $outputFile "JedecChain;" 37 | puts $outputFile " FileRevision(JESD32A);" 38 | puts $outputFile " DefaultMfr(6E);" 39 | puts $outputFile "" 40 | puts $outputFile " P ActionCode(Ign)" 41 | puts $outputFile " Device PartName(SOCVHPS) MfrSpec(OpMask(0));" 42 | puts $outputFile " P ActionCode(Cfg)" 43 | puts $outputFile " Device PartName($device) Path(\"$outpath/\") File(\"$revision.sof\") MfrSpec(OpMask(1));" 44 | puts $outputFile "ChainEnd;" 45 | puts $outputFile "" 46 | puts $outputFile "AlteraBegin;" 47 | puts $outputFile " ChainType(JTAG);" 48 | puts $outputFile "AlteraEnd;" 49 | } 50 | 51 | set project_name [lindex $quartus(args) 1] 52 | set revision [lindex $quartus(args) 2] 53 | 54 | if {[project_exists $project_name]} { 55 | if {[string equal "" $revision]} { 56 | project_open $project_name -revision [get_current_revision $project_name] 57 | } else { 58 | project_open $project_name -revision $revision 59 | } 60 | } else { 61 | post_message -type error "Project $project_name does not exist" 62 | exit 63 | } 64 | 65 | set device [get_global_assignment -name DEVICE] 66 | set outpath [get_global_assignment -name PROJECT_OUTPUT_DIRECTORY] 67 | 68 | if [is_project_open] { 69 | project_close 70 | } 71 | 72 | generateBuildID_Verilog 73 | generateCDF $revision $device $outpath 74 | -------------------------------------------------------------------------------- /sys/math.sv: -------------------------------------------------------------------------------- 1 | 2 | // result = num/div 3 | module sys_udiv 4 | #( 5 | parameter NB_NUM, 6 | parameter NB_DIV 7 | ) 8 | ( 9 | input clk, 10 | input start, 11 | output busy, 12 | 13 | input [NB_NUM-1:0] num, 14 | input [NB_DIV-1:0] div, 15 | output reg [NB_NUM-1:0] result, 16 | output reg [NB_DIV-1:0] remainder 17 | ); 18 | 19 | reg run; 20 | assign busy = run; 21 | 22 | always @(posedge clk) begin 23 | reg [5:0] cpt; 24 | reg [NB_NUM+NB_DIV+1:0] rem; 25 | 26 | if (start) begin 27 | cpt <= 0; 28 | run <= 1; 29 | rem <= num; 30 | end 31 | else if (run) begin 32 | cpt <= cpt + 1'd1; 33 | run <= (cpt != NB_NUM + 1'd1); 34 | remainder <= rem[NB_NUM+NB_DIV:NB_NUM+1]; 35 | if (!rem[NB_DIV + NB_NUM + 1'd1]) 36 | rem <= {rem[NB_DIV+NB_NUM:0] - (div << NB_NUM),1'b0}; 37 | else 38 | rem <= {rem[NB_DIV+NB_NUM:0] + (div << NB_NUM),1'b0}; 39 | result <= {result[NB_NUM-2:0], !rem[NB_DIV + NB_NUM + 1'd1]}; 40 | end 41 | end 42 | 43 | endmodule 44 | 45 | // result = mul1*mul2 46 | module sys_umul 47 | #( 48 | parameter NB_MUL1, 49 | parameter NB_MUL2 50 | ) 51 | ( 52 | input clk, 53 | input start, 54 | output busy, 55 | 56 | input [NB_MUL1-1:0] mul1, 57 | input [NB_MUL2-1:0] mul2, 58 | output reg [NB_MUL1+NB_MUL2-1:0] result 59 | ); 60 | 61 | reg run; 62 | assign busy = run; 63 | 64 | always @(posedge clk) begin 65 | reg [NB_MUL1+NB_MUL2-1:0] add; 66 | reg [NB_MUL2-1:0] map; 67 | 68 | if (start) begin 69 | run <= 1; 70 | result <= 0; 71 | add <= mul1; 72 | map <= mul2; 73 | end 74 | else if (run) begin 75 | if(!map) run <= 0; 76 | if(map[0]) result <= result + add; 77 | add <= add << 1; 78 | map <= map >> 1; 79 | end 80 | end 81 | 82 | endmodule 83 | 84 | // result = (mul1*mul2)/div 85 | module sys_umuldiv 86 | #( 87 | parameter NB_MUL1, 88 | parameter NB_MUL2, 89 | parameter NB_DIV 90 | ) 91 | ( 92 | input clk, 93 | input start, 94 | output busy, 95 | 96 | input [NB_MUL1-1:0] mul1, 97 | input [NB_MUL2-1:0] mul2, 98 | input [NB_DIV-1:0] div, 99 | output [NB_MUL1+NB_MUL2-1:0] result, 100 | output [NB_DIV-1:0] remainder 101 | ); 102 | 103 | wire mul_run; 104 | wire [NB_MUL1+NB_MUL2-1:0] mul_res; 105 | sys_umul #(NB_MUL1,NB_MUL2) umul(clk,start,mul_run,mul1,mul2,mul_res); 106 | 107 | sys_udiv #(NB_MUL1+NB_MUL2,NB_DIV) udiv(clk,start|mul_run,busy,mul_res,div,result,remainder); 108 | 109 | endmodule 110 | -------------------------------------------------------------------------------- /sys/sys_dual_sdram.tcl: -------------------------------------------------------------------------------- 1 | #============================================================ 2 | # Secondary SDRAM 3 | #============================================================ 4 | set_location_assignment PIN_Y15 -to SDRAM2_DQ[0] 5 | set_location_assignment PIN_AC24 -to SDRAM2_DQ[1] 6 | set_location_assignment PIN_AA15 -to SDRAM2_DQ[2] 7 | set_location_assignment PIN_AD26 -to SDRAM2_DQ[3] 8 | set_location_assignment PIN_AG28 -to SDRAM2_DQ[4] 9 | set_location_assignment PIN_AF28 -to SDRAM2_DQ[5] 10 | set_location_assignment PIN_AE25 -to SDRAM2_DQ[6] 11 | set_location_assignment PIN_AF27 -to SDRAM2_DQ[7] 12 | set_location_assignment PIN_AG26 -to SDRAM2_DQ[14] 13 | set_location_assignment PIN_AH27 -to SDRAM2_DQ[15] 14 | 15 | set_location_assignment PIN_AG25 -to SDRAM2_DQ[13] 16 | set_location_assignment PIN_AH26 -to SDRAM2_DQ[12] 17 | set_location_assignment PIN_AH24 -to SDRAM2_DQ[11] 18 | set_location_assignment PIN_AF25 -to SDRAM2_DQ[10] 19 | set_location_assignment PIN_AG23 -to SDRAM2_DQ[9] 20 | set_location_assignment PIN_AF23 -to SDRAM2_DQ[8] 21 | set_location_assignment PIN_AG24 -to SDRAM2_A[12] 22 | set_location_assignment PIN_AH22 -to SDRAM2_CLK 23 | set_location_assignment PIN_AH21 -to SDRAM2_A[9] 24 | set_location_assignment PIN_AG21 -to SDRAM2_A[11] 25 | set_location_assignment PIN_AH23 -to SDRAM2_A[7] 26 | set_location_assignment PIN_AA20 -to SDRAM2_A[8] 27 | set_location_assignment PIN_AF22 -to SDRAM2_A[5] 28 | set_location_assignment PIN_AE22 -to SDRAM2_A[6] 29 | set_location_assignment PIN_AG20 -to SDRAM2_nWE 30 | set_location_assignment PIN_AF21 -to SDRAM2_A[4] 31 | 32 | set_location_assignment PIN_AG19 -to SDRAM2_nCAS 33 | set_location_assignment PIN_AH19 -to SDRAM2_nRAS 34 | set_location_assignment PIN_AG18 -to SDRAM2_nCS 35 | set_location_assignment PIN_AH18 -to SDRAM2_BA[0] 36 | set_location_assignment PIN_AF18 -to SDRAM2_BA[1] 37 | set_location_assignment PIN_AF20 -to SDRAM2_A[10] 38 | set_location_assignment PIN_AG15 -to SDRAM2_A[0] 39 | set_location_assignment PIN_AE20 -to SDRAM2_A[1] 40 | set_location_assignment PIN_AE19 -to SDRAM2_A[2] 41 | set_location_assignment PIN_AE17 -to SDRAM2_A[3] 42 | 43 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM2_* 44 | set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM2_* 45 | set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM2_* 46 | set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM2_DQ[*] 47 | set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM2_DQ[*] 48 | set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to SDRAM2_DQ[*] 49 | set_instance_assignment -name ALLOW_SYNCH_CTRL_USAGE OFF -to *|SDRAM2_* 50 | 51 | set_global_assignment -name VERILOG_MACRO "MISTER_DUAL_SDRAM=1" 52 | -------------------------------------------------------------------------------- /sys/i2c.v: -------------------------------------------------------------------------------- 1 | 2 | module i2c 3 | ( 4 | input CLK, 5 | 6 | input START, 7 | input READ, 8 | input [6:0] I2C_ADDR, 9 | input I2C_WLEN, // 0 - one byte, 1 - two bytes 10 | input [7:0] I2C_WDATA1, 11 | input [7:0] I2C_WDATA2, 12 | output [7:0] I2C_RDATA, 13 | output reg END = 1, 14 | output reg ACK = 0, 15 | 16 | //I2C bus 17 | output I2C_SCL, 18 | inout I2C_SDA 19 | ); 20 | 21 | 22 | // Clock Setting 23 | parameter CLK_Freq = 50_000_000; // 50 MHz 24 | parameter I2C_Freq = 400_000; // 400 KHz 25 | 26 | localparam I2C_FreqX2 = I2C_Freq*2; 27 | 28 | reg I2C_CLOCK; 29 | reg [31:0] cnt; 30 | wire [31:0] cnt_next = cnt + I2C_FreqX2; 31 | 32 | always @(posedge CLK) begin 33 | cnt <= cnt_next; 34 | if(cnt_next >= CLK_Freq) begin 35 | cnt <= cnt_next - CLK_Freq; 36 | I2C_CLOCK <= ~I2C_CLOCK; 37 | end 38 | end 39 | 40 | assign I2C_SCL = (SCLK | I2C_CLOCK) ? 1'bZ : 1'b0; 41 | assign I2C_SDA = SDO[3] ? 1'bz : 1'b0; 42 | 43 | reg SCLK; 44 | reg [3:0] SDO; 45 | reg [0:7] rdata; 46 | 47 | reg [5:0] SD_COUNTER; 48 | reg [0:31] SD; 49 | 50 | initial begin 51 | SD_COUNTER = 'b111111; 52 | SD = 'hFFFF; 53 | SCLK = 1; 54 | SDO = 4'b1111; 55 | end 56 | 57 | assign I2C_RDATA = rdata; 58 | 59 | always @(posedge CLK) begin 60 | reg old_clk; 61 | reg old_st; 62 | reg rd,len; 63 | 64 | old_clk <= I2C_CLOCK; 65 | old_st <= START; 66 | 67 | // delay to make sure SDA changed while SCL is stabilized at low 68 | if(old_clk && ~I2C_CLOCK && ~SD_COUNTER[5]) SDO[0] <= SD[SD_COUNTER[4:0]]; 69 | SDO[3:1] <= SDO[2:0]; 70 | 71 | if(~old_st && START) begin 72 | SCLK <= 1; 73 | SDO <= 4'b1111; 74 | ACK <= 0; 75 | END <= 0; 76 | rd <= READ; 77 | len <= I2C_WLEN; 78 | if(READ) SD <= {2'b10, I2C_ADDR, 1'b1, 1'b1, 8'b11111111, 1'b1, 3'b011, 9'b111111111}; 79 | else SD <= {2'b10, I2C_ADDR, 1'b0, 1'b1, I2C_WDATA1, 1'b1, I2C_WDATA2, 4'b1011}; 80 | SD_COUNTER <= 0; 81 | end else begin 82 | if(~old_clk && I2C_CLOCK && ~&SD_COUNTER) begin 83 | SD_COUNTER <= SD_COUNTER + 6'd1; 84 | case(SD_COUNTER) 85 | 01: SCLK <= 0; 86 | 10: ACK <= ACK | I2C_SDA; 87 | 19: if(~rd) begin 88 | ACK <= ACK | I2C_SDA; 89 | if(~len) SD_COUNTER <= 29; 90 | end 91 | 20: if(rd) SCLK <= 1; 92 | 23: if(rd) END <= 1; 93 | 28: if(~rd) ACK <= ACK | I2C_SDA; 94 | 29: if(~rd) SCLK <= 1; 95 | 32: if(~rd) END <= 1; 96 | endcase 97 | 98 | if(SD_COUNTER >= 11 && SD_COUNTER <= 18) rdata[SD_COUNTER[4:0]-11] <= I2C_SDA; 99 | end 100 | end 101 | end 102 | 103 | endmodule 104 | -------------------------------------------------------------------------------- /sys/ddr_svc.sv: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2020 Alexey Melnikov 3 | // 4 | // 5 | // This source file is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published 7 | // by the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // This source file is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | // ------------------------------------------ 19 | // 20 | 21 | // 16-bit version 22 | 23 | module ddr_svc 24 | ( 25 | input clk, 26 | 27 | input ram_waitrequest, 28 | output [7:0] ram_burstcnt, 29 | output [28:0] ram_addr, 30 | input [63:0] ram_readdata, 31 | input ram_read_ready, 32 | output reg ram_read, 33 | output [63:0] ram_writedata, 34 | output [7:0] ram_byteenable, 35 | output reg ram_write, 36 | 37 | output [7:0] ram_bcnt, 38 | 39 | input [31:3] ch0_addr, 40 | input [7:0] ch0_burst, 41 | output [63:0] ch0_data, 42 | input ch0_req, 43 | output ch0_ready, 44 | 45 | input [31:3] ch1_addr, 46 | input [7:0] ch1_burst, 47 | output [63:0] ch1_data, 48 | input ch1_req, 49 | output ch1_ready 50 | ); 51 | 52 | assign ram_burstcnt = ram_burst; 53 | assign ram_byteenable = 8'hFF; 54 | assign ram_addr = ram_address; 55 | assign ram_writedata = 0; 56 | 57 | assign ch0_data = ram_q[0]; 58 | assign ch1_data = ram_q[1]; 59 | assign ch0_ready = ready[0]; 60 | assign ch1_ready = ready[1]; 61 | 62 | reg [7:0] ram_burst; 63 | reg [63:0] ram_q[2]; 64 | reg [31:3] ram_address; 65 | reg [1:0] ack = 0; 66 | reg [1:0] ready; 67 | reg state = 0; 68 | reg ch = 0; 69 | 70 | always @(posedge clk) begin 71 | ready <= 0; 72 | 73 | if(!ram_waitrequest) begin 74 | ram_read <= 0; 75 | ram_write <= 0; 76 | 77 | case(state) 78 | 0: if(ch0_req != ack[0]) begin 79 | ack[0] <= ch0_req; 80 | ram_address <= ch0_addr; 81 | ram_burst <= ch0_burst; 82 | ram_read <= 1; 83 | ch <= 0; 84 | ram_bcnt <= 8'hFF; 85 | state <= 1; 86 | end 87 | else if(ch1_req != ack[1]) begin 88 | ack[1] <= ch1_req; 89 | ram_address <= ch1_addr; 90 | ram_burst <= ch1_burst; 91 | ram_read <= 1; 92 | ch <= 1; 93 | ram_bcnt <= 8'hFF; 94 | state <= 1; 95 | end 96 | 1: begin 97 | if(ram_read_ready) begin 98 | ram_bcnt <= ram_bcnt + 1'd1; 99 | ram_q[ch] <= ram_readdata; 100 | ready[ch] <= 1; 101 | if ((ram_bcnt+2'd2) == ram_burst) state <= 0; 102 | end 103 | end 104 | endcase 105 | end 106 | end 107 | 108 | endmodule 109 | -------------------------------------------------------------------------------- /EDSAC.qsf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------- # 2 | # 3 | # MiSTer project 4 | # 5 | # WARNING WARNING WARNING: 6 | # Do not add files to project in Quartus IDE! It will mess this file! 7 | # Add the files manually to files.qip file. 8 | # 9 | # -------------------------------------------------------------------------- 10 | 11 | set_global_assignment -name TOP_LEVEL_ENTITY sys_top 12 | set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top 13 | set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top 14 | set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top 15 | 16 | set_global_assignment -name LAST_QUARTUS_VERSION "17.0.2 Lite Edition" 17 | 18 | set_global_assignment -name GENERATE_RBF_FILE ON 19 | set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files 20 | set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL 21 | set_global_assignment -name SAVE_DISK_SPACE OFF 22 | set_global_assignment -name SMART_RECOMPILE ON 23 | set_global_assignment -name MIN_CORE_JUNCTION_TEMP "-40" 24 | set_global_assignment -name MAX_CORE_JUNCTION_TEMP 100 25 | set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "23 MM HEAT SINK WITH 200 LFPM AIRFLOW" 26 | set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)" 27 | set_global_assignment -name TIMEQUEST_MULTICORNER_ANALYSIS OFF 28 | set_global_assignment -name OPTIMIZE_POWER_DURING_FITTING OFF 29 | set_global_assignment -name FINAL_PLACEMENT_OPTIMIZATION ALWAYS 30 | set_global_assignment -name FITTER_EFFORT "STANDARD FIT" 31 | set_global_assignment -name OPTIMIZATION_MODE "HIGH PERFORMANCE EFFORT" 32 | set_global_assignment -name ALLOW_POWER_UP_DONT_CARE ON 33 | set_global_assignment -name QII_AUTO_PACKED_REGISTERS NORMAL 34 | set_global_assignment -name ROUTER_LCELL_INSERTION_AND_LOGIC_DUPLICATION ON 35 | set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC ON 36 | set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_DUPLICATION ON 37 | set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_RETIMING ON 38 | set_global_assignment -name OPTIMIZATION_TECHNIQUE SPEED 39 | set_global_assignment -name MUX_RESTRUCTURE ON 40 | set_global_assignment -name AUTO_DELAY_CHAINS_FOR_HIGH_FANOUT_INPUT_PINS ON 41 | set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC_FOR_AREA ON 42 | set_global_assignment -name ADV_NETLIST_OPT_SYNTH_WYSIWYG_REMAP ON 43 | set_global_assignment -name SYNTH_GATED_CLOCK_CONVERSION ON 44 | set_global_assignment -name PRE_MAPPING_RESYNTHESIS ON 45 | set_global_assignment -name ROUTER_CLOCKING_TOPOLOGY_ANALYSIS ON 46 | set_global_assignment -name ECO_OPTIMIZE_TIMING ON 47 | set_global_assignment -name PERIPHERY_TO_CORE_PLACEMENT_AND_ROUTING_OPTIMIZATION ON 48 | set_global_assignment -name PHYSICAL_SYNTHESIS_ASYNCHRONOUS_SIGNAL_PIPELINING ON 49 | set_global_assignment -name ALM_REGISTER_PACKING_EFFORT LOW 50 | set_global_assignment -name SEED 1 51 | 52 | source sys/sys.tcl 53 | source sys/sys_analog.tcl 54 | source files.qip 55 | set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top -------------------------------------------------------------------------------- /sys/sys.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name QIP_FILE [join [list $::quartus(qip_path) pll_q [regexp -inline {[0-9]+} $quartus(version)] .qip] {}] 2 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) sys_top.v ] 3 | set_global_assignment -name SDC_FILE [file join $::quartus(qip_path) sys_top.sdc ] 4 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) ascal.vhd ] 5 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) pll_hdmi_adj.vhd ] 6 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) math.sv ] 7 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) hq2x.sv ] 8 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) scandoubler.v ] 9 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) scanlines.v ] 10 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) shadowmask.sv ] 11 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_cleaner.sv ] 12 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) gamma_corr.sv ] 13 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_mixer.sv ] 14 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_freak.sv ] 15 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_freezer.sv ] 16 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) arcade_video.v ] 17 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) osd.v ] 18 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) vga_out.sv ] 19 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) yc_out.sv ] 20 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) i2c.v ] 21 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) alsa.sv ] 22 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) i2s.v ] 23 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) spdif.v ] 24 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) audio_out.v ] 25 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) iir_filter.v ] 26 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) ltc2308.sv ] 27 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) sigma_delta_dac.v ] 28 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) mt32pi.sv ] 29 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) mcp23009.sv ] 30 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) f2sdram_safe_terminator.sv ] 31 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) ddr_svc.sv ] 32 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) sysmem.sv ] 33 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) sd_card.sv ] 34 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) hps_io.sv ] 35 | -------------------------------------------------------------------------------- /sys/sys_analog.tcl: -------------------------------------------------------------------------------- 1 | #============================================================ 2 | # SDIO 3 | #============================================================ 4 | set_location_assignment PIN_AF25 -to SDIO_DAT[0] 5 | set_location_assignment PIN_AF23 -to SDIO_DAT[1] 6 | set_location_assignment PIN_AD26 -to SDIO_DAT[2] 7 | set_location_assignment PIN_AF28 -to SDIO_DAT[3] 8 | set_location_assignment PIN_AF27 -to SDIO_CMD 9 | set_location_assignment PIN_AH26 -to SDIO_CLK 10 | set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDIO_* 11 | 12 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDIO_* 13 | set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to SDIO_DAT[*] 14 | set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to SDIO_CMD 15 | 16 | #============================================================ 17 | # VGA 18 | #============================================================ 19 | set_location_assignment PIN_AE17 -to VGA_R[0] 20 | set_location_assignment PIN_AE20 -to VGA_R[1] 21 | set_location_assignment PIN_AF20 -to VGA_R[2] 22 | set_location_assignment PIN_AH18 -to VGA_R[3] 23 | set_location_assignment PIN_AH19 -to VGA_R[4] 24 | set_location_assignment PIN_AF21 -to VGA_R[5] 25 | 26 | set_location_assignment PIN_AE19 -to VGA_G[0] 27 | set_location_assignment PIN_AG15 -to VGA_G[1] 28 | set_location_assignment PIN_AF18 -to VGA_G[2] 29 | set_location_assignment PIN_AG18 -to VGA_G[3] 30 | set_location_assignment PIN_AG19 -to VGA_G[4] 31 | set_location_assignment PIN_AG20 -to VGA_G[5] 32 | 33 | set_location_assignment PIN_AG21 -to VGA_B[0] 34 | set_location_assignment PIN_AA20 -to VGA_B[1] 35 | set_location_assignment PIN_AE22 -to VGA_B[2] 36 | set_location_assignment PIN_AF22 -to VGA_B[3] 37 | set_location_assignment PIN_AH23 -to VGA_B[4] 38 | set_location_assignment PIN_AH21 -to VGA_B[5] 39 | 40 | set_location_assignment PIN_AH22 -to VGA_HS 41 | set_location_assignment PIN_AG24 -to VGA_VS 42 | 43 | set_location_assignment PIN_AH27 -to VGA_EN 44 | set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to VGA_EN 45 | 46 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to VGA_* 47 | set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to VGA_* 48 | 49 | #============================================================ 50 | # AUDIO 51 | #============================================================ 52 | set_location_assignment PIN_AC24 -to AUDIO_L 53 | set_location_assignment PIN_AE25 -to AUDIO_R 54 | set_location_assignment PIN_AG26 -to AUDIO_SPDIF 55 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to AUDIO_* 56 | set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to AUDIO_* 57 | 58 | #============================================================ 59 | # I/O #1 60 | #============================================================ 61 | set_location_assignment PIN_Y15 -to LED_USER 62 | set_location_assignment PIN_AA15 -to LED_HDD 63 | set_location_assignment PIN_AG28 -to LED_POWER 64 | 65 | set_location_assignment PIN_AH24 -to BTN_USER 66 | set_location_assignment PIN_AG25 -to BTN_OSD 67 | set_location_assignment PIN_AG23 -to BTN_RESET 68 | 69 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to LED_* 70 | set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to BTN_* 71 | set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to BTN_* 72 | -------------------------------------------------------------------------------- /sys/video_freezer.sv: -------------------------------------------------------------------------------- 1 | // 2 | // video freeze with sync 3 | // (C) Alexey Melnikov 4 | // 5 | // 6 | // This program is free software; you can redistribute it and/or modify it 7 | // under the terms of the GNU General Public License as published by the Free 8 | // Software Foundation; either version 2 of the License, or (at your option) 9 | // any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT 12 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 | // more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along 17 | // with this program; if not, write to the Free Software Foundation, Inc., 18 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | 20 | 21 | module video_freezer 22 | ( 23 | input clk, 24 | 25 | output sync, 26 | input freeze, 27 | 28 | input hs_in, 29 | input vs_in, 30 | input hbl_in, 31 | input vbl_in, 32 | 33 | output hs_out, 34 | output vs_out, 35 | output hbl_out, 36 | output vbl_out 37 | ); 38 | 39 | sync_lock #(33) vs_lock 40 | ( 41 | .clk(clk), 42 | .sync_in(vs_in), 43 | .sync_out(vs_out), 44 | .de_in(vbl_in), 45 | .de_out(vbl_out), 46 | .freeze(freeze) 47 | ); 48 | 49 | wire sync_pt; 50 | sync_lock #(21) hs_lock 51 | ( 52 | .clk(clk), 53 | .sync_in(hs_in), 54 | .sync_out(hs_out), 55 | .de_in(hbl_in), 56 | .de_out(hbl_out), 57 | .freeze(freeze), 58 | .sync_pt(sync_pt) 59 | ); 60 | 61 | reg sync_o; 62 | always @(posedge clk) begin 63 | reg old_hs, old_vs; 64 | reg vs_sync; 65 | 66 | old_vs <= vs_out; 67 | 68 | if(~old_vs & vs_out) vs_sync <= 1; 69 | if(sync_pt & vs_sync) begin 70 | vs_sync <= 0; 71 | sync_o <= ~sync_o; 72 | end 73 | end 74 | 75 | assign sync = sync_o; 76 | 77 | endmodule 78 | 79 | 80 | module sync_lock #(parameter WIDTH) 81 | ( 82 | input clk, 83 | 84 | input sync_in, 85 | input de_in, 86 | 87 | output sync_out, 88 | output de_out, 89 | 90 | input freeze, 91 | output sync_pt, 92 | output valid 93 | ); 94 | 95 | reg [WIDTH-1:0] f_len, s_len, de_start, de_end; 96 | reg sync_valid; 97 | 98 | reg old_sync; 99 | always @(posedge clk) old_sync <= sync_in; 100 | 101 | always @(posedge clk) begin 102 | reg [WIDTH-1:0] cnti; 103 | reg f_valid; 104 | reg old_de; 105 | 106 | cnti <= cnti + 1'd1; 107 | if(~old_sync & sync_in) begin 108 | if(sync_valid) f_len <= cnti; 109 | f_valid <= 1; 110 | sync_valid <= f_valid; 111 | cnti <= 0; 112 | end 113 | 114 | if(old_sync & ~sync_in & sync_valid) s_len <= cnti; 115 | 116 | old_de <= de_in; 117 | if(~old_de & de_in & sync_valid) de_start <= cnti; 118 | if(old_de & ~de_in & sync_valid) de_end <= cnti; 119 | 120 | if(freeze) {f_valid, sync_valid} <= 0; 121 | end 122 | 123 | reg sync_o, de_o, sync_o_pre; 124 | always @(posedge clk) begin 125 | reg [WIDTH-1:0] cnto; 126 | 127 | cnto <= cnto + 1'd1; 128 | if(old_sync & ~sync_in & sync_valid) cnto <= s_len + 2'd2; 129 | if(cnto == f_len) cnto <= 0; 130 | 131 | sync_o_pre <= (cnto == (s_len>>1)); // middle in sync 132 | if(cnto == f_len) sync_o <= 1; 133 | if(cnto == s_len) sync_o <= 0; 134 | if(cnto == de_start) de_o <= 1; 135 | if(cnto == de_end) de_o <= 0; 136 | end 137 | 138 | assign sync_out = freeze ? sync_o : sync_in; 139 | assign valid = sync_valid; 140 | assign sync_pt = sync_o_pre; 141 | assign de_out = freeze ? de_o : de_in; 142 | 143 | endmodule 144 | -------------------------------------------------------------------------------- /rtl/rle_framebuffer.sv: -------------------------------------------------------------------------------- 1 | module rle_framebuffer 2 | ( 3 | input clock, 4 | input enable, 5 | input sync, 6 | input [1:0] active_mode, 7 | input [31:0] status, 8 | output reg [7:0] pixel, 9 | 10 | // Option to upload/change the ROM image file // 11 | input [7:0] data, 12 | input [16:0] wraddress, 13 | input wren 14 | ); 15 | 16 | /* 17 | This works by decompressing the provided ROM bitmap using a relatively simple RLE variant: 18 | Load byte. If LSB bit is 0, display remaining 7 bits as luma and proceed to the next byte. 19 | If LSB bit is 1, then use remaining 7 bits as luma but they will be repeated. Now we need to 20 | load repeat count. Keep loading bytes and extracting 7 bits from each of them until we get 21 | one with LSB set to 0, that is the end of SIZE data. Save that size data into a counter and 22 | decrement with every posedge clock, keeping the original 7 bits for pixel luma in the output 23 | register. After counter drops to zero, restart the entire process. 24 | */ 25 | 26 | wire [7:0] fp_rom_data; 27 | wire rom_clock = clock & enable; 28 | 29 | parameter 30 | FETCH = 2'b00, 31 | GET_LEN = 2'b01, 32 | COPY_CHAR = 2'b10; 33 | 34 | image_library fp_rom( 35 | .rdaddress({active_mode[1], rom_addr}), 36 | .wraddress(wraddress), 37 | .data(data), 38 | .wren(wren), 39 | .clock(rom_clock), 40 | .q(fp_rom_data) 41 | ); 42 | 43 | reg [21:0] repeat_count = 22'd0; 44 | reg [15:0] rom_addr = 16'b0; 45 | reg [1:0] phase = 2'd0; 46 | reg [2:0] size_len = 3'd0; 47 | 48 | reg old_sync; 49 | 50 | always @(posedge clock) 51 | begin 52 | 53 | if (sync) begin 54 | rom_addr <= 16'hfffe; 55 | phase <= FETCH; 56 | end 57 | 58 | else 59 | if (enable) 60 | begin 61 | 62 | rom_addr <= rom_addr + 1'b1; 63 | 64 | case (phase) 65 | FETCH: // Get pixel value 66 | begin 67 | repeat_count <= 22'b0; 68 | pixel <= {fp_rom_data[7:1], 1'b0}; 69 | size_len <= {2'b0, fp_rom_data[0]}; 70 | 71 | if (fp_rom_data[0]) // This pixel is encoded, let's get the repeat count 72 | phase <= GET_LEN; 73 | end 74 | 75 | 76 | GET_LEN: // Get up to 3 bytes of size 77 | begin 78 | 79 | // When we reach the end of size data, subtract the number of clocks spent fetching the size 80 | repeat_count <= {repeat_count[14:0], fp_rom_data[7:1]}; 81 | size_len <= size_len + 1'b1; // Keep tabs on clock count 82 | 83 | // There is more size data to come 84 | if (~fp_rom_data[0]) 85 | begin 86 | rom_addr <= rom_addr - {repeat_count[8:0], fp_rom_data[7:1]} + {14'b0, size_len} + 16'd2; 87 | phase <= COPY_CHAR; 88 | end 89 | end 90 | 91 | 92 | COPY_CHAR: // Churn out pixels 93 | begin 94 | // While repeat_count is not zero 95 | if(repeat_count > {19'b0, size_len} + 22'd1) 96 | repeat_count <= repeat_count - 1'b1; 97 | else begin 98 | phase <= FETCH; 99 | end 100 | end 101 | 102 | default: 103 | phase <= FETCH; 104 | endcase 105 | end 106 | end 107 | 108 | endmodule -------------------------------------------------------------------------------- /rtl/cos.sv: -------------------------------------------------------------------------------- 1 | 2 | module cos ( 3 | input [9:0] x, 4 | output [7:0] y 5 | ); 6 | 7 | wire [7:0] qcos[0:255] = '{ 8 | 8'b01111111, 8'b01111111, 8'b01111111, 8'b01111111, 8'b01111111, 8'b01111111, 8'b01111111, 8'b01111111, 9 | 8'b01111111, 8'b01111111, 8'b01111111, 8'b01111111, 8'b01111111, 8'b01111111, 8'b01111111, 8'b01111111, 10 | 8'b01111111, 8'b01111111, 8'b01111111, 8'b01111111, 8'b01111111, 8'b01111111, 8'b01111111, 8'b01111111, 11 | 8'b01111110, 8'b01111110, 8'b01111110, 8'b01111110, 8'b01111110, 8'b01111110, 8'b01111110, 8'b01111110, 12 | 8'b01111101, 8'b01111101, 8'b01111101, 8'b01111101, 8'b01111101, 8'b01111101, 8'b01111100, 8'b01111100, 13 | 8'b01111100, 8'b01111100, 8'b01111100, 8'b01111011, 8'b01111011, 8'b01111011, 8'b01111011, 8'b01111010, 14 | 8'b01111010, 8'b01111010, 8'b01111010, 8'b01111010, 8'b01111001, 8'b01111001, 8'b01111001, 8'b01111001, 15 | 8'b01111000, 8'b01111000, 8'b01111000, 8'b01110111, 8'b01110111, 8'b01110111, 8'b01110111, 8'b01110110, 16 | 8'b01110110, 8'b01110110, 8'b01110101, 8'b01110101, 8'b01110101, 8'b01110100, 8'b01110100, 8'b01110100, 17 | 8'b01110011, 8'b01110011, 8'b01110011, 8'b01110010, 8'b01110010, 8'b01110010, 8'b01110001, 8'b01110001, 18 | 8'b01110001, 8'b01110000, 8'b01110000, 8'b01101111, 8'b01101111, 8'b01101111, 8'b01101110, 8'b01101110, 19 | 8'b01101101, 8'b01101101, 8'b01101101, 8'b01101100, 8'b01101100, 8'b01101011, 8'b01101011, 8'b01101010, 20 | 8'b01101010, 8'b01101010, 8'b01101001, 8'b01101001, 8'b01101000, 8'b01101000, 8'b01100111, 8'b01100111, 21 | 8'b01100110, 8'b01100110, 8'b01100101, 8'b01100101, 8'b01100100, 8'b01100100, 8'b01100011, 8'b01100011, 22 | 8'b01100010, 8'b01100010, 8'b01100001, 8'b01100001, 8'b01100000, 8'b01100000, 8'b01011111, 8'b01011111, 23 | 8'b01011110, 8'b01011110, 8'b01011101, 8'b01011101, 8'b01011100, 8'b01011100, 8'b01011011, 8'b01011011, 24 | 8'b01011010, 8'b01011001, 8'b01011001, 8'b01011000, 8'b01011000, 8'b01010111, 8'b01010111, 8'b01010110, 25 | 8'b01010101, 8'b01010101, 8'b01010100, 8'b01010100, 8'b01010011, 8'b01010010, 8'b01010010, 8'b01010001, 26 | 8'b01010001, 8'b01010000, 8'b01001111, 8'b01001111, 8'b01001110, 8'b01001110, 8'b01001101, 8'b01001100, 27 | 8'b01001100, 8'b01001011, 8'b01001010, 8'b01001010, 8'b01001001, 8'b01001000, 8'b01001000, 8'b01000111, 28 | 8'b01000111, 8'b01000110, 8'b01000101, 8'b01000101, 8'b01000100, 8'b01000011, 8'b01000011, 8'b01000010, 29 | 8'b01000001, 8'b01000001, 8'b01000000, 8'b00111111, 8'b00111110, 8'b00111110, 8'b00111101, 8'b00111100, 30 | 8'b00111100, 8'b00111011, 8'b00111010, 8'b00111010, 8'b00111001, 8'b00111000, 8'b00111000, 8'b00110111, 31 | 8'b00110110, 8'b00110101, 8'b00110101, 8'b00110100, 8'b00110011, 8'b00110011, 8'b00110010, 8'b00110001, 32 | 8'b00110000, 8'b00110000, 8'b00101111, 8'b00101110, 8'b00101101, 8'b00101101, 8'b00101100, 8'b00101011, 33 | 8'b00101010, 8'b00101010, 8'b00101001, 8'b00101000, 8'b00100111, 8'b00100111, 8'b00100110, 8'b00100101, 34 | 8'b00100100, 8'b00100100, 8'b00100011, 8'b00100010, 8'b00100001, 8'b00100001, 8'b00100000, 8'b00011111, 35 | 8'b00011110, 8'b00011110, 8'b00011101, 8'b00011100, 8'b00011011, 8'b00011011, 8'b00011010, 8'b00011001, 36 | 8'b00011000, 8'b00011000, 8'b00010111, 8'b00010110, 8'b00010101, 8'b00010100, 8'b00010100, 8'b00010011, 37 | 8'b00010010, 8'b00010001, 8'b00010001, 8'b00010000, 8'b00001111, 8'b00001110, 8'b00001101, 8'b00001101, 38 | 8'b00001100, 8'b00001011, 8'b00001010, 8'b00001010, 8'b00001001, 8'b00001000, 8'b00000111, 8'b00000110, 39 | 8'b00000110, 8'b00000101, 8'b00000100, 8'b00000011, 8'b00000010, 8'b00000010, 8'b00000001, 8'b00000000 40 | }; 41 | 42 | wire ival = ^x[9:8]; 43 | assign y = qcos[x[7:0] ^ {8{x[8]}}] ^ {~ival,{7{ival}}}; 44 | 45 | endmodule 46 | 47 | -------------------------------------------------------------------------------- /sys/gamma_corr.sv: -------------------------------------------------------------------------------- 1 | module gamma_corr 2 | ( 3 | input clk_sys, 4 | input clk_vid, 5 | input ce_pix, 6 | input gamma_en, 7 | input gamma_wr, 8 | input [9:0] gamma_wr_addr, 9 | input [7:0] gamma_value, 10 | input HSync, 11 | input VSync, 12 | input HBlank, 13 | input VBlank, 14 | input [23:0] RGB_in, 15 | output reg HSync_out, 16 | output reg VSync_out, 17 | output reg HBlank_out, 18 | output reg VBlank_out, 19 | output reg [23:0] RGB_out 20 | ); 21 | 22 | (* ramstyle="no_rw_check" *) reg [7:0] gamma_curve[768]; 23 | 24 | always @(posedge clk_sys) if (gamma_wr) gamma_curve[gamma_wr_addr] <= gamma_value; 25 | always @(posedge clk_vid) gamma <= gamma_curve[gamma_index]; 26 | 27 | reg [9:0] gamma_index; 28 | reg [7:0] gamma; 29 | 30 | always @(posedge clk_vid) begin 31 | reg [7:0] R_in, G_in, B_in; 32 | reg [7:0] R_gamma, G_gamma; 33 | reg hs,vs,hb,vb; 34 | reg [1:0] ctr = 0; 35 | reg old_ce; 36 | 37 | old_ce <= ce_pix; 38 | if(~old_ce & ce_pix) begin 39 | {R_in,G_in,B_in} <= RGB_in; 40 | hs <= HSync; vs <= VSync; 41 | hb <= HBlank; vb <= VBlank; 42 | 43 | RGB_out <= gamma_en ? {R_gamma,G_gamma,gamma} : {R_in,G_in,B_in}; 44 | HSync_out <= hs; VSync_out <= vs; 45 | HBlank_out <= hb; VBlank_out <= vb; 46 | 47 | ctr <= 1; 48 | gamma_index <= {2'b00,RGB_in[23:16]}; 49 | end 50 | 51 | if (|ctr) ctr <= ctr + 1'd1; 52 | 53 | case(ctr) 54 | 1: begin gamma_index <= {2'b01,G_in}; end 55 | 2: begin R_gamma <= gamma; gamma_index <= {2'b10,B_in}; end 56 | 3: begin G_gamma <= gamma; end 57 | endcase 58 | end 59 | 60 | endmodule 61 | 62 | module gamma_fast 63 | ( 64 | input clk_vid, 65 | input ce_pix, 66 | 67 | inout [21:0] gamma_bus, 68 | 69 | input HSync, 70 | input VSync, 71 | input HBlank, 72 | input VBlank, 73 | input DE, 74 | input [23:0] RGB_in, 75 | 76 | output reg HSync_out, 77 | output reg VSync_out, 78 | output reg HBlank_out, 79 | output reg VBlank_out, 80 | output reg DE_out, 81 | output reg [23:0] RGB_out 82 | ); 83 | 84 | (* ramstyle="no_rw_check" *) reg [7:0] gamma_curve_r[256]; 85 | (* ramstyle="no_rw_check" *) reg [7:0] gamma_curve_g[256]; 86 | (* ramstyle="no_rw_check" *) reg [7:0] gamma_curve_b[256]; 87 | 88 | assign gamma_bus[21] = 1; 89 | wire clk_sys = gamma_bus[20]; 90 | wire gamma_en = gamma_bus[19]; 91 | wire gamma_wr = gamma_bus[18]; 92 | wire [9:0] gamma_wr_addr = gamma_bus[17:8]; 93 | wire [7:0] gamma_value = gamma_bus[7:0]; 94 | 95 | always @(posedge clk_sys) if (gamma_wr) begin 96 | case(gamma_wr_addr[9:8]) 97 | 0: gamma_curve_r[gamma_wr_addr[7:0]] <= gamma_value; 98 | 1: gamma_curve_g[gamma_wr_addr[7:0]] <= gamma_value; 99 | 2: gamma_curve_b[gamma_wr_addr[7:0]] <= gamma_value; 100 | endcase 101 | end 102 | 103 | reg [7:0] gamma_index_r,gamma_index_g,gamma_index_b; 104 | 105 | always @(posedge clk_vid) begin 106 | reg [7:0] R_in, G_in, B_in; 107 | reg [7:0] R_gamma, G_gamma; 108 | reg hs,vs,hb,vb,de; 109 | 110 | if(ce_pix) begin 111 | {gamma_index_r,gamma_index_g,gamma_index_b} <= RGB_in; 112 | hs <= HSync; vs <= VSync; 113 | hb <= HBlank; vb <= VBlank; 114 | de <= DE; 115 | 116 | RGB_out <= gamma_en ? {gamma_curve_r[gamma_index_r],gamma_curve_g[gamma_index_g],gamma_curve_b[gamma_index_b]} 117 | : {gamma_index_r,gamma_index_g,gamma_index_b}; 118 | HSync_out <= hs; VSync_out <= vs; 119 | HBlank_out <= hb; VBlank_out <= vb; 120 | DE_out <= de; 121 | end 122 | end 123 | 124 | endmodule 125 | -------------------------------------------------------------------------------- /sys/sys_top.sdc: -------------------------------------------------------------------------------- 1 | # Specify root clocks 2 | create_clock -period "50.0 MHz" [get_ports FPGA_CLK1_50] 3 | create_clock -period "50.0 MHz" [get_ports FPGA_CLK2_50] 4 | create_clock -period "50.0 MHz" [get_ports FPGA_CLK3_50] 5 | create_clock -period "100.0 MHz" [get_pins -compatibility_mode *|h2f_user0_clk] 6 | create_clock -period "100.0 MHz" [get_pins -compatibility_mode spi|sclk_out] -name spi_sck 7 | create_clock -period "10.0 MHz" [get_pins -compatibility_mode hdmi_i2c|out_clk] -name hdmi_sck 8 | 9 | derive_pll_clocks 10 | derive_clock_uncertainty 11 | 12 | # Decouple different clock groups (to simplify routing) 13 | set_clock_groups -exclusive \ 14 | -group [get_clocks { *|pll|pll_inst|altera_pll_i|*[*].*|divclk}] \ 15 | -group [get_clocks { pll_hdmi|pll_hdmi_inst|altera_pll_i|*[0].*|divclk}] \ 16 | -group [get_clocks { pll_audio|pll_audio_inst|altera_pll_i|*[0].*|divclk}] \ 17 | -group [get_clocks { spi_sck}] \ 18 | -group [get_clocks { hdmi_sck}] \ 19 | -group [get_clocks { *|h2f_user0_clk}] \ 20 | -group [get_clocks { FPGA_CLK1_50 }] \ 21 | -group [get_clocks { FPGA_CLK2_50 }] \ 22 | -group [get_clocks { FPGA_CLK3_50 }] 23 | 24 | set_false_path -from [get_ports {KEY*}] 25 | set_false_path -from [get_ports {BTN_*}] 26 | set_false_path -to [get_ports {LED_*}] 27 | set_false_path -to [get_ports {VGA_*}] 28 | set_false_path -from [get_ports {VGA_EN}] 29 | set_false_path -to [get_ports {AUDIO_SPDIF}] 30 | set_false_path -to [get_ports {AUDIO_L}] 31 | set_false_path -to [get_ports {AUDIO_R}] 32 | set_false_path -from {get_ports {SW[*]}} 33 | set_false_path -to {cfg[*]} 34 | set_false_path -from {cfg[*]} 35 | set_false_path -from {VSET[*]} 36 | set_false_path -to {wcalc[*] hcalc[*]} 37 | set_false_path -to {hdmi_width[*] hdmi_height[*]} 38 | set_false_path -to {deb_* btn_en btn_up} 39 | 40 | set_multicycle_path -to {*_osd|osd_vcnt*} -setup 2 41 | set_multicycle_path -to {*_osd|osd_vcnt*} -hold 1 42 | 43 | set_false_path -to {*_osd|v_cnt*} 44 | set_false_path -to {*_osd|v_osd_start*} 45 | set_false_path -to {*_osd|v_info_start*} 46 | set_false_path -to {*_osd|h_osd_start*} 47 | set_false_path -from {*_osd|v_osd_start*} 48 | set_false_path -from {*_osd|v_info_start*} 49 | set_false_path -from {*_osd|h_osd_start*} 50 | set_false_path -from {*_osd|rot*} 51 | set_false_path -from {*_osd|dsp_width*} 52 | set_false_path -to {*_osd|half} 53 | 54 | set_false_path -to {WIDTH[*] HFP[*] HS[*] HBP[*] HEIGHT[*] VFP[*] VS[*] VBP[*]} 55 | set_false_path -from {WIDTH[*] HFP[*] HS[*] HBP[*] HEIGHT[*] VFP[*] VS[*] VBP[*]} 56 | set_false_path -to {FB_BASE[*] FB_BASE[*] FB_WIDTH[*] FB_HEIGHT[*] LFB_HMIN[*] LFB_HMAX[*] LFB_VMIN[*] LFB_VMAX[*]} 57 | set_false_path -from {FB_BASE[*] FB_BASE[*] FB_WIDTH[*] FB_HEIGHT[*] LFB_HMIN[*] LFB_HMAX[*] LFB_VMIN[*] LFB_VMAX[*]} 58 | set_false_path -to {vol_att[*] scaler_flt[*] led_overtake[*] led_state[*]} 59 | set_false_path -from {vol_att[*] scaler_flt[*] led_overtake[*] led_state[*]} 60 | set_false_path -from {aflt_* acx* acy* areset* arc*} 61 | set_false_path -from {arx* ary*} 62 | set_false_path -from {vs_line*} 63 | set_false_path -from {ColorBurst_Range* PhaseInc* pal_en cvbs yc_en} 64 | 65 | set_false_path -from {ascal|o_ihsize*} 66 | set_false_path -from {ascal|o_ivsize*} 67 | set_false_path -from {ascal|o_format*} 68 | set_false_path -from {ascal|o_hdown} 69 | set_false_path -from {ascal|o_vdown} 70 | set_false_path -from {ascal|o_hmin* ascal|o_hmax* ascal|o_vmin* ascal|o_vmax* ascal|o_vrrmax* ascal|o_vrr} 71 | set_false_path -from {ascal|o_hdisp* ascal|o_vdisp*} 72 | set_false_path -from {ascal|o_htotal* ascal|o_vtotal*} 73 | set_false_path -from {ascal|o_hsstart* ascal|o_vsstart* ascal|o_hsend* ascal|o_vsend*} 74 | set_false_path -from {ascal|o_hsize* ascal|o_vsize*} 75 | 76 | set_false_path -from {mcp23009|flg_*} 77 | set_false_path -to {sysmem|fpga_interfaces|clocks_resets|f2h*} 78 | -------------------------------------------------------------------------------- /software/oxo.tap: -------------------------------------------------------------------------------- 1 |                                                                                                                                                                                        -------------------------------------------------------------------------------- /software/pg51b.tap: -------------------------------------------------------------------------------- 1 |                                              2 |       -------------------------------------------------------------------------------- /software/conway.tap: -------------------------------------------------------------------------------- 1 |    2 |  3 |                                                                                             -------------------------------------------------------------------------------- /software/cubes.tap: -------------------------------------------------------------------------------- 1 |          2 |  3 |              -------------------------------------------------------------------------------- /software/mandelbrot.tap: -------------------------------------------------------------------------------- 1 |      2 |                                                                                                                                              -------------------------------------------------------------------------------- /software/sieve.tap: -------------------------------------------------------------------------------- 1 |                                                                 2 |  3 |  -------------------------------------------------------------------------------- /software/squares_e0.tap: -------------------------------------------------------------------------------- 1 |                                                                                    -------------------------------------------------------------------------------- /software/wada.tap: -------------------------------------------------------------------------------- 1 |                       2 |  3 |                                        -------------------------------------------------------------------------------- /software/airy.tap: -------------------------------------------------------------------------------- 1 |                      2 |                    3 |            4 |         5 |   -------------------------------------------------------------------------------- /software/chapmanxsinx.tap: -------------------------------------------------------------------------------- 1 |                                      2 |  3 |                       4 |            5 |         6 |                                                   -------------------------------------------------------------------------------- /software/doddglennie.tap: -------------------------------------------------------------------------------- 1 |  2 |                         3 |            4 |         5 |   6 |                                                                    -------------------------------------------------------------------------------- /rtl/adpcm_decoder.v: -------------------------------------------------------------------------------- 1 | /* 2 | Implementation is done according to specifications that can be found at https://multimedia.cx/mirror/dialogic-adpcm.pdf 3 | 4 | Most important segments, quote: 5 | 6 | The decoder computes the difference between the previous linear output estimate and the anticipated one. 7 | This difference is added to the previous estimate to produce the linear output estimate. The input ADPCM 8 | sample is also presented to the step size calculator to compute the step size estimate 9 | 10 | The decoder accepts ADPCM code values, L(n), and step size values. It calculates a reproduced differential 11 | value, and accumulates an estimated waveform value, X. Here is a pseudocode algorithm: 12 | 13 | d(n) = (ss(n)*B2)+(ss(n)/2*B1)+(ss(n)/4*BO)+(ss(n)/8) 14 | if (B3 = 1) 15 | then d(n) = d(n) * (-1) 16 | X(n) = X(n-1) + d(n) 17 | 18 | ss(n+1) = ss(n) * 1.1M(L(n)) 19 | -> Calculated from a lookup table 20 | 21 | Initial conditions: When the ADPCM algorithm is reset, the step size ss(n) is set to the minimum value (16) and the 22 | estimated waveform value X is set to zero (half scale) 23 | */ 24 | 25 | module adpcm_decoder ( 26 | input reset, 27 | input clock, 28 | input [3:0] in_pcm, 29 | output reg signed [11:0] sample 30 | ); 31 | 32 | reg signed [11:0] differential_value; 33 | reg signed [6:0] index, delta; 34 | reg [10:0] step, pr_step; 35 | reg [15:0] pcm; 36 | 37 | wire signed [11:0] estimation = pcm[15] ? sample + differential_value : sample - differential_value; 38 | 39 | always @(posedge clock) 40 | begin 41 | if(reset) begin 42 | delta <= 7'd0; sample <= 12'd0; differential_value <= 12'd0; 43 | index <= 7'd0; step <= 11'd0; pr_step <= 11'd0; pcm <= 16'd0; 44 | end 45 | 46 | else begin 47 | 48 | pcm <= {pcm[11:0], in_pcm[3:0]}; 49 | pr_step <= step; 50 | 51 | case (in_pcm[2:0]) 52 | 3'b000: delta <= -7'd1; 3'b001: delta <= -7'd1; 3'b010: delta <= -7'd1; 3'b011: delta <= -7'd1; 53 | 3'b100: delta <= 7'd2; 3'b101: delta <= 7'd4; 3'b110: delta <= 7'd6; 3'b111: delta <= 7'd8; 54 | endcase 55 | 56 | if (index + delta < 0) index <= 0; 57 | else if (index + delta > 48) index <= 48; 58 | else index <= index + delta; 59 | 60 | case (index) 61 | 7'd00: step <= 11'd16; 7'd01: step <= 11'd17; 7'd02: step <= 11'd19; 7'd03: step <= 11'd21; 62 | 7'd04: step <= 11'd23; 7'd05: step <= 11'd25; 7'd06: step <= 11'd28; 7'd07: step <= 11'd31; 63 | 7'd08: step <= 11'd34; 7'd09: step <= 11'd37; 7'd10: step <= 11'd41; 7'd11: step <= 11'd45; 64 | 7'd12: step <= 11'd50; 7'd13: step <= 11'd55; 7'd14: step <= 11'd60; 7'd15: step <= 11'd66; 65 | 7'd16: step <= 11'd73; 7'd17: step <= 11'd80; 7'd18: step <= 11'd88; 7'd19: step <= 11'd97; 66 | 7'd20: step <= 11'd107; 7'd21: step <= 11'd118; 7'd22: step <= 11'd130; 7'd23: step <= 11'd143; 67 | 7'd24: step <= 11'd157; 7'd25: step <= 11'd173; 7'd26: step <= 11'd190; 7'd27: step <= 11'd209; 68 | 7'd28: step <= 11'd230; 7'd29: step <= 11'd253; 7'd30: step <= 11'd279; 7'd31: step <= 11'd307; 69 | 7'd32: step <= 11'd337; 7'd33: step <= 11'd371; 7'd34: step <= 11'd408; 7'd35: step <= 11'd449; 70 | 7'd36: step <= 11'd494; 7'd37: step <= 11'd544; 7'd38: step <= 11'd598; 7'd39: step <= 11'd658; 71 | 7'd40: step <= 11'd724; 7'd41: step <= 11'd796; 7'd42: step <= 11'd876; 7'd43: step <= 11'd963; 72 | 7'd44: step <= 11'd1060; 7'd45: step <= 11'd1166; 7'd46: step <= 11'd1282; 7'd47: step <= 11'd1411; 73 | 7'd48: step <= 11'd1552; 74 | default: step <= 11'd1552; 75 | endcase 76 | 77 | differential_value <= {pcm[10] ? pr_step : 12'd0} + {pcm[9] ? (pr_step>>1) : 12'd0} + {pcm[8] ? (pr_step>>2) : 12'd0} + (pr_step>>3); 78 | 79 | if ($signed(estimation) > $signed(2047)) sample <= 12'd2047; 80 | else if ($signed(estimation) < $signed(-2048)) sample <= -12'd2048; 81 | else sample <= estimation; 82 | 83 | end 84 | end 85 | endmodule 86 | -------------------------------------------------------------------------------- /sys/shadowmask.sv: -------------------------------------------------------------------------------- 1 | module shadowmask 2 | ( 3 | input clk, 4 | input clk_sys, 5 | 6 | input cmd_wr, 7 | input [15:0] cmd_in, 8 | 9 | input [23:0] din, 10 | input hs_in,vs_in, 11 | input de_in, 12 | input brd_in, 13 | input enable, 14 | 15 | output reg [23:0] dout, 16 | output reg hs_out,vs_out, 17 | output reg de_out 18 | ); 19 | 20 | 21 | reg [4:0] hmax; 22 | reg [4:0] vmax; 23 | reg [7:0] mask_idx; 24 | reg mask_2x; 25 | reg mask_rotate; 26 | reg mask_enable; 27 | reg [10:0] mask_lut[256]; 28 | 29 | always @(posedge clk) begin 30 | reg [4:0] hcount; 31 | reg [4:0] vcount; 32 | reg [3:0] hindex; 33 | reg [3:0] vindex; 34 | reg [4:0] hmax2; 35 | reg [4:0] vmax2; 36 | reg [11:0] pcnt,pde; 37 | reg old_hs, old_vs, old_brd; 38 | reg next_v; 39 | 40 | old_hs <= hs_in; 41 | old_vs <= vs_in; 42 | old_brd<= brd_in; 43 | 44 | // hcount and vcount counts pixel rows and columns 45 | // hindex and vindex half the value of the counters for double size patterns 46 | // hindex2, vindex2 swap the h and v counters for drawing rotated masks 47 | hindex <= mask_2x ? hcount[4:1] : hcount[3:0]; 48 | vindex <= mask_2x ? vcount[4:1] : vcount[3:0]; 49 | mask_idx <= mask_rotate ? {hindex,vindex} : {vindex,hindex}; 50 | 51 | // hmax and vmax store these sizes 52 | // hmax2 and vmax2 swap the values to handle rotation 53 | hmax2 <= ((mask_rotate ? vmax : hmax) << mask_2x) | mask_2x; 54 | vmax2 <= ((mask_rotate ? hmax : vmax) << mask_2x) | mask_2x; 55 | 56 | pcnt <= pcnt+1'd1; 57 | if(old_brd && ~brd_in) pde <= pcnt-4'd3; 58 | 59 | hcount <= hcount+1'b1; 60 | if(hcount == hmax2 || pde == pcnt) hcount <= 0; 61 | 62 | if(~old_brd && brd_in) next_v <= 1; 63 | if(old_vs && ~vs_in) vcount <= 0; 64 | if(old_hs && ~hs_in) begin 65 | vcount <= vcount + next_v; 66 | next_v <= 0; 67 | pcnt <= 0; 68 | if (vcount == vmax2) vcount <= 0; 69 | end 70 | end 71 | 72 | reg [4:0] r_mul, g_mul, b_mul; // 1.4 fixed point multipliers 73 | always @(posedge clk) begin 74 | reg [10:0] lut; 75 | 76 | lut <= mask_lut[mask_idx]; 77 | 78 | r_mul <= 5'b10000; g_mul <= 5'b10000; b_mul <= 5'b10000; // default 100% to all channels 79 | if (mask_enable) begin 80 | r_mul <= lut[10] ? {1'b1,lut[7:4]} : {1'b0,lut[3:0]}; 81 | g_mul <= lut[9] ? {1'b1,lut[7:4]} : {1'b0,lut[3:0]}; 82 | b_mul <= lut[8] ? {1'b1,lut[7:4]} : {1'b0,lut[3:0]}; 83 | end 84 | end 85 | 86 | always @(posedge clk) begin 87 | reg [11:0] vid; 88 | reg [7:0] r1, g1, b1; 89 | reg [7:0] r2, g2, b2; 90 | reg [7:0] r3_x, g3_x, b3_x; // 6.25% + 12.5% 91 | reg [8:0] r3_y, g3_y, b3_y; // 25% + 50% + 100% 92 | reg [8:0] r4, g4, b4; 93 | 94 | // C1 - data input 95 | {r1,g1,b1} <= din; 96 | vid <= {vid[8:0],vs_in, hs_in, de_in}; 97 | 98 | // C2 - relax timings 99 | {r2,g2,b2} <= {r1,g1,b1}; 100 | 101 | // C3 - perform multiplications 102 | r3_x <= ({4{r_mul[0]}} & r2[7:4]) + ({8{r_mul[1]}} & r2[7:3]); 103 | r3_y <= ({6{r_mul[2]}} & r2[7:2]) + ({7{r_mul[3]}} & r2[7:1]) + ({9{r_mul[4]}} & r2[7:0]); 104 | g3_x <= ({4{g_mul[0]}} & g2[7:4]) + ({8{g_mul[1]}} & g2[7:3]); 105 | g3_y <= ({6{g_mul[2]}} & g2[7:2]) + ({7{g_mul[3]}} & g2[7:1]) + ({9{g_mul[4]}} & g2[7:0]); 106 | b3_x <= ({4{b_mul[0]}} & b2[7:4]) + ({8{b_mul[1]}} & b2[7:3]); 107 | b3_y <= ({6{b_mul[2]}} & b2[7:2]) + ({7{b_mul[3]}} & b2[7:1]) + ({9{b_mul[4]}} & b2[7:0]); 108 | 109 | // C4 - combine results 110 | r4 <= r3_x + r3_y; 111 | g4 <= g3_x + g3_y; 112 | b4 <= b3_x + b3_y; 113 | 114 | // C5 - clamp and output 115 | dout <= {{8{r4[8]}} | r4[7:0], {8{g4[8]}} | g4[7:0], {8{b4[8]}} | b4[7:0]}; 116 | {vs_out,hs_out,de_out} <= vid[11:9]; 117 | end 118 | 119 | // clock in mask commands 120 | always @(posedge clk_sys) begin 121 | reg m_enable; 122 | reg [7:0] idx; 123 | 124 | if (cmd_wr) begin 125 | case(cmd_in[15:13]) 126 | 3'b000: begin {m_enable, mask_rotate, mask_2x} <= cmd_in[3:1]; idx <= 0; end 127 | 3'b001: vmax <= cmd_in[3:0]; 128 | 3'b010: hmax <= cmd_in[3:0]; 129 | 3'b011: begin mask_lut[idx] <= cmd_in[10:0]; idx <= idx + 1'd1; end 130 | endcase 131 | end 132 | 133 | mask_enable <= m_enable & enable; 134 | end 135 | 136 | endmodule 137 | -------------------------------------------------------------------------------- /sys/ltc2308.sv: -------------------------------------------------------------------------------- 1 | //============================================================================ 2 | // 3 | // LTC2308 controller 4 | // Copyright (C) 2019 Sorgelig 5 | // 6 | // 7 | // This program is free software; you can redistribute it and/or modify it 8 | // under the terms of the GNU General Public License as published by the Free 9 | // Software Foundation; either version 2 of the License, or (at your option) 10 | // any later version. 11 | // 12 | // This program is distributed in the hope that it will be useful, but WITHOUT 13 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 | // more details. 16 | // 17 | // You should have received a copy of the GNU General Public License along 18 | // with this program; if not, write to the Free Software Foundation, Inc., 19 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | // 21 | //============================================================================ 22 | 23 | 24 | // NUM_CH 1..8 25 | // Sampling rate = ADC_RATE/NUM_CH 26 | // ADC_RATE max is ~500KHz 27 | // CLK_RATE max is ~80MHz 28 | module ltc2308 #(parameter NUM_CH = 2, ADC_RATE = 96000, CLK_RATE = 50000000) 29 | ( 30 | input reset, 31 | input clk, 32 | 33 | inout [3:0] ADC_BUS, 34 | 35 | output reg dout_sync, // toggle with every ADC round 36 | output reg [(NUM_CH*12)-1:0] dout // 12 bits per channel (unsigned) 37 | ); 38 | 39 | localparam TCONV = CLK_RATE/625000; 40 | 41 | reg sck; 42 | wire sdo = cfg[5]; 43 | 44 | assign ADC_BUS[3] = sck; 45 | wire sdi = ADC_BUS[2]; 46 | assign ADC_BUS[1] = sdo; 47 | assign ADC_BUS[0] = convst; 48 | 49 | reg convst; 50 | reg [5:0] cfg; 51 | 52 | reg [31:0] sum; 53 | wire [31:0] next_sum = sum + ADC_RATE; 54 | 55 | reg [2:0] pin; 56 | wire [2:0] next_pin = (pin == (NUM_CH-1)) ? 3'd0 : (pin + 1'd1); 57 | 58 | always @(posedge clk) begin 59 | reg [7:0] tconv; 60 | reg [3:0] bitcnt; 61 | reg [10:0] adcin; 62 | 63 | convst <= 0; 64 | 65 | if(reset) begin 66 | sum <= 0; 67 | tconv <= 0; 68 | bitcnt <= 0; 69 | sck <= 0; 70 | cfg <= 0; 71 | dout <= 0; 72 | pin <= NUM_CH[2:0]-1'd1; 73 | end 74 | else begin 75 | sum <= next_sum; 76 | if(next_sum >= CLK_RATE) begin 77 | sum <= next_sum - CLK_RATE; 78 | tconv <= TCONV[7:0]; 79 | convst <= 1; 80 | bitcnt <= 12; 81 | cfg <= {1'b1, next_pin[0], next_pin[2:1], 1'b1, 1'b0}; 82 | if(!next_pin) dout_sync <= ~dout_sync; 83 | end 84 | 85 | if(tconv) tconv <= tconv - 1'd1; 86 | else if(bitcnt) begin 87 | sck <= ~sck; 88 | 89 | if(sck) cfg <= cfg<<1; 90 | else begin 91 | adcin <= {adcin[9:0],sdi}; 92 | bitcnt <= bitcnt - 1'd1; 93 | if(bitcnt == 1) begin 94 | dout[pin*12 +:12] <= {adcin,sdi}; 95 | pin <= next_pin; 96 | end 97 | end 98 | end 99 | else sck <= 0; 100 | end 101 | end 102 | 103 | endmodule 104 | 105 | module ltc2308_tape #(parameter HIST_LOW = 16, HIST_HIGH = 64, ADC_RATE = 48000, CLK_RATE = 50000000, NUM_CH = 1) 106 | ( 107 | input reset, 108 | input clk, 109 | 110 | inout [3:0] ADC_BUS, 111 | output reg dout, 112 | output active, 113 | output adc_sync, 114 | output [(NUM_CH*12)-1:0] adc_data 115 | ); 116 | 117 | ltc2308 #(NUM_CH, ADC_RATE, CLK_RATE) adc 118 | ( 119 | .reset(reset), 120 | .clk(clk), 121 | 122 | .ADC_BUS(ADC_BUS), 123 | .dout(adc_data), 124 | .dout_sync(adc_sync) 125 | ); 126 | 127 | always @(posedge clk) begin 128 | reg [13:0] data1,data2,data3,data4, sum; 129 | reg adc_sync_d; 130 | 131 | adc_sync_d<=adc_sync; 132 | if(adc_sync_d ^ adc_sync) begin 133 | data1 <= data2; 134 | data2 <= data3; 135 | data3 <= data4; 136 | data4 <= adc_data[11:0]; 137 | 138 | sum <= data1+data2+data3+data4; 139 | 140 | if(sum[13:2]HIST_HIGH) dout <= 1; 142 | end 143 | end 144 | 145 | assign active = |act; 146 | 147 | reg [1:0] act; 148 | always @(posedge clk) begin 149 | reg [31:0] onesec; 150 | reg old_dout; 151 | 152 | onesec <= onesec + 1; 153 | if(onesec>CLK_RATE) begin 154 | onesec <= 0; 155 | if(act) act <= act - 1'd1; 156 | end 157 | 158 | old_dout <= dout; 159 | if(old_dout ^ dout) act <= 2; 160 | end 161 | 162 | endmodule 163 | -------------------------------------------------------------------------------- /sys/alsa.sv: -------------------------------------------------------------------------------- 1 | //============================================================================ 2 | // 3 | // ALSA sound support for MiSTer 4 | // (c)2019,2020 Alexey Melnikov 5 | // 6 | // This program is free software; you can redistribute it and/or modify it 7 | // under the terms of the GNU General Public License as published by the Free 8 | // Software Foundation; either version 2 of the License, or (at your option) 9 | // any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, but WITHOUT 12 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 | // more details. 15 | // 16 | // You should have received a copy of the GNU General Public License along 17 | // with this program; if not, write to the Free Software Foundation, Inc., 18 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | // 20 | //============================================================================ 21 | 22 | module alsa 23 | #( 24 | parameter CLK_RATE = 24576000 25 | ) 26 | ( 27 | input reset, 28 | input clk, 29 | 30 | output reg [31:3] ram_address, 31 | input [63:0] ram_data, 32 | output reg ram_req = 0, 33 | input ram_ready, 34 | 35 | input spi_ss, 36 | input spi_sck, 37 | input spi_mosi, 38 | output spi_miso, 39 | 40 | output reg [15:0] pcm_l, 41 | output reg [15:0] pcm_r 42 | ); 43 | 44 | reg [60:0] buf_info; 45 | reg [6:0] spicnt = 0; 46 | always @(posedge spi_sck, posedge spi_ss) begin 47 | reg [95:0] spi_data; 48 | 49 | if(spi_ss) spicnt <= 0; 50 | else begin 51 | spi_data[{spicnt[6:3],~spicnt[2:0]}] <= spi_mosi; 52 | if(&spicnt) buf_info <= {spi_data[82:67],spi_data[50:35],spi_data[31:3]}; 53 | spicnt <= spicnt + 1'd1; 54 | end 55 | end 56 | 57 | assign spi_miso = spi_out[{spicnt[4:3],~spicnt[2:0]}]; 58 | 59 | reg [31:0] spi_out = 0; 60 | always @(posedge clk) if(spi_ss) spi_out <= {buf_rptr, hurryup, 8'h00}; 61 | 62 | 63 | reg [31:3] buf_addr; 64 | reg [18:3] buf_len; 65 | reg [18:3] buf_wptr = 0; 66 | 67 | always @(posedge clk) begin 68 | reg [60:0] data1,data2; 69 | 70 | data1 <= buf_info; 71 | data2 <= data1; 72 | if(data2 == data1) {buf_wptr,buf_len,buf_addr} <= data2; 73 | end 74 | 75 | reg [2:0] hurryup = 0; 76 | reg [18:3] buf_rptr = 0; 77 | 78 | always @(posedge clk) begin 79 | reg [18:3] len = 0; 80 | reg [1:0] ready = 0; 81 | reg [63:0] readdata; 82 | reg got_first = 0; 83 | reg [7:0] ce_cnt = 0; 84 | reg [1:0] state = 0; 85 | 86 | if(reset) begin 87 | ready <= 0; 88 | ce_cnt <= 0; 89 | state <= 0; 90 | got_first <= 0; 91 | len <= 0; 92 | end 93 | else begin 94 | 95 | //ramp up 96 | if(len[18:14] && (hurryup < 1)) hurryup <= 1; 97 | if(len[18:16] && (hurryup < 2)) hurryup <= 2; 98 | if(len[18:17] && (hurryup < 4)) hurryup <= 4; 99 | 100 | //ramp down 101 | if(!len[18:15] && (hurryup > 2)) hurryup <= 2; 102 | if(!len[18:13] && (hurryup > 1)) hurryup <= 1; 103 | if(!len[18:10]) hurryup <= 0; 104 | 105 | if(ce_sample && ~&ce_cnt) ce_cnt <= ce_cnt + 1'd1; 106 | 107 | case(state) 108 | 0: if(!ce_sample) begin 109 | if(ready) begin 110 | if(ce_cnt) begin 111 | {readdata[31:0],pcm_r,pcm_l} <= readdata; 112 | ready <= ready - 1'd1; 113 | ce_cnt <= ce_cnt - 1'd1; 114 | end 115 | end 116 | else if(buf_rptr != buf_wptr) begin 117 | if(~got_first) begin 118 | buf_rptr <= buf_wptr; 119 | got_first <= 1; 120 | end 121 | else begin 122 | ram_address <= buf_addr + buf_rptr; 123 | ram_req <= ~ram_req; 124 | buf_rptr <= buf_rptr + 1'd1; 125 | len <= (buf_wptr < buf_rptr) ? (buf_len + buf_wptr - buf_rptr) : (buf_wptr - buf_rptr); 126 | state <= 1; 127 | end 128 | end 129 | else begin 130 | len <= 0; 131 | ce_cnt <= 0; 132 | hurryup <= 0; 133 | end 134 | end 135 | 1: if(ram_ready) begin 136 | ready <= 2; 137 | readdata <= ram_data; 138 | if(buf_rptr >= buf_len) buf_rptr <= buf_rptr - buf_len; 139 | state <= 0; 140 | end 141 | endcase 142 | end 143 | end 144 | 145 | reg ce_sample; 146 | always @(posedge clk) begin 147 | reg [31:0] acc = 0; 148 | 149 | ce_sample <= 0; 150 | acc <= acc + 48000 + {hurryup,6'd0}; 151 | if(acc >= CLK_RATE) begin 152 | acc <= acc - CLK_RATE; 153 | ce_sample <= 1; 154 | end 155 | end 156 | 157 | endmodule 158 | -------------------------------------------------------------------------------- /sys/pll_cfg/pll_cfg.v: -------------------------------------------------------------------------------- 1 | // megafunction wizard: %Altera PLL Reconfig v17.0% 2 | // GENERATION: XML 3 | // pll_cfg.v 4 | 5 | // Generated using ACDS version 17.0 598 6 | 7 | `timescale 1 ps / 1 ps 8 | module pll_cfg #( 9 | parameter ENABLE_BYTEENABLE = 0, 10 | parameter BYTEENABLE_WIDTH = 4, 11 | parameter RECONFIG_ADDR_WIDTH = 6, 12 | parameter RECONFIG_DATA_WIDTH = 32, 13 | parameter reconf_width = 64, 14 | parameter WAIT_FOR_LOCK = 1 15 | ) ( 16 | input wire mgmt_clk, // mgmt_clk.clk 17 | input wire mgmt_reset, // mgmt_reset.reset 18 | output wire mgmt_waitrequest, // mgmt_avalon_slave.waitrequest 19 | input wire mgmt_read, // .read 20 | input wire mgmt_write, // .write 21 | output wire [31:0] mgmt_readdata, // .readdata 22 | input wire [5:0] mgmt_address, // .address 23 | input wire [31:0] mgmt_writedata, // .writedata 24 | output wire [63:0] reconfig_to_pll, // reconfig_to_pll.reconfig_to_pll 25 | input wire [63:0] reconfig_from_pll // reconfig_from_pll.reconfig_from_pll 26 | ); 27 | 28 | altera_pll_reconfig_top #( 29 | .device_family ("Cyclone V"), 30 | .ENABLE_MIF (0), 31 | .MIF_FILE_NAME ("sys/pll_cfg.mif"), 32 | .ENABLE_BYTEENABLE (ENABLE_BYTEENABLE), 33 | .BYTEENABLE_WIDTH (BYTEENABLE_WIDTH), 34 | .RECONFIG_ADDR_WIDTH (RECONFIG_ADDR_WIDTH), 35 | .RECONFIG_DATA_WIDTH (RECONFIG_DATA_WIDTH), 36 | .reconf_width (reconf_width), 37 | .WAIT_FOR_LOCK (WAIT_FOR_LOCK) 38 | ) pll_cfg_inst ( 39 | .mgmt_clk (mgmt_clk), // mgmt_clk.clk 40 | .mgmt_reset (mgmt_reset), // mgmt_reset.reset 41 | .mgmt_waitrequest (mgmt_waitrequest), // mgmt_avalon_slave.waitrequest 42 | .mgmt_read (mgmt_read), // .read 43 | .mgmt_write (mgmt_write), // .write 44 | .mgmt_readdata (mgmt_readdata), // .readdata 45 | .mgmt_address (mgmt_address), // .address 46 | .mgmt_writedata (mgmt_writedata), // .writedata 47 | .reconfig_to_pll (reconfig_to_pll), // reconfig_to_pll.reconfig_to_pll 48 | .reconfig_from_pll (reconfig_from_pll), // reconfig_from_pll.reconfig_from_pll 49 | .mgmt_byteenable (4'b0000) // (terminated) 50 | ); 51 | 52 | endmodule 53 | // Retrieval info: 54 | // 79 | // Retrieval info: 80 | // Retrieval info: 81 | // Retrieval info: 82 | // Retrieval info: 83 | // Retrieval info: 84 | // Retrieval info: 85 | // IPFS_FILES : pll_cfg.vo 86 | // RELATED_FILES: pll_cfg.v, altera_pll_reconfig_top.v, altera_pll_reconfig_core.v, altera_std_synchronizer.v 87 | -------------------------------------------------------------------------------- /util.sv: -------------------------------------------------------------------------------- 1 | parameter i_P = 5'b0; 2 | 3 | parameter 4 | i_E = 5'b00011, /* Conditional branch */ 5 | i_R = 5'b00100, /* Shift */ 6 | i_T = 5'b00101, /* Store */ 7 | i_Y = 5'b00110, /* Round */ 8 | i_U = 5'b00111, /* Store */ 9 | i_I = 5'b01000, /* Read */ 10 | i_O = 5'b01001, /* Output/Print */ 11 | i_S = 5'b01100, /* Subtract */ 12 | i_Z = 5'b01101, /* Stop and ring */ 13 | i_F = 5'b10001, /* Reread */ 14 | i_H = 5'b10101, /* Copy */ 15 | i_N = 5'b10110, /* Multiply */ 16 | i_L = 5'b11001, /* Shift */ 17 | i_X = 5'b11010, /* NOP */ 18 | i_G = 5'b11011, /* Conditional Branch */ 19 | i_A = 5'b11100, /* Add */ 20 | i_C = 5'b11110, /* Collate (And) */ 21 | i_V = 5'b11111; /* Multiply */ 22 | 23 | 24 | parameter 25 | SHORT = 1'b0, /* Short (17 bit) addressing mode */ 26 | LONG = 1'b1; /* Long (35 bit) addressing mode */ 27 | 28 | 29 | function [0:0] is_circle_8; /* Lookup table to decide if a (x, y) coordinate is within a circle of radius 8. */ 30 | input [3:0] coord_x; /* Contains only data for the first quadrant, and transforms other quadrants accordingly */ 31 | input [3:0] coord_y; 32 | begin 33 | /* Translate everything into the first quadrant */ 34 | if (coord_x < 4'd7) coord_x = ~coord_x; 35 | if (coord_y > 4'd7) coord_y = ~coord_y; 36 | 37 | case (coord_y) 38 | 4'd4: is_circle_8 = coord_x < 4'd15; 39 | 4'd3: is_circle_8 = coord_x < 4'd15; 40 | 4'd2: is_circle_8 = coord_x < 4'd14; 41 | 4'd1: is_circle_8 = coord_x < 4'd13; 42 | 4'd0: is_circle_8 = coord_x < 4'd11; 43 | default: is_circle_8 = 1'b1; 44 | endcase 45 | end 46 | 47 | endfunction 48 | 49 | function [0:0] is_circle_12; /* Lookup table to decide if a (x, y) coordinate is within a circle. */ 50 | input [4:0] coord_x; /* Contains only data for the first quadrant, and transforms other quadrants accordingly */ 51 | input [4:0] coord_y; 52 | begin 53 | /* Translate everything into the first quadrant */ 54 | if (coord_x < 5'd16) coord_x = ~coord_x; 55 | if (coord_y > 5'd16) coord_y = ~coord_y; 56 | 57 | case (coord_y) 58 | 5'd16: is_circle_12 = coord_x < 5'd23; 59 | 5'd15: is_circle_12 = coord_x < 5'd23; 60 | 5'd14: is_circle_12 = coord_x < 5'd23; 61 | 5'd13: is_circle_12 = coord_x < 5'd23; 62 | 5'd12: is_circle_12 = coord_x < 5'd23; 63 | 5'd11: is_circle_12 = coord_x < 5'd22; 64 | 5'd10: is_circle_12 = coord_x < 5'd22; 65 | 5'd9: is_circle_12 = coord_x < 5'd21; 66 | 5'd8: is_circle_12 = coord_x < 5'd19; 67 | default: is_circle_12 = 1'b0; 68 | endcase 69 | end 70 | 71 | endfunction 72 | 73 | 74 | function [0:0] is_circle_16; /* Lookup table to decide if a (x, y) coordinate is within a circle of radius 16. */ 75 | input [4:0] coord_x; /* Contains only data for the first quadrant, and transforms other quadrants accordingly */ 76 | input [4:0] coord_y; 77 | begin 78 | /* Translate everything into the first quadrant */ 79 | if (coord_x < 5'd16) coord_x = ~coord_x; 80 | if (coord_y >= 5'd16) coord_y = ~coord_y; 81 | 82 | case(coord_y) 83 | 9,10,11: is_circle_16 = coord_x < 5'd31; 84 | 8: is_circle_16 = coord_x < 5'd30; 85 | 2,3,4,5,6,7: is_circle_16 = coord_x < 5'd23 + coord_y; 86 | 1: is_circle_16 = coord_x < 5'd23; 87 | 0: is_circle_16 = coord_x < 5'd20; 88 | default: is_circle_16 = 1'b1; 89 | endcase 90 | 91 | 92 | end 93 | endfunction 94 | 95 | 96 | function [7:0] calc_pix; /* Lookup table for scope pixel luma, fading away as distance from center increases */ 97 | input [2:0] x; 98 | input [2:0] y; 99 | begin 100 | if (~x[2]) x = ~x; 101 | if (~y[2]) y = ~y; 102 | 103 | case({x[1:0], y[1:0]}) 104 | 4'b0000: calc_pix = 8'd192; 105 | 4'b0001, 4'b0100: calc_pix = 8'd160; 106 | 4'b0101: calc_pix = 8'd100; 107 | 4'b1000, 4'b0010: calc_pix = 8'd80; 108 | 4'b1001, 4'b0110: calc_pix = 8'd50; 109 | 4'b1100, 4'b0011, 4'b1010: calc_pix = 8'd30; 110 | 4'b0111, 4'b1101: calc_pix = 8'd20; 111 | 4'b1110, 4'b1011: calc_pix = 8'd10; 112 | 4'b1111: calc_pix = 8'd00; 113 | endcase 114 | 115 | end 116 | endfunction 117 | 118 | 119 | function [7:0] px_add; /* Pixel brightness addition with cap for max brightness to prevent overflow */ 120 | input [7:0] px1; 121 | input [7:0] px2; 122 | begin 123 | reg [8:0] sum = px1 + px2; 124 | return sum[8] ? 8'd255 : px1 + px2; 125 | end 126 | endfunction 127 | 128 | 129 | 130 | function [23:0] get_color; /* Only a few colors are used on the panel, so this simple palette is enough. */ 131 | input [7:0] luma; /* If luma matches one of these values, a color gets assigned. Otherwise, it stays B/W. */ 132 | begin 133 | case(luma) 134 | 8'h62: get_color = 24'hAA4400; 135 | 8'hE8: get_color = 24'hE5FF80; 136 | 8'hEA: get_color = 24'hA7A776; 137 | 138 | default: get_color = {3{luma}}; 139 | endcase 140 | end 141 | 142 | endfunction 143 | 144 | 145 | -------------------------------------------------------------------------------- /rtl/util.sv: -------------------------------------------------------------------------------- 1 | parameter i_P = 5'b0; 2 | 3 | parameter 4 | i_E = 5'b00011, /* Conditional branch */ 5 | i_R = 5'b00100, /* Shift */ 6 | i_T = 5'b00101, /* Store */ 7 | i_Y = 5'b00110, /* Round */ 8 | i_U = 5'b00111, /* Store */ 9 | i_I = 5'b01000, /* Read */ 10 | i_O = 5'b01001, /* Output/Print */ 11 | i_S = 5'b01100, /* Subtract */ 12 | i_Z = 5'b01101, /* Stop and ring */ 13 | i_F = 5'b10001, /* Reread */ 14 | i_H = 5'b10101, /* Copy */ 15 | i_N = 5'b10110, /* Multiply */ 16 | i_L = 5'b11001, /* Shift */ 17 | i_X = 5'b11010, /* NOP */ 18 | i_G = 5'b11011, /* Conditional Branch */ 19 | i_A = 5'b11100, /* Add */ 20 | i_C = 5'b11110, /* Collate (And) */ 21 | i_V = 5'b11111; /* Multiply */ 22 | 23 | 24 | parameter 25 | SHORT = 1'b0, /* Short (17 bit) addressing mode */ 26 | LONG = 1'b1; /* Long (35 bit) addressing mode */ 27 | 28 | 29 | function [0:0] is_circle_8; /* Lookup table to decide if a (x, y) coordinate is within a circle of radius 8. */ 30 | input [3:0] coord_x; /* Contains only data for the first quadrant, and transforms other quadrants accordingly */ 31 | input [3:0] coord_y; 32 | begin 33 | /* Translate everything into the first quadrant */ 34 | if (coord_x < 4'd7) coord_x = ~coord_x; 35 | if (coord_y > 4'd7) coord_y = ~coord_y; 36 | 37 | case (coord_y) 38 | 4'd4: is_circle_8 = coord_x < 4'd15; 39 | 4'd3: is_circle_8 = coord_x < 4'd15; 40 | 4'd2: is_circle_8 = coord_x < 4'd14; 41 | 4'd1: is_circle_8 = coord_x < 4'd13; 42 | 4'd0: is_circle_8 = coord_x < 4'd11; 43 | default: is_circle_8 = 1'b1; 44 | endcase 45 | end 46 | 47 | endfunction 48 | 49 | function [0:0] is_circle_12; /* Lookup table to decide if a (x, y) coordinate is within a circle. */ 50 | input [4:0] coord_x; /* Contains only data for the first quadrant, and transforms other quadrants accordingly */ 51 | input [4:0] coord_y; 52 | begin 53 | /* Translate everything into the first quadrant */ 54 | if (coord_x < 5'd16) coord_x = ~coord_x; 55 | if (coord_y > 5'd16) coord_y = ~coord_y; 56 | 57 | case (coord_y) 58 | 5'd16: is_circle_12 = coord_x < 5'd23; 59 | 5'd15: is_circle_12 = coord_x < 5'd23; 60 | 5'd14: is_circle_12 = coord_x < 5'd23; 61 | 5'd13: is_circle_12 = coord_x < 5'd23; 62 | 5'd12: is_circle_12 = coord_x < 5'd23; 63 | 5'd11: is_circle_12 = coord_x < 5'd22; 64 | 5'd10: is_circle_12 = coord_x < 5'd22; 65 | 5'd9: is_circle_12 = coord_x < 5'd21; 66 | 5'd8: is_circle_12 = coord_x < 5'd19; 67 | default: is_circle_12 = 1'b0; 68 | endcase 69 | end 70 | 71 | endfunction 72 | 73 | 74 | function [0:0] is_circle_16; /* Lookup table to decide if a (x, y) coordinate is within a circle of radius 16. */ 75 | input [4:0] coord_x; /* Contains only data for the first quadrant, and transforms other quadrants accordingly */ 76 | input [4:0] coord_y; 77 | begin 78 | /* Translate everything into the first quadrant */ 79 | if (coord_x < 5'd16) coord_x = ~coord_x; 80 | if (coord_y >= 5'd16) coord_y = ~coord_y; 81 | 82 | case(coord_y) 83 | 9,10,11: is_circle_16 = coord_x < 5'd31; 84 | 8: is_circle_16 = coord_x < 5'd30; 85 | 2,3,4,5,6,7: is_circle_16 = coord_x < 5'd23 + coord_y; 86 | 1: is_circle_16 = coord_x < 5'd23; 87 | 0: is_circle_16 = coord_x < 5'd20; 88 | default: is_circle_16 = 1'b1; 89 | endcase 90 | 91 | 92 | end 93 | endfunction 94 | 95 | 96 | function [7:0] calc_pix; /* Lookup table for scope pixel luma, fading away as distance from center increases */ 97 | input [2:0] x; 98 | input [2:0] y; 99 | begin 100 | if (~x[2]) x = ~x; 101 | if (~y[2]) y = ~y; 102 | 103 | case({x[1:0], y[1:0]}) 104 | 4'b0000: calc_pix = 8'd192; 105 | 4'b0001, 4'b0100: calc_pix = 8'd160; 106 | 4'b0101: calc_pix = 8'd100; 107 | 4'b1000, 4'b0010: calc_pix = 8'd80; 108 | 4'b1001, 4'b0110: calc_pix = 8'd50; 109 | 4'b1100, 4'b0011, 4'b1010: calc_pix = 8'd30; 110 | 4'b0111, 4'b1101: calc_pix = 8'd20; 111 | 4'b1110, 4'b1011: calc_pix = 8'd10; 112 | 4'b1111: calc_pix = 8'd00; 113 | endcase 114 | 115 | end 116 | endfunction 117 | 118 | 119 | function [7:0] px_add; /* Pixel brightness addition with cap for max brightness to prevent overflow */ 120 | input [7:0] px1; 121 | input [7:0] px2; 122 | begin 123 | reg [8:0] sum = px1 + px2; 124 | return sum[8] ? 8'd255 : px1 + px2; 125 | end 126 | endfunction 127 | 128 | 129 | 130 | function [23:0] get_color; /* Only a few colors are used on the panel, so this simple palette is enough. */ 131 | input [7:0] luma; /* If luma matches one of these values, a color gets assigned. Otherwise, it stays B/W. */ 132 | begin 133 | case(luma) 134 | 8'h62: get_color = 24'hAA4400; 135 | 8'hE8: get_color = 24'hE5FF80; 136 | 8'hEA: get_color = 24'hA7A776; 137 | 138 | default: get_color = {3{luma}}; 139 | endcase 140 | end 141 | 142 | endfunction 143 | 144 | 145 | -------------------------------------------------------------------------------- /sys/scandoubler.v: -------------------------------------------------------------------------------- 1 | // 2 | // scandoubler.v 3 | // 4 | // Copyright (c) 2015 Till Harbaum 5 | // Copyright (c) 2017-2021 Alexey Melnikov 6 | // 7 | // This source file is free software: you can redistribute it and/or modify 8 | // it under the terms of the GNU General Public License as published 9 | // by the Free Software Foundation, either version 3 of the License, or 10 | // (at your option) any later version. 11 | // 12 | // This source file is distributed in the hope that it will be useful, 13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | // GNU General Public License for more details. 16 | // 17 | // You should have received a copy of the GNU General Public License 18 | // along with this program. If not, see . 19 | 20 | // TODO: Delay vsync one line 21 | 22 | module scandoubler #(parameter LENGTH, parameter HALF_DEPTH) 23 | ( 24 | // system interface 25 | input clk_vid, 26 | input hq2x, 27 | 28 | // shifter video interface 29 | input ce_pix, 30 | input hs_in, 31 | input vs_in, 32 | input hb_in, 33 | input vb_in, 34 | input [DWIDTH:0] r_in, 35 | input [DWIDTH:0] g_in, 36 | input [DWIDTH:0] b_in, 37 | 38 | // output interface 39 | output ce_pix_out, 40 | output reg hs_out, 41 | output vs_out, 42 | output hb_out, 43 | output vb_out, 44 | output [DWIDTH:0] r_out, 45 | output [DWIDTH:0] g_out, 46 | output [DWIDTH:0] b_out 47 | ); 48 | 49 | localparam DWIDTH = HALF_DEPTH ? 3 : 7; 50 | 51 | reg [7:0] pix_len = 0; 52 | wire [7:0] pl = pix_len + 1'b1; 53 | 54 | reg [7:0] pix_in_cnt = 0; 55 | wire [7:0] pc_in = pix_in_cnt + 1'b1; 56 | reg [7:0] pixsz, pixsz2, pixsz4 = 0; 57 | 58 | reg ce_x4i, ce_x1i; 59 | always @(posedge clk_vid) begin 60 | reg old_ce, valid, hs; 61 | 62 | if(~&pix_len) pix_len <= pl; 63 | if(~&pix_in_cnt) pix_in_cnt <= pc_in; 64 | 65 | ce_x4i <= 0; 66 | ce_x1i <= 0; 67 | 68 | // use such odd comparison to place ce_x4 evenly if master clock isn't multiple of 4. 69 | if((pc_in == pixsz4) || (pc_in == pixsz2) || (pc_in == (pixsz2+pixsz4))) ce_x4i <= 1; 70 | 71 | old_ce <= ce_pix; 72 | if(~old_ce & ce_pix) begin 73 | if(valid & ~hb_in & ~vb_in) begin 74 | pixsz <= pl; 75 | pixsz2 <= {1'b0, pl[7:1]}; 76 | pixsz4 <= {2'b00, pl[7:2]}; 77 | end 78 | pix_len <= 0; 79 | valid <= 1; 80 | end 81 | 82 | hs <= hs_in; 83 | if((~hs & hs_in) || (pc_in >= pixsz)) begin 84 | ce_x4i <= 1; 85 | ce_x1i <= 1; 86 | pix_in_cnt <= 0; 87 | end 88 | 89 | if(hb_in | vb_in) valid <= 0; 90 | end 91 | 92 | reg req_line_reset; 93 | reg [DWIDTH:0] r_d, g_d, b_d; 94 | always @(posedge clk_vid) begin 95 | if(ce_x1i) begin 96 | req_line_reset <= hb_in; 97 | r_d <= r_in; 98 | g_d <= g_in; 99 | b_d <= b_in; 100 | end 101 | end 102 | 103 | Hq2x #(.LENGTH(LENGTH), .HALF_DEPTH(HALF_DEPTH)) Hq2x 104 | ( 105 | .clk(clk_vid), 106 | 107 | .ce_in(ce_x4i), 108 | .inputpixel({b_d,g_d,r_d}), 109 | .disable_hq2x(~hq2x), 110 | .reset_frame(vb_in), 111 | .reset_line(req_line_reset), 112 | 113 | .ce_out(ce_x4o), 114 | .read_y(sd_line), 115 | .hblank(hbo[0]&hbo[8]), 116 | .outpixel({b_out,g_out,r_out}) 117 | ); 118 | 119 | reg [7:0] pix_out_cnt = 0; 120 | wire [7:0] pc_out = pix_out_cnt + 1'b1; 121 | 122 | reg ce_x4o, ce_x2o; 123 | always @(posedge clk_vid) begin 124 | reg hs; 125 | 126 | if(~&pix_out_cnt) pix_out_cnt <= pc_out; 127 | 128 | ce_x4o <= 0; 129 | ce_x2o <= 0; 130 | 131 | // use such odd comparison to place ce_x4 evenly if master clock isn't multiple of 4. 132 | if((pc_out == pixsz4) || (pc_out == pixsz2) || (pc_out == (pixsz2+pixsz4))) ce_x4o <= 1; 133 | if( pc_out == pixsz2) ce_x2o <= 1; 134 | 135 | hs <= hs_out; 136 | if((~hs & hs_out) || (pc_out >= pixsz)) begin 137 | ce_x2o <= 1; 138 | ce_x4o <= 1; 139 | pix_out_cnt <= 0; 140 | end 141 | end 142 | 143 | reg [1:0] sd_line; 144 | reg [3:0] vbo; 145 | reg [3:0] vso; 146 | reg [8:0] hbo; 147 | always @(posedge clk_vid) begin 148 | 149 | reg [31:0] hcnt; 150 | reg [30:0] sd_hcnt; 151 | reg [30:0] hs_start, hs_end; 152 | reg [30:0] hde_start, hde_end; 153 | 154 | reg hs, hb; 155 | 156 | if(ce_x4o) begin 157 | hbo[8:1] <= hbo[7:0]; 158 | end 159 | 160 | // output counter synchronous to input and at twice the rate 161 | sd_hcnt <= sd_hcnt + 1'd1; 162 | if(sd_hcnt == hde_start) begin 163 | sd_hcnt <= 0; 164 | vbo[3:1] <= vbo[2:0]; 165 | end 166 | 167 | if(sd_hcnt == hs_end) begin 168 | sd_line <= sd_line + 1'd1; 169 | if(&vbo[3:2]) sd_line <= 1; 170 | vso[3:1] <= vso[2:0]; 171 | end 172 | 173 | if(sd_hcnt == hde_start)hbo[0] <= 0; 174 | if(sd_hcnt == hde_end) hbo[0] <= 1; 175 | 176 | // replicate horizontal sync at twice the speed 177 | if(sd_hcnt == hs_end) hs_out <= 0; 178 | if(sd_hcnt == hs_start) hs_out <= 1; 179 | 180 | hs <= hs_in; 181 | hb <= hb_in; 182 | 183 | hcnt <= hcnt + 1'd1; 184 | if(hb && !hb_in) begin 185 | hde_start <= hcnt[31:1]; 186 | hbo[0] <= 0; 187 | hcnt <= 0; 188 | sd_hcnt <= 0; 189 | vbo <= {vbo[2:0],vb_in}; 190 | end 191 | 192 | if(!hb && hb_in) hde_end <= hcnt[31:1]; 193 | 194 | // falling edge of hsync indicates start of line 195 | if(hs && !hs_in) begin 196 | hs_end <= hcnt[31:1]; 197 | vso[0] <= vs_in; 198 | end 199 | 200 | // save position of rising edge 201 | if(!hs && hs_in) hs_start <= hcnt[31:1]; 202 | end 203 | 204 | assign vs_out = vso[3]; 205 | assign ce_pix_out = hq2x ? ce_x4o : ce_x2o; 206 | 207 | //Compensate picture shift after HQ2x 208 | assign vb_out = vbo[3]; 209 | assign hb_out = hbo[6]; 210 | 211 | endmodule 212 | -------------------------------------------------------------------------------- /sys/video_mixer.sv: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // Copyright (c) 2017,2021 Alexey Melnikov 4 | // 5 | // This program is GPL Licensed. See COPYING for the full license. 6 | // 7 | // 8 | //////////////////////////////////////////////////////////////////////////////////////////////////////// 9 | 10 | `timescale 1ns / 1ps 11 | 12 | // 13 | // LINE_LENGTH: Length of display line in pixels when HBlank = 0; 14 | // HALF_DEPTH: If =1 then color dept is 4 bits per component 15 | // 16 | // altera message_off 10720 17 | // altera message_off 12161 18 | 19 | module video_mixer 20 | #( 21 | parameter LINE_LENGTH = 768, 22 | parameter HALF_DEPTH = 0, 23 | parameter GAMMA = 0 24 | ) 25 | ( 26 | input CLK_VIDEO, // should be multiple by (ce_pix*4) 27 | output reg CE_PIXEL, // output pixel clock enable 28 | 29 | input ce_pix, // input pixel clock or clock_enable 30 | 31 | input scandoubler, 32 | input hq2x, // high quality 2x scaling 33 | 34 | inout [21:0] gamma_bus, 35 | 36 | // color 37 | input [DWIDTH:0] R, 38 | input [DWIDTH:0] G, 39 | input [DWIDTH:0] B, 40 | 41 | // Positive pulses. 42 | input HSync, 43 | input VSync, 44 | input HBlank, 45 | input VBlank, 46 | 47 | // Freeze engine 48 | // HDMI: displays last frame 49 | // VGA: black screen with HSync and VSync 50 | input HDMI_FREEZE, 51 | output freeze_sync, 52 | 53 | // video output signals 54 | output reg [7:0] VGA_R, 55 | output reg [7:0] VGA_G, 56 | output reg [7:0] VGA_B, 57 | output reg VGA_VS, 58 | output reg VGA_HS, 59 | output reg VGA_DE 60 | ); 61 | 62 | localparam DWIDTH = HALF_DEPTH ? 3 : 7; 63 | localparam DWIDTH_SD = GAMMA ? 7 : DWIDTH; 64 | localparam HALF_DEPTH_SD = GAMMA ? 0 : HALF_DEPTH; 65 | 66 | wire frz_hs, frz_vs; 67 | wire frz_hbl, frz_vbl; 68 | video_freezer freezer 69 | ( 70 | .clk(CLK_VIDEO), 71 | .freeze(HDMI_FREEZE), 72 | .hs_in(HSync), 73 | .vs_in(VSync), 74 | .hbl_in(HBlank), 75 | .vbl_in(VBlank), 76 | .sync(freeze_sync), 77 | .hs_out(frz_hs), 78 | .vs_out(frz_vs), 79 | .hbl_out(frz_hbl), 80 | .vbl_out(frz_vbl) 81 | ); 82 | 83 | reg frz; 84 | always @(posedge CLK_VIDEO) begin 85 | reg frz1; 86 | 87 | frz1 <= HDMI_FREEZE; 88 | frz <= frz1; 89 | end 90 | 91 | generate 92 | if(GAMMA && HALF_DEPTH) begin 93 | wire [7:0] R_in = frz ? 8'd0 : {R,R}; 94 | wire [7:0] G_in = frz ? 8'd0 : {G,G}; 95 | wire [7:0] B_in = frz ? 8'd0 : {B,B}; 96 | end else begin 97 | wire [DWIDTH:0] R_in = frz ? 1'd0 : R; 98 | wire [DWIDTH:0] G_in = frz ? 1'd0 : G; 99 | wire [DWIDTH:0] B_in = frz ? 1'd0 : B; 100 | end 101 | endgenerate 102 | 103 | wire hs_g, vs_g; 104 | wire hb_g, vb_g; 105 | wire [DWIDTH_SD:0] R_gamma, G_gamma, B_gamma; 106 | 107 | generate 108 | if(GAMMA) begin 109 | assign gamma_bus[21] = 1; 110 | gamma_corr gamma( 111 | .clk_sys(gamma_bus[20]), 112 | .clk_vid(CLK_VIDEO), 113 | .ce_pix(ce_pix), 114 | 115 | .gamma_en(gamma_bus[19]), 116 | .gamma_wr(gamma_bus[18]), 117 | .gamma_wr_addr(gamma_bus[17:8]), 118 | .gamma_value(gamma_bus[7:0]), 119 | 120 | .HSync(frz_hs), 121 | .VSync(frz_vs), 122 | .HBlank(frz_hbl), 123 | .VBlank(frz_vbl), 124 | .RGB_in({R_in,G_in,B_in}), 125 | 126 | .HSync_out(hs_g), 127 | .VSync_out(vs_g), 128 | .HBlank_out(hb_g), 129 | .VBlank_out(vb_g), 130 | .RGB_out({R_gamma,G_gamma,B_gamma}) 131 | ); 132 | end else begin 133 | assign gamma_bus[21] = 0; 134 | assign {R_gamma,G_gamma,B_gamma} = {R_in,G_in,B_in}; 135 | assign {hs_g, vs_g, hb_g, vb_g} = {frz_hs, frz_vs, frz_hbl, frz_vbl}; 136 | end 137 | endgenerate 138 | 139 | wire [DWIDTH_SD:0] R_sd; 140 | wire [DWIDTH_SD:0] G_sd; 141 | wire [DWIDTH_SD:0] B_sd; 142 | wire hs_sd, vs_sd, hb_sd, vb_sd, ce_pix_sd; 143 | 144 | scandoubler #(.LENGTH(LINE_LENGTH), .HALF_DEPTH(HALF_DEPTH_SD)) sd 145 | ( 146 | .clk_vid(CLK_VIDEO), 147 | .hq2x(hq2x), 148 | 149 | .ce_pix(ce_pix), 150 | .hs_in(hs_g), 151 | .vs_in(vs_g), 152 | .hb_in(hb_g), 153 | .vb_in(vb_g), 154 | .r_in(R_gamma), 155 | .g_in(G_gamma), 156 | .b_in(B_gamma), 157 | 158 | .ce_pix_out(ce_pix_sd), 159 | .hs_out(hs_sd), 160 | .vs_out(vs_sd), 161 | .hb_out(hb_sd), 162 | .vb_out(vb_sd), 163 | .r_out(R_sd), 164 | .g_out(G_sd), 165 | .b_out(B_sd) 166 | ); 167 | 168 | wire [DWIDTH_SD:0] rt = (scandoubler ? R_sd : R_gamma); 169 | wire [DWIDTH_SD:0] gt = (scandoubler ? G_sd : G_gamma); 170 | wire [DWIDTH_SD:0] bt = (scandoubler ? B_sd : B_gamma); 171 | 172 | always @(posedge CLK_VIDEO) begin 173 | reg [7:0] r,g,b; 174 | reg hde,vde,hs,vs, old_vs; 175 | reg old_hde; 176 | reg old_ce; 177 | reg ce_osc, fs_osc; 178 | 179 | old_ce <= ce_pix; 180 | ce_osc <= ce_osc | (old_ce ^ ce_pix); 181 | 182 | old_vs <= vs; 183 | if(~old_vs & vs) begin 184 | fs_osc <= ce_osc; 185 | ce_osc <= 0; 186 | end 187 | 188 | CE_PIXEL <= scandoubler ? ce_pix_sd : fs_osc ? (~old_ce & ce_pix) : ce_pix; 189 | 190 | if(!GAMMA && HALF_DEPTH) begin 191 | r <= {rt,rt}; 192 | g <= {gt,gt}; 193 | b <= {bt,bt}; 194 | end 195 | else begin 196 | r <= rt; 197 | g <= gt; 198 | b <= bt; 199 | end 200 | 201 | hde <= scandoubler ? ~hb_sd : ~hb_g; 202 | vde <= scandoubler ? ~vb_sd : ~vb_g; 203 | vs <= scandoubler ? vs_sd : vs_g; 204 | hs <= scandoubler ? hs_sd : hs_g; 205 | 206 | if(CE_PIXEL) begin 207 | VGA_R <= r; 208 | VGA_G <= g; 209 | VGA_B <= b; 210 | 211 | VGA_VS <= vs; 212 | VGA_HS <= hs; 213 | 214 | old_hde <= hde; 215 | if(old_hde ^ hde) VGA_DE <= vde & hde; 216 | end 217 | end 218 | 219 | endmodule 220 | -------------------------------------------------------------------------------- /sys/audio_out.v: -------------------------------------------------------------------------------- 1 | 2 | module audio_out 3 | #( 4 | parameter CLK_RATE = 24576000 5 | ) 6 | ( 7 | input reset, 8 | input clk, 9 | 10 | //0 - 48KHz, 1 - 96KHz 11 | input sample_rate, 12 | 13 | input [31:0] flt_rate, 14 | input [39:0] cx, 15 | input [7:0] cx0, 16 | input [7:0] cx1, 17 | input [7:0] cx2, 18 | input [23:0] cy0, 19 | input [23:0] cy1, 20 | input [23:0] cy2, 21 | 22 | input [4:0] att, 23 | input [1:0] mix, 24 | 25 | input is_signed, 26 | input [15:0] core_l, 27 | input [15:0] core_r, 28 | 29 | input [15:0] alsa_l, 30 | input [15:0] alsa_r, 31 | 32 | // I2S 33 | output i2s_bclk, 34 | output i2s_lrclk, 35 | output i2s_data, 36 | 37 | // SPDIF 38 | output spdif, 39 | 40 | // Sigma-Delta DAC 41 | output dac_l, 42 | output dac_r 43 | ); 44 | 45 | localparam AUDIO_RATE = 48000; 46 | localparam AUDIO_DW = 16; 47 | 48 | localparam CE_RATE = AUDIO_RATE*AUDIO_DW*8; 49 | localparam FILTER_DIV = (CE_RATE/(AUDIO_RATE*32))-1; 50 | 51 | wire [31:0] real_ce = sample_rate ? {CE_RATE[30:0],1'b0} : CE_RATE[31:0]; 52 | 53 | reg mclk_ce; 54 | always @(posedge clk) begin 55 | reg [31:0] cnt; 56 | 57 | mclk_ce = 0; 58 | cnt = cnt + real_ce; 59 | if(cnt >= CLK_RATE) begin 60 | cnt = cnt - CLK_RATE; 61 | mclk_ce = 1; 62 | end 63 | end 64 | 65 | reg i2s_ce; 66 | always @(posedge clk) begin 67 | reg div; 68 | i2s_ce <= 0; 69 | if(mclk_ce) begin 70 | div <= ~div; 71 | i2s_ce <= div; 72 | end 73 | end 74 | 75 | i2s i2s 76 | ( 77 | .reset(reset), 78 | 79 | .clk(clk), 80 | .ce(i2s_ce), 81 | 82 | .sclk(i2s_bclk), 83 | .lrclk(i2s_lrclk), 84 | .sdata(i2s_data), 85 | 86 | .left_chan(al), 87 | .right_chan(ar) 88 | ); 89 | 90 | spdif toslink 91 | ( 92 | .rst_i(reset), 93 | 94 | .clk_i(clk), 95 | .bit_out_en_i(mclk_ce), 96 | 97 | .sample_i({ar,al}), 98 | .spdif_o(spdif) 99 | ); 100 | 101 | sigma_delta_dac #(15) sd_l 102 | ( 103 | .CLK(clk), 104 | .RESET(reset), 105 | .DACin({~al[15], al[14:0]}), 106 | .DACout(dac_l) 107 | ); 108 | 109 | sigma_delta_dac #(15) sd_r 110 | ( 111 | .CLK(clk), 112 | .RESET(reset), 113 | .DACin({~ar[15], ar[14:0]}), 114 | .DACout(dac_r) 115 | ); 116 | 117 | reg sample_ce; 118 | always @(posedge clk) begin 119 | reg [8:0] div = 0; 120 | reg [1:0] add = 0; 121 | 122 | div <= div + add; 123 | if(!div) begin 124 | div <= 2'd1 << sample_rate; 125 | add <= 2'd1 << sample_rate; 126 | end 127 | 128 | sample_ce <= !div; 129 | end 130 | 131 | reg flt_ce; 132 | always @(posedge clk) begin 133 | reg [31:0] cnt = 0; 134 | 135 | flt_ce = 0; 136 | cnt = cnt + {flt_rate[30:0],1'b0}; 137 | if(cnt >= CLK_RATE) begin 138 | cnt = cnt - CLK_RATE; 139 | flt_ce = 1; 140 | end 141 | end 142 | 143 | reg [15:0] cl,cr; 144 | always @(posedge clk) begin 145 | reg [15:0] cl1,cl2; 146 | reg [15:0] cr1,cr2; 147 | 148 | cl1 <= core_l; cl2 <= cl1; 149 | if(cl2 == cl1) cl <= cl2; 150 | 151 | cr1 <= core_r; cr2 <= cr1; 152 | if(cr2 == cr1) cr <= cr2; 153 | end 154 | 155 | reg a_en1 = 0, a_en2 = 0; 156 | always @(posedge clk, posedge reset) begin 157 | reg [1:0] dly1 = 0; 158 | reg [14:0] dly2 = 0; 159 | 160 | if(reset) begin 161 | dly1 <= 0; 162 | dly2 <= 0; 163 | a_en1 <= 0; 164 | a_en2 <= 0; 165 | end 166 | else begin 167 | if(flt_ce) begin 168 | if(~&dly1) dly1 <= dly1 + 1'd1; 169 | else a_en1 <= 1; 170 | end 171 | 172 | if(sample_ce) begin 173 | if(!dly2[13+sample_rate]) dly2 <= dly2 + 1'd1; 174 | else a_en2 <= 1; 175 | end 176 | end 177 | end 178 | 179 | wire [15:0] acl, acr; 180 | IIR_filter #(.use_params(0)) IIR_filter 181 | ( 182 | .clk(clk), 183 | .reset(reset), 184 | 185 | .ce(flt_ce & a_en1), 186 | .sample_ce(sample_ce), 187 | 188 | .cx(cx), 189 | .cx0(cx0), 190 | .cx1(cx1), 191 | .cx2(cx2), 192 | .cy0(cy0), 193 | .cy1(cy1), 194 | .cy2(cy2), 195 | 196 | .input_l({~is_signed ^ cl[15], cl[14:0]}), 197 | .input_r({~is_signed ^ cr[15], cr[14:0]}), 198 | .output_l(acl), 199 | .output_r(acr) 200 | ); 201 | 202 | wire [15:0] adl; 203 | DC_blocker dcb_l 204 | ( 205 | .clk(clk), 206 | .ce(sample_ce), 207 | .sample_rate(sample_rate), 208 | .mute(~a_en2), 209 | .din(acl), 210 | .dout(adl) 211 | ); 212 | 213 | wire [15:0] adr; 214 | DC_blocker dcb_r 215 | ( 216 | .clk(clk), 217 | .ce(sample_ce), 218 | .sample_rate(sample_rate), 219 | .mute(~a_en2), 220 | .din(acr), 221 | .dout(adr) 222 | ); 223 | 224 | wire [15:0] al, audio_l_pre; 225 | aud_mix_top audmix_l 226 | ( 227 | .clk(clk), 228 | .ce(sample_ce), 229 | .att(att), 230 | .mix(mix), 231 | 232 | .core_audio(adl), 233 | .pre_in(audio_r_pre), 234 | .linux_audio(alsa_l), 235 | 236 | .pre_out(audio_l_pre), 237 | .out(al) 238 | ); 239 | 240 | wire [15:0] ar, audio_r_pre; 241 | aud_mix_top audmix_r 242 | ( 243 | .clk(clk), 244 | .ce(sample_ce), 245 | .att(att), 246 | .mix(mix), 247 | 248 | .core_audio(adr), 249 | .pre_in(audio_l_pre), 250 | .linux_audio(alsa_r), 251 | 252 | .pre_out(audio_r_pre), 253 | .out(ar) 254 | ); 255 | 256 | endmodule 257 | 258 | module aud_mix_top 259 | ( 260 | input clk, 261 | input ce, 262 | 263 | input [4:0] att, 264 | input [1:0] mix, 265 | 266 | input [15:0] core_audio, 267 | input [15:0] linux_audio, 268 | input [15:0] pre_in, 269 | 270 | output reg [15:0] pre_out = 0, 271 | output reg [15:0] out = 0 272 | ); 273 | 274 | reg signed [16:0] a1, a2, a3, a4; 275 | always @(posedge clk) if (ce) begin 276 | 277 | a1 <= {core_audio[15],core_audio}; 278 | a2 <= a1 + {linux_audio[15],linux_audio}; 279 | 280 | pre_out <= a2[16:1]; 281 | 282 | case(mix) 283 | 0: a3 <= a2; 284 | 1: a3 <= $signed(a2) - $signed(a2[16:3]) + $signed(pre_in[15:2]); 285 | 2: a3 <= $signed(a2) - $signed(a2[16:2]) + $signed(pre_in[15:1]); 286 | 3: a3 <= {a2[16],a2[16:1]} + {pre_in[15],pre_in}; 287 | endcase 288 | 289 | if(att[4]) a4 <= 0; 290 | else a4 <= a3 >>> att[3:0]; 291 | 292 | //clamping 293 | out <= ^a4[16:15] ? {a4[16],{15{a4[15]}}} : a4[15:0]; 294 | end 295 | 296 | endmodule 297 | -------------------------------------------------------------------------------- /sys/iir_filter.v: -------------------------------------------------------------------------------- 1 | 2 | // 3-tap IIR filter for 2 channels. 3 | // Copyright (C) 2020 Sorgelig 4 | // 5 | // This program is free software; you can redistribute it and/or modify it 6 | // under the terms of the GNU General Public License as published by the Free 7 | // Software Foundation; either version 2 of the License, or (at your option) 8 | // any later version. 9 | // 10 | // This program is distributed in the hope that it will be useful, but WITHOUT 11 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 | // more details. 14 | // 15 | // You should have received a copy of the GNU General Public License along 16 | // with this program; if not, write to the Free Software Foundation, Inc., 17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | 19 | // 20 | // Can be converted to 2-tap (coeff_x2 = 0, coeff_y2 = 0) or 1-tap (coeff_x1,2 = 0, coeff_y1,2 = 0) 21 | // 22 | module IIR_filter 23 | #( 24 | parameter use_params = 1, // set to 1 to use following parameters, 0 for input port variables. 25 | parameter stereo = 1, // 0 for mono (input_l) 26 | 27 | parameter coeff_x = 0.00000774701983513660, // Base gain value for X. Float. Range: 0.0 ... 0.999(9) 28 | parameter coeff_x0 = 3, // Gain scale factor for X0. Integer. Range -7 ... +7 29 | parameter coeff_x1 = 3, // Gain scale factor for X1. Integer. Range -7 ... +7 30 | parameter coeff_x2 = 1, // Gain scale factor for X2. Integer. Range -7 ... +7 31 | parameter coeff_y0 = -2.96438150626551080000, // Coefficient for Y0. Float. Range -3.999(9) ... 3.999(9) 32 | parameter coeff_y1 = 2.92939452735121100000, // Coefficient for Y1. Float. Range -3.999(9) ... 3.999(9) 33 | parameter coeff_y2 = -0.96500747158831091000 // Coefficient for Y2. Float. Range -3.999(9) ... 3.999(9) 34 | ) 35 | ( 36 | input clk, 37 | input reset, 38 | 39 | input ce, // must be double of calculated rate for stereo! 40 | input sample_ce, // desired output sample rate 41 | 42 | input [39:0] cx, 43 | input [7:0] cx0, 44 | input [7:0] cx1, 45 | input [7:0] cx2, 46 | input [23:0] cy0, 47 | input [23:0] cy1, 48 | input [23:0] cy2, 49 | 50 | input [15:0] input_l, input_r, // signed samples 51 | output [15:0] output_l, output_r // signed samples 52 | ); 53 | 54 | localparam [39:0] pcoeff_x = coeff_x * 40'h8000000000; 55 | localparam [31:0] pcoeff_y0 = coeff_y0 * 24'h200000; 56 | localparam [31:0] pcoeff_y1 = coeff_y1 * 24'h200000; 57 | localparam [31:0] pcoeff_y2 = coeff_y2 * 24'h200000; 58 | 59 | wire [39:0] vcoeff = use_params ? pcoeff_x : cx; 60 | wire [23:0] vcoeff_y0 = use_params ? pcoeff_y0[23:0] : cy0; 61 | wire [23:0] vcoeff_y1 = use_params ? pcoeff_y1[23:0] : cy1; 62 | wire [23:0] vcoeff_y2 = use_params ? pcoeff_y2[23:0] : cy2; 63 | 64 | wire [59:0] inp_mul = $signed(inp) * $signed(vcoeff); 65 | 66 | wire [39:0] x = inp_mul[59:20]; 67 | wire [39:0] y = x + tap0; 68 | 69 | wire [39:0] tap0; 70 | iir_filter_tap iir_tap_0 71 | ( 72 | .clk(clk), 73 | .reset(reset), 74 | .ce(ce), 75 | .ch(ch), 76 | .cx(use_params ? coeff_x0[7:0] : cx0), 77 | .cy(vcoeff_y0), 78 | .x(x), 79 | .y(y), 80 | .z(tap1), 81 | .tap(tap0) 82 | ); 83 | 84 | wire [39:0] tap1; 85 | iir_filter_tap iir_tap_1 86 | ( 87 | .clk(clk), 88 | .reset(reset), 89 | .ce(ce), 90 | .ch(ch), 91 | .cx(use_params ? coeff_x1[7:0] : cx1), 92 | .cy(vcoeff_y1), 93 | .x(x), 94 | .y(y), 95 | .z(tap2), 96 | .tap(tap1) 97 | ); 98 | 99 | wire [39:0] tap2; 100 | iir_filter_tap iir_tap_2 101 | ( 102 | .clk(clk), 103 | .reset(reset), 104 | .ce(ce), 105 | .ch(ch), 106 | .cx(use_params ? coeff_x2[7:0] : cx2), 107 | .cy(vcoeff_y2), 108 | .x(x), 109 | .y(y), 110 | .z(0), 111 | .tap(tap2) 112 | ); 113 | 114 | wire [15:0] y_clamp = (~y[39] & |y[38:35]) ? 16'h7FFF : (y[39] & ~&y[38:35]) ? 16'h8000 : y[35:20]; 115 | 116 | reg ch = 0; 117 | reg [15:0] out_l, out_r, out_m; 118 | reg [15:0] inp, inp_m; 119 | always @(posedge clk) if (ce) begin 120 | if(!stereo) begin 121 | ch <= 0; 122 | inp <= input_l; 123 | out_l <= y_clamp; 124 | out_r <= y_clamp; 125 | end 126 | else begin 127 | ch <= ~ch; 128 | if(ch) begin 129 | out_m <= y_clamp; 130 | inp <= inp_m; 131 | end 132 | else begin 133 | out_l <= out_m; 134 | out_r <= y_clamp; 135 | inp <= input_l; 136 | inp_m <= input_r; 137 | end 138 | end 139 | end 140 | 141 | reg [31:0] out; 142 | always @(posedge clk) if (sample_ce) out <= {out_l, out_r}; 143 | 144 | assign {output_l, output_r} = out; 145 | 146 | endmodule 147 | 148 | module iir_filter_tap 149 | ( 150 | input clk, 151 | input reset, 152 | 153 | input ce, 154 | input ch, 155 | 156 | input [7:0] cx, 157 | input [23:0] cy, 158 | 159 | input [39:0] x, 160 | input [39:0] y, 161 | input [39:0] z, 162 | output [39:0] tap 163 | ); 164 | 165 | wire signed [60:0] y_mul = $signed(y[36:0]) * $signed(cy); 166 | 167 | function [39:0] x_mul; 168 | input [39:0] x; 169 | begin 170 | x_mul = 0; 171 | if(cx[0]) x_mul = x_mul + {{4{x[39]}}, x[39:4]}; 172 | if(cx[1]) x_mul = x_mul + {{3{x[39]}}, x[39:3]}; 173 | if(cx[2]) x_mul = x_mul + {{2{x[39]}}, x[39:2]}; 174 | if(cx[7]) x_mul = ~x_mul; //cheap NEG 175 | end 176 | endfunction 177 | 178 | (* ramstyle = "logic" *) reg [39:0] intreg[2]; 179 | always @(posedge clk, posedge reset) begin 180 | if(reset) {intreg[0],intreg[1]} <= 80'd0; 181 | else if(ce) intreg[ch] <= x_mul(x) - y_mul[60:21] + z; 182 | end 183 | 184 | assign tap = intreg[ch]; 185 | 186 | endmodule 187 | 188 | // simplified IIR 1-tap. 189 | module DC_blocker 190 | ( 191 | input clk, 192 | input ce, // 48/96 KHz 193 | input mute, 194 | 195 | input sample_rate, 196 | input [15:0] din, 197 | output [15:0] dout 198 | ); 199 | 200 | wire [39:0] x = {din[15], din, 23'd0}; 201 | wire [39:0] x0 = x - (sample_rate ? {{11{x[39]}}, x[39:11]} : {{10{x[39]}}, x[39:10]}); 202 | wire [39:0] y1 = y - (sample_rate ? {{10{y[39]}}, y[39:10]} : {{09{y[39]}}, y[39:09]}); 203 | wire [39:0] y0 = x0 - x1 + y1; 204 | 205 | reg [39:0] x1, y; 206 | always @(posedge clk) if(ce) begin 207 | x1 <= x0; 208 | y <= ^y0[39:38] ? {{2{y0[39]}},{38{y0[38]}}} : y0; 209 | end 210 | 211 | assign dout = mute ? 16'd0 : y[38:23]; 212 | 213 | endmodule 214 | -------------------------------------------------------------------------------- /sys/mt32pi.sv: -------------------------------------------------------------------------------- 1 | // 2 | // Communication module to MT32-pi (external MIDI emulator on RPi) 3 | // (C) 2020 Sorgelig, Kitrinx 4 | // 5 | // https://github.com/dwhinham/mt32-pi 6 | // 7 | 8 | module mt32pi 9 | ( 10 | input CLK_AUDIO, 11 | 12 | input CLK_VIDEO, 13 | input CE_PIXEL, 14 | input VGA_VS, 15 | input VGA_DE, 16 | 17 | input [6:0] USER_IN, 18 | output [6:0] USER_OUT, 19 | 20 | input reset, 21 | input midi_tx, 22 | output midi_rx, 23 | 24 | output reg [15:0] mt32_i2s_r, 25 | output reg [15:0] mt32_i2s_l, 26 | 27 | output reg mt32_available, 28 | 29 | input mt32_mode_req, 30 | input [1:0] mt32_rom_req, 31 | input [7:0] mt32_sf_req, 32 | 33 | output reg [7:0] mt32_mode, 34 | output reg [7:0] mt32_rom, 35 | output reg [7:0] mt32_sf, 36 | output reg mt32_newmode, 37 | 38 | output reg mt32_lcd_en, 39 | output reg mt32_lcd_pix, 40 | output reg mt32_lcd_update 41 | ); 42 | 43 | // 44 | // Pin | USB Name | Signal 45 | // ----+----------+-------------- 46 | // 0 | D+ | I/O I2C_SDA / RX (midi in) 47 | // 1 | D- | O TX (midi out) 48 | // 2 | TX- | I I2S_WS (1 == right) 49 | // 3 | GND_d | I I2C_SCL 50 | // 4 | RX+ | I I2S_BCLK 51 | // 5 | RX- | I I2S_DAT 52 | // 6 | TX+ | - none 53 | // 54 | 55 | assign USER_OUT[0] = sda_out; 56 | assign USER_OUT[1] = midi_tx; 57 | assign USER_OUT[6:2] = '1; 58 | 59 | 60 | // 61 | // crossed/straight cable selection 62 | // 63 | 64 | generate 65 | genvar i; 66 | for(i = 0; i<2; i++) begin : clk_rate 67 | wire clk_in = i ? USER_IN[6] : USER_IN[4]; 68 | reg [4:0] cnt; 69 | always @(posedge CLK_AUDIO) begin : clkr 70 | reg clk_sr, clk, old_clk; 71 | reg [4:0] cnt_tmp; 72 | 73 | clk_sr <= clk_in; 74 | if (clk_sr == clk_in) clk <= clk_sr; 75 | 76 | if(~&cnt_tmp) cnt_tmp <= cnt_tmp + 1'd1; 77 | else cnt <= '1; 78 | 79 | old_clk <= clk; 80 | if(~old_clk & clk) begin 81 | cnt <= cnt_tmp; 82 | cnt_tmp <= 0; 83 | end 84 | end 85 | end 86 | 87 | reg crossed; 88 | always @(posedge CLK_AUDIO) crossed <= (clk_rate[0].cnt <= clk_rate[1].cnt); 89 | endgenerate 90 | 91 | wire i2s_ws = crossed ? USER_IN[2] : USER_IN[5]; 92 | wire i2s_data = crossed ? USER_IN[5] : USER_IN[2]; 93 | wire i2s_bclk = crossed ? USER_IN[4] : USER_IN[6]; 94 | assign midi_rx = ~mt32_available ? USER_IN[0] : crossed ? USER_IN[6] : USER_IN[4]; 95 | 96 | 97 | // 98 | // i2s receiver 99 | // 100 | 101 | always @(posedge CLK_AUDIO) begin : i2s_proc 102 | reg [15:0] i2s_buf = 0; 103 | reg [4:0] i2s_cnt = 0; 104 | reg clk_sr; 105 | reg i2s_clk = 0; 106 | reg old_clk, old_ws; 107 | reg i2s_next = 0; 108 | 109 | // Debounce clock 110 | clk_sr <= i2s_bclk; 111 | if (clk_sr == i2s_bclk) i2s_clk <= clk_sr; 112 | 113 | // Latch data and ws on rising edge 114 | old_clk <= i2s_clk; 115 | if (i2s_clk && ~old_clk) begin 116 | 117 | if (~i2s_cnt[4]) begin 118 | i2s_cnt <= i2s_cnt + 1'd1; 119 | i2s_buf[~i2s_cnt[3:0]] <= i2s_data; 120 | end 121 | 122 | // Word Select will change 1 clock before the new word starts 123 | old_ws <= i2s_ws; 124 | if (old_ws != i2s_ws) i2s_next <= 1; 125 | end 126 | 127 | if (i2s_next) begin 128 | i2s_next <= 0; 129 | i2s_cnt <= 0; 130 | i2s_buf <= 0; 131 | 132 | if (i2s_ws) mt32_i2s_l <= i2s_buf; 133 | else mt32_i2s_r <= i2s_buf; 134 | end 135 | 136 | if (reset) begin 137 | i2s_buf <= 0; 138 | mt32_i2s_l <= 0; 139 | mt32_i2s_r <= 0; 140 | end 141 | end 142 | 143 | 144 | // 145 | // i2c slave 146 | // 147 | 148 | reg sda_out; 149 | reg [7:0] lcd_data[1024]; 150 | reg lcd_sz; 151 | 152 | reg reset_r = 0; 153 | wire [7:0] mode_req = reset_r ? 8'hA0 : mt32_mode_req ? 8'hA2 : 8'hA1; 154 | wire [7:0] rom_req = {6'd0, mt32_rom_req}; 155 | 156 | always @(posedge CLK_AUDIO) begin : i2c_slave 157 | reg sda_sr, scl_sr; 158 | reg old_sda, old_scl; 159 | reg sda, scl; 160 | reg [7:0] tmp; 161 | reg [3:0] cnt = 0; 162 | reg [10:0] bcnt = 0; 163 | reg ack; 164 | reg i2c_rw; 165 | reg disp, dispdata; 166 | reg [2:0] div; 167 | reg old_reset; 168 | 169 | old_reset <= reset; 170 | if(old_reset & ~reset) sda_out <= 1; 171 | 172 | div <= div + 1'd1; 173 | if(!div) begin 174 | sda_sr <= USER_IN[0]; 175 | if(sda_sr == USER_IN[0]) sda <= sda_sr; 176 | old_sda <= sda; 177 | 178 | scl_sr <= USER_IN[3]; 179 | if(scl_sr == USER_IN[3]) scl <= scl_sr; 180 | old_scl <= scl; 181 | 182 | //start 183 | if(old_scl & scl & old_sda & ~sda) begin 184 | cnt <= 9; 185 | bcnt <= 0; 186 | ack <= 0; 187 | i2c_rw <= 0; 188 | disp <= 0; 189 | dispdata <= 0; 190 | end 191 | 192 | //stop 193 | if(old_scl & scl & ~old_sda & sda) begin 194 | cnt <= 0; 195 | if(dispdata) begin 196 | lcd_sz <= ~bcnt[9]; 197 | mt32_lcd_update <= ~mt32_lcd_update; 198 | end 199 | end 200 | 201 | //data latch 202 | if(~old_scl && scl && cnt) begin 203 | tmp <= {tmp[6:0], sda}; 204 | cnt <= cnt - 1'd1; 205 | end 206 | 207 | if(!cnt) sda_out <= 1; 208 | 209 | //data set 210 | if(old_scl && ~scl) begin 211 | sda_out <= 1; 212 | if(cnt == 1) begin 213 | if(!bcnt) begin 214 | if(tmp[7:1] == 'h45 || tmp[7:1] == 'h3c) begin 215 | disp <= (tmp[7:1] == 'h3c); 216 | sda_out <= 0; 217 | mt32_available <= 1; 218 | ack <= 1; 219 | i2c_rw <= tmp[0]; 220 | bcnt <= bcnt + 1'd1; 221 | cnt <= 10; 222 | end 223 | else begin 224 | // wrong address, stop 225 | cnt <= 0; 226 | end 227 | end 228 | else if(ack) begin 229 | if(~i2c_rw) begin 230 | if(disp) begin 231 | if(bcnt == 1) dispdata <= (tmp[7:6] == 2'b01); 232 | else if(dispdata) lcd_data[bcnt[9:0] - 2'd2] <= tmp; 233 | end 234 | else begin 235 | if(bcnt == 1) mt32_mode <= tmp; 236 | if(bcnt == 2) mt32_rom <= tmp; 237 | if(bcnt == 3) mt32_sf <= tmp; 238 | if(bcnt == 3) mt32_newmode <= ~mt32_newmode; 239 | end 240 | end 241 | if(~&bcnt) bcnt <= bcnt + 1'd1; 242 | sda_out <= 0; 243 | cnt <= 10; 244 | end 245 | end 246 | else if(i2c_rw && ack && cnt && ~disp) begin 247 | if(bcnt == 1) sda_out <= mode_req[cnt[2:0] - 2'd2]; 248 | if(bcnt == 2) sda_out <= rom_req[cnt[2:0] - 2'd2]; 249 | if(bcnt == 3) sda_out <= mt32_sf_req[cnt[2:0] - 2'd2]; 250 | if(bcnt == 3) reset_r <= 0; 251 | end 252 | end 253 | end 254 | 255 | if(reset) begin 256 | reset_r <= 1; 257 | mt32_available <= 0; 258 | end 259 | end 260 | 261 | always @(posedge CLK_VIDEO) begin 262 | reg old_de, old_vs; 263 | reg [7:0] hcnt; 264 | reg [6:0] vcnt; 265 | reg [7:0] sh; 266 | 267 | if(CE_PIXEL) begin 268 | old_de <= VGA_DE; 269 | old_vs <= VGA_VS; 270 | 271 | if(~&hcnt) hcnt <= hcnt + 1'd1; 272 | sh <= (sh << 1) | (~old_de & VGA_DE); 273 | if(sh[7]) hcnt <= 0; 274 | 275 | if(old_de & ~VGA_DE & ~&vcnt) vcnt <= vcnt + 1'd1; 276 | if(~old_vs & VGA_VS) vcnt <= 0; 277 | 278 | mt32_lcd_en <= mt32_available & ~hcnt[7] && (lcd_sz ? !vcnt[6] : !vcnt[6:5]); 279 | mt32_lcd_pix <= lcd_data[{vcnt[5:3],hcnt[6:0]}][vcnt[2:0]]; 280 | end 281 | end 282 | 283 | endmodule 284 | -------------------------------------------------------------------------------- /sys/pll_hdmi/pll_hdmi_0002.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/10ps 2 | module pll_hdmi_0002( 3 | 4 | // interface 'refclk' 5 | input wire refclk, 6 | 7 | // interface 'reset' 8 | input wire rst, 9 | 10 | // interface 'outclk0' 11 | output wire outclk_0, 12 | 13 | // interface 'locked' 14 | output wire locked, 15 | 16 | // interface 'reconfig_to_pll' 17 | input wire [63:0] reconfig_to_pll, 18 | 19 | // interface 'reconfig_from_pll' 20 | output wire [63:0] reconfig_from_pll 21 | ); 22 | 23 | altera_pll #( 24 | .fractional_vco_multiplier("true"), 25 | .reference_clock_frequency("50.0 MHz"), 26 | .pll_fractional_cout(32), 27 | .pll_dsm_out_sel("1st_order"), 28 | .operation_mode("direct"), 29 | .number_of_clocks(1), 30 | .output_clock_frequency0("148.500000 MHz"), 31 | .phase_shift0("0 ps"), 32 | .duty_cycle0(50), 33 | .output_clock_frequency1("0 MHz"), 34 | .phase_shift1("0 ps"), 35 | .duty_cycle1(50), 36 | .output_clock_frequency2("0 MHz"), 37 | .phase_shift2("0 ps"), 38 | .duty_cycle2(50), 39 | .output_clock_frequency3("0 MHz"), 40 | .phase_shift3("0 ps"), 41 | .duty_cycle3(50), 42 | .output_clock_frequency4("0 MHz"), 43 | .phase_shift4("0 ps"), 44 | .duty_cycle4(50), 45 | .output_clock_frequency5("0 MHz"), 46 | .phase_shift5("0 ps"), 47 | .duty_cycle5(50), 48 | .output_clock_frequency6("0 MHz"), 49 | .phase_shift6("0 ps"), 50 | .duty_cycle6(50), 51 | .output_clock_frequency7("0 MHz"), 52 | .phase_shift7("0 ps"), 53 | .duty_cycle7(50), 54 | .output_clock_frequency8("0 MHz"), 55 | .phase_shift8("0 ps"), 56 | .duty_cycle8(50), 57 | .output_clock_frequency9("0 MHz"), 58 | .phase_shift9("0 ps"), 59 | .duty_cycle9(50), 60 | .output_clock_frequency10("0 MHz"), 61 | .phase_shift10("0 ps"), 62 | .duty_cycle10(50), 63 | .output_clock_frequency11("0 MHz"), 64 | .phase_shift11("0 ps"), 65 | .duty_cycle11(50), 66 | .output_clock_frequency12("0 MHz"), 67 | .phase_shift12("0 ps"), 68 | .duty_cycle12(50), 69 | .output_clock_frequency13("0 MHz"), 70 | .phase_shift13("0 ps"), 71 | .duty_cycle13(50), 72 | .output_clock_frequency14("0 MHz"), 73 | .phase_shift14("0 ps"), 74 | .duty_cycle14(50), 75 | .output_clock_frequency15("0 MHz"), 76 | .phase_shift15("0 ps"), 77 | .duty_cycle15(50), 78 | .output_clock_frequency16("0 MHz"), 79 | .phase_shift16("0 ps"), 80 | .duty_cycle16(50), 81 | .output_clock_frequency17("0 MHz"), 82 | .phase_shift17("0 ps"), 83 | .duty_cycle17(50), 84 | .pll_type("Cyclone V"), 85 | .pll_subtype("Reconfigurable"), 86 | .m_cnt_hi_div(4), 87 | .m_cnt_lo_div(4), 88 | .n_cnt_hi_div(256), 89 | .n_cnt_lo_div(256), 90 | .m_cnt_bypass_en("false"), 91 | .n_cnt_bypass_en("true"), 92 | .m_cnt_odd_div_duty_en("false"), 93 | .n_cnt_odd_div_duty_en("false"), 94 | .c_cnt_hi_div0(2), 95 | .c_cnt_lo_div0(1), 96 | .c_cnt_prst0(1), 97 | .c_cnt_ph_mux_prst0(0), 98 | .c_cnt_in_src0("ph_mux_clk"), 99 | .c_cnt_bypass_en0("false"), 100 | .c_cnt_odd_div_duty_en0("true"), 101 | .c_cnt_hi_div1(1), 102 | .c_cnt_lo_div1(1), 103 | .c_cnt_prst1(1), 104 | .c_cnt_ph_mux_prst1(0), 105 | .c_cnt_in_src1("ph_mux_clk"), 106 | .c_cnt_bypass_en1("true"), 107 | .c_cnt_odd_div_duty_en1("false"), 108 | .c_cnt_hi_div2(1), 109 | .c_cnt_lo_div2(1), 110 | .c_cnt_prst2(1), 111 | .c_cnt_ph_mux_prst2(0), 112 | .c_cnt_in_src2("ph_mux_clk"), 113 | .c_cnt_bypass_en2("true"), 114 | .c_cnt_odd_div_duty_en2("false"), 115 | .c_cnt_hi_div3(1), 116 | .c_cnt_lo_div3(1), 117 | .c_cnt_prst3(1), 118 | .c_cnt_ph_mux_prst3(0), 119 | .c_cnt_in_src3("ph_mux_clk"), 120 | .c_cnt_bypass_en3("true"), 121 | .c_cnt_odd_div_duty_en3("false"), 122 | .c_cnt_hi_div4(1), 123 | .c_cnt_lo_div4(1), 124 | .c_cnt_prst4(1), 125 | .c_cnt_ph_mux_prst4(0), 126 | .c_cnt_in_src4("ph_mux_clk"), 127 | .c_cnt_bypass_en4("true"), 128 | .c_cnt_odd_div_duty_en4("false"), 129 | .c_cnt_hi_div5(1), 130 | .c_cnt_lo_div5(1), 131 | .c_cnt_prst5(1), 132 | .c_cnt_ph_mux_prst5(0), 133 | .c_cnt_in_src5("ph_mux_clk"), 134 | .c_cnt_bypass_en5("true"), 135 | .c_cnt_odd_div_duty_en5("false"), 136 | .c_cnt_hi_div6(1), 137 | .c_cnt_lo_div6(1), 138 | .c_cnt_prst6(1), 139 | .c_cnt_ph_mux_prst6(0), 140 | .c_cnt_in_src6("ph_mux_clk"), 141 | .c_cnt_bypass_en6("true"), 142 | .c_cnt_odd_div_duty_en6("false"), 143 | .c_cnt_hi_div7(1), 144 | .c_cnt_lo_div7(1), 145 | .c_cnt_prst7(1), 146 | .c_cnt_ph_mux_prst7(0), 147 | .c_cnt_in_src7("ph_mux_clk"), 148 | .c_cnt_bypass_en7("true"), 149 | .c_cnt_odd_div_duty_en7("false"), 150 | .c_cnt_hi_div8(1), 151 | .c_cnt_lo_div8(1), 152 | .c_cnt_prst8(1), 153 | .c_cnt_ph_mux_prst8(0), 154 | .c_cnt_in_src8("ph_mux_clk"), 155 | .c_cnt_bypass_en8("true"), 156 | .c_cnt_odd_div_duty_en8("false"), 157 | .c_cnt_hi_div9(1), 158 | .c_cnt_lo_div9(1), 159 | .c_cnt_prst9(1), 160 | .c_cnt_ph_mux_prst9(0), 161 | .c_cnt_in_src9("ph_mux_clk"), 162 | .c_cnt_bypass_en9("true"), 163 | .c_cnt_odd_div_duty_en9("false"), 164 | .c_cnt_hi_div10(1), 165 | .c_cnt_lo_div10(1), 166 | .c_cnt_prst10(1), 167 | .c_cnt_ph_mux_prst10(0), 168 | .c_cnt_in_src10("ph_mux_clk"), 169 | .c_cnt_bypass_en10("true"), 170 | .c_cnt_odd_div_duty_en10("false"), 171 | .c_cnt_hi_div11(1), 172 | .c_cnt_lo_div11(1), 173 | .c_cnt_prst11(1), 174 | .c_cnt_ph_mux_prst11(0), 175 | .c_cnt_in_src11("ph_mux_clk"), 176 | .c_cnt_bypass_en11("true"), 177 | .c_cnt_odd_div_duty_en11("false"), 178 | .c_cnt_hi_div12(1), 179 | .c_cnt_lo_div12(1), 180 | .c_cnt_prst12(1), 181 | .c_cnt_ph_mux_prst12(0), 182 | .c_cnt_in_src12("ph_mux_clk"), 183 | .c_cnt_bypass_en12("true"), 184 | .c_cnt_odd_div_duty_en12("false"), 185 | .c_cnt_hi_div13(1), 186 | .c_cnt_lo_div13(1), 187 | .c_cnt_prst13(1), 188 | .c_cnt_ph_mux_prst13(0), 189 | .c_cnt_in_src13("ph_mux_clk"), 190 | .c_cnt_bypass_en13("true"), 191 | .c_cnt_odd_div_duty_en13("false"), 192 | .c_cnt_hi_div14(1), 193 | .c_cnt_lo_div14(1), 194 | .c_cnt_prst14(1), 195 | .c_cnt_ph_mux_prst14(0), 196 | .c_cnt_in_src14("ph_mux_clk"), 197 | .c_cnt_bypass_en14("true"), 198 | .c_cnt_odd_div_duty_en14("false"), 199 | .c_cnt_hi_div15(1), 200 | .c_cnt_lo_div15(1), 201 | .c_cnt_prst15(1), 202 | .c_cnt_ph_mux_prst15(0), 203 | .c_cnt_in_src15("ph_mux_clk"), 204 | .c_cnt_bypass_en15("true"), 205 | .c_cnt_odd_div_duty_en15("false"), 206 | .c_cnt_hi_div16(1), 207 | .c_cnt_lo_div16(1), 208 | .c_cnt_prst16(1), 209 | .c_cnt_ph_mux_prst16(0), 210 | .c_cnt_in_src16("ph_mux_clk"), 211 | .c_cnt_bypass_en16("true"), 212 | .c_cnt_odd_div_duty_en16("false"), 213 | .c_cnt_hi_div17(1), 214 | .c_cnt_lo_div17(1), 215 | .c_cnt_prst17(1), 216 | .c_cnt_ph_mux_prst17(0), 217 | .c_cnt_in_src17("ph_mux_clk"), 218 | .c_cnt_bypass_en17("true"), 219 | .c_cnt_odd_div_duty_en17("false"), 220 | .pll_vco_div(2), 221 | .pll_cp_current(20), 222 | .pll_bwctrl(4000), 223 | .pll_output_clk_frequency("445.499999 MHz"), 224 | .pll_fractional_division("3908420153"), 225 | .mimic_fbclk_type("none"), 226 | .pll_fbclk_mux_1("glb"), 227 | .pll_fbclk_mux_2("m_cnt"), 228 | .pll_m_cnt_in_src("ph_mux_clk"), 229 | .pll_slf_rst("true") 230 | ) altera_pll_i ( 231 | .rst (rst), 232 | .outclk ({outclk_0}), 233 | .locked (locked), 234 | .reconfig_to_pll (reconfig_to_pll), 235 | .fboutclk ( ), 236 | .fbclk (1'b0), 237 | .refclk (refclk), 238 | .reconfig_from_pll (reconfig_from_pll) 239 | ); 240 | endmodule 241 | 242 | -------------------------------------------------------------------------------- /EDSAC.srf: -------------------------------------------------------------------------------- 1 | { "" "" "" "Variable or input pin \"data_b\" is defined but never used." { } { } 0 287013 "" 0 0 "Design Software" 0 -1 0 ""} 2 | { "" "" "" "Found combinational loop of 47 nodes" { } { } 0 332125 "" 0 0 "Design Software" 0 -1 0 ""} 3 | { "" "" "" "LOCKED port on the PLL is not properly connected on instance \"pll_hdmi:pll_hdmi\|pll_hdmi_0002:pll_hdmi_inst\|altera_pll:altera_pll_i\|general\[0\].gpll\". The LOCKED port on the PLL should be connected when the FBOUTCLK port is connected. Although it is unnecessary to connect the LOCKED signal, any logic driven off of an output clock of the PLL will not know when the PLL is locked and ready." { } { } 0 21300 "" 0 0 "Design Software" 0 -1 0 ""} 4 | { "" "" "" "Net \"soc_system:soc_system\|soc_system_Video_Output:video_output\|alt_vip_cvo_core:cvo_core\|genlock_enable_sync1\[1\]\" is missing source, defaulting to GND" { } { } 0 12110 "" 0 0 "Design Software" 0 -1 0 ""} 5 | { "" "" "" "Inferred RAM node \"zxspectrum:emu\|mist_io:mist_io\|ps2_kbd_fifo_rtl_0\" from synchronous design logic. Pass-through logic has been added to match the read-during-write behavior of the original design." { } { } 0 276020 "" 0 0 "Design Software" 0 -1 0 ""} 6 | { "" "" "" "Inferred RAM node \"zxspectrum:emu\|mist_io:mist_io\|ps2_mouse_fifo_rtl_0\" from synchronous design logic. Pass-through logic has been added to match the read-during-write behavior of the original design." { } { } 0 276020 "" 0 0 "Design Software" 0 -1 0 ""} 7 | { "" "" "" "No destination clock period was found satisfying the set_net_delay assignment from \"\[get_keepers \{soc_system\|video_output\|cvo_core\|mode_banks\|h_sync_polarity_reg\}\]\" to \"\[get_keepers \{soc_system\|video_output\|cvo_core\|mode_banks\|vid_h_sync_polarity\}\]\". This assignment will be ignored." { } { } 0 17897 "" 0 0 "Design Software" 0 -1 0 ""} 8 | { "" "" "" "No destination clock period was found satisfying the set_net_delay assignment from \"\[get_keepers \{soc_system\|video_output\|cvo_core\|mode_banks\|v_sync_polarity_reg\}\]\" to \"\[get_keepers \{soc_system\|video_output\|cvo_core\|mode_banks\|vid_v_sync_polarity\}\]\". This assignment will be ignored." { } { } 0 17897 "" 0 0 "Design Software" 0 -1 0 ""} 9 | { "" "" "" "No destination clock period was found satisfying the set_net_delay assignment from \"\[get_keepers \{soc_system\|video_output\|cvo_core\|mode_banks\|interlaced_field_reg\[*\]\}\]\" to \"\[get_keepers \{soc_system\|video_output\|cvo_core\|mode_banks\|vid_interlaced_field\[*\]\}\]\". This assignment will be ignored." { } { } 0 17897 "" 0 0 "Design Software" 0 -1 0 ""} 10 | { "" "" "" "Some pins have incomplete I/O assignments. Refer to the I/O Assignment Warnings report for details" { } { } 0 15714 "" 0 0 "Design Software" 0 -1 0 ""} 11 | { "" "" "" "55 hierarchies have connectivity warnings - see the Connectivity Checks report folder" { } { } 0 12241 "" 0 0 "Design Software" 0 -1 0 ""} 12 | { "" "" "" "Inferred RAM node \"emu:emu\|mister_io:mister_io\|ps2_kbd_fifo_rtl_0\" from synchronous design logic. Pass-through logic has been added to match the read-during-write behavior of the original design." { } { } 0 276020 "" 0 0 "Design Software" 0 -1 0 ""} 13 | { "" "" "" "Inferred RAM node \"emu:emu\|mister_io:mister_io\|ps2_mouse_fifo_rtl_0\" from synchronous design logic. Pass-through logic has been added to match the read-during-write behavior of the original design." { } { } 0 276020 "" 0 0 "Design Software" 0 -1 0 ""} 14 | { "" "" "" "Verilog HDL or VHDL warning at de10_top.v(97): object \"io_win\" assigned a value but never read" { } { } 0 10036 "" 0 0 "Design Software" 0 -1 0 ""} 15 | { "" "" "" "Verilog HDL or VHDL warning at de10_top.v(102): object \"io_sdd\" assigned a value but never read" { } { } 0 10036 "" 0 0 "Design Software" 0 -1 0 ""} 16 | { "" "" "" "Overwriting existing clock: vip\|hps\|fpga_interfaces\|clocks_resets\|h2f_user0_clk" { } { } 0 332043 "" 0 0 "Design Software" 0 -1 0 ""} 17 | { "" "" "" "Variable or input pin \"data_a\" is defined but never used." { } { } 0 287013 "" 0 0 "Design Software" 0 -1 0 ""} 18 | { "" "" "" "*" { } { } 0 169085 "" 0 0 "Design Software" 0 -1 0 ""} 19 | { "" "" "" "*" { } { } 0 174073 "" 0 0 "Design Software" 0 -1 0 ""} 20 | { "" "" "" "*" { } { } 0 332174 "" 0 0 "Design Software" 0 -1 0 ""} 21 | { "" "" "" "*" { } { } 0 13009 "" 0 0 "Design Software" 0 -1 0 ""} 22 | { "" "" "" "*" { } { } 0 21300 "" 0 0 "Design Software" 0 -1 0 ""} 23 | { "" "" "" "alt_vip_cvo_mode_banks" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 24 | { "" "" "" "hps_sdram_pll.sv" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 25 | { "" "" "" "alt_vip_common_frame_counter.v" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 26 | { "" "" "" "hps_sdram_p0_acv_hard_memphy.v" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 27 | { "" "" "" "hps_sdram_p0_acv_ldc.v" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 28 | { "" "" "" "hps_sdram_p0_acv_hard_io_pads.v" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 29 | { "" "" "" "altera_mem_if_hard_memory_controller_top_cyclonev.sv" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 30 | { "" "" "" "genlock_enable_sync" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 31 | { "" "" "" "u_calculate_mode" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 32 | { "" "" "" "genlock_enable" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 33 | { "" "" "" "reset_value" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 34 | { "" "" "" "soc_system:soc_system\|soc_system_pll_video:pll_video\|altera_pll:altera_pll_i\|general\[0\].gpll" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 35 | { "" "" "" "alt_vip_cvo_core.sdc" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 36 | { "" "" "" "alt_vip_packet_transfer.sdc" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 37 | { "" "" "" "hps_sdram_p0.sdc" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 38 | { "" "" "" "alt_vip_common_dc_mixed_widths_fifo.sdc" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 39 | { "" "" "" "altera_mem_if_hhp_qseq_synth_top" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 40 | { "" "" "" "soc_system:soc_system\|soc_system_vip_vout:vip_vout\|alt_vip_cvo_core:cvo_core\|genlock_enable_sync1" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 41 | { "" "" "" "soc_system:soc_system\|soc_system_vip_fb:vip_fb\|alt_vip_packet_transfer:pkt_trans_rd\|alt_vip_packet_transfer_read_proc:READ_BLOCK.read_proc_instance\|alt_vip_common_fifo2:output_msg_queue\|scfifo:scfifo_component\|scfifo_scd1:auto_generated\|a_dpfifo_e471:dpfifo\|altsyncram_ums1:FIFOram\|q_b" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 42 | { "" "" "" "soc_system:soc_system\|soc_system_Video_Input:video_input\|alt_vip_cvi_core:cvi_core\|alt_vip_cvi_write_fifo_buffer:write_fifo_buffer" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 43 | { "" "" "" "soc_system:soc_system\|soc_system_Frame_Buffer:frame_buffer\|alt_vip_packet_transfer:pkt_trans_rd" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 44 | { "" "" "" "soc_system_hps_fpga_interfaces.sdc" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 45 | { "" "" "" "soc_system_HPS_fpga_interfaces.sdc" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 46 | { "" "" "" "RST" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 47 | { "" "" "" "alt_vip_scaler_alg_core" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 48 | { "" "" "" "cvo_core" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 49 | { "" "" "" "vip_HPS_fpga_interfaces.sdc" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 50 | { "" "" "" "alt_vip_dil_vof_scheduler.sdc" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 51 | { "" "" "" "alt_vip_dil_scheduler.sdc" { } { } 0 9999 "" 0 0 "Design Software" 0 -1 0 ""} 52 | -------------------------------------------------------------------------------- /rtl/edsac_cpu.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////// 3 | // 4 | // Copyright (C) 2020, Hrvoje Cavrak. 5 | // 6 | // Redistribution and use in source and binary forms, with or without 7 | // modification, are permitted provided that the following conditions are met: 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above copyright 11 | // notice, this list of conditions and the following disclaimer in the 12 | // documentation and/or other materials provided with the distribution. 13 | // * The names of contributors may not be used to endorse or promote products 14 | // derived from this software without specific prior written permission. 15 | // 16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | // ARE DISCLAIMED. IN NO EVENT SHALL Thomas Skibo OR CONTRIBUTORS BE LIABLE FOR 20 | // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 | // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 | // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | // SUCH DAMAGE. 27 | // 28 | ////////////////////////////////////////////////////////////////////////////// 29 | 30 | `define SWORD 18 31 | `define LWORD 36 32 | `define ACCU_LEN 71 33 | 34 | 35 | module edsac_cpu 36 | ( 37 | input clock, 38 | input enable, 39 | input [`LWORD-2:0] memory_in, 40 | input resume, 41 | input reset, 42 | input cpu_halt, 43 | 44 | input [4:0] rotary_dial_in, 45 | input [4:0] tape_data_in, 46 | 47 | output reg [8:0] cpu_addr_out, 48 | output reg [`LWORD-2:0] cpu_data_out, 49 | output reg memory_wren, 50 | output reg character_strobe, 51 | output reg [4:0] character, 52 | output reg tape_read_strobe, 53 | output cpu_running, 54 | 55 | output [70:0] o_abc, 56 | output [34:0] o_rs, 57 | output [9:0] o_scr, 58 | output [16:0] o_ir, 59 | output [10:0] o_phase 60 | 61 | ); 62 | 63 | `include "util.sv" 64 | 65 | ////////////////////////////////////////////////////////////// 66 | // Registers 67 | ////////////////////////////////////////////////////////////// 68 | 69 | reg [16:0] IR; /* Instruction Register */ 70 | 71 | reg signed [70:0] ABC = 0; /* Accumulator */ 72 | `define AB ABC[70:36] 73 | `define A ABC[70:54] 74 | 75 | reg signed [34:0] RS = 35'd0; /* Multiplier Register */ 76 | `define R RS[34:18] 77 | 78 | reg [9:0] SCR = 0; /* Sequence Control Register a.k.a. Program Counter */ 79 | reg [16:0] OT; /* Order Tank a.k.a. Instruction Register */ 80 | 81 | reg HALT = 1'b1; /* Start halted */ 82 | reg NOP; 83 | 84 | assign cpu_running = ~HALT; 85 | 86 | /* The order format is: 87 | 88 | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 89 | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 90 | | op |xx| address |SL| 91 | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 92 | 93 | op = instruction, 94 | address = 10 bit address in memory, 95 | S/L = length code 96 | 97 | */ 98 | 99 | function integer shift_count; 100 | input [16:0] value; 101 | 102 | for (shift_count=1; |value && ~value[0]; shift_count=shift_count+1) 103 | value = value>>1; 104 | 105 | endfunction 106 | 107 | 108 | function signed [70:0] mult; 109 | input signed [34:0] a; 110 | input signed [34:0] b; 111 | 112 | mult = (a * b) << 2; /* Multiplication needs to be shifted 2 places left to preserve decimal point */ 113 | 114 | endfunction 115 | 116 | 117 | function [34:0] short_write; 118 | input [16:0] word; 119 | short_write = IR[1] ? {word, memory_in[17:0]} : {memory_in[34:17], word}; 120 | endfunction 121 | 122 | 123 | 124 | task exec_instruction; 125 | input [16:0] instruction; 126 | input signed [`LWORD-2:0] memory_in; 127 | input signed [16:0] short; 128 | begin 129 | 130 | `define OPCODE instruction[16:12] 131 | `define ADDRESS instruction[10:1] 132 | `define MODE instruction[0] 133 | 134 | case (`OPCODE) 135 | i_A: ABC <= ABC + (`MODE ? {memory_in, 36'b0} : {short, 54'b0}); 136 | i_S: ABC <= ABC - (`MODE ? {memory_in, 36'b0} : {short, 54'b0}); 137 | 138 | i_H: RS <= `MODE ? memory_in : {short, 18'b0}; // Short RS write destroys lower half as well! 139 | 140 | i_V: ABC <= ABC + (`MODE ? (memory_in * RS) << 2 : mult({short, 18'b0}, RS)); // Short mode does not mean whole RS isn't used as well 141 | i_N: ABC <= ABC - (`MODE ? (memory_in * RS) << 2 : mult({short, 18'b0}, RS)); // Short mode does not mean whole RS isn't used as well 142 | 143 | i_C: ABC <= ABC + (`MODE ? {memory_in & RS, 36'b0} : {short & `R, 54'b0}); 144 | 145 | i_T: begin cpu_data_out <= (`MODE ? `AB : short_write(`A)); ABC <= 71'b0; end 146 | i_U: cpu_data_out <= (`MODE ? `AB : short_write(`A)); 147 | 148 | i_F: cpu_data_out <= (`MODE ? {character, 30'b0} : short_write({character, 12'b0})); 149 | i_I: cpu_data_out <= (`MODE ? {12'b0, tape_data_in, 18'b0} : short_write({12'b0, tape_data_in})); 150 | 151 | i_R: ABC <= ABC >>> shift_count(instruction); 152 | i_L: ABC <= ABC << shift_count(instruction); 153 | 154 | i_E: if(~ABC[70]) {SCR, jump} <= {`ADDRESS, 1'b1}; /* If A >= 0 (MSB == 0), PC <= address. */ 155 | i_G: if(ABC[70]) {SCR, jump} <= {`ADDRESS, 1'b1}; /* If A < 0 (MSB == 1), PC <= address. */ 156 | 157 | i_Y: ABC <= ABC + {35'b0, 1'b1, 35'b0}; 158 | 159 | i_O: begin character_strobe <= 1'b1; character <= short[16:12]; end 160 | 161 | i_Z: HALT <= 1'b1; 162 | i_X: NOP <= 1'b1; 163 | default: HALT <= 1'b1; /* Unknown instruction causes HALT */ 164 | endcase 165 | 166 | end 167 | 168 | endtask 169 | 170 | 171 | /* In order to match the original speed, we have many cycles to waste. 172 | Stuff happens only when phase counter is one of these: 173 | */ 174 | `define PREFETCH 11'b00000000000 175 | `define FETCH 11'b01000000000 176 | `define RD_MEM 11'b01010000000 177 | `define EXECUTE 11'b10000000000 178 | `define WR_MEM 11'b10100000000 179 | `define CLEANUP 11'b11000000000 180 | `define PC_STEP 11'b11010000000 181 | 182 | /* These instructions write to RAM */ 183 | wire ram_write = (IR[16:12] == i_T || IR[16:12] == i_U || IR[16:12] == i_I || IR[16:12] == i_F); 184 | 185 | reg [10:0] phase = 0; 186 | reg jump = 0; 187 | reg old_resume = 0; 188 | 189 | always @(posedge clock) begin 190 | 191 | old_resume <= resume; 192 | 193 | if(enable) begin 194 | phase <= HALT ? 11'b0 : phase + 1'b1; 195 | 196 | case(phase) 197 | `PREFETCH: cpu_addr_out <= SCR[9:1]; 198 | `FETCH: IR <= SCR[0] ? memory_in [34:18] : memory_in[16:0]; 199 | `RD_MEM: cpu_addr_out <= IR[10:2]; 200 | `EXECUTE: exec_instruction(IR, memory_in[34:0], IR[1] ? memory_in[34:18] : memory_in[16:0]); 201 | `WR_MEM: memory_wren <= ram_write ? 1'b1 : 1'b0; 202 | `CLEANUP: memory_wren <= 1'b0; 203 | `PC_STEP: {SCR, jump, character_strobe} <= {SCR + !jump, 2'b0}; 204 | endcase 205 | 206 | tape_read_strobe <= (IR[16:12] == i_I); 207 | end 208 | 209 | 210 | if (!old_resume && resume) begin 211 | HALT <= 1'b0; 212 | `A <= `A + rotary_dial_in; 213 | SCR <= SCR + 1'b1; 214 | end 215 | 216 | if(reset) begin 217 | ABC <= 0; 218 | SCR <= 0; 219 | RS <= 0; 220 | HALT <= 1'b0; 221 | end 222 | 223 | if(cpu_halt) 224 | HALT <= 1; 225 | 226 | end 227 | 228 | 229 | // These are used for panel and scope display 230 | 231 | assign o_abc = ABC; 232 | assign o_rs = RS; 233 | assign o_scr = SCR; 234 | assign o_ir = IR; 235 | assign o_phase = phase; 236 | 237 | endmodule 238 | 239 | -------------------------------------------------------------------------------- /sys/osd.v: -------------------------------------------------------------------------------- 1 | // A simple OSD implementation. Can be hooked up between a cores 2 | // VGA output and the physical VGA pins 3 | 4 | module osd 5 | ( 6 | input clk_sys, 7 | input io_osd, 8 | input io_strobe, 9 | input [15:0] io_din, 10 | 11 | input clk_video, 12 | input [23:0] din, 13 | input de_in, 14 | input vs_in, 15 | input hs_in, 16 | output [23:0] dout, 17 | output reg de_out, 18 | output reg vs_out, 19 | output reg hs_out, 20 | 21 | output reg osd_status 22 | ); 23 | 24 | parameter OSD_COLOR = 3'd4; 25 | 26 | localparam OSD_WIDTH = 12'd256; 27 | localparam OSD_HEIGHT = 12'd64; 28 | 29 | `ifdef OSD_HEADER 30 | localparam OSD_HDR = 12'd24; 31 | `else 32 | localparam OSD_HDR = 12'd0; 33 | `endif 34 | 35 | reg osd_enable; 36 | (* ramstyle="no_rw_check" *) reg [7:0] osd_buffer[OSD_HDR ? (4096+1024) : 4096]; 37 | 38 | reg info = 0; 39 | reg [8:0] infoh; 40 | reg [8:0] infow; 41 | reg [21:0] infox; 42 | reg [21:0] infoy; 43 | reg [21:0] osd_h; 44 | reg [21:0] osd_t; 45 | reg [21:0] osd_w; 46 | 47 | reg [1:0] rot = 0; 48 | 49 | always@(posedge clk_sys) begin 50 | reg [12:0] bcnt; 51 | reg [7:0] cmd; 52 | reg has_cmd; 53 | reg old_strobe; 54 | reg highres = 0; 55 | 56 | osd_t <= rot[0] ? OSD_WIDTH : (OSD_HEIGHT<<1); 57 | osd_h <= rot[0] ? (info ? infow : OSD_WIDTH) : info ? infoh : (OSD_HEIGHT<> (9-rot[0])) > 1) ? (((cnt+1'b1) >> (9-rot[0])) - 1'd1) : 22'd0; 119 | pixcnt <= 0; 120 | end 121 | end 122 | 123 | reg [2:0] osd_de; 124 | reg osd_pixel; 125 | reg [21:0] v_cnt; 126 | reg v_cnt_h, v_cnt_1, v_cnt_2, v_cnt_3, v_cnt_4; 127 | reg [21:0] v_osd_start_h, v_osd_start_1, v_osd_start_2, v_osd_start_3, v_osd_start_4, v_osd_start_5; 128 | reg [21:0] v_info_start_h, v_info_start_1, v_info_start_2, v_info_start_3, v_info_start_4, v_info_start_5; 129 | 130 | wire [21:0] osd_h_hdr = (info || rot) ? osd_h : (osd_h + OSD_HDR); 131 | 132 | // pipeline the comparisons a bit 133 | always @(posedge clk_video) if(ce_pix) begin 134 | v_cnt_h <= v_cnt <= osd_t; 135 | v_cnt_1 <= v_cnt < 320; 136 | v_cnt_2 <= v_cnt < 640; 137 | v_cnt_3 <= v_cnt < 960; 138 | v_cnt_4 <= v_cnt < 1280; 139 | 140 | v_osd_start_h <= (v_cnt-(osd_h_hdr>>1))>>1; 141 | v_osd_start_1 <= (v_cnt-osd_h_hdr)>>1; 142 | v_osd_start_2 <= (v_cnt-(osd_h_hdr<<1))>>1; 143 | v_osd_start_3 <= (v_cnt-(osd_h_hdr + (osd_h_hdr<<1)))>>1; 144 | v_osd_start_4 <= (v_cnt-(osd_h_hdr<<2))>>1; 145 | v_osd_start_5 <= (v_cnt-(osd_h_hdr + (osd_h_hdr<<2)))>>1; 146 | 147 | v_info_start_h <= rot[0] ? infox : infoy; 148 | v_info_start_1 <= rot[0] ? infox : infoy; 149 | v_info_start_2 <= rot[0] ? (infox<<1) : (infoy<<1); 150 | v_info_start_3 <= rot[0] ? (infox + (infox << 1)) : (infoy + (infoy << 1)); 151 | v_info_start_4 <= rot[0] ? (infox << 2) : (infoy << 2); 152 | v_info_start_5 <= rot[0] ? (infox + (infox << 2)) : (infoy + (infoy << 2)); 153 | end 154 | 155 | always @(posedge clk_video) begin 156 | reg deD; 157 | reg [2:0] osd_div; 158 | reg [2:0] multiscan; 159 | reg [7:0] osd_byte; 160 | reg [23:0] h_cnt; 161 | reg [21:0] dsp_width; 162 | reg [21:0] osd_vcnt; 163 | reg [21:0] h_osd_start; 164 | reg [21:0] v_osd_start; 165 | reg [21:0] osd_hcnt; 166 | reg [21:0] osd_hcnt2; 167 | reg osd_de1,osd_de2; 168 | reg [1:0] osd_en; 169 | reg f1; 170 | reg half; 171 | 172 | if(ce_pix) begin 173 | 174 | deD <= de_in; 175 | if(~&h_cnt) h_cnt <= h_cnt + 1'd1; 176 | 177 | if(~&osd_hcnt) osd_hcnt <= osd_hcnt + 1'd1; 178 | if(~&osd_hcnt2) osd_hcnt2 <= osd_hcnt2 + 1'd1; 179 | 180 | if (h_cnt == h_osd_start) begin 181 | osd_de[0] <= osd_en[1] && osd_h && ( 182 | osd_vcnt[11] ? (osd_vcnt[7] && (osd_vcnt[6:0] >= 4) && (osd_vcnt[6:0] < 19)) : 183 | (info && (rot == 3)) ? !osd_vcnt[21:8] : 184 | (osd_vcnt < osd_h) 185 | ); 186 | osd_hcnt <= 0; 187 | osd_hcnt2 <= 0; 188 | if(info && rot == 1) osd_hcnt2 <= 22'd128-infoh; 189 | end 190 | if (osd_hcnt+1 == osd_w) osd_de[0] <= 0; 191 | 192 | // falling edge of de 193 | if(!de_in && deD) dsp_width <= h_cnt[21:0]; 194 | 195 | // rising edge of de 196 | if(de_in && !deD) begin 197 | h_cnt <= 0; 198 | v_cnt <= v_cnt + 1'd1; 199 | h_osd_start <= info ? (rot[0] ? infoy : infox) : (((dsp_width - osd_w)>>1) - 2'd2); 200 | 201 | if(h_cnt > {dsp_width, 2'b00}) begin 202 | v_cnt <= 1; 203 | f1 <= ~f1; // skip every other frame for interlace compatibility. 204 | if(~f1) begin 205 | 206 | osd_en <= (osd_en << 1) | osd_enable; 207 | if(~osd_enable) osd_en <= 0; 208 | 209 | half <= 0; 210 | if(v_cnt_h) begin 211 | multiscan <= 0; 212 | v_osd_start <= info ? v_info_start_h : v_osd_start_h; 213 | half <= 1; 214 | end 215 | else if(v_cnt_1 | (rot[0] & v_cnt_2)) begin 216 | multiscan <= 0; 217 | v_osd_start <= info ? v_info_start_1 : v_osd_start_1; 218 | end 219 | else if(rot[0] ? v_cnt_3 : v_cnt_2) begin 220 | multiscan <= 1; 221 | v_osd_start <= info ? v_info_start_2 : v_osd_start_2; 222 | end 223 | else if(rot[0] ? v_cnt_4 : v_cnt_3) begin 224 | multiscan <= 2; 225 | v_osd_start <= info ? v_info_start_3 : v_osd_start_3; 226 | end 227 | else if(rot[0] | v_cnt_4) begin 228 | multiscan <= 3; 229 | v_osd_start <= info ? v_info_start_4 : v_osd_start_4; 230 | end 231 | else begin 232 | multiscan <= 4; 233 | v_osd_start <= info ? v_info_start_5 : v_osd_start_5; 234 | end 235 | end 236 | end 237 | 238 | osd_div <= osd_div + 1'd1; 239 | if(osd_div == multiscan) begin 240 | osd_div <= 0; 241 | if(~osd_vcnt[10]) osd_vcnt <= osd_vcnt + 1'd1 + half; 242 | if(osd_vcnt == 'b100010011111 && ~info) osd_vcnt <= 0; 243 | end 244 | if(v_osd_start == v_cnt) begin 245 | {osd_div,osd_vcnt} <= 0; 246 | if(info && rot == 3) osd_vcnt <= 22'd256-infow; 247 | else if(OSD_HDR && !rot) osd_vcnt <= {~info, 3'b000, ~info, 7'b0000000}; 248 | end 249 | end 250 | 251 | osd_byte <= osd_buffer[rot[0] ? ({osd_hcnt2[6:3], osd_vcnt[7:0]} ^ { {4{~rot[1]}}, {8{rot[1]}} }) : {osd_vcnt[7:3], osd_hcnt[7:0]}]; 252 | osd_pixel <= osd_byte[rot[0] ? ((osd_hcnt2[2:0]-1'd1) ^ {3{~rot[1]}}) : osd_vcnt[2:0]]; 253 | osd_de[2:1] <= osd_de[1:0]; 254 | end 255 | end 256 | 257 | reg [23:0] rdout; 258 | assign dout = rdout; 259 | 260 | always @(posedge clk_video) begin 261 | reg [23:0] ordout1, nrdout1, rdout2, rdout3; 262 | reg de1,de2,de3; 263 | reg osd_mux; 264 | reg vs1,vs2,vs3; 265 | reg hs1,hs2,hs3; 266 | 267 | nrdout1 <= din; 268 | ordout1 <= {{osd_pixel, osd_pixel, OSD_COLOR[2], din[23:19]},// 23:16 269 | {osd_pixel, osd_pixel, OSD_COLOR[1], din[15:11]},// 15:8 270 | {osd_pixel, osd_pixel, OSD_COLOR[0], din[7:3]}}; // 7:0 271 | 272 | osd_mux <= ~osd_de[2]; 273 | rdout2 <= osd_mux ? nrdout1 : ordout1; 274 | rdout3 <= rdout2; 275 | 276 | de1 <= de_in; de2 <= de1; de3 <= de2; 277 | hs1 <= hs_in; hs2 <= hs1; hs3 <= hs2; 278 | vs1 <= vs_in; vs2 <= vs1; vs3 <= vs2; 279 | 280 | rdout <= rdout3; 281 | de_out <= de3; 282 | hs_out <= hs3; 283 | vs_out <= vs3; 284 | end 285 | 286 | endmodule 287 | -------------------------------------------------------------------------------- /sys/f2sdram_safe_terminator.sv: -------------------------------------------------------------------------------- 1 | // ============================================================================ 2 | // 3 | // f2sdram_safe_terminator for MiSTer platform 4 | // 5 | // ============================================================================ 6 | // Copyright (c) 2021 bellwood420 7 | // 8 | // Background: 9 | // 10 | // Terminating a transaction of burst writing(/reading) in its midstream 11 | // seems to cause an illegal state to f2sdram interface. 12 | // 13 | // Forced reset request that occurs when loading other core is inevitable. 14 | // 15 | // So if it happens exactly within the transaction period, 16 | // unexpected issues with accessing to f2sdram interface will be caused 17 | // in next loaded core. 18 | // 19 | // It seems that only way to reset broken f2sdram interface is to reset 20 | // whole SDRAM Controller Subsystem from HPS via permodrst register 21 | // in Reset Manager. 22 | // But it cannot be done safely while Linux is running. 23 | // It is usually done when cold or warm reset is issued in HPS. 24 | // 25 | // Main_MiSTer is issuing reset for FPGA <> HPS bridges 26 | // via brgmodrst register in Reset Manager when loading rbf. 27 | // But it has no effect on f2sdram interface. 28 | // f2sdram interface seems to belong to SDRAM Controller Subsystem 29 | // rather than FPGA-to-HPS bridge. 30 | // 31 | // Main_MiSTer is also trying to issuing reset for f2sdram ports 32 | // via fpgaportrst register in SDRAM Controller Subsystem when loading rbf. 33 | // But according to the Intel's document, fpgaportrst register can be 34 | // used to stretch the port reset. 35 | // It seems that it cannot be used to assert the port reset. 36 | // 37 | // According to the Intel's document, there seems to be a reset port on 38 | // Avalon-MM slave interface, but it cannot be found in Qsys generated HDL. 39 | // 40 | // To conclude, the only thing FPGA can do is not to break the transaction. 41 | // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 42 | // 43 | // Purpose: 44 | // To prevent the issue, this module completes ongoing transaction 45 | // on behalf of user logic, when reset is asserted. 46 | // 47 | // Usage: 48 | // Insert this module into the bus line between 49 | // f2sdram (Avalon-MM slave) and user logic (Avalon-MM master). 50 | // 51 | // Notice: 52 | // Asynchronous reset request is not supported. 53 | // Please feed reset request synchronized to clock. 54 | // 55 | module f2sdram_safe_terminator #( 56 | parameter DATA_WIDTH = 64, 57 | parameter BURSTCOUNT_WIDTH = 8 58 | ) ( 59 | // clk should be the same as one provided to f2sdram port 60 | // clk should not be stop when reset is asserted 61 | input clk, 62 | // rst_req_sync should be synchronized to clk 63 | // Asynchronous reset request is not supported 64 | input rst_req_sync, 65 | 66 | // Master port: connecting to Alavon-MM slave(f2sdram) 67 | input waitrequest_master, 68 | output [BURSTCOUNT_WIDTH-1:0] burstcount_master, 69 | output [ADDRESS_WITDH-1:0] address_master, 70 | input [DATA_WIDTH-1:0] readdata_master, 71 | input readdatavalid_master, 72 | output read_master, 73 | output [DATA_WIDTH-1:0] writedata_master, 74 | output [BYTEENABLE_WIDTH-1:0] byteenable_master, 75 | output write_master, 76 | 77 | // Slave port: connecting to Alavon-MM master(user logic) 78 | output waitrequest_slave, 79 | input [BURSTCOUNT_WIDTH-1:0] burstcount_slave, 80 | input [ADDRESS_WITDH-1:0] address_slave, 81 | output [DATA_WIDTH-1:0] readdata_slave, 82 | output readdatavalid_slave, 83 | input read_slave, 84 | input [DATA_WIDTH-1:0] writedata_slave, 85 | input [BYTEENABLE_WIDTH-1:0] byteenable_slave, 86 | input write_slave 87 | ); 88 | 89 | localparam BYTEENABLE_WIDTH = DATA_WIDTH/8; 90 | localparam ADDRESS_WITDH = 32-$clog2(BYTEENABLE_WIDTH); 91 | 92 | /* 93 | * Capture init reset deaseert 94 | */ 95 | reg init_reset_deasserted = 1'b0; 96 | 97 | always_ff @(posedge clk) begin 98 | if (!rst_req_sync) begin 99 | init_reset_deasserted <= 1'b1; 100 | end 101 | end 102 | 103 | /* 104 | * Lock stage 105 | */ 106 | reg lock_stage = 1'b0; 107 | 108 | always_ff @(posedge clk) begin 109 | if (rst_req_sync) begin 110 | // Reset assert 111 | if (init_reset_deasserted) begin 112 | lock_stage <= 1'b1; 113 | end 114 | end 115 | else begin 116 | // Reset deassert 117 | lock_stage <= 1'b0; 118 | end 119 | end 120 | 121 | /* 122 | * Write burst transaction observer 123 | */ 124 | reg state_write = 1'b0; 125 | wire next_state_write; 126 | 127 | wire burst_write_start = !state_write && next_state_write; 128 | wire valid_write_data = state_write && !waitrequest_master; 129 | wire burst_write_end = state_write && (write_burstcounter == write_burstcount_latch - 1'd1); 130 | wire valid_non_burst_write = !state_write && write_slave && (burstcount_slave == 1) && !waitrequest_master; 131 | 132 | reg [BURSTCOUNT_WIDTH-1:0] write_burstcounter = 0; 133 | reg [BURSTCOUNT_WIDTH-1:0] write_burstcount_latch = 0; 134 | reg [ADDRESS_WITDH-1:0] write_address_latch = 0; 135 | 136 | always_ff @(posedge clk) begin 137 | state_write <= next_state_write; 138 | 139 | if (burst_write_start) begin 140 | write_burstcounter <= waitrequest_master ? 1'd0 : 1'd1; 141 | write_burstcount_latch <= burstcount_slave; 142 | write_address_latch <= address_slave; 143 | end 144 | else if (valid_write_data) begin 145 | write_burstcounter <= write_burstcounter + 1'd1; 146 | end 147 | end 148 | 149 | always_comb begin 150 | if (!state_write) begin 151 | if (valid_non_burst_write) 152 | next_state_write = 1'b0; 153 | else if (write_slave) 154 | next_state_write = 1'b1; 155 | else 156 | next_state_write = 1'b0; 157 | end 158 | else begin 159 | if (burst_write_end) 160 | next_state_write = 1'b0; 161 | else 162 | next_state_write = 1'b1; 163 | end 164 | end 165 | 166 | reg [BURSTCOUNT_WIDTH-1:0] write_terminate_counter = 0; 167 | reg [BURSTCOUNT_WIDTH-1:0] burstcount_latch = 0; 168 | reg [ADDRESS_WITDH-1:0] address_latch = 0; 169 | 170 | reg terminating = 0; 171 | reg read_terminating = 0; 172 | reg write_terminating = 0; 173 | 174 | wire on_write_transaction = state_write && next_state_write; 175 | wire on_start_write_transaction = !state_write && next_state_write; 176 | 177 | always_ff @(posedge clk) begin 178 | if (rst_req_sync) begin 179 | // Reset assert 180 | if (init_reset_deasserted) begin 181 | if (!lock_stage) begin 182 | // Even not knowing reading is in progress or not, 183 | // if it is in progress, it will finish at some point, and no need to do anything. 184 | // Assume that reading is in progress when we are not on write transaction. 185 | burstcount_latch <= burstcount_slave; 186 | address_latch <= address_slave; 187 | terminating <= 1; 188 | 189 | if (on_write_transaction) begin 190 | write_terminating <= 1; 191 | burstcount_latch <= write_burstcount_latch; 192 | address_latch <= write_address_latch; 193 | write_terminate_counter <= waitrequest_master ? write_burstcounter : write_burstcounter + 1'd1; 194 | end 195 | else if (on_start_write_transaction) begin 196 | if (!valid_non_burst_write) begin 197 | write_terminating <= 1; 198 | write_terminate_counter <= waitrequest_master ? 1'd0 : 1'd1; 199 | end 200 | end 201 | else if (read_slave && waitrequest_master) begin 202 | // Need to keep read signal, burstcount and address until waitrequest_master deasserted 203 | read_terminating <= 1; 204 | end 205 | end 206 | else if (!waitrequest_master) begin 207 | read_terminating <= 0; 208 | end 209 | end 210 | end 211 | else begin 212 | // Reset deassert 213 | if (!write_terminating) terminating <= 0; 214 | read_terminating <= 0; 215 | end 216 | 217 | if (write_terminating) begin 218 | // Continue write transaction until the end 219 | if (!waitrequest_master) write_terminate_counter <= write_terminate_counter + 1'd1; 220 | if (write_terminate_counter == burstcount_latch - 1'd1) write_terminating <= 0; 221 | end 222 | end 223 | 224 | /* 225 | * Bus mux depending on the stage. 226 | */ 227 | always_comb begin 228 | if (terminating) begin 229 | burstcount_master = burstcount_latch; 230 | address_master = address_latch; 231 | read_master = read_terminating; 232 | write_master = write_terminating; 233 | byteenable_master = 0; 234 | end 235 | else begin 236 | burstcount_master = burstcount_slave; 237 | address_master = address_slave; 238 | read_master = read_slave; 239 | byteenable_master = byteenable_slave; 240 | write_master = write_slave; 241 | end 242 | end 243 | 244 | // Just passing master <-> slave 245 | assign writedata_master = writedata_slave; 246 | assign readdata_slave = readdata_master; 247 | assign readdatavalid_slave = readdatavalid_master; 248 | assign waitrequest_slave = waitrequest_master; 249 | 250 | endmodule 251 | --------------------------------------------------------------------------------