├── 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 |
--------------------------------------------------------------------------------