├── doc ├── rygar-banner.jpg └── rygar-schematic.pdf ├── src ├── opl3 │ ├── fw │ │ ├── OPL3.COM │ │ ├── bin2mem.exe │ │ ├── clean.bat │ │ ├── bin2mem.c │ │ ├── OPL3.PRJ │ │ └── YMF262.H │ ├── opl.vhd │ ├── opl3.sv │ ├── opl3fm.sv │ └── NextZ80Reg.v ├── rygar.sdc ├── t80.qip ├── opl3.qip ├── util │ ├── clock_divider.vhd │ ├── edge_detector.vhd │ └── download_buffer.vhd ├── snd │ ├── pcm_counter.vhd │ └── msm5205.vhd ├── mem │ ├── single_port_rom.vhd │ ├── single_port_ram.vhd │ ├── dual_port_ram.vhd │ ├── true_dual_port_ram.vhd │ └── segment.vhd ├── gpu │ ├── palette.vhd │ ├── frame_buffer.vhd │ ├── char_layer.vhd │ ├── video_gen.vhd │ ├── scroll_layer.vhd │ └── sprite_blitter.vhd ├── t80 │ ├── T80_Reg.vhd │ └── T80s.vhd └── sound.vhd ├── README.md ├── .gitignore ├── .editorconfig ├── sys ├── pll_hdmi │ ├── pll_hdmi_0002.qip │ ├── pll_hdmi_0002_q13.qip │ └── pll_hdmi_0002.v ├── pll_q17.qip ├── pll │ ├── pll_0002.qip │ ├── pll_0002_q13.qip │ └── pll_0002.v ├── pll_q13.qip ├── pll.13.qip ├── i2s.v ├── sigma_delta_dac.v ├── pll_hdmi.13.qip ├── scanlines.v ├── i2c.v ├── video_cleaner.sv ├── build_id.tcl ├── sys.qip ├── fbpal.sv ├── sys_top.sdc ├── audio_out.v ├── sys_analog.tcl ├── vga_out.sv ├── alsa.sv ├── ltc2308.sv ├── video_mixer.sv ├── pll_cfg.v ├── pll_cfg.qip ├── scandoubler.v ├── osd.v └── hdmi_config.sv ├── Makefile ├── CHANGELOG.md ├── LICENCE ├── rygar.qpf ├── files.qip └── rygar.qsf /doc/rygar-banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nullobject/rygar-fpga/HEAD/doc/rygar-banner.jpg -------------------------------------------------------------------------------- /src/opl3/fw/OPL3.COM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nullobject/rygar-fpga/HEAD/src/opl3/fw/OPL3.COM -------------------------------------------------------------------------------- /doc/rygar-schematic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nullobject/rygar-fpga/HEAD/doc/rygar-schematic.pdf -------------------------------------------------------------------------------- /src/opl3/fw/bin2mem.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nullobject/rygar-fpga/HEAD/src/opl3/fw/bin2mem.exe -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repo has been moved to the MiSTer project: https://github.com/MiSTer-devel/Arcade-Rygar_MiSTer 2 | -------------------------------------------------------------------------------- /src/opl3/fw/clean.bat: -------------------------------------------------------------------------------- 1 | del /q *.as 2 | del /q *.obj 3 | del /q *.map 4 | del /q *.sym 5 | del /q *.bak 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.qws 2 | *.zip 3 | a.rygar.rom 4 | build_id.v 5 | c5_pin_model_dump.txt 6 | db 7 | incremental_db 8 | jtag.cdf 9 | output_files 10 | rom 11 | rygar_assignment_defaults.qdf 12 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [Makefile] 12 | indent_style = tab 13 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /sys/pll_q17.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) 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_cfg.qip ] 4 | -------------------------------------------------------------------------------- /sys/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 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: program clean 2 | 3 | build: 4 | quartus_sh --flow compile rygar 5 | 6 | program: 7 | quartus_pgm -m jtag -c 1 -o "p;output_files/rygar.sof@2" 8 | 9 | release: 10 | zip -j9 rygar-mister.zip build-rom.bat build-rom.sh output_files/rygar.rbf LICENCE README.md 11 | 12 | clean: 13 | rm -rf db incremental_db output_files 14 | -------------------------------------------------------------------------------- /sys/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 | -------------------------------------------------------------------------------- /src/rygar.sdc: -------------------------------------------------------------------------------- 1 | create_clock -name clk -period 20 [get_ports clk] 2 | 3 | derive_pll_clocks 4 | 5 | create_generated_clock -name SDRAM_CLK -source [get_pins {my_pll|pll_inst|altera_pll_i|outclk_wire[1]~CLKENA0|outclk}] [get_ports SDRAM_CLK] 6 | 7 | derive_clock_uncertainty 8 | 9 | # constrain input ports 10 | set_false_path -from * -to [get_ports {key*}] 11 | 12 | # constrain output ports 13 | set_false_path -from * -to [get_ports {vga*}] 14 | -------------------------------------------------------------------------------- /sys/pll_hdmi/pll_hdmi_0002_q13.qip: -------------------------------------------------------------------------------- 1 | set_instance_assignment -name PLL_COMPENSATION_MODE DIRECT -to "*pll_hdmi_0002*|altera_pll:altera_pll_i*|*" 2 | set_instance_assignment -name PLL_CHANNEL_SPACING "0.0 KHz" -to "*pll_hdmi_0002*|altera_pll:altera_pll_i*|*" 3 | set_instance_assignment -name PLL_AUTO_RESET ON -to "*pll_hdmi_0002*|altera_pll:altera_pll_i*|*" 4 | set_instance_assignment -name PLL_BANDWIDTH_PRESET AUTO -to "*pll_hdmi_0002*|altera_pll:altera_pll_i*|*" 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 VERILOG_FILE [file join $::quartus(qip_path) pll_cfg.v ] 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) pll_cfg/altera_pll_reconfig_core.v ] 5 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) pll_cfg/altera_pll_reconfig_top.v ] 6 | -------------------------------------------------------------------------------- /src/t80.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) t80/T80pa.vhd ] 2 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) t80/T80s.vhd ] 3 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) t80/T80_Reg.vhd ] 4 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) t80/T80_MCode.vhd] 5 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) t80/T80_ALU.vhd ] 6 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) t80/T80.vhd ] 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## Unreleased 4 | 5 | * Centre CRT image 6 | 7 | ## v1.0.0-beta.2 (2019-11-20) 8 | 9 | * Add sound 10 | 11 | ## v1.0.0-beta.1 (2019-10-24) 12 | 13 | * Swap fire and jump buttons 14 | * Fix MD5 check when building ROM on MacOS 15 | * Fix background layer vertical scroll position 16 | * Add 270 degree phase shift to SDRAM clock 17 | * Fix SDRAM timing constraints 18 | * Fix SDRAM startup sequence 19 | * Add SDRAM write recovery delay 20 | * Register SDRAM output 21 | * Allow SDRAM refresh as soon as a request has completed 22 | * Fix timing issues in ROM controller 23 | 24 | ## v1.0.0-beta.0 (2019-09-22) 25 | 26 | * Initial release 27 | -------------------------------------------------------------------------------- /src/opl3.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) opl3/opl3.sv ] 2 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) opl3/opl3fm.sv ] 3 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) opl3/opl3seq.sv ] 4 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) opl3/compressor.sv] 5 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) opl3/NextZ80Reg.v ] 6 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) opl3/NextZ80CPU.v ] 7 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) opl3/NextZ80ALU.v ] 8 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) opl3/opl.vhd ] 9 | -------------------------------------------------------------------------------- /src/opl3/fw/bin2mem.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | int c1,c2,d=1,i; 7 | FILE *in = fopen("opl3.com", "rb"); 8 | 9 | for(i=0; i<4096; i++) 10 | { 11 | if(i<128) 12 | { 13 | switch(i) 14 | { 15 | case 0: printf("00C3\n"); break; 16 | case 1: printf("0001\n"); break; 17 | case 2: printf("C300\n"); break; 18 | case 3: printf("00FF\n"); break; 19 | case 127: printf("C900\n"); break; 20 | default: printf("0000\n"); break; 21 | } 22 | } 23 | else if(d) 24 | { 25 | c1 = fgetc(in); 26 | if(c1 == -1) 27 | { 28 | d = 0; 29 | c1 = 0; 30 | c2 = 0; 31 | } 32 | else 33 | { 34 | c2 = fgetc(in); 35 | if(c2 == -1) 36 | { 37 | d = 0; 38 | c2 = 0; 39 | } 40 | } 41 | printf("%02X%02X\n", c2&0xff, c1&0xff); 42 | } 43 | else 44 | { 45 | printf("0000\n"); 46 | } 47 | } 48 | fclose(in); 49 | } 50 | -------------------------------------------------------------------------------- /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 [file join $::quartus(qip_path) "pll.v"] 8 | set_global_assignment -library "pll" -name VERILOG_FILE [file join $::quartus(qip_path) "pll/pll_0002.v"] 9 | set_global_assignment -library "pll" -name QIP_FILE [file join $::quartus(qip_path) "pll/pll_0002_q13.qip"] 10 | 11 | set_global_assignment -entity "pll_0002" -library "pll" -name IP_TOOL_NAME "altera_pll" 12 | set_global_assignment -entity "pll_0002" -library "pll" -name IP_TOOL_VERSION "13.1" 13 | set_global_assignment -entity "pll_0002" -library "pll" -name IP_TOOL_ENV "mwpim" 14 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | set_global_assignment -library "pll_hdmi" -name QIP_FILE [file join $::quartus(qip_path) "pll_hdmi/pll_hdmi_0002_q13.qip"] 10 | 11 | set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_TOOL_NAME "altera_pll" 12 | set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_TOOL_VERSION "13.1" 13 | set_global_assignment -entity "pll_hdmi_0002" -library "pll_hdmi" -name IP_TOOL_ENV "mwpim" 14 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | The MIT Licence (MIT) 2 | 3 | Copyright (c) 2019 Josh Bassett 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/scanlines.v: -------------------------------------------------------------------------------- 1 | module scanlines #(parameter v2=0) 2 | ( 3 | input clk, 4 | 5 | input [1:0] scanlines, 6 | input [23:0] din, 7 | output reg [23:0] dout, 8 | input hs,vs 9 | ); 10 | 11 | reg [1:0] scanline; 12 | always @(posedge clk) begin 13 | reg old_hs, old_vs; 14 | 15 | old_hs <= hs; 16 | old_vs <= vs; 17 | 18 | if(old_hs && ~hs) begin 19 | if(v2) begin 20 | scanline <= scanline + 1'd1; 21 | if (scanline == scanlines) scanline <= 0; 22 | end 23 | else scanline <= scanline ^ scanlines; 24 | end 25 | if(old_vs && ~vs) scanline <= 0; 26 | end 27 | 28 | wire [7:0] r,g,b; 29 | assign {r,g,b} = din; 30 | 31 | always @(*) begin 32 | case(scanline) 33 | 1: // reduce 25% = 1/2 + 1/4 34 | dout = {{1'b0, r[7:1]} + {2'b00, r[7:2]}, 35 | {1'b0, g[7:1]} + {2'b00, g[7:2]}, 36 | {1'b0, b[7:1]} + {2'b00, b[7:2]}}; 37 | 38 | 2: // reduce 50% = 1/2 39 | dout = {{1'b0, r[7:1]}, 40 | {1'b0, g[7:1]}, 41 | {1'b0, b[7:1]}}; 42 | 43 | 3: // reduce 75% = 1/4 44 | dout = {{2'b00, r[7:2]}, 45 | {2'b00, g[7:2]}, 46 | {2'b00, b[7:2]}}; 47 | 48 | default: dout = {r,g,b}; 49 | endcase 50 | end 51 | 52 | endmodule 53 | -------------------------------------------------------------------------------- /rygar.qpf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------- # 2 | # 3 | # Copyright (C) 2018 Intel Corporation. All rights reserved. 4 | # Your use of Intel Corporation's design tools, logic functions 5 | # and other software and tools, and its AMPP partner logic 6 | # functions, and any output files from any of the foregoing 7 | # (including device programming or simulation files), and any 8 | # associated documentation or information are expressly subject 9 | # to the terms and conditions of the Intel Program License 10 | # Subscription Agreement, the Intel Quartus Prime License Agreement, 11 | # the Intel FPGA IP License Agreement, or other applicable license 12 | # agreement, including, without limitation, that your use is for 13 | # the sole purpose of programming logic devices manufactured by 14 | # Intel and sold by Intel or its authorized distributors. Please 15 | # refer to the applicable agreement for further details. 16 | # 17 | # -------------------------------------------------------------------------- # 18 | # 19 | # Quartus Prime 20 | # Version 18.1.0 Build 625 09/12/2018 SJ Lite Edition 21 | # Date created = 16:15:06 June 21, 2019 22 | # 23 | # -------------------------------------------------------------------------- # 24 | 25 | QUARTUS_VERSION = "18.1" 26 | DATE = "16:15:06 June 21, 2019" 27 | 28 | # Revisions 29 | 30 | PROJECT_REVISION = "rygar" 31 | -------------------------------------------------------------------------------- /sys/i2c.v: -------------------------------------------------------------------------------- 1 | 2 | module i2c 3 | ( 4 | input CLK, 5 | 6 | input START, 7 | input [23:0] I2C_DATA, 8 | output reg END = 1, 9 | output reg ACK = 0, 10 | 11 | //I2C bus 12 | output I2C_SCL, 13 | inout I2C_SDA 14 | ); 15 | 16 | 17 | // Clock Setting 18 | parameter CLK_Freq = 50_000_000; // 50 MHz 19 | parameter I2C_Freq = 400_000; // 400 KHz 20 | 21 | reg I2C_CLOCK; 22 | always@(negedge CLK) begin 23 | integer mI2C_CLK_DIV = 0; 24 | if(mI2C_CLK_DIV < (CLK_Freq/I2C_Freq)) begin 25 | mI2C_CLK_DIV <= mI2C_CLK_DIV + 1; 26 | end else begin 27 | mI2C_CLK_DIV <= 0; 28 | I2C_CLOCK <= ~I2C_CLOCK; 29 | end 30 | end 31 | 32 | assign I2C_SCL = SCLK | I2C_CLOCK; 33 | assign I2C_SDA = SDO ? 1'bz : 1'b0; 34 | 35 | reg SCLK = 1, SDO = 1; 36 | 37 | always @(posedge CLK) begin 38 | reg old_clk; 39 | reg old_st; 40 | 41 | reg [5:0] SD_COUNTER = 'b111111; 42 | reg [0:31] SD; 43 | 44 | old_clk <= I2C_CLOCK; 45 | old_st <= START; 46 | 47 | if(~old_st && START) begin 48 | SCLK <= 1; 49 | SDO <= 1; 50 | ACK <= 0; 51 | END <= 0; 52 | SD <= {2'b10, I2C_DATA[23:16], 1'b1, I2C_DATA[15:8], 1'b1, I2C_DATA[7:0], 4'b1011}; 53 | SD_COUNTER <= 0; 54 | end else begin 55 | if(~old_clk && I2C_CLOCK && ~&SD_COUNTER) begin 56 | SD_COUNTER <= SD_COUNTER + 6'd1; 57 | case(SD_COUNTER) 58 | 01: SCLK <= 0; 59 | 10,19,28: ACK <= ACK | I2C_SDA; 60 | 29: SCLK <= 1; 61 | 32: END <= 1; 62 | endcase 63 | end 64 | 65 | if(old_clk && ~I2C_CLOCK && ~SD_COUNTER[5]) SDO <= SD[SD_COUNTER[4:0]]; 66 | end 67 | end 68 | 69 | endmodule 70 | -------------------------------------------------------------------------------- /files.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name QIP_FILE src/opl3.qip 2 | set_global_assignment -name QIP_FILE src/t80.qip 3 | set_global_assignment -name VHDL_FILE src/common.vhd 4 | set_global_assignment -name VHDL_FILE src/gpu/char_layer.vhd 5 | set_global_assignment -name VHDL_FILE src/gpu/frame_buffer.vhd 6 | set_global_assignment -name VHDL_FILE src/gpu/gpu.vhd 7 | set_global_assignment -name VHDL_FILE src/gpu/palette.vhd 8 | set_global_assignment -name VHDL_FILE src/gpu/scroll_layer.vhd 9 | set_global_assignment -name VHDL_FILE src/gpu/sprite_blitter.vhd 10 | set_global_assignment -name VHDL_FILE src/gpu/sprite_layer.vhd 11 | set_global_assignment -name VHDL_FILE src/gpu/video_gen.vhd 12 | set_global_assignment -name VHDL_FILE src/mem/dual_port_ram.vhd 13 | set_global_assignment -name VHDL_FILE src/mem/rom_controller.vhd 14 | set_global_assignment -name VHDL_FILE src/mem/sdram.vhd 15 | set_global_assignment -name VHDL_FILE src/mem/segment.vhd 16 | set_global_assignment -name VHDL_FILE src/mem/single_port_ram.vhd 17 | set_global_assignment -name VHDL_FILE src/mem/single_port_rom.vhd 18 | set_global_assignment -name VHDL_FILE src/mem/true_dual_port_ram.vhd 19 | set_global_assignment -name VHDL_FILE src/rygar.vhd 20 | set_global_assignment -name VHDL_FILE src/sound.vhd 21 | set_global_assignment -name VHDL_FILE src/snd/msm5205.vhd 22 | set_global_assignment -name VHDL_FILE src/snd/pcm_counter.vhd 23 | set_global_assignment -name VHDL_FILE src/util/clock_divider.vhd 24 | set_global_assignment -name VHDL_FILE src/util/download_buffer.vhd 25 | set_global_assignment -name VHDL_FILE src/util/edge_detector.vhd 26 | set_global_assignment -name SYSTEMVERILOG_FILE Arcade-Rygar.sv 27 | -------------------------------------------------------------------------------- /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 | // video output signals 27 | output reg [7:0] VGA_R, 28 | output reg [7:0] VGA_G, 29 | output reg [7:0] VGA_B, 30 | output reg VGA_VS, 31 | output reg VGA_HS, 32 | output VGA_DE, 33 | 34 | // optional aligned blank 35 | output reg HBlank_out, 36 | output reg VBlank_out 37 | ); 38 | 39 | wire hs, vs; 40 | s_fix sync_v(clk_vid, HSync, hs); 41 | s_fix sync_h(clk_vid, VSync, vs); 42 | 43 | wire hbl = hs | HBlank; 44 | wire vbl = vs | VBlank; 45 | 46 | assign VGA_DE = ~(HBlank_out | VBlank_out); 47 | 48 | always @(posedge clk_vid) begin 49 | if(ce_pix) begin 50 | HBlank_out <= hbl; 51 | 52 | VGA_VS <= vs; 53 | VGA_HS <= hs; 54 | VGA_R <= R; 55 | VGA_G <= G; 56 | VGA_B <= B; 57 | 58 | if(HBlank_out & ~hbl) VBlank_out <= vbl; 59 | end 60 | end 61 | 62 | endmodule 63 | 64 | module s_fix 65 | ( 66 | input clk, 67 | 68 | input sync_in, 69 | output sync_out 70 | ); 71 | 72 | assign sync_out = sync_in ^ pol; 73 | 74 | reg pol; 75 | always @(posedge clk) begin 76 | integer pos = 0, neg = 0, cnt = 0; 77 | reg s1,s2; 78 | 79 | s1 <= sync_in; 80 | s2 <= s1; 81 | 82 | if(~s2 & s1) neg <= cnt; 83 | if(s2 & ~s1) pos <= cnt; 84 | 85 | cnt <= cnt + 1; 86 | if(s2 != s1) cnt <= 0; 87 | 88 | pol <= pos > neg; 89 | end 90 | 91 | endmodule 92 | -------------------------------------------------------------------------------- /src/util/clock_divider.vhd: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2019 Josh Bassett 2 | -- 3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 4 | -- of this software and associated documentation files (the "Software"), to deal 5 | -- in the Software without restriction, including without limitation the rights 6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | -- copies of the Software, and to permit persons to whom the Software is 8 | -- furnished to do so, subject to the following conditions: 9 | -- 10 | -- The above copyright notice and this permission notice shall be included in all 11 | -- copies or substantial portions of the Software. 12 | -- 13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | -- SOFTWARE. 20 | 21 | library ieee; 22 | use ieee.std_logic_1164.all; 23 | use ieee.numeric_std.all; 24 | 25 | -- Generates a clock enable signal by dividing the input clock. 26 | entity clock_divider is 27 | generic ( 28 | DIVISOR : natural 29 | ); 30 | port ( 31 | -- clock 32 | clk : in std_logic; 33 | 34 | -- clock enable output strobe 35 | cen : out std_logic 36 | ); 37 | end clock_divider; 38 | 39 | architecture arch of clock_divider is 40 | signal count : natural range 0 to DIVISOR-1; 41 | begin 42 | process (clk) 43 | begin 44 | if rising_edge(clk) then 45 | if count < DIVISOR-1 then 46 | count <= count + 1; 47 | cen <= '0'; 48 | else 49 | count <= 0; 50 | cen <= '1'; 51 | end if; 52 | end if; 53 | end process; 54 | end architecture arch; 55 | -------------------------------------------------------------------------------- /src/util/edge_detector.vhd: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2019 Josh Bassett 2 | -- 3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 4 | -- of this software and associated documentation files (the "Software"), to deal 5 | -- in the Software without restriction, including without limitation the rights 6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | -- copies of the Software, and to permit persons to whom the Software is 8 | -- furnished to do so, subject to the following conditions: 9 | -- 10 | -- The above copyright notice and this permission notice shall be included in all 11 | -- copies or substantial portions of the Software. 12 | -- 13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | -- SOFTWARE. 20 | 21 | library ieee; 22 | use ieee.std_logic_1164.all; 23 | use ieee.numeric_std.all; 24 | 25 | -- Generates a pulse when a rising or falling edge is detected for the input 26 | -- signal. 27 | entity edge_detector is 28 | generic ( 29 | RISING : boolean := false; 30 | FALLING : boolean := false 31 | ); 32 | port ( 33 | -- clock 34 | clk : in std_logic; 35 | 36 | -- data input 37 | data : in std_logic; 38 | 39 | -- output data 40 | q : out std_logic 41 | ); 42 | end edge_detector; 43 | 44 | architecture arch of edge_detector is 45 | signal t0 : std_logic; 46 | signal a, b : std_logic; 47 | begin 48 | process (clk) 49 | begin 50 | if rising_edge(clk) then 51 | t0 <= data; 52 | end if; 53 | end process; 54 | 55 | a <= (not t0 and data) when RISING else '0'; 56 | b <= (t0 and not data) when FALLING else '0'; 57 | q <= a or b; 58 | end architecture arch; 59 | -------------------------------------------------------------------------------- /src/snd/pcm_counter.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | use work.common.all; 7 | 8 | -- The PCM counter increments an address range in nibbles. 9 | -- 10 | -- The address is used to load data from the PCM ROM. 11 | entity pcm_counter is 12 | generic ( 13 | ADDR_WIDTH : natural 14 | ); 15 | port ( 16 | reset : in std_logic; 17 | 18 | clk : in std_logic; 19 | vck : in std_logic; 20 | 21 | data : in byte_t; 22 | we : in std_logic; 23 | set_low : in std_logic; 24 | set_high : in std_logic; 25 | 26 | -- output address 27 | addr : out unsigned(ADDR_WIDTH-1 downto 0); 28 | nibble : out std_logic; 29 | 30 | -- The done signal is asserted when the counter has reached the end 31 | -- address. 32 | done : buffer std_logic 33 | ); 34 | end pcm_counter; 35 | 36 | architecture rtl of pcm_counter is 37 | signal vck_falling : std_logic; 38 | 39 | -- registers 40 | signal ctr : unsigned(ADDR_WIDTH+1 downto 0); 41 | signal ctr_end : unsigned(7 downto 0); 42 | begin 43 | -- detect falling edges of the VCK signal 44 | vck_edge_detector : entity work.edge_detector 45 | generic map (FALLING => true) 46 | port map ( 47 | clk => clk, 48 | data => vck, 49 | q => vck_falling 50 | ); 51 | 52 | latch_comp : process (clk, reset) 53 | begin 54 | if reset = '1' then 55 | ctr_end <= (others => '0'); 56 | elsif rising_edge(clk) then 57 | if set_high = '1' and we = '1' then 58 | ctr_end <= unsigned(data); 59 | end if; 60 | end if; 61 | end process; 62 | 63 | latch_counter : process (clk, reset) 64 | begin 65 | if reset = '1' then 66 | ctr <= (others => '0'); 67 | elsif rising_edge(clk) then 68 | if set_low = '1' and we = '1' then 69 | ctr(ADDR_WIDTH+1 downto ADDR_WIDTH-6) <= unsigned(data); 70 | ctr(ADDR_WIDTH-7 downto 0) <= (others => '0'); 71 | elsif vck_falling = '1' and done = '0' then 72 | ctr <= ctr + 1; 73 | end if; 74 | end if; 75 | end process; 76 | 77 | -- set the address and nibble 78 | addr <= ctr(ADDR_WIDTH downto 1); 79 | nibble <= ctr(0); 80 | 81 | -- set the done signal 82 | done <= '1' when ctr_end = ctr(ADDR_WIDTH+1 downto ADDR_WIDTH-6) else '0'; 83 | end rtl; 84 | -------------------------------------------------------------------------------- /src/opl3/fw/OPL3.PRJ: -------------------------------------------------------------------------------- 1 | ;Project file: Z:\OPL3FW\OPL3.PRJ for HI-TECH C Z80/Z180/64180 V7.80 2 | 3 | List: Source Files Rel Auto 4 | Entry: YMF262.C 5 | Endlist: 6 | 7 | List: Object Files Abs Auto 8 | Entry: $(LIB)\RTZ80-c.OBJ 9 | Endlist: 10 | 11 | List: CPP Include Paths Abs Auto 12 | Entry: $(INC) 13 | Endlist: 14 | 15 | List: CPP Pre-defined Symbols Abs Auto 16 | Entry: -Dz80 17 | Entry: -DHI_TECH_C 18 | Entry: -SP2,2,2,2,2,2,2 19 | Entry: -S1,2,2,4,4,4 20 | Entry: -D_HOSTED 21 | Entry: -DCPM 22 | Entry: -DSMALL_MODEL 23 | Entry: -D_HTC_VER_MAJOR_=7 24 | Entry: -D_HTC_VER_MINOR_=80 25 | Entry: -D_HTC_VER_PATCH_=2 26 | Endlist: 27 | 28 | List: Libraries Abs Auto 29 | Entry: $(LIB)\Z80-cC.LIB 30 | Endlist: 31 | 32 | List: Linker options Abs Frozen Warned 33 | Entry: -pvectors=0,lowtext,text,strings,const,im2vecs,bss 34 | Entry: -pnvram=bss,heap 35 | Entry: -Pdata=1900h 36 | Endlist: 37 | 38 | List: Objtohex options Abs Auto 39 | Entry: -b100h 40 | Endlist: 41 | 42 | Depfiles: 43 | Entry: $(INC)\STRING.H 44 | Entry: $(INC)\SYS.H 45 | Entry: ymf262.h 46 | Enddeps: 47 | 48 | Dependencies: 49 | Entry: 1528935816 3 0 1 2 50 | Enddeps: 51 | 52 | 53 | Int: Checksize: 1 54 | Int: OuputFormat: 0 55 | Int: Warnlevel: 0 56 | Int: IdLength: 31 57 | Int: DebugBaud: 0 58 | Int: ComPort: 0 59 | Int: GlobOptLevel: 9 60 | Time: OptionsModified: 1528921310 61 | Int: Rom_addr: 0 62 | Int: Ram_addr: 32768 63 | Int: Ram_size: 32768 64 | Int: Nvram_addr: 0 65 | Int: Ram_phys: 262144 66 | Int: Bank_addr: 8192 67 | Int: Bank_size: 24576 68 | Int: Bank_phys: 8192 69 | Int: Size_phys: 1040384 70 | Int: Modelno: 2 71 | Int: Chiptype: 0 72 | 73 | Bool: Globopt: 1 74 | Bool: Postopt: 1 75 | Bool: Assemopt: 0 76 | Bool: Symbolic_debug: 0 77 | Bool: Nolocal: 0 78 | Bool: Uselong: 0 79 | Bool: Usefloat: 0 80 | Bool: Autoload: 0 81 | Bool: Cppasm: 0 82 | Bool: Genlist: 0 83 | Bool: GenSrclist: 0 84 | Bool: Gotadrs: 1 85 | Bool: Multirom: 0 86 | Bool: Avocet_symbols: 0 87 | Bool: Stopwarn: 1 88 | Bool: StrictANSI: 0 89 | Bool: Savedeps: 1 90 | Bool: NumericSort: 0 91 | Bool: Romdata: 0 92 | Bool: Port8: 0 93 | Bool: UseAltReg: 0 94 | 95 | String: Outfile:OPL3.COM 96 | String: Mapfile: 97 | String: Symfile: 98 | ROM Ranges: 99 | EndROM 100 | Checksums: 101 | EndChecksums 102 | -------------------------------------------------------------------------------- /sys/build_id.tcl: -------------------------------------------------------------------------------- 1 | 2 | # Build TimeStamp Verilog Module 3 | # Jeff Wiencrot - 8/1/2011 4 | proc generateBuildID_Verilog {} { 5 | 6 | # Get the timestamp (see: http://www.altera.com/support/examples/tcl/tcl-date-time-stamp.html) 7 | set buildDate [ clock format [ clock seconds ] -format %y%m%d ] 8 | set buildTime [ clock format [ clock seconds ] -format %H%M%S ] 9 | 10 | # Create a Verilog file for output 11 | set outputFileName "build_id.v" 12 | set outputFile [open $outputFileName "w"] 13 | 14 | # Output the Verilog source 15 | puts $outputFile "`define BUILD_DATE \"$buildDate\"" 16 | puts $outputFile "`define BUILD_TIME \"$buildTime\"" 17 | close $outputFile 18 | 19 | # Send confirmation message to the Messages window 20 | post_message "Generated build identification Verilog module: [pwd]/$outputFileName" 21 | post_message "Date: $buildDate" 22 | post_message "Time: $buildTime" 23 | } 24 | 25 | # Build CDF file 26 | # Sorgelig - 17/2/2018 27 | proc generateCDF {revision device outpath} { 28 | 29 | set outputFileName "jtag.cdf" 30 | set outputFile [open $outputFileName "w"] 31 | 32 | puts $outputFile "JedecChain;" 33 | puts $outputFile " FileRevision(JESD32A);" 34 | puts $outputFile " DefaultMfr(6E);" 35 | puts $outputFile "" 36 | puts $outputFile " P ActionCode(Ign)" 37 | puts $outputFile " Device PartName(SOCVHPS) MfrSpec(OpMask(0));" 38 | puts $outputFile " P ActionCode(Cfg)" 39 | puts $outputFile " Device PartName($device) Path(\"$outpath/\") File(\"$revision.sof\") MfrSpec(OpMask(1));" 40 | puts $outputFile "ChainEnd;" 41 | puts $outputFile "" 42 | puts $outputFile "AlteraBegin;" 43 | puts $outputFile " ChainType(JTAG);" 44 | puts $outputFile "AlteraEnd;" 45 | } 46 | 47 | set project_name [lindex $quartus(args) 1] 48 | set revision [lindex $quartus(args) 2] 49 | 50 | if {[project_exists $project_name]} { 51 | if {[string equal "" $revision]} { 52 | project_open $project_name -revision [get_current_revision $project_name] 53 | } else { 54 | project_open $project_name -revision $revision 55 | } 56 | } else { 57 | post_message -type error "Project $project_name does not exist" 58 | exit 59 | } 60 | 61 | set device [get_global_assignment -name DEVICE] 62 | set outpath [get_global_assignment -name PROJECT_OUTPUT_DIRECTORY] 63 | 64 | if [is_project_open] { 65 | project_close 66 | } 67 | 68 | generateBuildID_Verilog 69 | generateCDF $revision $device $outpath 70 | -------------------------------------------------------------------------------- /sys/sys.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) pll.qip ] 2 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) pll_cfg.qip ] 3 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) pll_hdmi.qip ] 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) sys_top.v ] 5 | set_global_assignment -name SDC_FILE [file join $::quartus(qip_path) sys_top.sdc ] 6 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) ascal.vhd ] 7 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) pll_hdmi_adj.vhd ] 8 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) fbpal.sv ] 9 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) hq2x.sv ] 10 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) scandoubler.v ] 11 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) scanlines.v ] 12 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_cleaner.sv ] 13 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) video_mixer.sv ] 14 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) osd.v ] 15 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) vga_out.sv ] 16 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) i2c.v ] 17 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) alsa.sv ] 18 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) i2s.v ] 19 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) spdif.v ] 20 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) audio_out.v ] 21 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) ltc2308.sv ] 22 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) sigma_delta_dac.v ] 23 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) hdmi_config.sv ] 24 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) sysmem.sv ] 25 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) sd_card.v ] 26 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) hps_io.v ] 27 | -------------------------------------------------------------------------------- /sys/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 'outclk1' 14 | output wire outclk_1, 15 | 16 | // interface 'locked' 17 | output wire locked 18 | ); 19 | 20 | altera_pll #( 21 | .fractional_vco_multiplier("false"), 22 | .reference_clock_frequency("50.0 MHz"), 23 | .operation_mode("direct"), 24 | .number_of_clocks(2), 25 | .output_clock_frequency0("48.000000 MHz"), 26 | .phase_shift0("0 ps"), 27 | .duty_cycle0(50), 28 | .output_clock_frequency1("48.000000 MHz"), 29 | .phase_shift1("15625 ps"), 30 | .duty_cycle1(50), 31 | .output_clock_frequency2("0 MHz"), 32 | .phase_shift2("0 ps"), 33 | .duty_cycle2(50), 34 | .output_clock_frequency3("0 MHz"), 35 | .phase_shift3("0 ps"), 36 | .duty_cycle3(50), 37 | .output_clock_frequency4("0 MHz"), 38 | .phase_shift4("0 ps"), 39 | .duty_cycle4(50), 40 | .output_clock_frequency5("0 MHz"), 41 | .phase_shift5("0 ps"), 42 | .duty_cycle5(50), 43 | .output_clock_frequency6("0 MHz"), 44 | .phase_shift6("0 ps"), 45 | .duty_cycle6(50), 46 | .output_clock_frequency7("0 MHz"), 47 | .phase_shift7("0 ps"), 48 | .duty_cycle7(50), 49 | .output_clock_frequency8("0 MHz"), 50 | .phase_shift8("0 ps"), 51 | .duty_cycle8(50), 52 | .output_clock_frequency9("0 MHz"), 53 | .phase_shift9("0 ps"), 54 | .duty_cycle9(50), 55 | .output_clock_frequency10("0 MHz"), 56 | .phase_shift10("0 ps"), 57 | .duty_cycle10(50), 58 | .output_clock_frequency11("0 MHz"), 59 | .phase_shift11("0 ps"), 60 | .duty_cycle11(50), 61 | .output_clock_frequency12("0 MHz"), 62 | .phase_shift12("0 ps"), 63 | .duty_cycle12(50), 64 | .output_clock_frequency13("0 MHz"), 65 | .phase_shift13("0 ps"), 66 | .duty_cycle13(50), 67 | .output_clock_frequency14("0 MHz"), 68 | .phase_shift14("0 ps"), 69 | .duty_cycle14(50), 70 | .output_clock_frequency15("0 MHz"), 71 | .phase_shift15("0 ps"), 72 | .duty_cycle15(50), 73 | .output_clock_frequency16("0 MHz"), 74 | .phase_shift16("0 ps"), 75 | .duty_cycle16(50), 76 | .output_clock_frequency17("0 MHz"), 77 | .phase_shift17("0 ps"), 78 | .duty_cycle17(50), 79 | .pll_type("General"), 80 | .pll_subtype("General") 81 | ) altera_pll_i ( 82 | .rst (rst), 83 | .outclk ({outclk_1, outclk_0}), 84 | .locked (locked), 85 | .fboutclk ( ), 86 | .fbclk (1'b0), 87 | .refclk (refclk) 88 | ); 89 | endmodule 90 | 91 | -------------------------------------------------------------------------------- /sys/fbpal.sv: -------------------------------------------------------------------------------- 1 | //============================================================================ 2 | // 3 | // Framebuffer Palette support for MiSTer 4 | // (c)2019 Sorgelig 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 fbpal 23 | ( 24 | input reset, 25 | 26 | input en_in, 27 | output reg en_out, 28 | 29 | input ram_clk, 30 | output reg [28:0] ram_address, 31 | output reg [7:0] ram_burstcount, 32 | input ram_waitrequest, 33 | input [63:0] ram_readdata, 34 | input ram_readdatavalid, 35 | output reg ram_read, 36 | 37 | input [31:0] fb_address, 38 | 39 | input pal_en, 40 | output reg [7:0] pal_a, 41 | output reg [23:0] pal_d, 42 | output reg pal_wr 43 | ); 44 | 45 | reg [31:0] base_addr; 46 | always @(posedge ram_clk) base_addr <= fb_address - 4096; 47 | 48 | reg [6:0] buf_rptr = 0; 49 | always @(posedge ram_clk) begin 50 | reg [23:0] odd_d; 51 | 52 | if(~pal_a[0] & pal_wr) {pal_a[0], pal_d} <= {1'b1, odd_d}; 53 | else pal_wr <= 0; 54 | 55 | if(~ram_waitrequest) ram_read <= 0; 56 | 57 | if(pal_en & ~reset) begin 58 | if(ram_burstcount) begin 59 | if(ram_readdatavalid) begin 60 | ram_burstcount <= 0; 61 | 62 | odd_d <= ram_readdata[55:32]; 63 | pal_d <= ram_readdata[23:0]; 64 | pal_a <= {buf_rptr, 1'b0}; 65 | pal_wr <= 1; 66 | 67 | en_out <= en_in; 68 | buf_rptr <= buf_rptr + 1'd1; 69 | end 70 | end 71 | else begin 72 | if(~ram_waitrequest && en_out != en_in) begin 73 | ram_address <= base_addr[31:3] + buf_rptr; 74 | ram_burstcount <= 1; 75 | ram_read <= 1; 76 | end 77 | end 78 | end 79 | else begin 80 | en_out <= en_in; 81 | buf_rptr <= 0; 82 | ram_burstcount <= 0; 83 | end 84 | end 85 | 86 | endmodule 87 | -------------------------------------------------------------------------------- /src/mem/single_port_rom.vhd: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2019 Josh Bassett 2 | -- 3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 4 | -- of this software and associated documentation files (the "Software"), to deal 5 | -- in the Software without restriction, including without limitation the rights 6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | -- copies of the Software, and to permit persons to whom the Software is 8 | -- furnished to do so, subject to the following conditions: 9 | -- 10 | -- The above copyright notice and this permission notice shall be included in all 11 | -- copies or substantial portions of the Software. 12 | -- 13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | -- SOFTWARE. 20 | 21 | library ieee; 22 | use ieee.std_logic_1164.all; 23 | use ieee.numeric_std.all; 24 | 25 | library altera_mf; 26 | use altera_mf.altera_mf_components.all; 27 | 28 | entity single_port_rom is 29 | generic ( 30 | ADDR_WIDTH : natural := 8; 31 | DATA_WIDTH : natural := 8; 32 | INIT_FILE : string := "" 33 | ); 34 | port ( 35 | -- clock 36 | clk : in std_logic; 37 | 38 | -- chip select 39 | cs : in std_logic := '1'; 40 | 41 | -- address 42 | addr : in unsigned(ADDR_WIDTH-1 downto 0); 43 | 44 | -- data out 45 | dout : out std_logic_vector(DATA_WIDTH-1 downto 0) 46 | ); 47 | end single_port_rom; 48 | 49 | architecture arch of single_port_rom is 50 | signal q : std_logic_vector(DATA_WIDTH-1 downto 0); 51 | begin 52 | altsyncram_component : altsyncram 53 | generic map ( 54 | address_aclr_a => "NONE", 55 | clock_enable_input_a => "BYPASS", 56 | clock_enable_output_a => "BYPASS", 57 | init_file => INIT_FILE, 58 | intended_device_family => "Cyclone V", 59 | lpm_hint => "ENABLE_RUNTIME_MOD=NO", 60 | lpm_type => "altsyncram", 61 | numwords_a => 2**ADDR_WIDTH, 62 | operation_mode => "ROM", 63 | outdata_aclr_a => "NONE", 64 | outdata_reg_a => "UNREGISTERED", 65 | width_a => DATA_WIDTH, 66 | width_byteena_a => 1, 67 | widthad_a => ADDR_WIDTH 68 | ) 69 | port map ( 70 | address_a => std_logic_vector(addr), 71 | clock0 => clk, 72 | q_a => q 73 | ); 74 | 75 | dout <= q when cs = '1' else (others => '0'); 76 | end architecture arch; 77 | -------------------------------------------------------------------------------- /src/util/download_buffer.vhd: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2019 Josh Bassett 2 | -- 3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 4 | -- of this software and associated documentation files (the "Software"), to deal 5 | -- in the Software without restriction, including without limitation the rights 6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | -- copies of the Software, and to permit persons to whom the Software is 8 | -- furnished to do so, subject to the following conditions: 9 | -- 10 | -- The above copyright notice and this permission notice shall be included in all 11 | -- copies or substantial portions of the Software. 12 | -- 13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | -- SOFTWARE. 20 | 21 | library ieee; 22 | use ieee.std_logic_1164.all; 23 | use ieee.numeric_std.all; 24 | 25 | use work.common.all; 26 | 27 | -- The download buffer writes a stream of bytes to an internal buffer. When the 28 | -- buffer is full, it is flushed as a single word. 29 | -- 30 | -- For example, with a buffer size of four, every four bytes written will be 31 | -- flushed as a single 32-bit word. 32 | entity download_buffer is 33 | generic ( 34 | -- the size of the buffer (in bytes) 35 | SIZE : natural 36 | ); 37 | port ( 38 | -- reset 39 | reset : in std_logic := '0'; 40 | 41 | -- clock 42 | clk : in std_logic; 43 | 44 | -- data in 45 | din : in byte_t; 46 | 47 | -- data out 48 | dout : out std_logic_vector(SIZE*8-1 downto 0); 49 | 50 | -- write enable 51 | we : in std_logic; 52 | 53 | -- when the valid signal is asserted there is a word on the output data bus 54 | valid : out std_logic 55 | ); 56 | end download_buffer; 57 | 58 | architecture arch of download_buffer is 59 | signal counter : natural range 0 to SIZE-1; 60 | begin 61 | process (clk, reset) 62 | begin 63 | if reset = '1' then 64 | counter <= 0; 65 | valid <= '0'; 66 | elsif rising_edge(clk) then 67 | if we = '1' then 68 | -- write the word to the output data bus 69 | dout((SIZE-counter)*8-1 downto (SIZE-counter-1)*8) <= din; 70 | 71 | -- increment the counter 72 | counter <= counter + 1; 73 | 74 | -- flush the buffer if it is full 75 | if counter = SIZE-1 then 76 | valid <= '1'; 77 | else 78 | valid <= '0'; 79 | end if; 80 | end if; 81 | end if; 82 | end process; 83 | end architecture; 84 | -------------------------------------------------------------------------------- /sys/sys_top.sdc: -------------------------------------------------------------------------------- 1 | # Specify root clocks 2 | create_clock -period 20.0 [get_ports {FPGA_CLK1_50}] 3 | create_clock -period 20.0 [get_ports {FPGA_CLK2_50}] 4 | create_clock -period 20.0 [get_ports {FPGA_CLK3_50}] 5 | create_clock -period 10.0 [get_pins -compatibility_mode {*|h2f_user0_clk}] 6 | create_clock -period 10.0 -name spi_sck [get_pins -compatibility_mode {spi|sclk_out}] 7 | 8 | derive_pll_clocks 9 | 10 | create_generated_clock -name SDRAM_CLK \ 11 | -source [get_pins -compatibility_mode {emu|pll|pll_inst|altera_pll_i|general[1].gpll~PLL_OUTPUT_COUNTER|divclk}] \ 12 | [get_ports {SDRAM_CLK}] 13 | 14 | create_generated_clock -name HDMI_CLK \ 15 | -source [get_pins -compatibility_mode {pll_hdmi|pll_hdmi_inst|altera_pll_i|*[0].*|divclk}] \ 16 | [get_ports {HDMI_TX_CLK}] 17 | 18 | derive_clock_uncertainty 19 | 20 | # data access delay (tAC) plus a small margin to allow for propagation delay 21 | set_input_delay -clock SDRAM_CLK -max [expr 6.0 + 0.5] [get_ports {SDRAM_DQ[*]}] 22 | 23 | # data output hold time (tOH) 24 | set_input_delay -clock SDRAM_CLK -min 2.5 [get_ports {SDRAM_DQ[*]}] 25 | 26 | # data input setup time (tIS) 27 | set_output_delay -clock SDRAM_CLK -max 1.5 [get_ports {SDRAM_A* SDRAM_BA* SDRAM_D* SDRAM_CKE SDRAM_n*}] 28 | 29 | # data input hold time (tIH) 30 | set_output_delay -clock SDRAM_CLK -min -0.8 [get_ports {SDRAM_A* SDRAM_BA* SDRAM_D* SDRAM_CKE SDRAM_n*}] 31 | 32 | # use proper edges for the timing calculations 33 | set_multicycle_path -setup -end \ 34 | -rise_from [get_clocks {SDRAM_CLK}] \ 35 | -rise_to [get_clocks {emu|pll|pll_inst|altera_pll_i|general[0].gpll~PLL_OUTPUT_COUNTER|divclk}] 2 36 | 37 | # decouple different clock groups (to simplify routing) 38 | set_clock_groups -exclusive \ 39 | -group [get_clocks {FPGA_CLK1_50 FPGA_CLK2_50 FPGA_CLK3_50}] \ 40 | -group [get_clocks {*|h2f_user0_clk}] \ 41 | -group [get_clocks {pll_hdmi|pll_hdmi_inst|altera_pll_i|*[0].*|divclk}] \ 42 | -group [get_clocks {*|pll|pll_inst|altera_pll_i|*[*].*|divclk}] 43 | 44 | set_output_delay -clock HDMI_CLK -max 4.0 [get_ports {HDMI_TX_D[*] HDMI_TX_DE HDMI_TX_HS HDMI_TX_VS}] 45 | set_output_delay -clock HDMI_CLK -min 3.0 [get_ports {HDMI_TX_D[*] HDMI_TX_DE HDMI_TX_HS HDMI_TX_VS}] 46 | 47 | set_false_path -from {*} -to [get_registers {wcalc[*] hcalc[*]}] 48 | 49 | # Put constraints on input ports 50 | set_false_path -from [get_ports {KEY*}] -to * 51 | set_false_path -from [get_ports {BTN_*}] -to * 52 | 53 | # Put constraints on output ports 54 | set_false_path -from * -to [get_ports {LED_*}] 55 | set_false_path -from * -to [get_ports {VGA_*}] 56 | set_false_path -from * -to [get_ports {AUDIO_SPDIF}] 57 | set_false_path -from * -to [get_ports {AUDIO_L}] 58 | set_false_path -from * -to [get_ports {AUDIO_R}] 59 | set_false_path -from * -to [get_keepers {cfg[*]}] 60 | -------------------------------------------------------------------------------- /src/opl3/opl.vhd: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2019 Josh Bassett 2 | -- 3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 4 | -- of this software and associated documentation files (the "Software"), to deal 5 | -- in the Software without restriction, including without limitation the rights 6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | -- copies of the Software, and to permit persons to whom the Software is 8 | -- furnished to do so, subject to the following conditions: 9 | -- 10 | -- The above copyright notice and this permission notice shall be included in all 11 | -- copies or substantial portions of the Software. 12 | -- 13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | -- SOFTWARE. 20 | 21 | library ieee; 22 | use ieee.std_logic_1164.all; 23 | use ieee.numeric_std.all; 24 | 25 | entity opl is 26 | port ( 27 | reset : in std_logic; 28 | clk : in std_logic; 29 | 30 | irq_n : out std_logic; 31 | 32 | cs : in std_logic; 33 | addr : in std_logic_vector(1 downto 0); 34 | dout : out std_logic_vector(7 downto 0); 35 | din : in std_logic_vector(7 downto 0); 36 | we : in std_logic; 37 | 38 | sample : out signed(15 downto 0) 39 | ); 40 | end entity opl; 41 | 42 | architecture arch of opl is 43 | signal opl3_dout : std_logic_vector(7 downto 0); 44 | 45 | component opl3 is 46 | generic ( 47 | OPLCLK : natural 48 | ); 49 | port ( 50 | clk : in std_logic; 51 | clk_opl : in std_logic; 52 | rst_n : in std_logic; 53 | irq_n : out std_logic; 54 | 55 | period_80us : in std_logic_vector(12 downto 0); 56 | 57 | addr : in std_logic_vector(1 downto 0); 58 | dout : out std_logic_vector(7 downto 0); 59 | din : in std_logic_vector(7 downto 0); 60 | we : in std_logic; 61 | 62 | sample_l : out signed(15 downto 0); 63 | sample_r : out signed(15 downto 0) 64 | ); 65 | end component opl3; 66 | begin 67 | opl3_inst : component opl3 68 | generic map ( 69 | OPLCLK => 48000000 70 | ) 71 | port map ( 72 | rst_n => not reset, 73 | 74 | clk => clk, 75 | clk_opl => clk, 76 | 77 | irq_n => irq_n, 78 | 79 | period_80us => std_logic_vector(to_unsigned(3840, 13)), 80 | 81 | addr => addr, 82 | din => din, 83 | dout => opl3_dout, 84 | we => cs and we, 85 | 86 | sample_l => sample, 87 | sample_r => open 88 | ); 89 | 90 | dout <= opl3_dout when cs = '1' else (others => '0'); 91 | end architecture arch; 92 | -------------------------------------------------------------------------------- /sys/audio_out.v: -------------------------------------------------------------------------------- 1 | 2 | module audio_out 3 | #( 4 | parameter CLK_RATE = 50000000 5 | ) 6 | ( 7 | input reset, 8 | input clk, 9 | 10 | //0 - 48KHz, 1 - 96KHz 11 | input sample_rate, 12 | 13 | input [15:0] left_in, 14 | input [15:0] right_in, 15 | 16 | // I2S 17 | output i2s_bclk, 18 | output i2s_lrclk, 19 | output i2s_data, 20 | 21 | // SPDIF 22 | output spdif, 23 | 24 | // Sigma-Delta DAC 25 | output dac_l, 26 | output dac_r 27 | ); 28 | 29 | localparam AUDIO_RATE = 48000; 30 | localparam AUDIO_DW = 16; 31 | 32 | localparam CE_RATE = AUDIO_RATE*AUDIO_DW*8; 33 | localparam FILTER_DIV = (CE_RATE/(AUDIO_RATE*32))-1; 34 | 35 | wire [31:0] real_ce = sample_rate ? {CE_RATE[30:0],1'b0} : CE_RATE[31:0]; 36 | 37 | reg mclk_ce; 38 | always @(posedge clk) begin 39 | reg [31:0] cnt; 40 | 41 | mclk_ce <= 0; 42 | cnt = cnt + real_ce; 43 | if(cnt >= CLK_RATE) begin 44 | cnt = cnt - CLK_RATE; 45 | mclk_ce <= 1; 46 | end 47 | end 48 | 49 | reg i2s_ce; 50 | always @(posedge clk) begin 51 | reg div; 52 | i2s_ce <= 0; 53 | if(mclk_ce) begin 54 | div <= ~div; 55 | i2s_ce <= div; 56 | end 57 | end 58 | 59 | reg lpf_ce; 60 | always @(posedge clk) begin 61 | integer div; 62 | lpf_ce <= 0; 63 | if(mclk_ce) begin 64 | div <= div + 1; 65 | if(div == FILTER_DIV) begin 66 | div <= 0; 67 | lpf_ce <= 1; 68 | end 69 | end 70 | end 71 | 72 | i2s i2s 73 | ( 74 | .reset(reset), 75 | 76 | .clk(clk), 77 | .ce(i2s_ce), 78 | 79 | .sclk(i2s_bclk), 80 | .lrclk(i2s_lrclk), 81 | .sdata(i2s_data), 82 | 83 | .left_chan(al), 84 | .right_chan(ar) 85 | ); 86 | 87 | spdif toslink 88 | ( 89 | .rst_i(reset), 90 | 91 | .clk_i(clk), 92 | .bit_out_en_i(mclk_ce), 93 | 94 | .sample_i({ar,al}), 95 | .spdif_o(spdif) 96 | ); 97 | 98 | sigma_delta_dac #(15) sd_l 99 | ( 100 | .CLK(clk), 101 | .RESET(reset), 102 | .DACin({~al[15], al[14:0]}), 103 | .DACout(dac_l) 104 | ); 105 | 106 | sigma_delta_dac #(15) sd_r 107 | ( 108 | .CLK(clk), 109 | .RESET(reset), 110 | .DACin({~ar[15], ar[14:0]}), 111 | .DACout(dac_r) 112 | ); 113 | 114 | wire [15:0] al, ar; 115 | lpf_aud lpf_l 116 | ( 117 | .CLK(clk), 118 | .CE(lpf_ce), 119 | .IDATA(left_in), 120 | .ODATA(al) 121 | ); 122 | 123 | lpf_aud lpf_r 124 | ( 125 | .CLK(clk), 126 | .CE(lpf_ce), 127 | .IDATA(right_in), 128 | .ODATA(ar) 129 | ); 130 | 131 | endmodule 132 | 133 | module lpf_aud 134 | ( 135 | input CLK, 136 | input CE, 137 | input [15:0] IDATA, 138 | output reg [15:0] ODATA 139 | ); 140 | 141 | reg [511:0] acc; 142 | reg [20:0] sum; 143 | 144 | always @(*) begin 145 | integer i; 146 | sum = 0; 147 | for (i = 0; i < 32; i = i+1) sum = sum + {{5{acc[(i*16)+15]}}, acc[i*16 +:16]}; 148 | end 149 | 150 | always @(posedge CLK) begin 151 | if(CE) begin 152 | acc <= {acc[495:0], IDATA}; 153 | ODATA <= sum[20:5]; 154 | end 155 | end 156 | 157 | endmodule 158 | -------------------------------------------------------------------------------- /src/mem/single_port_ram.vhd: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2019 Josh Bassett 2 | -- 3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 4 | -- of this software and associated documentation files (the "Software"), to deal 5 | -- in the Software without restriction, including without limitation the rights 6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | -- copies of the Software, and to permit persons to whom the Software is 8 | -- furnished to do so, subject to the following conditions: 9 | -- 10 | -- The above copyright notice and this permission notice shall be included in all 11 | -- copies or substantial portions of the Software. 12 | -- 13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | -- SOFTWARE. 20 | 21 | library ieee; 22 | use ieee.std_logic_1164.all; 23 | use ieee.numeric_std.all; 24 | 25 | library altera_mf; 26 | use altera_mf.altera_mf_components.all; 27 | 28 | entity single_port_ram is 29 | generic ( 30 | ADDR_WIDTH : natural := 8; 31 | DATA_WIDTH : natural := 8 32 | ); 33 | port ( 34 | -- clock 35 | clk : in std_logic; 36 | 37 | -- chip select 38 | cs : in std_logic := '1'; 39 | 40 | -- address 41 | addr : in unsigned(ADDR_WIDTH-1 downto 0); 42 | 43 | -- data in 44 | din : in std_logic_vector(DATA_WIDTH-1 downto 0) := (others => '0'); 45 | 46 | -- data out 47 | dout : out std_logic_vector(DATA_WIDTH-1 downto 0); 48 | 49 | -- write enable 50 | we : in std_logic := '0' 51 | ); 52 | end single_port_ram; 53 | 54 | architecture arch of single_port_ram is 55 | signal q : std_logic_vector(DATA_WIDTH-1 downto 0); 56 | begin 57 | altsyncram_component : altsyncram 58 | generic map ( 59 | clock_enable_input_a => "BYPASS", 60 | clock_enable_output_a => "BYPASS", 61 | intended_device_family => "Cyclone V", 62 | lpm_hint => "ENABLE_RUNTIME_MOD=NO", 63 | lpm_type => "altsyncram", 64 | numwords_a => 2**ADDR_WIDTH, 65 | operation_mode => "SINGLE_PORT", 66 | outdata_aclr_a => "NONE", 67 | outdata_reg_a => "UNREGISTERED", 68 | power_up_uninitialized => "FALSE", 69 | read_during_write_mode_port_a => "NEW_DATA_NO_NBE_READ", 70 | width_a => DATA_WIDTH, 71 | width_byteena_a => 1, 72 | widthad_a => ADDR_WIDTH 73 | ) 74 | port map ( 75 | address_a => std_logic_vector(addr), 76 | clock0 => clk, 77 | data_a => din, 78 | wren_a => cs and we, 79 | q_a => q 80 | ); 81 | 82 | dout <= q when cs = '1' else (others => '0'); 83 | end architecture arch; 84 | -------------------------------------------------------------------------------- /rygar.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 "19.1.0 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 TIMING_ANALYZER_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 REMOVE_REDUNDANT_LOGIC_CELLS ON 41 | set_global_assignment -name AUTO_DELAY_CHAINS_FOR_HIGH_FANOUT_INPUT_PINS ON 42 | set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC_FOR_AREA ON 43 | set_global_assignment -name ADV_NETLIST_OPT_SYNTH_WYSIWYG_REMAP ON 44 | set_global_assignment -name SYNTH_GATED_CLOCK_CONVERSION ON 45 | set_global_assignment -name PRE_MAPPING_RESYNTHESIS ON 46 | set_global_assignment -name ROUTER_CLOCKING_TOPOLOGY_ANALYSIS ON 47 | set_global_assignment -name ECO_OPTIMIZE_TIMING ON 48 | set_global_assignment -name PERIPHERY_TO_CORE_PLACEMENT_AND_ROUTING_OPTIMIZATION ON 49 | set_global_assignment -name PHYSICAL_SYNTHESIS_ASYNCHRONOUS_SIGNAL_PIPELINING ON 50 | set_global_assignment -name ALM_REGISTER_PACKING_EFFORT LOW 51 | set_global_assignment -name PLACEMENT_EFFORT_MULTIPLIER 1.0 52 | set_global_assignment -name SEED 1 53 | 54 | source sys/sys.tcl 55 | source sys/sys_analog.tcl 56 | source files.qip 57 | 58 | set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top -------------------------------------------------------------------------------- /src/gpu/palette.vhd: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2019 Josh Bassett 2 | -- 3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 4 | -- of this software and associated documentation files (the "Software"), to deal 5 | -- in the Software without restriction, including without limitation the rights 6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | -- copies of the Software, and to permit persons to whom the Software is 8 | -- furnished to do so, subject to the following conditions: 9 | -- 10 | -- The above copyright notice and this permission notice shall be included in all 11 | -- copies or substantial portions of the Software. 12 | -- 13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | -- SOFTWARE. 20 | 21 | library ieee; 22 | use ieee.std_logic_1164.all; 23 | use ieee.numeric_std.all; 24 | 25 | use work.common.all; 26 | 27 | -- The palette combines data from the different graphics layers to produce an 28 | -- actual RGB value that can be rendered on the screen. 29 | entity palette is 30 | port ( 31 | -- clock signals 32 | clk : in std_logic; 33 | cen_6 : in std_logic; 34 | 35 | -- palette RAM 36 | ram_addr : out unsigned(PALETTE_RAM_GPU_ADDR_WIDTH-1 downto 0); 37 | ram_data : in std_logic_vector(PALETTE_RAM_GPU_DATA_WIDTH-1 downto 0); 38 | 39 | -- layer data 40 | sprite_data : in byte_t; 41 | char_data : in byte_t; 42 | fg_data : in byte_t; 43 | bg_data : in byte_t; 44 | 45 | -- sprite priority 46 | sprite_priority : in priority_t; 47 | 48 | -- video signals 49 | video : in video_t; 50 | rgb : out rgb_t 51 | ); 52 | end palette; 53 | 54 | architecture arch of palette is 55 | -- current layer 56 | signal layer : layer_t; 57 | begin 58 | -- latch RGB data from the palette RAM 59 | latch_rgb_data : process (clk) 60 | begin 61 | if rising_edge(clk) then 62 | if cen_6 = '1' then 63 | if video.enable = '1' then 64 | rgb.r <= ram_data(15 downto 12); 65 | rgb.g <= ram_data(11 downto 8); 66 | rgb.b <= ram_data(3 downto 0); 67 | else 68 | rgb.r <= (others => '0'); 69 | rgb.g <= (others => '0'); 70 | rgb.b <= (others => '0'); 71 | end if; 72 | end if; 73 | end if; 74 | end process; 75 | 76 | -- set current layer 77 | layer <= mux_layers(sprite_priority, sprite_data, char_data, fg_data, bg_data); 78 | 79 | -- set palette RAM address 80 | with layer select 81 | ram_addr <= "00" & unsigned(sprite_data) when SPRITE_LAYER, 82 | "01" & unsigned(char_data) when CHAR_LAYER, 83 | "10" & unsigned(fg_data) when FG_LAYER, 84 | "11" & unsigned(bg_data) when BG_LAYER, 85 | "0100000000" when FILL_LAYER; 86 | end arch; 87 | -------------------------------------------------------------------------------- /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/vga_out.sv: -------------------------------------------------------------------------------- 1 | 2 | module vga_out 3 | ( 4 | input ypbpr_full, 5 | input ypbpr_en, 6 | 7 | input [23:0] din, 8 | output [23:0] dout 9 | ); 10 | 11 | wire [5:0] yuv_full[225] = '{ 12 | 6'd0, 6'd0, 6'd0, 6'd0, 6'd1, 6'd1, 6'd1, 6'd1, 13 | 6'd2, 6'd2, 6'd2, 6'd3, 6'd3, 6'd3, 6'd3, 6'd4, 14 | 6'd4, 6'd4, 6'd5, 6'd5, 6'd5, 6'd5, 6'd6, 6'd6, 15 | 6'd6, 6'd7, 6'd7, 6'd7, 6'd7, 6'd8, 6'd8, 6'd8, 16 | 6'd9, 6'd9, 6'd9, 6'd9, 6'd10, 6'd10, 6'd10, 6'd11, 17 | 6'd11, 6'd11, 6'd11, 6'd12, 6'd12, 6'd12, 6'd13, 6'd13, 18 | 6'd13, 6'd13, 6'd14, 6'd14, 6'd14, 6'd15, 6'd15, 6'd15, 19 | 6'd15, 6'd16, 6'd16, 6'd16, 6'd17, 6'd17, 6'd17, 6'd17, 20 | 6'd18, 6'd18, 6'd18, 6'd19, 6'd19, 6'd19, 6'd19, 6'd20, 21 | 6'd20, 6'd20, 6'd21, 6'd21, 6'd21, 6'd21, 6'd22, 6'd22, 22 | 6'd22, 6'd23, 6'd23, 6'd23, 6'd23, 6'd24, 6'd24, 6'd24, 23 | 6'd25, 6'd25, 6'd25, 6'd25, 6'd26, 6'd26, 6'd26, 6'd27, 24 | 6'd27, 6'd27, 6'd27, 6'd28, 6'd28, 6'd28, 6'd29, 6'd29, 25 | 6'd29, 6'd29, 6'd30, 6'd30, 6'd30, 6'd31, 6'd31, 6'd31, 26 | 6'd31, 6'd32, 6'd32, 6'd32, 6'd33, 6'd33, 6'd33, 6'd33, 27 | 6'd34, 6'd34, 6'd34, 6'd35, 6'd35, 6'd35, 6'd35, 6'd36, 28 | 6'd36, 6'd36, 6'd36, 6'd37, 6'd37, 6'd37, 6'd38, 6'd38, 29 | 6'd38, 6'd38, 6'd39, 6'd39, 6'd39, 6'd40, 6'd40, 6'd40, 30 | 6'd40, 6'd41, 6'd41, 6'd41, 6'd42, 6'd42, 6'd42, 6'd42, 31 | 6'd43, 6'd43, 6'd43, 6'd44, 6'd44, 6'd44, 6'd44, 6'd45, 32 | 6'd45, 6'd45, 6'd46, 6'd46, 6'd46, 6'd46, 6'd47, 6'd47, 33 | 6'd47, 6'd48, 6'd48, 6'd48, 6'd48, 6'd49, 6'd49, 6'd49, 34 | 6'd50, 6'd50, 6'd50, 6'd50, 6'd51, 6'd51, 6'd51, 6'd52, 35 | 6'd52, 6'd52, 6'd52, 6'd53, 6'd53, 6'd53, 6'd54, 6'd54, 36 | 6'd54, 6'd54, 6'd55, 6'd55, 6'd55, 6'd56, 6'd56, 6'd56, 37 | 6'd56, 6'd57, 6'd57, 6'd57, 6'd58, 6'd58, 6'd58, 6'd58, 38 | 6'd59, 6'd59, 6'd59, 6'd60, 6'd60, 6'd60, 6'd60, 6'd61, 39 | 6'd61, 6'd61, 6'd62, 6'd62, 6'd62, 6'd62, 6'd63, 6'd63, 40 | 6'd63 41 | }; 42 | 43 | wire [5:0] red = din[23:18]; 44 | wire [5:0] green = din[15:10]; 45 | wire [5:0] blue = din[7:2]; 46 | 47 | // http://marsee101.blog19.fc2.com/blog-entry-2311.html 48 | // Y = 16 + 0.257*R + 0.504*G + 0.098*B (Y = 0.299*R + 0.587*G + 0.114*B) 49 | // Pb = 128 - 0.148*R - 0.291*G + 0.439*B (Pb = -0.169*R - 0.331*G + 0.500*B) 50 | // Pr = 128 + 0.439*R - 0.368*G - 0.071*B (Pr = 0.500*R - 0.419*G - 0.081*B) 51 | 52 | wire [18:0] y_8 = 19'd04096 + ({red, 8'd0} + {red, 3'd0}) + ({green, 9'd0} + {green, 2'd0}) + ({blue, 6'd0} + {blue, 5'd0} + {blue, 2'd0}); 53 | wire [18:0] pb_8 = 19'd32768 - ({red, 7'd0} + {red, 4'd0} + {red, 3'd0}) - ({green, 8'd0} + {green, 5'd0} + {green, 3'd0}) + ({blue, 8'd0} + {blue, 7'd0} + {blue, 6'd0}); 54 | wire [18:0] pr_8 = 19'd32768 + ({red, 8'd0} + {red, 7'd0} + {red, 6'd0}) - ({green, 8'd0} + {green, 6'd0} + {green, 5'd0} + {green, 4'd0} + {green, 3'd0}) - ({blue, 6'd0} + {blue , 3'd0}); 55 | 56 | wire [7:0] y = ( y_8[17:8] < 16) ? 8'd16 : ( y_8[17:8] > 235) ? 8'd235 : y_8[15:8]; 57 | wire [7:0] pb = (pb_8[17:8] < 16) ? 8'd16 : (pb_8[17:8] > 240) ? 8'd240 : pb_8[15:8]; 58 | wire [7:0] pr = (pr_8[17:8] < 16) ? 8'd16 : (pr_8[17:8] > 240) ? 8'd240 : pr_8[15:8]; 59 | 60 | assign dout[23:16] = ypbpr_en ? {(ypbpr_full ? yuv_full[pr-8'd16] : pr[7:2]), 2'b00} : din[23:16]; 61 | assign dout[15:8] = ypbpr_en ? {(ypbpr_full ? yuv_full[y -8'd16] : y[7:2]), 2'b00} : din[15:8]; 62 | assign dout[7:0] = ypbpr_en ? {(ypbpr_full ? yuv_full[pb-8'd16] : pb[7:2]), 2'b00} : din[7:0]; 63 | 64 | 65 | endmodule 66 | -------------------------------------------------------------------------------- /sys/alsa.sv: -------------------------------------------------------------------------------- 1 | //============================================================================ 2 | // 3 | // ALSA sound support for MiSTer 4 | // (c)2019 Sorgelig 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 | input reset, 25 | 26 | output reg en_out, 27 | input en_in, 28 | 29 | input ram_clk, 30 | output reg [28:0] ram_address, 31 | output reg [7:0] ram_burstcount, 32 | input ram_waitrequest, 33 | input [63:0] ram_readdata, 34 | input ram_readdatavalid, 35 | output reg ram_read, 36 | 37 | input spi_ss, 38 | input spi_sck, 39 | input spi_mosi, 40 | 41 | output reg [15:0] pcm_l, 42 | output reg [15:0] pcm_r 43 | ); 44 | 45 | reg spi_new = 0; 46 | reg [127:0] spi_data; 47 | always @(posedge spi_sck, posedge spi_ss) begin 48 | reg [7:0] mosi; 49 | reg [6:0] spicnt = 0; 50 | 51 | if(spi_ss) spicnt <= 0; 52 | else begin 53 | mosi <= {mosi[6:0],spi_mosi}; 54 | 55 | spicnt <= spicnt + 1'd1; 56 | if(&spicnt[2:0]) begin 57 | spi_data[{spicnt[6:3],3'b000} +:8] <= {mosi[6:0],spi_mosi}; 58 | spi_new <= &spicnt; 59 | end 60 | end 61 | end 62 | 63 | reg [31:0] buf_addr; 64 | reg [31:0] buf_len; 65 | reg [31:0] buf_wptr = 0; 66 | 67 | always @(posedge ram_clk) begin 68 | reg n1,n2,n3; 69 | reg [127:0] data1,data2; 70 | 71 | n1 <= spi_new; 72 | n2 <= n1; 73 | n3 <= n2; 74 | 75 | data1 <= spi_data; 76 | data2 <= data1; 77 | 78 | if(~n3 & n2) {buf_wptr,buf_len,buf_addr} <= data2[95:0]; 79 | end 80 | 81 | reg [31:0] buf_rptr = 0; 82 | always @(posedge ram_clk) begin 83 | reg got_first = 0; 84 | reg ready = 0; 85 | reg ud = 0; 86 | reg [31:0] readdata; 87 | 88 | if(~ram_waitrequest) ram_read <= 0; 89 | if(ram_readdatavalid && ram_burstcount) begin 90 | ram_burstcount <= 0; 91 | ready <= 1; 92 | readdata <= ud ? ram_readdata[63:32] : ram_readdata[31:0]; 93 | if(buf_rptr[31:2] >= buf_len[31:2]) buf_rptr <= 0; 94 | end 95 | 96 | if(reset) {ready, got_first, ram_burstcount} <= 0; 97 | else 98 | if(buf_rptr[31:2] != buf_wptr[31:2]) begin 99 | if(~got_first) begin 100 | buf_rptr <= buf_wptr; 101 | got_first <= 1; 102 | end 103 | else 104 | if(!ram_burstcount && ~ram_waitrequest && ~ready && en_out == en_in) begin 105 | ram_address <= buf_addr[31:3] + buf_rptr[31:3]; 106 | ud <= buf_rptr[2]; 107 | ram_burstcount <= 1; 108 | ram_read <= 1; 109 | buf_rptr <= buf_rptr + 4; 110 | end 111 | end 112 | 113 | if(ready & ce_48k) begin 114 | {pcm_r,pcm_l} <= readdata; 115 | ready <= 0; 116 | end 117 | 118 | if(ce_48k) en_out <= ~en_out; 119 | end 120 | 121 | reg ce_48k; 122 | always @(posedge ram_clk) begin 123 | reg [15:0] acc = 0; 124 | 125 | ce_48k <= 0; 126 | acc <= acc + 16'd48; 127 | if(acc >= 50000) begin 128 | acc <= acc - 16'd50000; 129 | ce_48k <= 1; 130 | end 131 | end 132 | 133 | endmodule 134 | -------------------------------------------------------------------------------- /src/mem/dual_port_ram.vhd: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2019 Josh Bassett 2 | -- 3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 4 | -- of this software and associated documentation files (the "Software"), to deal 5 | -- in the Software without restriction, including without limitation the rights 6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | -- copies of the Software, and to permit persons to whom the Software is 8 | -- furnished to do so, subject to the following conditions: 9 | -- 10 | -- The above copyright notice and this permission notice shall be included in all 11 | -- copies or substantial portions of the Software. 12 | -- 13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | -- SOFTWARE. 20 | 21 | library ieee; 22 | use ieee.std_logic_1164.all; 23 | use ieee.numeric_std.all; 24 | 25 | library altera_mf; 26 | use altera_mf.altera_mf_components.all; 27 | 28 | entity dual_port_ram is 29 | generic ( 30 | ADDR_WIDTH : natural := 8; 31 | DATA_WIDTH : natural := 8 32 | ); 33 | port ( 34 | -- clock 35 | clk : in std_logic; 36 | 37 | -- chip select 38 | cs : in std_logic := '1'; 39 | 40 | -- port A (write) 41 | addr_a : in unsigned(ADDR_WIDTH-1 downto 0); 42 | din_a : in std_logic_vector(DATA_WIDTH-1 downto 0) := (others => '0'); 43 | we_a : in std_logic := '1'; 44 | 45 | -- port B (read) 46 | addr_b : in unsigned(ADDR_WIDTH-1 downto 0); 47 | dout_b : out std_logic_vector(DATA_WIDTH-1 downto 0); 48 | re_b : in std_logic := '1' 49 | ); 50 | end dual_port_ram; 51 | 52 | architecture arch of dual_port_ram is 53 | signal q : std_logic_vector(DATA_WIDTH-1 downto 0); 54 | begin 55 | altsyncram_component : altsyncram 56 | generic map ( 57 | address_reg_b => "CLOCK0", 58 | clock_enable_input_a => "BYPASS", 59 | clock_enable_input_b => "BYPASS", 60 | clock_enable_output_a => "BYPASS", 61 | clock_enable_output_b => "BYPASS", 62 | indata_reg_b => "CLOCK0", 63 | intended_device_family => "Cyclone V", 64 | lpm_type => "altsyncram", 65 | numwords_a => 2**ADDR_WIDTH, 66 | numwords_b => 2**ADDR_WIDTH, 67 | operation_mode => "DUAL_PORT", 68 | outdata_aclr_a => "NONE", 69 | outdata_aclr_b => "NONE", 70 | outdata_reg_a => "UNREGISTERED", 71 | outdata_reg_b => "UNREGISTERED", 72 | power_up_uninitialized => "FALSE", 73 | rdcontrol_reg_b => "CLOCK0", 74 | read_during_write_mode_mixed_ports => "OLD_DATA", 75 | width_a => DATA_WIDTH, 76 | width_b => DATA_WIDTH, 77 | width_byteena_a => 1, 78 | width_byteena_b => 1, 79 | widthad_a => ADDR_WIDTH, 80 | widthad_b => ADDR_WIDTH 81 | ) 82 | port map ( 83 | address_a => std_logic_vector(addr_a), 84 | address_b => std_logic_vector(addr_b), 85 | clock0 => clk, 86 | wren_a => cs and we_a, 87 | rden_b => cs and re_b, 88 | data_a => din_a, 89 | q_b => q 90 | ); 91 | 92 | -- output 93 | dout_b <= q when cs = '1' else (others => '0'); 94 | end architecture arch; 95 | -------------------------------------------------------------------------------- /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) 106 | ( 107 | input reset, 108 | input clk, 109 | 110 | inout [3:0] ADC_BUS, 111 | output reg dout, 112 | output active 113 | ); 114 | 115 | wire [11:0] adc_data; 116 | wire adc_sync; 117 | ltc2308 #(1, 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; 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 | -------------------------------------------------------------------------------- /src/mem/true_dual_port_ram.vhd: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2019 Josh Bassett 2 | -- 3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 4 | -- of this software and associated documentation files (the "Software"), to deal 5 | -- in the Software without restriction, including without limitation the rights 6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | -- copies of the Software, and to permit persons to whom the Software is 8 | -- furnished to do so, subject to the following conditions: 9 | -- 10 | -- The above copyright notice and this permission notice shall be included in all 11 | -- copies or substantial portions of the Software. 12 | -- 13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | -- SOFTWARE. 20 | 21 | library ieee; 22 | use ieee.std_logic_1164.all; 23 | use ieee.numeric_std.all; 24 | 25 | library altera_mf; 26 | use altera_mf.altera_mf_components.all; 27 | 28 | entity true_dual_port_ram is 29 | generic ( 30 | ADDR_WIDTH_A : natural := 8; 31 | ADDR_WIDTH_B : natural := 8; 32 | DATA_WIDTH_A : natural := 8; 33 | DATA_WIDTH_B : natural := 8 34 | ); 35 | port ( 36 | -- port A 37 | clk_a : in std_logic; 38 | cs_a : in std_logic := '1'; 39 | addr_a : in unsigned(ADDR_WIDTH_A-1 downto 0); 40 | din_a : in std_logic_vector(DATA_WIDTH_A-1 downto 0) := (others => '0'); 41 | dout_a : out std_logic_vector(DATA_WIDTH_A-1 downto 0); 42 | we_a : in std_logic := '0'; 43 | 44 | -- port B 45 | clk_b : in std_logic; 46 | cs_b : in std_logic := '1'; 47 | addr_b : in unsigned(ADDR_WIDTH_B-1 downto 0); 48 | din_b : in std_logic_vector(DATA_WIDTH_B-1 downto 0) := (others => '0'); 49 | dout_b : out std_logic_vector(DATA_WIDTH_B-1 downto 0); 50 | we_b : in std_logic := '0' 51 | ); 52 | end true_dual_port_ram; 53 | 54 | architecture arch of true_dual_port_ram is 55 | signal q_a : std_logic_vector(DATA_WIDTH_A-1 downto 0); 56 | signal q_b : std_logic_vector(DATA_WIDTH_B-1 downto 0); 57 | begin 58 | altsyncram_component : altsyncram 59 | generic map ( 60 | address_reg_b => "CLOCK1", 61 | clock_enable_input_a => "BYPASS", 62 | clock_enable_input_b => "BYPASS", 63 | clock_enable_output_a => "BYPASS", 64 | clock_enable_output_b => "BYPASS", 65 | indata_reg_b => "CLOCK1", 66 | intended_device_family => "Cyclone V", 67 | lpm_type => "altsyncram", 68 | numwords_a => 2**ADDR_WIDTH_A, 69 | numwords_b => 2**ADDR_WIDTH_B, 70 | operation_mode => "BIDIR_DUAL_PORT", 71 | outdata_aclr_a => "NONE", 72 | outdata_aclr_b => "NONE", 73 | outdata_reg_a => "UNREGISTERED", 74 | outdata_reg_b => "UNREGISTERED", 75 | power_up_uninitialized => "FALSE", 76 | read_during_write_mode_port_a => "NEW_DATA_NO_NBE_READ", 77 | read_during_write_mode_port_b => "NEW_DATA_NO_NBE_READ", 78 | width_a => DATA_WIDTH_A, 79 | width_b => DATA_WIDTH_B, 80 | width_byteena_a => 1, 81 | width_byteena_b => 1, 82 | widthad_a => ADDR_WIDTH_A, 83 | widthad_b => ADDR_WIDTH_B, 84 | wrcontrol_wraddress_reg_b => "CLOCK1" 85 | ) 86 | port map ( 87 | address_a => std_logic_vector(addr_a), 88 | address_b => std_logic_vector(addr_b), 89 | clock0 => clk_a, 90 | clock1 => clk_b, 91 | data_a => din_a, 92 | data_b => din_b, 93 | wren_a => cs_a and we_a, 94 | wren_b => cs_b and we_b, 95 | q_a => q_a, 96 | q_b => q_b 97 | ); 98 | 99 | -- output 100 | dout_a <= q_a when cs_a = '1' else (others => '0'); 101 | dout_b <= q_b when cs_b = '1' else (others => '0'); 102 | end architecture arch; 103 | -------------------------------------------------------------------------------- /sys/video_mixer.sv: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // Copyright (c) 2017 Sorgelig 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 14 | // Usually it's length from HSync to HSync. 15 | // May be less if line_start is used. 16 | // 17 | // HALF_DEPTH: If =1 then color dept is 4 bits per component 18 | // For half depth 8 bits monochrome is available with 19 | // mono signal enabled and color = {G, R} 20 | 21 | module video_mixer 22 | #( 23 | parameter LINE_LENGTH = 768, 24 | parameter HALF_DEPTH = 0 25 | ) 26 | ( 27 | // master clock 28 | // it should be multiple by (ce_pix*4). 29 | input clk_sys, 30 | 31 | // Pixel clock or clock_enable (both are accepted). 32 | input ce_pix, 33 | output ce_pix_out, 34 | 35 | input scandoubler, 36 | 37 | // scanlines (00-none 01-25% 10-50% 11-75%) 38 | input [1:0] scanlines, 39 | 40 | // High quality 2x scaling 41 | input hq2x, 42 | 43 | // color 44 | input [DWIDTH:0] R, 45 | input [DWIDTH:0] G, 46 | input [DWIDTH:0] B, 47 | 48 | // Monochrome mode (for HALF_DEPTH only) 49 | input mono, 50 | 51 | // Positive pulses. 52 | input HSync, 53 | input VSync, 54 | input HBlank, 55 | input VBlank, 56 | 57 | // video output signals 58 | output reg [7:0] VGA_R, 59 | output reg [7:0] VGA_G, 60 | output reg [7:0] VGA_B, 61 | output reg VGA_VS, 62 | output reg VGA_HS, 63 | output reg VGA_DE 64 | ); 65 | 66 | localparam DWIDTH = HALF_DEPTH ? 3 : 7; 67 | 68 | wire [DWIDTH:0] R_sd; 69 | wire [DWIDTH:0] G_sd; 70 | wire [DWIDTH:0] B_sd; 71 | wire hs_sd, vs_sd, hb_sd, vb_sd, ce_pix_sd; 72 | 73 | scandoubler #(.LENGTH(LINE_LENGTH), .HALF_DEPTH(HALF_DEPTH)) sd 74 | ( 75 | .*, 76 | .hs_in(HSync), 77 | .vs_in(VSync), 78 | .hb_in(HBlank), 79 | .vb_in(VBlank), 80 | .r_in(R), 81 | .g_in(G), 82 | .b_in(B), 83 | 84 | .ce_pix_out(ce_pix_sd), 85 | .hs_out(hs_sd), 86 | .vs_out(vs_sd), 87 | .hb_out(hb_sd), 88 | .vb_out(vb_sd), 89 | .r_out(R_sd), 90 | .g_out(G_sd), 91 | .b_out(B_sd) 92 | ); 93 | 94 | wire [DWIDTH:0] rt = (scandoubler ? R_sd : R); 95 | wire [DWIDTH:0] gt = (scandoubler ? G_sd : G); 96 | wire [DWIDTH:0] bt = (scandoubler ? B_sd : B); 97 | 98 | generate 99 | if(HALF_DEPTH) begin 100 | wire [7:0] r = mono ? {gt,rt} : {rt,rt}; 101 | wire [7:0] g = mono ? {gt,rt} : {gt,gt}; 102 | wire [7:0] b = mono ? {gt,rt} : {bt,bt}; 103 | end else begin 104 | wire [7:0] r = rt; 105 | wire [7:0] g = gt; 106 | wire [7:0] b = bt; 107 | end 108 | endgenerate 109 | 110 | wire hs = (scandoubler ? hs_sd : HSync); 111 | wire vs = (scandoubler ? vs_sd : VSync); 112 | 113 | assign ce_pix_out = scandoubler ? ce_pix_sd : ce_pix; 114 | 115 | 116 | reg scanline = 0; 117 | always @(posedge clk_sys) begin 118 | reg old_hs, old_vs; 119 | 120 | old_hs <= hs; 121 | old_vs <= vs; 122 | 123 | if(old_hs && ~hs) scanline <= ~scanline; 124 | if(old_vs && ~vs) scanline <= 0; 125 | end 126 | 127 | wire hde = scandoubler ? ~hb_sd : ~HBlank; 128 | wire vde = scandoubler ? ~vb_sd : ~VBlank; 129 | 130 | always @(posedge clk_sys) begin 131 | reg old_hde; 132 | 133 | case(scanlines & {scanline, scanline}) 134 | 1: begin // reduce 25% = 1/2 + 1/4 135 | VGA_R <= {1'b0, r[7:1]} + {2'b00, r[7:2]}; 136 | VGA_G <= {1'b0, g[7:1]} + {2'b00, g[7:2]}; 137 | VGA_B <= {1'b0, b[7:1]} + {2'b00, b[7:2]}; 138 | end 139 | 140 | 2: begin // reduce 50% = 1/2 141 | VGA_R <= {1'b0, r[7:1]}; 142 | VGA_G <= {1'b0, g[7:1]}; 143 | VGA_B <= {1'b0, b[7:1]}; 144 | end 145 | 146 | 3: begin // reduce 75% = 1/4 147 | VGA_R <= {2'b00, r[7:2]}; 148 | VGA_G <= {2'b00, g[7:2]}; 149 | VGA_B <= {2'b00, b[7:2]}; 150 | end 151 | 152 | default: begin 153 | VGA_R <= r; 154 | VGA_G <= g; 155 | VGA_B <= b; 156 | end 157 | endcase 158 | 159 | VGA_VS <= vs; 160 | VGA_HS <= hs; 161 | 162 | old_hde <= hde; 163 | if(~old_hde && hde) VGA_DE <= vde; 164 | if(old_hde && ~hde) VGA_DE <= 0; 165 | end 166 | 167 | endmodule 168 | -------------------------------------------------------------------------------- /src/gpu/frame_buffer.vhd: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2019 Josh Bassett 2 | -- 3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 4 | -- of this software and associated documentation files (the "Software"), to deal 5 | -- in the Software without restriction, including without limitation the rights 6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | -- copies of the Software, and to permit persons to whom the Software is 8 | -- furnished to do so, subject to the following conditions: 9 | -- 10 | -- The above copyright notice and this permission notice shall be included in all 11 | -- copies or substantial portions of the Software. 12 | -- 13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | -- SOFTWARE. 20 | 21 | library ieee; 22 | use ieee.std_logic_1164.all; 23 | use ieee.numeric_std.all; 24 | 25 | -- The frame buffer is a memory device used for caching graphics data. It is 26 | -- used by the sprite renderer to ensure glitch-free graphics. 27 | -- 28 | -- Internally, it contains two memory pages which are accessed alternately for 29 | -- reading and writing, so that while one page is being written to, the other 30 | -- is being read from. 31 | -- 32 | -- The frame buffer automatically clears pixels during read operations, so that 33 | -- the page is clean when it is flipped. 34 | entity frame_buffer is 35 | generic ( 36 | ADDR_WIDTH : natural := 8; 37 | DATA_WIDTH : natural := 8 38 | ); 39 | port ( 40 | -- clock 41 | clk : in std_logic; 42 | 43 | -- chip select 44 | cs : in std_logic := '1'; 45 | 46 | -- When the flip signal is asserted, the memory pages are swapped. The page 47 | -- that was previously being written to will be read from, and the page 48 | -- that was being read from will be written to. 49 | flip : in std_logic := '0'; 50 | 51 | -- port A (write) 52 | addr_a : in unsigned(ADDR_WIDTH-1 downto 0); 53 | din_a : in std_logic_vector(DATA_WIDTH-1 downto 0) := (others => '0'); 54 | we_a : in std_logic := '0'; 55 | 56 | -- port B (read) 57 | addr_b : in unsigned(ADDR_WIDTH-1 downto 0); 58 | dout_b : out std_logic_vector(DATA_WIDTH-1 downto 0); 59 | re_b : in std_logic := '1' 60 | ); 61 | end frame_buffer; 62 | 63 | architecture arch of frame_buffer is 64 | type page_t is record 65 | addr : unsigned(ADDR_WIDTH-1 downto 0); 66 | din : std_logic_vector(DATA_WIDTH-1 downto 0); 67 | dout : std_logic_vector(DATA_WIDTH-1 downto 0); 68 | re : std_logic; 69 | we : std_logic; 70 | end record page_t; 71 | 72 | signal page_1, page_2 : page_t; 73 | begin 74 | page_1_ram : entity work.dual_port_ram 75 | generic map ( 76 | ADDR_WIDTH => ADDR_WIDTH, 77 | DATA_WIDTH => DATA_WIDTH 78 | ) 79 | port map ( 80 | clk => clk, 81 | cs => cs, 82 | addr_a => page_1.addr, 83 | din_a => page_1.din, 84 | we_a => page_1.we, 85 | addr_b => page_1.addr, 86 | dout_b => page_1.dout, 87 | re_b => page_1.re 88 | ); 89 | 90 | page_2_ram : entity work.dual_port_ram 91 | generic map ( 92 | ADDR_WIDTH => ADDR_WIDTH, 93 | DATA_WIDTH => DATA_WIDTH 94 | ) 95 | port map ( 96 | clk => clk, 97 | cs => cs, 98 | addr_a => page_2.addr, 99 | din_a => page_2.din, 100 | we_a => page_2.we, 101 | addr_b => page_2.addr, 102 | dout_b => page_2.dout, 103 | re_b => page_2.re 104 | ); 105 | 106 | page_1.addr <= addr_b when flip = '0' else addr_a; 107 | page_2.addr <= addr_b when flip = '1' else addr_a; 108 | 109 | page_1.re <= re_b; 110 | page_2.re <= re_b; 111 | 112 | page_1.we <= we_a when flip = '1' else re_b; 113 | page_2.we <= we_a when flip = '0' else re_b; 114 | 115 | page_1.din <= din_a when we_a = '1' and flip = '1' else (others => '0'); 116 | page_2.din <= din_a when we_a = '1' and flip = '0' else (others => '0'); 117 | 118 | -- set data 119 | dout_b <= page_1.dout when re_b = '1' and flip = '0' else 120 | page_2.dout when re_b = '1' and flip = '1' else 121 | (others => '0'); 122 | end architecture arch; 123 | -------------------------------------------------------------------------------- /sys/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 | -------------------------------------------------------------------------------- /src/gpu/char_layer.vhd: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2019 Josh Bassett 2 | -- 3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 4 | -- of this software and associated documentation files (the "Software"), to deal 5 | -- in the Software without restriction, including without limitation the rights 6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | -- copies of the Software, and to permit persons to whom the Software is 8 | -- furnished to do so, subject to the following conditions: 9 | -- 10 | -- The above copyright notice and this permission notice shall be included in all 11 | -- copies or substantial portions of the Software. 12 | -- 13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | -- SOFTWARE. 20 | 21 | library ieee; 22 | use ieee.std_logic_1164.all; 23 | use ieee.numeric_std.all; 24 | 25 | use work.common.all; 26 | 27 | -- The character layer is the part of the graphics pipeline that handles things 28 | -- like the logo, score, playfield, and other static graphics. 29 | -- 30 | -- It consists of a 32x32 grid of 8x8 tiles. 31 | entity char_layer is 32 | port ( 33 | -- clock signals 34 | clk : in std_logic; 35 | cen_6 : in std_logic; 36 | 37 | -- char RAM 38 | ram_addr : out unsigned(CHAR_RAM_GPU_ADDR_WIDTH-1 downto 0); 39 | ram_data : in std_logic_vector(CHAR_RAM_GPU_DATA_WIDTH-1 downto 0); 40 | 41 | -- tile ROM 42 | rom_addr : out unsigned(CHAR_ROM_ADDR_WIDTH-1 downto 0); 43 | rom_data : in std_logic_vector(CHAR_ROM_DATA_WIDTH-1 downto 0); 44 | 45 | -- video signals 46 | video : in video_t; 47 | 48 | -- graphics data 49 | data : out byte_t 50 | ); 51 | end char_layer; 52 | 53 | architecture arch of char_layer is 54 | -- represents the position of a pixel in a 8x8 tile 55 | type tile_pos_t is record 56 | x : unsigned(2 downto 0); 57 | y : unsigned(2 downto 0); 58 | end record tile_pos_t; 59 | 60 | -- tile signals 61 | signal tile_data : byte_t; 62 | signal tile_code : tile_code_t; 63 | signal tile_color : tile_color_t; 64 | signal tile_row : tile_row_t; 65 | signal tile_pixel : tile_pixel_t; 66 | 67 | -- aliases to extract the components of the horizontal and vertical position 68 | alias col : unsigned(4 downto 0) is video.pos.x(7 downto 3); 69 | alias row : unsigned(4 downto 0) is video.pos.y(7 downto 3); 70 | alias offset_x : unsigned(2 downto 0) is video.pos.x(2 downto 0); 71 | alias offset_y : unsigned(2 downto 0) is video.pos.y(2 downto 0); 72 | begin 73 | -- Load tile data from the character RAM. 74 | -- 75 | -- While the current tile is being rendered, we need to fetch data for the 76 | -- next tile ahead, so that it is loaded in time to render it on the screen. 77 | -- 78 | -- The 16-bit tile data words aren't stored contiguously in RAM, instead they 79 | -- are split into high and low bytes. The high bytes are stored in the 80 | -- upper-half of the RAM, while the low bytes are stored in the lower-half. 81 | -- 82 | -- We latch the tile code well before the end of the row, to allow the GPU 83 | -- enough time to fetch pixel data from the tile ROM. 84 | tile_data_pipeline : process (clk) 85 | begin 86 | if rising_edge(clk) then 87 | if cen_6 = '1' then 88 | case to_integer(offset_x) is 89 | when 0 => 90 | -- load high byte 91 | ram_addr <= '1' & row & (col+1); 92 | 93 | when 1 => 94 | -- latch high byte 95 | tile_data <= ram_data; 96 | 97 | -- load low byte 98 | ram_addr <= '0' & row & (col+1); 99 | 100 | when 2 => 101 | -- latch tile code 102 | tile_code <= unsigned(tile_data(1 downto 0) & ram_data); 103 | 104 | when 7 => 105 | -- latch colour 106 | tile_color <= tile_data(7 downto 4); 107 | 108 | when others => null; 109 | end case; 110 | end if; 111 | end if; 112 | end process; 113 | 114 | -- latch the next row from the tile ROM when rendering the last pixel in 115 | -- every row 116 | latch_tile_row : process (clk) 117 | begin 118 | if rising_edge(clk) then 119 | if cen_6 = '1' then 120 | if video.pos.x(2 downto 0) = 7 then 121 | tile_row <= rom_data; 122 | end if; 123 | end if; 124 | end if; 125 | end process; 126 | 127 | -- Set the tile ROM address. 128 | -- 129 | -- This address points to a row of an 8x8 tile. 130 | rom_addr <= tile_code & offset_y(2 downto 0); 131 | 132 | -- decode the pixel from the tile row data 133 | tile_pixel <= decode_tile_row(tile_row, video.pos.x(2 downto 0)); 134 | 135 | -- set graphics data 136 | data <= tile_color & tile_pixel; 137 | end architecture arch; 138 | -------------------------------------------------------------------------------- /sys/pll_cfg.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_TOOL_NAME "altera_pll_reconfig" 2 | set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_TOOL_VERSION "17.0" 3 | set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_TOOL_ENV "mwpim" 4 | set_global_assignment -library "pll_cfg" -name MISC_FILE [file join $::quartus(qip_path) "pll_cfg.cmp"] 5 | set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_TARGETED_DEVICE_FAMILY "Cyclone V" 6 | set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_GENERATED_DEVICE_FAMILY "{Cyclone V}" 7 | set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_QSYS_MODE "UNKNOWN" 8 | set_global_assignment -name SYNTHESIS_ONLY_QIP ON 9 | set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_NAME "cGxsX2hkbWlfY2Zn" 10 | set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_DISPLAY_NAME "QWx0ZXJhIFBMTCBSZWNvbmZpZw==" 11 | set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_REPORT_HIERARCHY "Off" 12 | set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_INTERNAL "Off" 13 | set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_AUTHOR "QWx0ZXJhIENvcnBvcmF0aW9u" 14 | set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_VERSION "MTcuMA==" 15 | set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_DESCRIPTION "QWx0ZXJhIFBoYXNlLUxvY2tlZCBMb29wIFJlY29uZmlndXJhdGlvbiBCbG9jayhBTFRFUkFfUExMX1JFQ09ORklHKQ==" 16 | set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "RU5BQkxFX0JZVEVFTkFCTEU=::ZmFsc2U=::QWRkIGJ5dGVlbmFibGUgcG9ydA==" 17 | set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "QllURUVOQUJMRV9XSURUSA==::NA==::QllURUVOQUJMRV9XSURUSA==" 18 | set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "UkVDT05GSUdfQUREUl9XSURUSA==::Ng==::UkVDT05GSUdfQUREUl9XSURUSA==" 19 | set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "UkVDT05GSUdfREFUQV9XSURUSA==::MzI=::UkVDT05GSUdfREFUQV9XSURUSA==" 20 | set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "cmVjb25mX3dpZHRo::NjQ=::cmVjb25mX3dpZHRo" 21 | set_global_assignment -entity "pll_cfg" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "V0FJVF9GT1JfTE9DSw==::dHJ1ZQ==::V0FJVF9GT1JfTE9DSw==" 22 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_NAME "YWx0ZXJhX3BsbF9yZWNvbmZpZ190b3A=" 23 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_DISPLAY_NAME "QWx0ZXJhIFBMTCBSZWNvbmZpZw==" 24 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_REPORT_HIERARCHY "Off" 25 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_INTERNAL "Off" 26 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_AUTHOR "QWx0ZXJhIENvcnBvcmF0aW9u" 27 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_VERSION "MTcuMA==" 28 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_DESCRIPTION "QWx0ZXJhIFBoYXNlLUxvY2tlZCBMb29wIFJlY29uZmlndXJhdGlvbiBCbG9jayhBTFRFUkFfUExMX1JFQ09ORklHKQ==" 29 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "ZGV2aWNlX2ZhbWlseQ==::Q3ljbG9uZSBW::ZGV2aWNlX2ZhbWlseQ==" 30 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "RU5BQkxFX01JRg==::ZmFsc2U=::RW5hYmxlIE1JRiBTdHJlYW1pbmc=" 31 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "RU5BQkxFX0JZVEVFTkFCTEU=::ZmFsc2U=::QWRkIGJ5dGVlbmFibGUgcG9ydA==" 32 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "QllURUVOQUJMRV9XSURUSA==::NA==::QllURUVOQUJMRV9XSURUSA==" 33 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "UkVDT05GSUdfQUREUl9XSURUSA==::Ng==::UkVDT05GSUdfQUREUl9XSURUSA==" 34 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "UkVDT05GSUdfREFUQV9XSURUSA==::MzI=::UkVDT05GSUdfREFUQV9XSURUSA==" 35 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "cmVjb25mX3dpZHRo::NjQ=::cmVjb25mX3dpZHRo" 36 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_COMPONENT_PARAMETER "V0FJVF9GT1JfTE9DSw==::dHJ1ZQ==::V0FJVF9GT1JfTE9DSw==" 37 | 38 | set_global_assignment -library "pll_cfg" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_cfg.v"] 39 | set_global_assignment -library "pll_cfg" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_cfg/altera_pll_reconfig_top.v"] 40 | set_global_assignment -library "pll_cfg" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_cfg/altera_pll_reconfig_core.v"] 41 | 42 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_TOOL_NAME "altera_pll_reconfig" 43 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_TOOL_VERSION "17.0" 44 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_cfg" -name IP_TOOL_ENV "mwpim" 45 | -------------------------------------------------------------------------------- /src/mem/segment.vhd: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2019 Josh Bassett 2 | -- 3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 4 | -- of this software and associated documentation files (the "Software"), to deal 5 | -- in the Software without restriction, including without limitation the rights 6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | -- copies of the Software, and to permit persons to whom the Software is 8 | -- furnished to do so, subject to the following conditions: 9 | -- 10 | -- The above copyright notice and this permission notice shall be included in all 11 | -- copies or substantial portions of the Software. 12 | -- 13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | -- SOFTWARE. 20 | 21 | library ieee; 22 | use ieee.std_logic_1164.all; 23 | use ieee.numeric_std.all; 24 | 25 | use work.common.all; 26 | 27 | -- A segment provides a read-only interface to a contiguous block of ROM data, 28 | -- located somewhere in memory. 29 | entity segment is 30 | generic ( 31 | -- the width of the ROM address bus 32 | ROM_ADDR_WIDTH : natural; 33 | 34 | -- the width of the ROM data bus 35 | ROM_DATA_WIDTH : natural; 36 | 37 | -- the byte offset of the ROM data in memory 38 | ROM_OFFSET : natural := 0 39 | ); 40 | port ( 41 | -- reset 42 | reset : in std_logic; 43 | 44 | -- clock 45 | clk : in std_logic; 46 | 47 | -- When the chip select signal is asserted, the segment will request data 48 | -- from the ROM controller when there is a cache miss. 49 | cs : in std_logic := '1'; 50 | 51 | -- When the output enable signal is asserted, the output buffer is enabled 52 | -- and the word at the requested address will be placed on the ROM data 53 | -- bus. 54 | oe : in std_logic := '1'; 55 | 56 | -- controller interface 57 | ctrl_addr : buffer unsigned(SDRAM_CTRL_ADDR_WIDTH-1 downto 0); 58 | ctrl_req : out std_logic; 59 | ctrl_ack : in std_logic; 60 | ctrl_valid : in std_logic; 61 | ctrl_data : in std_logic_vector(SDRAM_CTRL_DATA_WIDTH-1 downto 0); 62 | 63 | -- ROM interface 64 | rom_addr : in unsigned(ROM_ADDR_WIDTH-1 downto 0); 65 | rom_data : out std_logic_vector(ROM_DATA_WIDTH-1 downto 0) 66 | ); 67 | end segment; 68 | 69 | architecture arch of segment is 70 | -- the number of ROM words in a 32-bit word (e.g. there are four 8-bit ROM 71 | -- words in a 32-bit word) 72 | constant ROM_WORDS : natural := SDRAM_CTRL_DATA_WIDTH/ROM_DATA_WIDTH; 73 | 74 | -- the number of bits in the offset component of the ROM address 75 | constant OFFSET_WIDTH : natural := ilog2(ROM_WORDS); 76 | 77 | -- the offset of the word from the requested ROM address in the cache 78 | signal offset : natural range 0 to ROM_WORDS-1; 79 | 80 | -- control signals 81 | signal hit : std_logic; 82 | 83 | -- registers 84 | signal full : std_logic; 85 | signal pending : std_logic; 86 | signal pending_addr : unsigned(SDRAM_CTRL_ADDR_WIDTH-1 downto 0); 87 | signal cache_addr : unsigned(SDRAM_CTRL_ADDR_WIDTH-1 downto 0); 88 | signal cache_data : std_logic_vector(SDRAM_CTRL_DATA_WIDTH-1 downto 0); 89 | begin 90 | -- latch data received from the memory controller 91 | latch_data : process (clk, reset) 92 | begin 93 | if reset = '1' then 94 | full <= '0'; 95 | pending <= '0'; 96 | elsif rising_edge(clk) then 97 | if ctrl_ack = '1' then 98 | -- set the pending register 99 | pending <= '1'; 100 | 101 | -- set the pending addr 102 | pending_addr <= ctrl_addr; 103 | elsif ctrl_valid = '1' then 104 | -- set the full register 105 | full <= '1'; 106 | 107 | -- clear the pending register 108 | pending <= '0'; 109 | 110 | -- set the cached address/data 111 | cache_addr <= pending_addr; 112 | cache_data <= ctrl_data; 113 | end if; 114 | end if; 115 | end process; 116 | 117 | -- assert the hit signal when the cache has been filled, and the requested 118 | -- address is in the cache 119 | hit <= '1' when full = '1' and ctrl_addr = cache_addr else '0'; 120 | 121 | -- calculate the offset of the ROM address within a 32-bit word 122 | offset <= to_integer(rom_addr(OFFSET_WIDTH-1 downto 0)) when OFFSET_WIDTH > 0 else 0; 123 | 124 | -- extract the word at the requested offset in the cache 125 | rom_data <= cache_data((ROM_WORDS-offset)*ROM_DATA_WIDTH-1 downto (ROM_WORDS-offset-1)*ROM_DATA_WIDTH) when cs = '1' and oe = '1' else (others => '0'); 126 | 127 | -- we need to divide the ROM offset by four, because we are converting from 128 | -- an 8-bit ROM offset to a 32-bit address 129 | ctrl_addr <= resize(shift_right(rom_addr, OFFSET_WIDTH), SDRAM_CTRL_ADDR_WIDTH) + ROM_OFFSET/4; 130 | 131 | -- assert the request signal unless there is a pending request or a cache hit 132 | ctrl_req <= cs and not (pending or hit); 133 | end architecture arch; 134 | -------------------------------------------------------------------------------- /src/opl3/fw/YMF262.H: -------------------------------------------------------------------------------- 1 | // license:GPL-2.0+ 2 | // copyright-holders:Jarek Burczynski 3 | 4 | #define OPL3_SAMPLE_BITS 16 5 | 6 | #define TL_RES_LEN (256) /* 8 bits addressing (real chip) */ 7 | #define TL_TAB_LEN (13*2*TL_RES_LEN) 8 | 9 | /* sinwave entries */ 10 | #define SIN_BITS 10 11 | #define SIN_LEN (1<>KSR */ 64 | uint8_t key; /* 29 - 0 = KEY OFF, >0 = KEY ON */ 65 | uint16_t mul; /* 30 - multiple: mul_tab[ML] */ 66 | uint16_t sl; /* 32 - sustain level: sl_tab[SL] */ 67 | uint8_t vib; /* 34 - bool - LFO Phase Modulation enable flag (active high)*/ 68 | uint8_t waveform_number; /* 35 */ 69 | int16_t connect; /* 36 - slot output pointer */ 70 | uint8_t eg_sh_ar; /* 38 - (attack state) */ 71 | uint8_t eg_sel_ar; /* 39 - (attack state) */ 72 | uint8_t eg_sh_dr; /* 40 - (decay state) */ 73 | uint8_t eg_sel_dr; /* 41 - (decay state) */ 74 | uint8_t eg_sh_rr; /* 42 - (release state) */ 75 | uint8_t eg_sel_rr; /* 43 - (release state) */ 76 | } OPL3_SLOT; 77 | 78 | typedef struct _OPL3_CH // 96 bytes 79 | { 80 | OPL3_SLOT SLOT0; /* 0 */ 81 | uint16_t block_fnum; /* 44 - block+fnum */ 82 | int16_t chanout; /* 46 */ 83 | /* 84 | there are 12 2-operator channels which can be combined in pairs 85 | to form six 4-operator channel, they are: 86 | 0 and 3, 87 | 1 and 4, 88 | 2 and 5, 89 | 9 and 12, 90 | 10 and 13, 91 | 11 and 14 92 | */ 93 | OPL3_SLOT SLOT1; /* 48 */ 94 | 95 | uint8_t extended; /* SLOT1+44 - bool - set to 1 if this channel forms up a 4op channel with another channel(only used by first of pair of channels, ie 0,1,2 and 9,10,11) */ 96 | uint8_t ksl_base; /* 45 - KeyScaleLevel Base step */ 97 | uint8_t kcode; /* 46 - key code (for key scaling) */ 98 | uint8_t pad; /* 47 */ 99 | } OPL3_CH; 100 | 101 | /* OPL3 state */ 102 | typedef struct _OPL3 103 | { 104 | OPL3_CH P_CH[18]; /* OPL3 chips have 18 channels */ 105 | int16_t phase_modulation; /* 0 - phase modulation input (SLOT 2) */ 106 | int16_t phase_modulation2; /* 2 - phase modulation input (SLOT 3 in 4 operator channels) */ 107 | uint32_t panA; /* 4 - channels output masks */ 108 | uint32_t panB; /* 8 - channels output masks */ 109 | /* LFO */ 110 | uint8_t lfo_am_depth; /* 12 - bool */ 111 | uint8_t lfo_pm_depth_range;/* 13 */ 112 | uint8_t OPL3_mode; /* 14 - bool - OPL3 extension enable flag */ 113 | uint8_t rhythm; /* 15 - bool - Rhythm mode */ 114 | uint16_t address; /* 16 - address register */ 115 | uint8_t nts; /* 20 - NTS (note select) */ 116 | } OPL3; 117 | 118 | 119 | void OPL3ResetChip(); 120 | void OPL3Write(uint8_t a, uint8_t v); 121 | 122 | 123 | -------------------------------------------------------------------------------- /src/gpu/video_gen.vhd: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2019 Josh Bassett 2 | -- 3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 4 | -- of this software and associated documentation files (the "Software"), to deal 5 | -- in the Software without restriction, including without limitation the rights 6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | -- copies of the Software, and to permit persons to whom the Software is 8 | -- furnished to do so, subject to the following conditions: 9 | -- 10 | -- The above copyright notice and this permission notice shall be included in all 11 | -- copies or substantial portions of the Software. 12 | -- 13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | -- SOFTWARE. 20 | 21 | library ieee; 22 | use ieee.std_logic_1164.all; 23 | use ieee.numeric_std.all; 24 | 25 | use work.common.all; 26 | 27 | -- This module generates the video timing signals for a 256x224 screen 28 | -- resolution. This is a very common resolution for older arcade games. 29 | -- 30 | -- The sync signals tell the CRT when to start and stop scanning. The 31 | -- horizontal sync tells the CRT when to start a new scanline, and the vertical 32 | -- sync tells it when to start a new field. 33 | -- 34 | -- The blanking signals indicate whether the beam is in the horizontal or 35 | -- vertical blanking (non-visible) regions. Video output should be disabled 36 | -- while the beam is in these regions, they are also used to do things like 37 | -- fetch graphics data. 38 | -- 39 | -- horizontal frequency: 6Mhz / 384 = 15.625kHz 40 | -- vertical frequency: 15.625kHz / 264 = 59.185 Hz 41 | entity video_gen is 42 | port ( 43 | -- clock signals 44 | clk : in std_logic; 45 | cen : in std_logic; 46 | 47 | -- video signals 48 | video : out video_t 49 | ); 50 | end video_gen; 51 | 52 | architecture arch of video_gen is 53 | -- horizontal regions 54 | constant H_FRONT_PORCH : natural := 40; 55 | constant H_RETRACE : natural := 32; 56 | constant H_BACK_PORCH : natural := 56; 57 | constant H_DISPLAY : natural := 256; 58 | constant H_SCAN : natural := H_FRONT_PORCH+H_RETRACE+H_BACK_PORCH+H_DISPLAY; -- 384 59 | 60 | -- vertical regions 61 | constant V_FRONT_PORCH : natural := 16; 62 | constant V_RETRACE : natural := 8; 63 | constant V_BACK_PORCH : natural := 16; 64 | constant V_DISPLAY : natural := 224; 65 | constant V_SCAN : natural := V_FRONT_PORCH+V_RETRACE+V_BACK_PORCH+V_DISPLAY; -- 264 66 | 67 | -- initial counter values 68 | constant H_START : natural := 128; 69 | constant V_START : natural := 248; 70 | 71 | -- position counters 72 | signal x : natural range 0 to 511 := H_START; 73 | signal y : natural range 0 to 511 := V_START; 74 | 75 | -- sync signals 76 | signal hsync, vsync : std_logic; 77 | 78 | -- blank signals 79 | signal hblank, vblank : std_logic; 80 | begin 81 | -- generate horizontal timing signals 82 | horizontal_timing : process (clk) 83 | begin 84 | if rising_edge(clk) then 85 | if cen = '1' then 86 | if x = x'high then 87 | x <= H_START; 88 | else 89 | x <= x + 1; 90 | end if; 91 | 92 | -- Assert the HSYNC signal after the front porch region. Deassert it 93 | -- after the horizontal retrace. 94 | if x = H_START+H_FRONT_PORCH+H_RETRACE-1 then 95 | hsync <= '0'; 96 | elsif x = H_START+H_FRONT_PORCH-1 then 97 | hsync <= '1'; 98 | end if; 99 | 100 | -- Assert the HBLANK signal at the end of the scan line. Deassert it 101 | -- after the back porch region. 102 | if x = H_START+H_FRONT_PORCH+H_RETRACE+H_BACK_PORCH-1 then 103 | hblank <= '0'; 104 | elsif x = H_START+H_SCAN-1 then 105 | hblank <= '1'; 106 | end if; 107 | end if; 108 | end if; 109 | end process; 110 | 111 | -- generate vertical timing signals 112 | vertical_timing : process (clk) 113 | begin 114 | if rising_edge(clk) then 115 | if cen = '1' then 116 | if x = H_START+H_FRONT_PORCH-1 then 117 | if y = y'high then 118 | y <= V_START; 119 | else 120 | y <= y + 1; 121 | end if; 122 | 123 | if y = V_START+V_RETRACE-1 then 124 | vsync <= '0'; 125 | elsif y = V_START+V_SCAN-1 then 126 | vsync <= '1'; 127 | end if; 128 | 129 | if y = V_START+V_RETRACE+V_BACK_PORCH-1 then 130 | vblank <= '0'; 131 | elsif y = V_START+V_RETRACE+V_BACK_PORCH+V_DISPLAY-1 then 132 | vblank <= '1'; 133 | end if; 134 | end if; 135 | end if; 136 | end if; 137 | end process; 138 | 139 | -- set video position 140 | video.pos.x <= to_unsigned(x, video.pos.x'length); 141 | video.pos.y <= to_unsigned(y, video.pos.y'length); 142 | 143 | -- set sync signals 144 | video.hsync <= hsync; 145 | video.vsync <= vsync; 146 | 147 | -- set blank signals 148 | video.hblank <= hblank; 149 | video.vblank <= vblank; 150 | 151 | -- set output enable 152 | video.enable <= not (hblank or vblank); 153 | end architecture arch; 154 | -------------------------------------------------------------------------------- /src/t80/T80_Reg.vhd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- **** 3 | -- T80(c) core. Attempt to finish all undocumented features and provide 4 | -- accurate timings. 5 | -- Version 350. 6 | -- Copyright (c) 2018 Sorgelig 7 | -- Test passed: ZEXDOC, ZEXALL, Z80Full(*), Z80memptr 8 | -- (*) Currently only SCF and CCF instructions aren't passed X/Y flags check as 9 | -- correct implementation is still unclear. 10 | -- 11 | -- **** 12 | -- T80(b) core. In an effort to merge and maintain bug fixes .... 13 | -- 14 | -- 15 | -- Ver 300 started tidyup 16 | -- MikeJ March 2005 17 | -- Latest version from www.fpgaarcade.com (original www.opencores.org) 18 | -- 19 | -- **** 20 | -- 21 | -- T80 Registers, technology independent 22 | -- 23 | -- Version : 0244 24 | -- 25 | -- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org) 26 | -- 27 | -- All rights reserved 28 | -- 29 | -- Redistribution and use in source and synthezised forms, with or without 30 | -- modification, are permitted provided that the following conditions are met: 31 | -- 32 | -- Redistributions of source code must retain the above copyright notice, 33 | -- this list of conditions and the following disclaimer. 34 | -- 35 | -- Redistributions in synthesized form must reproduce the above copyright 36 | -- notice, this list of conditions and the following disclaimer in the 37 | -- documentation and/or other materials provided with the distribution. 38 | -- 39 | -- Neither the name of the author nor the names of other contributors may 40 | -- be used to endorse or promote products derived from this software without 41 | -- specific prior written permission. 42 | -- 43 | -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 44 | -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 45 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 46 | -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 47 | -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 48 | -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 49 | -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 50 | -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 51 | -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 52 | -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 53 | -- POSSIBILITY OF SUCH DAMAGE. 54 | -- 55 | -- Please report bugs to the author, but before you do so, please 56 | -- make sure that this is not a derivative work and that 57 | -- you have the latest version of this file. 58 | -- 59 | -- The latest version of this file can be found at: 60 | -- http://www.opencores.org/cvsweb.shtml/t51/ 61 | -- 62 | -- Limitations : 63 | -- 64 | -- File history : 65 | -- 66 | -- 0242 : Initial release 67 | -- 68 | -- 0244 : Changed to single register file 69 | -- 70 | 71 | library IEEE; 72 | use IEEE.std_logic_1164.all; 73 | use IEEE.numeric_std.all; 74 | 75 | entity T80_Reg is 76 | port( 77 | Clk : in std_logic; 78 | CEN : in std_logic; 79 | WEH : in std_logic; 80 | WEL : in std_logic; 81 | AddrA : in std_logic_vector(2 downto 0); 82 | AddrB : in std_logic_vector(2 downto 0); 83 | AddrC : in std_logic_vector(2 downto 0); 84 | DIH : in std_logic_vector(7 downto 0); 85 | DIL : in std_logic_vector(7 downto 0); 86 | DOAH : out std_logic_vector(7 downto 0); 87 | DOAL : out std_logic_vector(7 downto 0); 88 | DOBH : out std_logic_vector(7 downto 0); 89 | DOBL : out std_logic_vector(7 downto 0); 90 | DOCH : out std_logic_vector(7 downto 0); 91 | DOCL : out std_logic_vector(7 downto 0); 92 | DOR : out std_logic_vector(127 downto 0); 93 | DIRSet : in std_logic; 94 | DIR : in std_logic_vector(127 downto 0) 95 | ); 96 | end T80_Reg; 97 | 98 | architecture rtl of T80_Reg is 99 | 100 | type Register_Image is array (natural range <>) of std_logic_vector(7 downto 0); 101 | signal RegsH : Register_Image(0 to 7); 102 | signal RegsL : Register_Image(0 to 7); 103 | 104 | begin 105 | 106 | process (Clk) 107 | begin 108 | if rising_edge(Clk) then 109 | if DIRSet = '1' then 110 | RegsL(0) <= DIR( 7 downto 0); 111 | RegsH(0) <= DIR( 15 downto 8); 112 | 113 | RegsL(1) <= DIR( 23 downto 16); 114 | RegsH(1) <= DIR( 31 downto 24); 115 | 116 | RegsL(2) <= DIR( 39 downto 32); 117 | RegsH(2) <= DIR( 47 downto 40); 118 | 119 | RegsL(3) <= DIR( 55 downto 48); 120 | RegsH(3) <= DIR( 63 downto 56); 121 | 122 | RegsL(4) <= DIR( 71 downto 64); 123 | RegsH(4) <= DIR( 79 downto 72); 124 | 125 | RegsL(5) <= DIR( 87 downto 80); 126 | RegsH(5) <= DIR( 95 downto 88); 127 | 128 | RegsL(6) <= DIR(103 downto 96); 129 | RegsH(6) <= DIR(111 downto 104); 130 | 131 | RegsL(7) <= DIR(119 downto 112); 132 | RegsH(7) <= DIR(127 downto 120); 133 | elsif CEN = '1' then 134 | if WEH = '1' then 135 | RegsH(to_integer(unsigned(AddrA))) <= DIH; 136 | end if; 137 | if WEL = '1' then 138 | RegsL(to_integer(unsigned(AddrA))) <= DIL; 139 | end if; 140 | end if; 141 | end if; 142 | end process; 143 | 144 | DOAH <= RegsH(to_integer(unsigned(AddrA))); 145 | DOAL <= RegsL(to_integer(unsigned(AddrA))); 146 | DOBH <= RegsH(to_integer(unsigned(AddrB))); 147 | DOBL <= RegsL(to_integer(unsigned(AddrB))); 148 | DOCH <= RegsH(to_integer(unsigned(AddrC))); 149 | DOCL <= RegsL(to_integer(unsigned(AddrC))); 150 | DOR <= RegsH(7) & RegsL(7) & RegsH(6) & RegsL(6) & RegsH(5) & RegsL(5) & RegsH(4) & RegsL(4) & RegsH(3) & RegsL(3) & RegsH(2) & RegsL(2) & RegsH(1) & RegsL(1) & RegsH(0) & RegsL(0); 151 | 152 | end; 153 | -------------------------------------------------------------------------------- /src/snd/msm5205.vhd: -------------------------------------------------------------------------------- 1 | library ieee; 2 | 3 | use ieee.std_logic_1164.all; 4 | use ieee.numeric_std.all; 5 | 6 | use work.common.all; 7 | 8 | entity MSM5205 is 9 | generic ( 10 | -- 00=clk/96, 01=clk/64, 10=clk/48, 11=prohibited 11 | SAMPLE_FREQ : std_logic_vector(1 downto 0) := "00" 12 | ); 13 | port ( 14 | reset : in std_logic; 15 | 16 | clk : in std_logic; 17 | cen : in std_logic; 18 | 19 | -- sampling output clock 20 | vck : out std_logic; 21 | 22 | -- ADPCM input data 23 | din : in std_logic_vector(3 downto 0); 24 | 25 | -- 12-bit PCM output data 26 | sample : out signed(11 downto 0) 27 | ); 28 | end MSM5205; 29 | 30 | architecture rtl of MSM5205 is 31 | signal vck_reg : std_logic := '0'; 32 | signal vck_ena : std_logic := '0'; 33 | 34 | signal out_val : signed(15 downto 0) := (others => '0'); 35 | signal sum_val : signed(12 downto 0) := (others => '0'); 36 | signal sign_val : signed(12 downto 0) := (others => '0'); 37 | 38 | signal ctr : unsigned(6 downto 0) := (others => '0'); 39 | signal step : unsigned(5 downto 0) := (others => '0'); 40 | signal divctr : unsigned(3 downto 0) := (others => '0'); 41 | 42 | signal stepval : signed(11 downto 0) := (others => '0'); 43 | 44 | signal stepval1, stepval2, stepval4, stepval8 : signed(12 downto 0) := (others => '0'); 45 | 46 | -- Dialogic ADPCM Algorithm, table 2 47 | type STEPVAL_ARRAY is array(0 to 48) of signed(11 downto 0); 48 | constant STEP_VAL_TABLE : STEPVAL_ARRAY := ( 49 | x"010", x"011", x"013", x"015", x"017", x"019", x"01C", x"01F", 50 | x"022", x"025", x"029", x"02D", x"032", x"037", x"03C", x"042", 51 | x"049", x"050", x"058", x"061", x"06B", x"076", x"082", x"08F", 52 | x"09D", x"0AD", x"0BE", x"0D1", x"0E6", x"0FD", x"117", x"133", 53 | x"151", x"173", x"198", x"1C1", x"1EE", x"220", x"256", x"292", 54 | x"2D4", x"31C", x"36C", x"3C3", x"424", x"48E", x"502", x"583", 55 | x"610" 56 | ); 57 | begin 58 | p_vck : process (clk) 59 | begin 60 | if rising_edge(clk) then 61 | if cen = '1' and vck_ena = '1' then 62 | vck_reg <= not vck_reg; 63 | end if; 64 | end if; 65 | end process; 66 | 67 | -- sample clock selector 68 | p_clk_sel : process (clk) 69 | begin 70 | if rising_edge(clk) then 71 | if cen = '1' then 72 | case SAMPLE_FREQ is 73 | when "00" => divctr <= x"6"; -- L L fosc/96 74 | when "01" => divctr <= x"4"; -- L H fosc/64 75 | when "10" => divctr <= x"3"; -- H L fosc/48 76 | when others => divctr <= x"0"; -- H H prohibited 77 | end case; 78 | end if; 79 | end if; 80 | end process; 81 | 82 | -- divide main clock by a selectable divisor 83 | p_div : process (clk) 84 | begin 85 | if rising_edge(clk) then 86 | if cen = '1' then 87 | if ctr(6 downto 3) = divctr then 88 | ctr <= "0000001"; 89 | vck_ena <= '1'; 90 | else 91 | ctr <= ctr + 1; 92 | vck_ena <= '0'; 93 | end if; 94 | end if; 95 | end if; 96 | end process; 97 | 98 | -- Dialogic ADPCM Algorithm, table 1 99 | -- 100 | -- Adjust step value based on current ADPCM sample keep it within 0-48 limits. 101 | process (clk) 102 | begin 103 | if rising_edge(clk) then 104 | if cen = '1' and vck_ena = '1' and vck_reg = '1' then 105 | if reset = '1' then 106 | step <= to_unsigned(1, 6); 107 | else 108 | case din(2 downto 0) is 109 | when "111" => if step < 41 then step <= step + 8; else step <= to_unsigned(48, 6); end if; 110 | when "110" => if step < 43 then step <= step + 6; else step <= to_unsigned(48, 6); end if; 111 | when "101" => if step < 45 then step <= step + 4; else step <= to_unsigned(48, 6); end if; 112 | when "100" => if step < 47 then step <= step + 2; else step <= to_unsigned(48, 6); end if; 113 | when others => if step > 0 then step <= step - 1; else step <= to_unsigned( 0, 6); end if; 114 | end case; 115 | end if; 116 | end if; 117 | end if; 118 | end process; 119 | 120 | process (clk) 121 | begin 122 | if rising_edge(clk) then 123 | if cen = '1' and vck_ena = '1' and vck_reg = '1' then 124 | if reset = '1' then 125 | out_val <= to_signed(0, 16); 126 | else 127 | -- hard limit math results to 12 bit values 128 | if (out_val + sign_val < -2048) then 129 | out_val <= to_signed(-2048, 16); -- underflow, stay on max negative value 130 | elsif (out_val + sign_val > 2047) then 131 | out_val <= to_signed(2047, 16); -- overflow, stay on max positive value 132 | else 133 | out_val <= out_val + sign_val; 134 | end if; 135 | end if; 136 | end if; 137 | end if; 138 | end process; 139 | 140 | sample <= out_val(11 downto 0); 141 | 142 | -- table lookup only has positive values 143 | stepval <= STEP_VAL_TABLE(to_integer(step)); 144 | 145 | -- so we can afford to just shift in zeroes from the left without sign extension 146 | stepval1 <= "0" & stepval(11 downto 0) when din(2) = '1' else (others => '0'); -- value/1 147 | stepval2 <= "00" & stepval(11 downto 1) when din(1) = '1' else (others => '0'); -- value/2 148 | stepval4 <= "000" & stepval(11 downto 2) when din(0) = '1' else (others => '0'); -- value/4 149 | stepval8 <= "0000" & stepval(11 downto 3); -- value/8 150 | 151 | sum_val <= (stepval1 + stepval2) + (stepval4 + stepval8); 152 | 153 | sign_val <= sum_val when din(3) = '0' else -sum_val; -- din(3) determines if we return sum or -sum 154 | 155 | vck <= vck_reg; 156 | end rtl; 157 | -------------------------------------------------------------------------------- /sys/scandoubler.v: -------------------------------------------------------------------------------- 1 | // 2 | // scandoubler.v 3 | // 4 | // Copyright (c) 2015 Till Harbaum 5 | // Copyright (c) 2017-2019 Sorgelig 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_sys, 26 | input ce_pix, 27 | output ce_pix_out, 28 | 29 | input hq2x, 30 | 31 | // shifter video interface 32 | input hs_in, 33 | input vs_in, 34 | input hb_in, 35 | input vb_in, 36 | 37 | input [DWIDTH:0] r_in, 38 | input [DWIDTH:0] g_in, 39 | input [DWIDTH:0] b_in, 40 | input mono, 41 | 42 | // output interface 43 | output reg hs_out, 44 | output vs_out, 45 | output hb_out, 46 | output vb_out, 47 | output [DWIDTH:0] r_out, 48 | output [DWIDTH:0] g_out, 49 | output [DWIDTH:0] b_out 50 | ); 51 | 52 | localparam DWIDTH = HALF_DEPTH ? 3 : 7; 53 | 54 | reg [7:0] pix_len = 0; 55 | wire [7:0] pl = pix_len + 1'b1; 56 | 57 | reg [7:0] pix_in_cnt = 0; 58 | wire [7:0] pc_in = pix_in_cnt + 1'b1; 59 | reg [7:0] pixsz, pixsz2, pixsz4 = 0; 60 | 61 | reg ce_x4i, ce_x1i; 62 | always @(negedge clk_sys) begin 63 | reg old_ce, valid, hs; 64 | 65 | if(~&pix_len) pix_len <= pl; 66 | if(~&pix_in_cnt) pix_in_cnt <= pc_in; 67 | 68 | ce_x4i <= 0; 69 | ce_x1i <= 0; 70 | 71 | // use such odd comparison to place ce_x4 evenly if master clock isn't multiple of 4. 72 | if((pc_in == pixsz4) || (pc_in == pixsz2) || (pc_in == (pixsz2+pixsz4))) ce_x4i <= 1; 73 | 74 | old_ce <= ce_pix; 75 | if(~old_ce & ce_pix) begin 76 | if(valid & ~hb_in & ~vb_in) begin 77 | pixsz <= pl; 78 | pixsz2 <= {1'b0, pl[7:1]}; 79 | pixsz4 <= {2'b00, pl[7:2]}; 80 | end 81 | pix_len <= 0; 82 | valid <= 1; 83 | end 84 | 85 | hs <= hs_in; 86 | if((~hs & hs_in) || (pc_in >= pixsz)) begin 87 | ce_x4i <= 1; 88 | ce_x1i <= 1; 89 | pix_in_cnt <= 0; 90 | end 91 | 92 | if(hb_in | vb_in) valid <= 0; 93 | end 94 | 95 | reg req_line_reset; 96 | reg [DWIDTH:0] r_d, g_d, b_d; 97 | always @(posedge clk_sys) begin 98 | if(ce_x1i) begin 99 | req_line_reset <= hb_in; 100 | r_d <= r_in; 101 | g_d <= g_in; 102 | b_d <= b_in; 103 | end 104 | end 105 | 106 | Hq2x #(.LENGTH(LENGTH), .HALF_DEPTH(HALF_DEPTH)) Hq2x 107 | ( 108 | .clk(clk_sys), 109 | 110 | .ce_in(ce_x4i), 111 | .inputpixel({b_d,g_d,r_d}), 112 | .mono(mono), 113 | .disable_hq2x(~hq2x), 114 | .reset_frame(vb_in), 115 | .reset_line(req_line_reset), 116 | 117 | .ce_out(ce_x4o), 118 | .read_y(sd_line), 119 | .hblank(hbo[0]&hbo[8]), 120 | .outpixel({b_out,g_out,r_out}) 121 | ); 122 | 123 | reg [7:0] pix_out_cnt = 0; 124 | wire [7:0] pc_out = pix_out_cnt + 1'b1; 125 | 126 | reg ce_x4o, ce_x2o; 127 | always @(negedge clk_sys) begin 128 | reg hs; 129 | 130 | if(~&pix_out_cnt) pix_out_cnt <= pc_out; 131 | 132 | ce_x4o <= 0; 133 | ce_x2o <= 0; 134 | 135 | // use such odd comparison to place ce_x4 evenly if master clock isn't multiple of 4. 136 | if((pc_out == pixsz4) || (pc_out == pixsz2) || (pc_out == (pixsz2+pixsz4))) ce_x4o <= 1; 137 | if( pc_out == pixsz2) ce_x2o <= 1; 138 | 139 | hs <= hs_out; 140 | if((~hs & hs_out) || (pc_out >= pixsz)) begin 141 | ce_x2o <= 1; 142 | ce_x4o <= 1; 143 | pix_out_cnt <= 0; 144 | end 145 | end 146 | 147 | reg [1:0] sd_line; 148 | reg [3:0] vbo; 149 | reg [3:0] vso; 150 | reg [8:0] hbo; 151 | always @(posedge clk_sys) begin 152 | 153 | reg [31:0] hcnt; 154 | reg [30:0] sd_hcnt; 155 | reg [30:0] hs_start, hs_end; 156 | reg [30:0] hde_start, hde_end; 157 | 158 | reg hs, hb; 159 | 160 | if(ce_x4o) begin 161 | hbo[8:1] <= hbo[7:0]; 162 | end 163 | 164 | // output counter synchronous to input and at twice the rate 165 | sd_hcnt <= sd_hcnt + 1'd1; 166 | if(sd_hcnt == hde_start) begin 167 | sd_hcnt <= 0; 168 | vbo[3:1] <= vbo[2:0]; 169 | end 170 | 171 | if(sd_hcnt == hs_end) begin 172 | sd_line <= sd_line + 1'd1; 173 | if(&vbo[3:2]) sd_line <= 1; 174 | vso[3:1] <= vso[2:0]; 175 | end 176 | 177 | if(sd_hcnt == hde_start)hbo[0] <= 0; 178 | if(sd_hcnt == hde_end) hbo[0] <= 1; 179 | 180 | // replicate horizontal sync at twice the speed 181 | if(sd_hcnt == hs_end) hs_out <= 0; 182 | if(sd_hcnt == hs_start) hs_out <= 1; 183 | 184 | hs <= hs_in; 185 | hb <= hb_in; 186 | 187 | hcnt <= hcnt + 1'd1; 188 | if(hb && !hb_in) begin 189 | hde_start <= hcnt[31:1]; 190 | hbo[0] <= 0; 191 | hcnt <= 0; 192 | sd_hcnt <= 0; 193 | vbo <= {vbo[2:0],vb_in}; 194 | end 195 | 196 | if(!hb && hb_in) hde_end <= hcnt[31:1]; 197 | 198 | // falling edge of hsync indicates start of line 199 | if(hs && !hs_in) begin 200 | hs_end <= hcnt[31:1]; 201 | vso[0] <= vs_in; 202 | end 203 | 204 | // save position of rising edge 205 | if(!hs && hs_in) hs_start <= hcnt[31:1]; 206 | end 207 | 208 | assign vs_out = vso[3]; 209 | assign ce_pix_out = hq2x ? ce_x4o : ce_x2o; 210 | 211 | //Compensate picture shift after HQ2x 212 | assign vb_out = vbo[3]; 213 | assign hb_out = hbo[6]; 214 | 215 | endmodule 216 | -------------------------------------------------------------------------------- /src/opl3/opl3.sv: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Aleksander Osman 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * * Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | module opl3 28 | #( 29 | parameter OPLCLK = 64000000 // opl_clk in Hz 30 | ) 31 | ( 32 | input clk, 33 | input clk_opl, 34 | input rst_n, 35 | output reg irq_n, 36 | 37 | input [12:0] period_80us, // from clk 38 | 39 | input [1:0] addr, 40 | output [7:0] dout, 41 | input [7:0] din, 42 | input we, 43 | 44 | output signed [15:0] sample_l, 45 | output signed [15:0] sample_r 46 | ); 47 | 48 | //------------------------------------------------------------------------------ 49 | 50 | wire [7:0] io_readdata = { timer1_overflow | timer2_overflow, timer1_overflow, timer2_overflow, 5'd0 }; 51 | assign dout = !addr ? io_readdata : 8'hFF; 52 | 53 | //------------------------------------------------------------------------------ 54 | 55 | reg old_write; 56 | always @(posedge clk) old_write <= we; 57 | 58 | wire write = (~old_write & we); 59 | 60 | reg [8:0] index; 61 | always @(posedge clk or negedge rst_n) begin 62 | if(rst_n == 0) index <= 0; 63 | else if(~addr[0] && write) index <= {addr[1], din}; 64 | end 65 | 66 | wire io_write = (addr[0] && write); 67 | wire [7:0] io_writedata = din; 68 | 69 | //------------------------------------------------------------------------------ timer 1 70 | 71 | reg [7:0] timer1_preset; 72 | always @(posedge clk or negedge rst_n) begin 73 | if(rst_n == 0) timer1_preset <= 0; 74 | else if(io_write && index == 2) timer1_preset <= io_writedata; 75 | end 76 | 77 | reg timer1_mask; 78 | reg timer1_active; 79 | always @(posedge clk or negedge rst_n) begin 80 | if(rst_n == 0) {timer1_mask, timer1_active} <= 0; 81 | else if(io_write && index == 4 && ~io_writedata[7]) {timer1_mask, timer1_active} <= {io_writedata[6], io_writedata[0]}; 82 | end 83 | 84 | wire timer1_pulse; 85 | timer timer1( clk, period_80us, timer1_preset, timer1_active, timer1_pulse ); 86 | 87 | reg timer1_overflow; 88 | always @(posedge clk or negedge rst_n) begin 89 | if(rst_n == 0) timer1_overflow <= 0; 90 | else begin 91 | if(io_write && index == 4 && io_writedata[7]) timer1_overflow <= 0; 92 | if(timer1_pulse) timer1_overflow <= 1; 93 | end 94 | end 95 | 96 | 97 | //------------------------------------------------------------------------------ timer 2 98 | 99 | reg [7:0] timer2_preset; 100 | always @(posedge clk or negedge rst_n) begin 101 | if(rst_n == 0) timer2_preset <= 0; 102 | else if(io_write && index == 3) timer2_preset <= io_writedata; 103 | end 104 | 105 | reg timer2_mask; 106 | reg timer2_active; 107 | always @(posedge clk or negedge rst_n) begin 108 | if(rst_n == 0) {timer2_mask, timer2_active} <= 0; 109 | else if(io_write && index == 4 && ~io_writedata[7]) {timer2_mask, timer2_active} <= {io_writedata[5], io_writedata[1]}; 110 | end 111 | 112 | wire timer2_pulse; 113 | timer timer2( clk, {period_80us, 2'b00}, timer2_preset, timer2_active, timer2_pulse ); 114 | 115 | reg timer2_overflow; 116 | always @(posedge clk or negedge rst_n) begin 117 | if(rst_n == 0) timer2_overflow <= 0; 118 | else begin 119 | if(io_write && index == 4 && io_writedata[7]) timer2_overflow <= 0; 120 | if(timer2_pulse) timer2_overflow <= 1; 121 | end 122 | end 123 | 124 | 125 | //------------------------------------------------------------------------------ IRQ 126 | 127 | always @(posedge clk or negedge rst_n) begin 128 | if(rst_n == 0) irq_n <= 1; 129 | else begin 130 | if(io_write && index == 4 && io_writedata[7]) irq_n <= 1; 131 | if(~timer1_mask && timer1_pulse) irq_n <= 0; 132 | if(~timer2_mask && timer2_pulse) irq_n <= 0; 133 | end 134 | end 135 | 136 | opl3sw #(OPLCLK) opl3 137 | ( 138 | .reset(~rst_n), 139 | 140 | .cpu_clk(clk), 141 | .addr(addr), 142 | .din(din), 143 | .wr(write), 144 | 145 | .clk(clk_opl), 146 | .left(sample_l), 147 | .right(sample_r) 148 | ); 149 | 150 | endmodule 151 | 152 | module timer 153 | ( 154 | input clk, 155 | input [14:0] resolution, 156 | input [7:0] init, 157 | input active, 158 | output reg overflow_pulse 159 | ); 160 | 161 | always @(posedge clk) begin 162 | reg [7:0] counter = 0; 163 | reg [14:0] sub_counter = 0; 164 | reg old_act; 165 | 166 | old_act <= active; 167 | overflow_pulse <= 0; 168 | 169 | if(~old_act && active) begin 170 | counter <= init; 171 | sub_counter <= resolution; 172 | end 173 | else if(active) begin 174 | sub_counter <= sub_counter - 1'd1; 175 | if(!sub_counter) begin 176 | sub_counter <= resolution; 177 | counter <= counter + 1'd1; 178 | if(&counter) begin 179 | overflow_pulse <= 1; 180 | counter <= init; 181 | end 182 | end 183 | end 184 | end 185 | 186 | endmodule 187 | -------------------------------------------------------------------------------- /src/gpu/scroll_layer.vhd: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2019 Josh Bassett 2 | -- 3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 4 | -- of this software and associated documentation files (the "Software"), to deal 5 | -- in the Software without restriction, including without limitation the rights 6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | -- copies of the Software, and to permit persons to whom the Software is 8 | -- furnished to do so, subject to the following conditions: 9 | -- 10 | -- The above copyright notice and this permission notice shall be included in all 11 | -- copies or substantial portions of the Software. 12 | -- 13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | -- SOFTWARE. 20 | 21 | library ieee; 22 | use ieee.std_logic_1164.all; 23 | use ieee.numeric_std.all; 24 | 25 | use work.common.all; 26 | 27 | -- The scroll module handles the scrolling foreground and background layers in 28 | -- the graphics pipeline. 29 | -- 30 | -- It consists of a 32x16 grid of 16x16 tiles. Each 16x16 tile is made up of 31 | -- four separate 8x8 tiles, stored in a left-to-right, top-to-bottom order. 32 | -- 33 | -- Each tile in the tilemap is represented by two bytes in the scroll RAM, 34 | -- a high byte and a low byte, which contains the tile colour and code. 35 | -- 36 | -- Because a scrolling layer is twice the width of the screen, it can never be 37 | -- entirely visible on the screen at once. The horizontal and vertical scroll 38 | -- positions are used to set the position of the visible area. 39 | entity scroll_layer is 40 | generic ( 41 | RAM_ADDR_WIDTH : natural; 42 | RAM_DATA_WIDTH : natural; 43 | ROM_ADDR_WIDTH : natural; 44 | ROM_DATA_WIDTH : natural 45 | ); 46 | port ( 47 | -- clock signals 48 | clk : in std_logic; 49 | cen_6 : in std_logic; 50 | 51 | -- scroll RAM 52 | ram_addr : out unsigned(RAM_ADDR_WIDTH-1 downto 0); 53 | ram_data : in std_logic_vector(RAM_DATA_WIDTH-1 downto 0); 54 | 55 | -- tile ROM 56 | rom_addr : out unsigned(ROM_ADDR_WIDTH-1 downto 0); 57 | rom_data : in std_logic_vector(ROM_DATA_WIDTH-1 downto 0); 58 | 59 | -- video signals 60 | video : in video_t; 61 | 62 | -- scroll position 63 | scroll_pos : in pos_t; 64 | 65 | -- graphics data 66 | data : out byte_t 67 | ); 68 | end scroll_layer; 69 | 70 | architecture arch of scroll_layer is 71 | -- represents the position of a pixel in a 16x16 tile 72 | type tile_pos_t is record 73 | x : unsigned(3 downto 0); 74 | y : unsigned(3 downto 0); 75 | end record tile_pos_t; 76 | 77 | -- tile signals 78 | signal tile_data : byte_t; 79 | signal tile_code : tile_code_t; 80 | signal tile_color : tile_color_t; 81 | signal tile_pixel : tile_pixel_t; 82 | signal tile_row : tile_row_t; 83 | 84 | -- destination position 85 | signal dest_pos : pos_t; 86 | 87 | -- aliases to extract the components of the horizontal and vertical position 88 | alias col : unsigned(4 downto 0) is dest_pos.x(8 downto 4); 89 | alias row : unsigned(3 downto 0) is dest_pos.y(7 downto 4); 90 | alias offset_x : unsigned(3 downto 0) is dest_pos.x(3 downto 0); 91 | alias offset_y : unsigned(3 downto 0) is dest_pos.y(3 downto 0); 92 | begin 93 | -- update position counter 94 | update_pos_counter : process (clk) 95 | begin 96 | if rising_edge(clk) then 97 | if cen_6 = '1' then 98 | if video.hsync = '1' then 99 | -- reset to the horizontal scroll position 100 | dest_pos.x <= scroll_pos.x; 101 | else 102 | dest_pos.x <= dest_pos.x + 1; 103 | end if; 104 | end if; 105 | end if; 106 | end process; 107 | 108 | -- Load tile data from the scroll RAM. 109 | -- 110 | -- While the current tile is being rendered, we need to fetch data for the 111 | -- next tile ahead, so that it is loaded in time to render it on the screen. 112 | -- 113 | -- The 16-bit tile data words aren't stored contiguously in RAM, instead they 114 | -- are split into high and low bytes. The high bytes are stored in the 115 | -- upper-half of the RAM, while the low bytes are stored in the lower-half. 116 | -- 117 | -- We latch the tile code well before the end of the row, to allow the GPU 118 | -- enough time to fetch pixel data from the tile ROM. 119 | tile_data_pipeline : process (clk) 120 | begin 121 | if rising_edge(clk) then 122 | if cen_6 = '1' then 123 | case to_integer(offset_x) is 124 | when 8 => 125 | -- load high byte 126 | ram_addr <= '1' & row & (col+1); 127 | 128 | when 9 => 129 | -- latch high byte 130 | tile_data <= ram_data; 131 | 132 | -- load low byte 133 | ram_addr <= '0' & row & (col+1); 134 | 135 | when 10 => 136 | -- latch tile code 137 | tile_code <= unsigned(tile_data(1 downto 0) & ram_data); 138 | 139 | when 15 => 140 | -- latch colour 141 | tile_color <= tile_data(7 downto 4); 142 | 143 | when others => null; 144 | end case; 145 | end if; 146 | end if; 147 | end process; 148 | 149 | -- latch the next row from the tile ROM when rendering the last pixel in 150 | -- every row 151 | latch_tile_row : process (clk) 152 | begin 153 | if rising_edge(clk) then 154 | if cen_6 = '1' then 155 | if dest_pos.x(2 downto 0) = 7 then 156 | tile_row <= rom_data; 157 | end if; 158 | end if; 159 | end if; 160 | end process; 161 | 162 | -- set vertical position 163 | dest_pos.y(7 downto 0) <= video.pos.y(7 downto 0) + scroll_pos.y(7 downto 0); 164 | 165 | -- Set the tile ROM address. 166 | -- 167 | -- This address points to a row of an 8x8 tile. 168 | rom_addr <= tile_code & offset_y(3) & (not offset_x(3)) & offset_y(2 downto 0); 169 | 170 | -- decode the pixel from the tile row data 171 | tile_pixel <= decode_tile_row(tile_row, dest_pos.x(2 downto 0)); 172 | 173 | -- set graphics data 174 | data <= tile_color & tile_pixel; 175 | end architecture arch; 176 | -------------------------------------------------------------------------------- /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 | 8 | input io_osd, 9 | input io_strobe, 10 | input [15:0] io_din, 11 | 12 | input clk_video, 13 | input [23:0] din, 14 | output [23:0] dout, 15 | input de_in, 16 | output reg de_out, 17 | output reg osd_status 18 | ); 19 | 20 | parameter OSD_COLOR = 3'd4; 21 | parameter OSD_X_OFFSET = 12'd0; 22 | parameter OSD_Y_OFFSET = 12'd0; 23 | 24 | localparam OSD_WIDTH = 12'd256; 25 | localparam OSD_HEIGHT = 12'd64; 26 | 27 | `ifdef OSD_HEADER 28 | localparam OSD_HDR = 12'd32; 29 | `else 30 | localparam OSD_HDR = 12'd0; 31 | `endif 32 | 33 | reg osd_enable; 34 | reg [7:0] osd_buffer[OSD_HDR ? (4096+1024) : 4096]; 35 | 36 | reg info = 0; 37 | reg [8:0] infoh; 38 | reg [8:0] infow; 39 | reg [11:0] infox; 40 | reg [21:0] infoy; 41 | reg [21:0] hrheight; 42 | 43 | always@(posedge clk_sys) begin 44 | reg [12:0] bcnt; 45 | reg [7:0] cmd; 46 | reg has_cmd; 47 | reg old_strobe; 48 | reg highres = 0; 49 | 50 | hrheight <= info ? infoh : ((OSD_HEIGHT<> 9) > 1) ? (((cnt+1'b1) >> 9) - 1) : 0; 110 | pixcnt <= 0; 111 | end 112 | end 113 | 114 | reg [2:0] osd_de; 115 | reg osd_pixel; 116 | reg [21:0] v_cnt; 117 | 118 | reg v_cnt_below320, v_cnt_below640, v_cnt_below960; 119 | 120 | reg [21:0] v_osd_start_320, v_osd_start_640, v_osd_start_960, v_osd_start_other; 121 | 122 | // pipeline the comparisons a bit 123 | always @(posedge clk_video) if(ce_pix) begin 124 | v_cnt_below320 <= v_cnt < 320; 125 | v_cnt_below640 <= v_cnt < 640; 126 | v_cnt_below960 <= v_cnt < 960; 127 | v_osd_start_320 <= ((v_cnt-hrheight)>>1) + OSD_Y_OFFSET; 128 | v_osd_start_640 <= ((v_cnt-(hrheight<<1))>>1) + OSD_Y_OFFSET; 129 | v_osd_start_960 <= ((v_cnt-(hrheight + (hrheight<<1)))>>1) + OSD_Y_OFFSET; 130 | v_osd_start_other <= ((v_cnt-(hrheight<<2))>>1) + OSD_Y_OFFSET; 131 | end 132 | 133 | always @(posedge clk_video) begin 134 | reg deD; 135 | reg [1:0] osd_div; 136 | reg [1:0] multiscan; 137 | reg [7:0] osd_byte; 138 | reg [23:0] h_cnt; 139 | reg [21:0] dsp_width; 140 | reg [21:0] osd_vcnt; 141 | reg [21:0] h_osd_start; 142 | reg [21:0] v_osd_start; 143 | reg [21:0] osd_hcnt; 144 | reg osd_de1,osd_de2; 145 | reg [1:0] osd_en; 146 | 147 | if(ce_pix) begin 148 | 149 | deD <= de_in; 150 | if(~&h_cnt) h_cnt <= h_cnt + 1'd1; 151 | 152 | if(~&osd_hcnt) osd_hcnt <= osd_hcnt + 1'd1; 153 | if (h_cnt == h_osd_start) begin 154 | osd_de[0] <= osd_en[1] && hrheight && (info ? (osd_vcnt < hrheight) : 155 | (!osd_vcnt[11:7] || (osd_vcnt[11] && osd_vcnt[7] && (osd_vcnt[6:0] >= 4) && (osd_vcnt[6:0] < 19)))); 156 | osd_hcnt <= 0; 157 | end 158 | if (osd_hcnt+1 == (info ? infow : OSD_WIDTH)) osd_de[0] <= 0; 159 | 160 | // falling edge of de 161 | if(!de_in && deD) dsp_width <= h_cnt[21:0]; 162 | 163 | // rising edge of de 164 | if(de_in && !deD) begin 165 | h_cnt <= 0; 166 | v_cnt <= v_cnt + 1'd1; 167 | h_osd_start <= info ? infox : (((dsp_width - OSD_WIDTH)>>1) + OSD_X_OFFSET - 2'd2); 168 | 169 | if(h_cnt > {dsp_width, 2'b00}) begin 170 | v_cnt <= 1; 171 | 172 | osd_en <= (osd_en << 1) | osd_enable; 173 | if(~osd_enable) osd_en <= 0; 174 | 175 | if(v_cnt_below320) begin 176 | multiscan <= 0; 177 | v_osd_start <= info ? infoy : v_osd_start_320; 178 | end 179 | else if(v_cnt_below640) begin 180 | multiscan <= 1; 181 | v_osd_start <= info ? (infoy<<1) : v_osd_start_640; 182 | end 183 | else if(v_cnt_below960) begin 184 | multiscan <= 2; 185 | v_osd_start <= info ? (infoy + (infoy << 1)) : v_osd_start_960; 186 | end 187 | else begin 188 | multiscan <= 3; 189 | v_osd_start <= info ? (infoy<<2) : v_osd_start_other; 190 | end 191 | end 192 | 193 | osd_div <= osd_div + 1'd1; 194 | if(osd_div == multiscan) begin 195 | osd_div <= 0; 196 | if(~osd_vcnt[10]) osd_vcnt <= osd_vcnt + 1'd1; 197 | if(osd_vcnt == 'b100010011111 && ~info) osd_vcnt <= 0; 198 | end 199 | if(v_osd_start == v_cnt) {osd_div, osd_vcnt} <= OSD_HDR ? {~info, 3'b000, ~info, 7'b0000000} : 22'd0; 200 | end 201 | 202 | osd_byte <= osd_buffer[{osd_vcnt[7:3], osd_hcnt[7:0]}]; 203 | osd_pixel <= osd_byte[osd_vcnt[2:0]]; 204 | osd_de[2:1] <= osd_de[1:0]; 205 | end 206 | end 207 | 208 | reg [23:0] rdout; 209 | assign dout = rdout; 210 | 211 | reg [23:0] osd_rdout, normal_rdout; 212 | reg osd_mux; 213 | reg de_dly; 214 | 215 | always @(posedge clk_video) begin 216 | normal_rdout <= din; 217 | osd_rdout <= {{osd_pixel, osd_pixel, OSD_COLOR[2], din[23:19]},// 23:16 218 | {osd_pixel, osd_pixel, OSD_COLOR[1], din[15:11]},// 15:8 219 | {osd_pixel, osd_pixel, OSD_COLOR[0], din[7:3]}}; // 7:0 220 | osd_mux <= ~osd_de[2]; 221 | rdout <= osd_mux ? normal_rdout : osd_rdout; 222 | de_dly <= de_in; 223 | de_out <= de_dly; 224 | end 225 | 226 | endmodule 227 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/opl3/opl3fm.sv: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // 4 | // This file is part of the Next186 Soc PC project 5 | // http://opencores.org/project,next186 6 | // 7 | // Filename: opl3seq.v 8 | // Description: Part of the Next186 SoC PC project, OPL3 9 | // Version 1.0 10 | // Creation date: 13:55:57 02/27/2017 11 | // 12 | // Author: Nicolae Dumitrache 13 | // e-mail: ndumitrache@opencores.org 14 | // 15 | ///////////////////////////////////////////////////////////////////////////////// 16 | // 17 | // Copyright (C) 2017 Nicolae Dumitrache 18 | // 19 | // This source file may be used and distributed without 20 | // restriction provided that this copyright statement is not 21 | // removed from the file and that any derivative work contains 22 | // the original copyright notice and the associated disclaimer. 23 | // 24 | // This source file is free software; you can redistribute it 25 | // and/or modify it under the terms of the GNU Lesser General 26 | // Public License as published by the Free Software Foundation; 27 | // either version 2.1 of the License, or (at your option) any 28 | // later version. 29 | // 30 | // This source is distributed in the hope that it will be 31 | // useful, but WITHOUT ANY WARRANTY; without even the implied 32 | // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 33 | // PURPOSE. See the GNU Lesser General Public License for more 34 | // details. 35 | // 36 | // You should have received a copy of the GNU Lesser General 37 | // Public License along with this source; if not, download it 38 | // from http://www.opencores.org/lgpl.shtml 39 | // 40 | /////////////////////////////////////////////////////////////////////////////////// 41 | // Additional Comments: 42 | // 43 | // Port0 (R) = 4'b0000, Addr[1:0], qempty, ready 44 | // Port1 (R) = Value[7:0], advance queue 45 | // 46 | /////////////////////////////////////////////////////////////////////////////////// 47 | 48 | // 49 | // Improved reset stability and firmware portability by Sorgelig. 50 | // 51 | 52 | module opl3sw #(parameter OPLCLK = 50000000) 53 | ( 54 | input reset, 55 | 56 | // CPU interface 57 | input cpu_clk, 58 | input [1:0] addr, 59 | input [7:0] din, 60 | input wr, 61 | 62 | // OPL sequencer 63 | input clk, // 50Mhz (min 45Mhz) 64 | output [15:0] left, 65 | output [15:0] right 66 | ); 67 | 68 | wire [7:0] ram_dout; 69 | opl3_mem ram 70 | ( 71 | .clk(clk), 72 | .addr1(CPU_ADDR[12:0]), 73 | .we1(CPU_MREQ & CPU_WR & CE), 74 | .data_in1(CPU_DOUT), 75 | .data_out1(ram_dout), 76 | 77 | .addr2(OPL3Struct_base+seq_addr), 78 | .we2(seq_wr), 79 | .data_in2(seq_wdata), 80 | .data_out2(seq_rdata) 81 | ); 82 | 83 | wire [9:0] qdata; 84 | wire qempty; 85 | 86 | // show ahead fifo 87 | opl3_fifo in_queue 88 | ( 89 | .aclr(reset), 90 | 91 | .wrclk(cpu_clk), 92 | .data({addr, din}), 93 | .wrreq(wr), 94 | 95 | .rdclk(clk), 96 | .q(qdata), 97 | .rdreq(CE && CPU_IORQ && !CPU_WR && CPU_ADDR[0]), 98 | .rdempty(qempty) 99 | ); 100 | 101 | 102 | reg stb44100; 103 | always @(posedge clk) begin 104 | integer cnt; 105 | localparam RATE = (OPLCLK/44100)-1; 106 | 107 | cnt <= cnt+1; 108 | if(cnt == RATE) cnt <= 0; 109 | 110 | stb44100 <= !cnt; 111 | end 112 | 113 | wire seq_wr; 114 | wire [11:0] seq_addr; 115 | wire [15:0] seq_rdata; 116 | wire [15:0] seq_wdata; 117 | wire ready; 118 | 119 | reg [11:0] OPL3Struct_base = 0; 120 | reg seq_reset_n = 0; 121 | 122 | always @(posedge clk) begin 123 | if(reset) seq_reset_n <= 0; 124 | 125 | if(CPU_IORQ & CPU_WR & CE) begin 126 | if(CPU_ADDR[0]) {seq_reset_n, OPL3Struct_base[11:7]} <= {1'b1, CPU_DOUT[4:0]}; 127 | else OPL3Struct_base[6:0] <= CPU_DOUT[7:1]; 128 | end 129 | end 130 | 131 | opl3seq opl3seq 132 | ( 133 | .clk(clk), 134 | .reset(~seq_reset_n), 135 | .rd(stb44100), 136 | .A(A), 137 | .B(B), 138 | .ready(ready), 139 | .ram_wr(seq_wr), 140 | .ram_addr(seq_addr), 141 | .ram_rdata(seq_rdata), 142 | .ram_wdata(seq_wdata) 143 | ); 144 | 145 | wire [15:0] A,B; 146 | compressor compressor 147 | ( 148 | clk, 149 | stb44100, 150 | 151 | A[15:4], B[15:4], 152 | left, right 153 | ); 154 | 155 | wire [15:0] CPU_ADDR; 156 | wire [7:0] CPU_DOUT; 157 | wire CPU_WR; 158 | wire CPU_MREQ; 159 | wire CPU_IORQ; 160 | 161 | NextZ80 Z80 162 | ( 163 | .DI(~CPU_IORQ ? ram_dout : CPU_ADDR[0] ? qdata[7:0] : {4'b0000, qdata[9:8], qempty, ready}), 164 | .DO(CPU_DOUT), 165 | .ADDR(CPU_ADDR), 166 | .WR(CPU_WR), 167 | .MREQ(CPU_MREQ), 168 | .IORQ(CPU_IORQ), 169 | .HALT(), 170 | .M1(), 171 | .CLK(clk), 172 | .RESET(reset), 173 | .INT(0), 174 | .NMI(0), 175 | .WAIT(!CE) 176 | ); 177 | 178 | reg CE = 0; 179 | always @(posedge clk) CE <= !CE; 180 | 181 | endmodule 182 | 183 | module opl3_mem 184 | #( 185 | parameter 186 | DATA_WIDTH1 = 8, 187 | ADDRESS_WIDTH1 = 13, 188 | ADDRESS_WIDTH2 = 12, 189 | INIT_FILE = "opl3prg.mem" 190 | ) 191 | ( 192 | input clk, 193 | input we1, 194 | input [ADDRESS_WIDTH1-1:0] addr1, 195 | input [DATA_WIDTH1-1:0] data_in1, 196 | output reg [DATA_WIDTH1-1:0] data_out1, 197 | 198 | input we2, 199 | input [ADDRESS_WIDTH2-1:0] addr2, 200 | input [DATA_WIDTH2-1:0] data_in2, 201 | output reg [DATA_WIDTH2-1:0] data_out2 202 | ); 203 | 204 | localparam RATIO = 1 << (ADDRESS_WIDTH1 - ADDRESS_WIDTH2); 205 | localparam DATA_WIDTH2 = DATA_WIDTH1 * RATIO; 206 | localparam RAM_DEPTH = 1 << ADDRESS_WIDTH2; 207 | 208 | reg [RATIO-1:0] [DATA_WIDTH1-1:0] ram[0:RAM_DEPTH-1]; 209 | initial $readmemh(INIT_FILE, ram); 210 | 211 | // Port A 212 | always@(posedge clk) if(we1) ram[addr1 / RATIO][addr1 % RATIO] = data_in1; 213 | always@(posedge clk) data_out1 <= ram[addr1 / RATIO][addr1 % RATIO]; 214 | 215 | // port B 216 | always@(posedge clk) if(we2) ram[addr2] = data_in2; 217 | always@(posedge clk) data_out2 <= ram[addr2]; 218 | 219 | endmodule 220 | 221 | module opl3_fifo 222 | ( 223 | input aclr, 224 | input [9:0] data, 225 | input rdclk, 226 | input rdreq, 227 | input wrclk, 228 | input wrreq, 229 | output [9:0] q, 230 | output rdempty 231 | ); 232 | 233 | dcfifo dcfifo_component ( 234 | .aclr (aclr), 235 | .data (data), 236 | .rdclk (rdclk), 237 | .rdreq (rdreq), 238 | .wrclk (wrclk), 239 | .wrreq (wrreq), 240 | .q (q), 241 | .rdempty (rdempty), 242 | .eccstatus (), 243 | .rdfull (), 244 | .rdusedw (), 245 | .wrempty (), 246 | .wrfull (), 247 | .wrusedw ()); 248 | defparam 249 | dcfifo_component.intended_device_family = "Cyclone V", 250 | dcfifo_component.lpm_numwords = 1024, 251 | dcfifo_component.lpm_showahead = "ON", 252 | dcfifo_component.lpm_type = "dcfifo", 253 | dcfifo_component.lpm_width = 10, 254 | dcfifo_component.lpm_widthu = 10, 255 | dcfifo_component.overflow_checking = "ON", 256 | dcfifo_component.rdsync_delaypipe = 5, 257 | dcfifo_component.read_aclr_synch = "ON", 258 | dcfifo_component.underflow_checking = "ON", 259 | dcfifo_component.use_eab = "ON", 260 | dcfifo_component.write_aclr_synch = "ON", 261 | dcfifo_component.wrsync_delaypipe = 5; 262 | 263 | endmodule 264 | -------------------------------------------------------------------------------- /src/opl3/NextZ80Reg.v: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // This file is part of the NextZ80 project 4 | // http://www.opencores.org/cores/nextz80/ 5 | // 6 | // Filename: NextZ80Regs.v 7 | // Description: Implementation of Z80 compatible CPU - registers 8 | // Version 1.0 9 | // Creation date: 28Jan2011 - 18Mar2011 10 | // 11 | // Author: Nicolae Dumitrache 12 | // e-mail: ndumitrache@opencores.org 13 | // 14 | ///////////////////////////////////////////////////////////////////////////////// 15 | // 16 | // Copyright (C) 2011 Nicolae Dumitrache 17 | // 18 | // This source file may be used and distributed without 19 | // restriction provided that this copyright statement is not 20 | // removed from the file and that any derivative work contains 21 | // the original copyright notice and the associated disclaimer. 22 | // 23 | // This source file is free software; you can redistribute it 24 | // and/or modify it under the terms of the GNU Lesser General 25 | // Public License as published by the Free Software Foundation; 26 | // either version 2.1 of the License, or (at your option) any 27 | // later version. 28 | // 29 | // This source is distributed in the hope that it will be 30 | // useful, but WITHOUT ANY WARRANTY; without even the implied 31 | // warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 32 | // PURPOSE. See the GNU Lesser General Public License for more 33 | // details. 34 | // 35 | // You should have received a copy of the GNU Lesser General 36 | // Public License along with this source; if not, download it 37 | // from http://www.opencores.org/lgpl.shtml 38 | // 39 | /////////////////////////////////////////////////////////////////////////////////// 40 | 41 | // altera message_off 10027 42 | 43 | `timescale 1ns / 1ps 44 | 45 | module Z80Reg( 46 | input wire [7:0]rstatus, // 0=af-af', 1=exx, 2=hl-de, 3=hl'-de',4=hl-ixy, 5=ix-iy, 6=IFF1, 7=IFF2 47 | input wire M1, 48 | input wire [5:0]WE, // 5 = flags, 4 = PC, 3 = SP, 2 = tmpHI, 1 = hi, 0 = lo 49 | input wire CLK, 50 | input wire [15:0]ALU8OUT, // CPU data out bus (output of alu8) 51 | input wire [7:0]DI, // CPU data in bus 52 | output reg [7:0]DO, // CPU data out bus 53 | input wire [15:0]ADDR, // CPU addr bus 54 | input wire [7:0]CONST, 55 | output reg [7:0]ALU80, 56 | output reg [7:0]ALU81, 57 | output reg [15:0]ALU160, 58 | output wire[7:0]ALU161, 59 | input wire [7:0]ALU8FLAGS, 60 | output wire [7:0]FLAGS, 61 | 62 | input wire [1:0]DO_SEL, // select DO betwen ALU8OUT lo and th register 63 | input wire ALU160_sel, // 0=REG_RSEL, 1=PC 64 | input wire [3:0]REG_WSEL, // rdow: [3:1] 0=BC, 1=DE, 2=HL, 3=A-TL, 4=I-x ----- [0] = 0HI,1LO 65 | input wire [3:0]REG_RSEL, // mux_rdor: [3:1] 0=BC, 1=DE, 2=HL, 3=A-TL, 4=I-R, 5=SP, 7=tmpSP ----- [0] = 0HI, 1LO 66 | input wire DINW_SEL, // select RAM write data between (0)ALU8OUT, and 1(DI) 67 | input wire XMASK, // 0 if REG_WSEL should not use IX, IY, even if rstatus[4] == 1 68 | input wire [2:0]ALU16OP, // ALU16OP 69 | input wire WAIT // wait 70 | ); 71 | 72 | // latch registers 73 | reg [15:0]pc=0; // program counter 74 | reg [15:0]sp; // stack pointer 75 | reg [7:0]r; // refresh 76 | reg [15:0]flg = 0; 77 | reg [7:0]th; // temp high 78 | 79 | // internal wires 80 | wire [15:0]rdor; // R out from RAM 81 | wire [15:0]rdow; // W out from RAM 82 | wire [3:0]SELW; // RAM W port sel 83 | wire [3:0]SELR; // RAM R port sel 84 | reg [15:0]DIN; // RAM W in data 85 | reg [15:0]mux_rdor; // (3)A reversed mixed with TL, (4)I mixed with R (5)SP 86 | 87 | //------------------------------------ RAM block registers ---------------------------------- 88 | // 0:BC, 1:DE, 2:HL, 3:A-x, 4:I-x, 5:IX, 6:IY, 7:x-x, 8:BC', 9:DE', 10:HL', 11:A'-x, 12: tmpSP, 13:zero 89 | RAM16X8D_regs regs_lo ( 90 | .DPO(rdor[7:0]), // Read-only data output 91 | .SPO(rdow[7:0]), // R/W data output 92 | .A(SELW), // R/W address 93 | .D(DIN[7:0]), // Write data input 94 | .DPRA(SELR), // Read-only address 95 | .WCLK(CLK), // Write clock input 96 | .WE(WE[0] & !WAIT) // Write enable input 97 | ); 98 | 99 | RAM16X8D_regs regs_hi ( 100 | .DPO(rdor[15:8]), // Read-only data output 101 | .SPO(rdow[15:8]), // R/W data output 102 | .A(SELW), // R/W address 103 | .D(DIN[15:8]), // Write data input 104 | .DPRA(SELR), // Read-only address 105 | .WCLK(CLK), // Write clock input 106 | .WE(WE[1] & !WAIT) // Write enable input 107 | ); 108 | 109 | wire [15:0]ADDR1 = ADDR + !ALU16OP[2]; // address post increment 110 | wire [7:0]flgmux = {ALU8FLAGS[7:3], SELR[3:0] == 4'b0100 ? rstatus[7] : ALU8FLAGS[2], ALU8FLAGS[1:0]}; // LD A, I/R IFF2 flag on parity 111 | always @(posedge CLK) 112 | if(!WAIT) begin 113 | if(WE[2]) th <= DI; 114 | if(WE[3]) sp <= ADDR1; 115 | if(WE[4]) pc <= ADDR1; 116 | if({REG_WSEL, WE[0]} == 5'b10011) r <= ALU8OUT[7:0]; 117 | else if(M1) r[6:0] <= r[6:0] + 1'd1; 118 | if(WE[5]) 119 | if(rstatus[0]) flg[15:8] <= flgmux; 120 | else flg[7:0] <= flgmux; 121 | end 122 | 123 | assign ALU161 = th; 124 | assign FLAGS = rstatus[0] ? flg[15:8] : flg[7:0]; 125 | 126 | always @* begin 127 | DIN = DINW_SEL ? {DI, DI} : ALU8OUT; 128 | ALU80 = REG_WSEL[0] ? rdow[7:0] : rdow[15:8]; 129 | ALU81 = REG_RSEL[0] ? mux_rdor[7:0] : mux_rdor[15:8]; 130 | ALU160 = ALU160_sel ? pc : mux_rdor; 131 | 132 | case({REG_WSEL[3], DO_SEL}) 133 | 0: DO = ALU80; 134 | 1: DO = th; 135 | 2: DO = FLAGS; 136 | 3: DO = ALU8OUT[7:0]; 137 | 4: DO = pc[15:8]; 138 | 5: DO = pc[7:0]; 139 | 6: DO = sp[15:8]; 140 | 7: DO = sp[7:0]; 141 | endcase 142 | case({ALU16OP == 4, REG_RSEL[3:0]}) 143 | 5'b01001, 5'b11001: mux_rdor = {rdor[15:8], r}; 144 | 5'b01010, 5'b01011: mux_rdor = sp; 145 | 5'b01100, 5'b01101, 5'b11100, 5'b11101: mux_rdor = {8'b0, CONST}; 146 | default: mux_rdor = rdor; 147 | endcase 148 | end 149 | 150 | RegSelect WSelectW(.SEL(REG_WSEL[3:1]), .RAMSEL(SELW), .rstatus({rstatus[5], rstatus[4] & XMASK, rstatus[3:0]})); 151 | RegSelect WSelectR(.SEL(REG_RSEL[3:1]), .RAMSEL(SELR), .rstatus(rstatus[5:0])); 152 | 153 | endmodule 154 | 155 | 156 | module RegSelect( 157 | input [2:0]SEL, 158 | output reg [3:0]RAMSEL, 159 | input [5:0]rstatus // 0=af-af', 1=exx, 2=hl-de, 3=hl'-de',4=hl-ixy, 5=ix-iy 160 | ); 161 | 162 | always @* begin 163 | RAMSEL = 4'bxxxx; 164 | case(SEL) 165 | 0: RAMSEL = {rstatus[1], 3'b000}; // BC 166 | 1: //DE 167 | if(rstatus[{1'b1, rstatus[1]}]) RAMSEL = {rstatus[1], 3'b010}; // HL 168 | else RAMSEL = {rstatus[1], 3'b001}; // DE 169 | 2: // HL 170 | case({rstatus[5:4], rstatus[{1'b1, rstatus[1]}]}) 171 | 0,4: RAMSEL = {rstatus[1], 3'b010}; // HL 172 | 1,5: RAMSEL = {rstatus[1], 3'b001}; // DE 173 | 2,3: RAMSEL = 4'b0101; // IX 174 | 6,7: RAMSEL = 4'b0110; // IY 175 | endcase 176 | 3: RAMSEL = {rstatus[0], 3'b011}; // A-TL 177 | 4: RAMSEL = 4; // I-R 178 | 5: RAMSEL = 12; // tmp SP 179 | 6: RAMSEL = 13; // zero 180 | 7: RAMSEL = 7; // temp reg for BIT/SET/RES 181 | endcase 182 | end 183 | endmodule 184 | 185 | module RAM16X8D_regs( 186 | output [7:0]DPO, // Read-only data output 187 | output [7:0]SPO, // R/W data output 188 | input [3:0]A, // R/W address 189 | input [7:0]D, // Write data input 190 | input [3:0]DPRA, // Read-only address 191 | input WCLK, // Write clock 192 | input WE // Write enable 193 | ); 194 | 195 | reg [7:0]data[15:0]; 196 | assign DPO = data[DPRA]; 197 | assign SPO = data[A]; 198 | 199 | always @(posedge WCLK) 200 | if(WE) data[A] <= D; 201 | 202 | endmodule 203 | -------------------------------------------------------------------------------- /src/sound.vhd: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2019 Josh Bassett 2 | -- 3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 4 | -- of this software and associated documentation files (the "Software"), to deal 5 | -- in the Software without restriction, including without limitation the rights 6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | -- copies of the Software, and to permit persons to whom the Software is 8 | -- furnished to do so, subject to the following conditions: 9 | -- 10 | -- The above copyright notice and this permission notice shall be included in all 11 | -- copies or substantial portions of the Software. 12 | -- 13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | -- SOFTWARE. 20 | 21 | library ieee; 22 | use ieee.std_logic_1164.all; 23 | use ieee.numeric_std.all; 24 | 25 | use work.common.all; 26 | 27 | entity sound is 28 | port ( 29 | reset : in std_logic; 30 | 31 | -- clock signals 32 | clk : in std_logic; 33 | cen_4 : in std_logic; 34 | cen_384 : in std_logic; 35 | 36 | -- CPU interface 37 | req : in std_logic; 38 | data : in byte_t; 39 | 40 | -- audio data 41 | audio : out audio_t 42 | ); 43 | end entity sound; 44 | 45 | architecture arch of sound is 46 | -- CPU signals 47 | signal cpu_addr : unsigned(CPU_ADDR_WIDTH-1 downto 0); 48 | signal cpu_din : byte_t; 49 | signal cpu_dout : byte_t; 50 | signal cpu_mreq_n : std_logic; 51 | signal cpu_rd_n : std_logic; 52 | signal cpu_wr_n : std_logic; 53 | signal cpu_rfsh_n : std_logic; 54 | signal cpu_nmi_n : std_logic := '1'; 55 | signal cpu_int_n : std_logic := '1'; 56 | 57 | -- chip select signals 58 | signal sound_rom_1_cs : std_logic; 59 | signal sound_ram_cs : std_logic; 60 | signal req_cs : std_logic; 61 | signal req_off_cs : std_logic; 62 | 63 | -- data signals 64 | signal sound_rom_1_data : byte_t; 65 | signal sound_rom_2_data : byte_t; 66 | signal sound_ram_data : byte_t; 67 | signal req_data : byte_t; 68 | 69 | -- registers 70 | signal data_reg : byte_t; 71 | 72 | -- FM signals 73 | signal fm_cs : std_logic; 74 | signal fm_data : byte_t; 75 | signal fm_sample : audio_t; 76 | 77 | -- PCM signals 78 | signal pcm_low_cs : std_logic; 79 | signal pcm_high_cs : std_logic; 80 | signal pcm_vol_cs : std_logic; 81 | signal pcm_addr : unsigned(SOUND_ROM_2_ADDR_WIDTH-1 downto 0); 82 | signal pcm_nibble : std_logic; 83 | signal pcm_done : std_logic; 84 | signal pcm_vck : std_logic; 85 | signal pcm_data : nibble_t; 86 | signal pcm_sample : signed(11 downto 0); 87 | begin 88 | cpu : entity work.T80s 89 | port map ( 90 | RESET_n => not reset, 91 | CLK => clk, 92 | CEN => cen_4, 93 | INT_n => cpu_int_n, 94 | NMI_n => cpu_nmi_n, 95 | MREQ_n => cpu_mreq_n, 96 | IORQ_n => open, 97 | RD_n => cpu_rd_n, 98 | WR_n => cpu_wr_n, 99 | RFSH_n => cpu_rfsh_n, 100 | HALT_n => open, 101 | BUSAK_n => open, 102 | std_logic_vector(A) => cpu_addr, 103 | DI => cpu_din, 104 | DO => cpu_dout 105 | ); 106 | 107 | -- contains sound program data 108 | sound_rom_1 : entity work.single_port_rom 109 | generic map ( 110 | ADDR_WIDTH => SOUND_ROM_1_ADDR_WIDTH, 111 | INIT_FILE => "rom/cpu_4h.mif" 112 | ) 113 | port map ( 114 | clk => clk, 115 | cs => sound_rom_1_cs, 116 | addr => cpu_addr(SOUND_ROM_1_ADDR_WIDTH-1 downto 0), 117 | dout => sound_rom_1_data 118 | ); 119 | 120 | -- contains PCM data 121 | sound_rom_2 : entity work.single_port_rom 122 | generic map ( 123 | ADDR_WIDTH => SOUND_ROM_2_ADDR_WIDTH, 124 | INIT_FILE => "rom/cpu_1f.mif" 125 | ) 126 | port map ( 127 | clk => clk, 128 | addr => pcm_addr, 129 | dout => sound_rom_2_data 130 | ); 131 | 132 | sound_ram : entity work.single_port_ram 133 | generic map (ADDR_WIDTH => SOUND_RAM_ADDR_WIDTH) 134 | port map ( 135 | clk => clk, 136 | cs => sound_ram_cs, 137 | addr => cpu_addr(SOUND_RAM_ADDR_WIDTH-1 downto 0), 138 | din => cpu_dout, 139 | dout => sound_ram_data, 140 | we => not cpu_wr_n 141 | ); 142 | 143 | opl : entity work.opl 144 | port map ( 145 | reset => reset, 146 | clk => clk, 147 | irq_n => cpu_int_n, 148 | cs => fm_cs, 149 | addr => ('0' & cpu_addr(0)), 150 | din => cpu_dout, 151 | dout => fm_data, 152 | we => not cpu_wr_n, 153 | sample => fm_sample 154 | ); 155 | 156 | pcm_counter : entity work.pcm_counter 157 | generic map (ADDR_WIDTH => SOUND_ROM_2_ADDR_WIDTH) 158 | port map ( 159 | reset => reset, 160 | clk => clk, 161 | vck => pcm_vck, 162 | data => cpu_dout, 163 | we => not cpu_wr_n, 164 | set_low => pcm_low_cs, 165 | set_high => pcm_high_cs, 166 | addr => pcm_addr, 167 | nibble => pcm_nibble, 168 | done => pcm_done 169 | ); 170 | 171 | msm5205 : entity work.msm5205 172 | generic map (SAMPLE_FREQ => "10") 173 | port map ( 174 | reset => pcm_done, 175 | clk => clk, 176 | cen => cen_384, 177 | vck => pcm_vck, 178 | din => pcm_data, 179 | sample => pcm_sample 180 | ); 181 | 182 | nmi : process (clk, reset) 183 | begin 184 | if reset = '1' then 185 | cpu_nmi_n <= '1'; 186 | elsif rising_edge(clk) then 187 | if req_off_cs = '1' and cpu_wr_n = '0' then 188 | -- clear NMI 189 | cpu_nmi_n <= '1'; 190 | elsif req = '1' then 191 | -- set NMI 192 | cpu_nmi_n <= '0'; 193 | 194 | -- latch data 195 | data_reg <= data; 196 | end if; 197 | end if; 198 | end process; 199 | 200 | -- address description 201 | -- ----------+----------------- 202 | -- 0000-3fff | sound ROM #1 203 | -- 4000-7fff | sound RAM 204 | -- 8000-bfff | FM 205 | -- c000-ffff | request 206 | -- c000-cfff | PCM low 207 | -- d000-dfff | PCM high 208 | -- e000-efff | PCM volume 209 | -- f000-ffff | request off 210 | sound_rom_1_cs <= '1' when cpu_addr >= x"0000" and cpu_addr <= x"3fff" and cpu_mreq_n = '0' and cpu_rfsh_n = '1' else '0'; 211 | sound_ram_cs <= '1' when cpu_addr >= x"4000" and cpu_addr <= x"7fff" and cpu_mreq_n = '0' and cpu_rfsh_n = '1' else '0'; 212 | fm_cs <= '1' when cpu_addr >= x"8000" and cpu_addr <= x"bfff" and cpu_mreq_n = '0' and cpu_rfsh_n = '1' else '0'; 213 | req_cs <= '1' when cpu_addr >= x"c000" and cpu_addr <= x"ffff" and cpu_mreq_n = '0' and cpu_rfsh_n = '1' else '0'; 214 | pcm_low_cs <= '1' when cpu_addr >= x"c000" and cpu_addr <= x"cfff" and cpu_mreq_n = '0' and cpu_rfsh_n = '1' else '0'; 215 | pcm_high_cs <= '1' when cpu_addr >= x"d000" and cpu_addr <= x"dfff" and cpu_mreq_n = '0' and cpu_rfsh_n = '1' else '0'; 216 | pcm_vol_cs <= '1' when cpu_addr >= x"e000" and cpu_addr <= x"efff" and cpu_mreq_n = '0' and cpu_rfsh_n = '1' else '0'; 217 | req_off_cs <= '1' when cpu_addr >= x"f000" and cpu_addr <= x"ffff" and cpu_mreq_n = '0' and cpu_rfsh_n = '1' else '0'; 218 | 219 | -- set request data 220 | req_data <= data_reg when req_cs = '1' and cpu_rd_n = '0' else (others => '0'); 221 | 222 | -- mux CPU data input 223 | cpu_din <= sound_rom_1_data or 224 | sound_ram_data or 225 | fm_data or 226 | req_data; 227 | 228 | -- set the input data for the MSM5205 229 | pcm_data <= sound_rom_2_data(7 downto 4) when pcm_nibble = '1' else 230 | sound_rom_2_data(3 downto 0); 231 | 232 | -- mix FM and PCM samples 233 | audio <= fm_sample + (pcm_sample & "000"); 234 | end architecture arch; 235 | -------------------------------------------------------------------------------- /sys/hdmi_config.sv: -------------------------------------------------------------------------------- 1 | 2 | module hdmi_config 3 | ( 4 | // Host Side 5 | input iCLK, 6 | input iRST_N, 7 | 8 | input dvi_mode, 9 | input audio_96k, 10 | input [1:0] limited, 11 | input ypbpr, 12 | 13 | output reg done, 14 | 15 | // I2C Side 16 | output I2C_SCL, 17 | inout I2C_SDA 18 | ); 19 | 20 | // Internal Registers/Wires 21 | reg mI2C_GO = 0; 22 | wire mI2C_END; 23 | wire mI2C_ACK; 24 | reg [15:0] LUT_DATA; 25 | reg [7:0] LUT_INDEX = 0; 26 | 27 | i2c #(50_000_000, 20_000) i2c_av 28 | ( 29 | .CLK(iCLK), 30 | 31 | .I2C_SCL(I2C_SCL), // I2C CLOCK 32 | .I2C_SDA(I2C_SDA), // I2C DATA 33 | 34 | .I2C_DATA({8'h72,init_data[LUT_INDEX]}), // DATA:[SLAVE_ADDR,SUB_ADDR,DATA]. 0x72 is the Slave Address of the ADV7513 chip! 35 | .START(mI2C_GO), // START transfer 36 | .END(mI2C_END), // END transfer 37 | .ACK(mI2C_ACK) // ACK 38 | ); 39 | 40 | ////////////////////// Config Control //////////////////////////// 41 | always@(posedge iCLK or negedge iRST_N) begin 42 | reg [1:0] mSetup_ST = 0; 43 | 44 | if(!iRST_N) begin 45 | LUT_INDEX <= 0; 46 | mSetup_ST <= 0; 47 | mI2C_GO <= 0; 48 | done <= 0; 49 | end else begin 50 | if(init_data[LUT_INDEX] != 16'hFFFF) begin 51 | case(mSetup_ST) 52 | 0: begin 53 | mI2C_GO <= 1; 54 | mSetup_ST <= 1; 55 | end 56 | 1: if(~mI2C_END) mSetup_ST <= 2; 57 | 2: begin 58 | mI2C_GO <= 0; 59 | if(mI2C_END) begin 60 | mSetup_ST <= 0; 61 | if(!mI2C_ACK) LUT_INDEX <= LUT_INDEX + 8'd1; 62 | end 63 | end 64 | endcase 65 | end 66 | else done <= 1; 67 | end 68 | end 69 | 70 | //////////////////////////////////////////////////////////////////// 71 | ///////////////////// Config Data LUT ////////////////////////// 72 | 73 | wire [15:0] init_data[82] = 74 | '{ 75 | 16'h9803, // ADI required Write. 76 | 77 | {8'hD6, 8'b1100_0000}, // [7:6] HPD Control... 78 | // 00 = HPD is from both HPD pin or CDC HPD 79 | // 01 = HPD is from CDC HPD 80 | // 10 = HPD is from HPD pin 81 | // 11 = HPD is always high 82 | 83 | 16'h4110, // Power Down control 84 | 16'h9A70, // ADI required Write. 85 | 16'h9C30, // ADI required Write. 86 | {8'h9D, 8'b0110_0001}, // [7:4] must be b0110!. 87 | // [3:2] b00 = Input clock not divided. b01 = Clk divided by 2. b10 = Clk divided by 4. b11 = invalid! 88 | // [1:0] must be b01! 89 | 16'hA2A4, // ADI required Write. 90 | 16'hA3A4, // ADI required Write. 91 | 16'hE0D0, // ADI required Write. 92 | 93 | 94 | 16'h35_40, 95 | 16'h36_D9, 96 | 16'h37_0A, 97 | 16'h38_00, 98 | 16'h39_2D, 99 | 16'h3A_00, 100 | 101 | {8'h16, 8'b0011_1000}, // Output Format 444 [7]=0. 102 | // [6] must be 0! 103 | // Colour Depth for Input Video data [5:4] b11 = 8-bit. 104 | // Input Style [3:2] b10 = Style 1 (ignored when using 444 input). 105 | // DDR Input Edge falling [1]=0 (not using DDR atm). 106 | // Output Colour Space RGB [0]=0. 107 | 108 | {8'h17, 8'b01100010}, // Aspect ratio 16:9 [1]=1, 4:3 [1]=0 109 | 110 | {8'h18, ypbpr ? 8'h88 : limited[0] ? 8'h8D : limited[1] ? 8'h8E : 8'h00}, // CSC Scaling Factors and Coefficients for RGB Full->Limited. 111 | {8'h19, ypbpr ? 8'h2E : limited[0] ? 8'hBC : 8'hFE}, // Taken from table in ADV7513 Programming Guide. 112 | {8'h1A, ypbpr ? 8'h18 : 8'h00}, // CSC Channel A. 113 | {8'h1B, ypbpr ? 8'h93 : 8'h00}, 114 | {8'h1C, ypbpr ? 8'h1F : 8'h00}, 115 | {8'h1D, ypbpr ? 8'h3F : 8'h00}, 116 | {8'h1E, ypbpr ? 8'h08 : 8'h01}, 117 | {8'h1F, 8'h00}, 118 | 119 | {8'h20, ypbpr ? 8'h03 : 8'h00}, // CSC Channel B. 120 | {8'h21, ypbpr ? 8'h67 : 8'h00}, 121 | {8'h22, ypbpr ? 8'h0B : limited[0] ? 8'h0D : 8'h0E}, 122 | {8'h23, ypbpr ? 8'h71 : limited[0] ? 8'hBC : 8'hFE}, 123 | {8'h24, ypbpr ? 8'h01 : 8'h00}, 124 | {8'h25, ypbpr ? 8'h28 : 8'h00}, 125 | {8'h26, ypbpr ? 8'h00 : 8'h01}, 126 | {8'h27, 8'h00}, 127 | 128 | {8'h28, ypbpr ? 8'h1E : 8'h00}, // CSC Channel C. 129 | {8'h29, ypbpr ? 8'h21 : 8'h00}, 130 | {8'h2A, ypbpr ? 8'h19 : 8'h00}, 131 | {8'h2B, ypbpr ? 8'hB2 : 8'h00}, 132 | {8'h2C, ypbpr ? 8'h08 : limited[0] ? 8'h0D : 8'h0E}, 133 | {8'h2D, ypbpr ? 8'h2D : limited[0] ? 8'hBC : 8'hFE}, 134 | {8'h2E, ypbpr ? 8'h08 : 8'h01}, 135 | {8'h2F, 8'h00}, 136 | 137 | {8'h3B, 8'b0000_0000}, // Pixel repetition [6:5] b00 AUTO. [4:3] b00 x1 mult of input clock. [2:1] b00 x1 pixel rep to send to HDMI Rx. 138 | 139 | 16'h4000, // General Control Packet Enable 140 | 141 | {8'h48, 8'b0000_1000}, // [6]=0 Normal bus order! 142 | // [5] DDR Alignment. 143 | // [4:3] b01 Data right justified (for YCbCr 422 input modes). 144 | 145 | 16'h49A8, // ADI required Write. 146 | 16'h4C00, // ADI required Write. 147 | 148 | {8'h55, 8'b0001_0000}, // [7] must be 0!. Set RGB444 in AVinfo Frame [6:5], Set active format [4]. 149 | // AVI InfoFrame Valid [4]. 150 | // Bar Info [3:2] b00 Bars invalid. b01 Bars vertical. b10 Bars horizontal. b11 Bars both. 151 | // Scan Info [1:0] b00 (No data). b01 TV. b10 PC. b11 None. 152 | 153 | {8'h57, 1'b0, // [7] IT Content. 0 - No. 1 - Yes (type set in register h59). 154 | 3'b000, // [6:4] Color space (ignored for RGB) 155 | (ypbpr | limited) ? 2'b01 : 2'b10, // [3:2] RGB Quantization range 156 | 2'b00}, // [1:0] Non-Uniform Scaled: 00 - None. 01 - Horiz. 10 - Vert. 11 - Both. 157 | 158 | 16'h7301, 159 | 160 | {8'h94, 8'b1000_0000}, // [7]=1 HPD Interrupt ENabled. 161 | 162 | 16'h9902, // ADI required Write. 163 | 16'h9B18, // ADI required Write. 164 | 165 | 16'h9F00, // ADI required Write. 166 | 167 | {8'hA1, 8'b0000_0000}, // [6]=1 Monitor Sense Power Down DISabled. 168 | 169 | 16'hA408, // ADI required Write. 170 | 16'hA504, // ADI required Write. 171 | 16'hA600, // ADI required Write. 172 | 16'hA700, // ADI required Write. 173 | 16'hA800, // ADI required Write. 174 | 16'hA900, // ADI required Write. 175 | 16'hAA00, // ADI required Write. 176 | 16'hAB40, // ADI required Write. 177 | 178 | {8'hAF, 6'b0000_01,~dvi_mode,1'b0}, // [7]=0 HDCP Disabled. 179 | // [6:5] must be b00! 180 | // [4]=0 Current frame is unencrypted 181 | // [3:2] must be b01! 182 | // [1]=1 HDMI Mode. 183 | // [0] must be b0! 184 | 185 | 16'hB900, // ADI required Write. 186 | 187 | {8'hBA, 8'b0110_0000}, // [7:5] Input Clock delay... 188 | // b000 = -1.2ns. 189 | // b001 = -0.8ns. 190 | // b010 = -0.4ns. 191 | // b011 = No delay. 192 | // b100 = 0.4ns. 193 | // b101 = 0.8ns. 194 | // b110 = 1.2ns. 195 | // b111 = 1.6ns. 196 | 197 | 16'hBB00, // ADI required Write. 198 | 199 | 16'hDE9C, // ADI required Write. 200 | 16'hE460, // ADI required Write. 201 | 16'hFA7D, // Nbr of times to search for good phase 202 | 203 | 204 | // (Audio stuff on Programming Guide, Page 66)... 205 | 206 | {8'h0A, 8'b0000_0000}, // [6:4] Audio Select. b000 = I2S. 207 | // [3:2] Audio Mode. (HBR stuff, leave at 00!). 208 | 209 | {8'h0B, 8'b0000_1110}, // 210 | 211 | {8'h0C, 8'b0000_0100}, // [7] 0 = Use sampling rate from I2S stream. 1 = Use samp rate from I2C Register. 212 | // [6] 0 = Use Channel Status bits from stream. 1 = Use Channel Status bits from I2C register. 213 | // [2] 1 = I2S0 Enable. 214 | // [1:0] I2S Format: 00 = Standard. 01 = Right Justified. 10 = Left Justified. 11 = AES. 215 | 216 | {8'h0D, 8'b0001_0000}, // [4:0] I2S Bit (Word) Width for Right-Justified. 217 | {8'h14, 8'b0000_0010}, // [3:0] Audio Word Length. b0010 = 16 bits. 218 | {8'h15, audio_96k, 7'b010_0000}, // I2S Sampling Rate [7:4]. b0000 = (44.1KHz). b0010 = 48KHz. 219 | // Input ID [3:1] b000 (0) = 24-bit RGB 444 or YCrCb 444 with Separate Syncs. 220 | 221 | // Audio Clock Config 222 | 16'h0100, // 223 | audio_96k ? 16'h0230 : 16'h0218, // Set N Value 12288/6144 224 | 16'h0300, // 225 | 226 | 16'h0701, // 227 | 16'h0822, // Set CTS Value 74250 228 | 16'h090A, // 229 | 230 | 16'hFFFF // END 231 | }; 232 | 233 | //////////////////////////////////////////////////////////////////// 234 | 235 | endmodule -------------------------------------------------------------------------------- /src/t80/T80s.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- Z80 compatible microprocessor core, synchronous top level 3 | -- Different timing than the original z80 4 | -- Inputs needs to be synchronous and outputs may glitch 5 | -- 6 | -- Version : 0242 7 | -- 8 | -- Copyright (c) 2001-2002 Daniel Wallner (jesus@opencores.org) 9 | -- 10 | -- All rights reserved 11 | -- 12 | -- Redistribution and use in source and synthezised forms, with or without 13 | -- modification, are permitted provided that the following conditions are met: 14 | -- 15 | -- Redistributions of source code must retain the above copyright notice, 16 | -- this list of conditions and the following disclaimer. 17 | -- 18 | -- Redistributions in synthesized form must reproduce the above copyright 19 | -- notice, this list of conditions and the following disclaimer in the 20 | -- documentation and/or other materials provided with the distribution. 21 | -- 22 | -- Neither the name of the author nor the names of other contributors may 23 | -- be used to endorse or promote products derived from this software without 24 | -- specific prior written permission. 25 | -- 26 | -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 28 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 | -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 30 | -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 | -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 | -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 | -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 | -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 | -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 | -- POSSIBILITY OF SUCH DAMAGE. 37 | -- 38 | -- Please report bugs to the author, but before you do so, please 39 | -- make sure that this is not a derivative work and that 40 | -- you have the latest version of this file. 41 | -- 42 | -- The latest version of this file can be found at: 43 | -- http://www.opencores.org/cvsweb.shtml/t80/ 44 | -- 45 | -- Limitations : 46 | -- 47 | -- File history : 48 | -- 49 | -- 0208 : First complete release 50 | -- 51 | -- 0210 : Fixed read with wait 52 | -- 53 | -- 0211 : Fixed interrupt cycle 54 | -- 55 | -- 0235 : Updated for T80 interface change 56 | -- 57 | -- 0236 : Added T2Write generic 58 | -- 59 | -- 0237 : Fixed T2Write with wait state 60 | -- 61 | -- 0238 : Updated for T80 interface change 62 | -- 63 | -- 0240 : Updated for T80 interface change 64 | -- 65 | -- 0242 : Updated for T80 interface change 66 | -- 67 | 68 | library IEEE; 69 | use IEEE.std_logic_1164.all; 70 | use IEEE.numeric_std.all; 71 | use IEEE.STD_LOGIC_UNSIGNED.all; 72 | 73 | entity T80s is 74 | generic( 75 | Mode : integer := 0; -- 0 => Z80, 1 => Fast Z80, 2 => 8080, 3 => GB 76 | T2Write : integer := 1; -- 0 => WR_n active in T3, /=0 => WR_n active in T2 77 | IOWait : integer := 1 -- 0 => Single cycle I/O, 1 => Std I/O cycle 78 | ); 79 | port( 80 | RESET_n : in std_logic; 81 | CLK : in std_logic; 82 | CEN : in std_logic := '1'; 83 | WAIT_n : in std_logic := '1'; 84 | INT_n : in std_logic := '1'; 85 | NMI_n : in std_logic := '1'; 86 | BUSRQ_n : in std_logic := '1'; 87 | M1_n : out std_logic; 88 | MREQ_n : out std_logic; 89 | IORQ_n : out std_logic; 90 | RD_n : out std_logic; 91 | WR_n : out std_logic; 92 | RFSH_n : out std_logic; 93 | HALT_n : out std_logic; 94 | BUSAK_n : out std_logic; 95 | OUT0 : in std_logic := '0'; -- 0 => OUT(C),0, 1 => OUT(C),255 96 | A : out std_logic_vector(15 downto 0); 97 | DI : in std_logic_vector(7 downto 0); 98 | DO : out std_logic_vector(7 downto 0) 99 | ); 100 | end T80s; 101 | 102 | architecture rtl of T80s is 103 | component T80 104 | generic( 105 | Mode : integer := 0; -- 0 => Z80, 1 => Fast Z80, 2 => 8080, 3 => GB 106 | IOWait : integer := 0; -- 0 => Single cycle I/O, 1 => Std I/O cycle 107 | Flag_C : integer := 0; 108 | Flag_N : integer := 1; 109 | Flag_P : integer := 2; 110 | Flag_X : integer := 3; 111 | Flag_H : integer := 4; 112 | Flag_Y : integer := 5; 113 | Flag_Z : integer := 6; 114 | Flag_S : integer := 7 115 | ); 116 | port( 117 | RESET_n : in std_logic; 118 | CLK_n : in std_logic; 119 | CEN : in std_logic; 120 | WAIT_n : in std_logic; 121 | INT_n : in std_logic; 122 | NMI_n : in std_logic; 123 | BUSRQ_n : in std_logic; 124 | M1_n : out std_logic; 125 | IORQ : out std_logic; 126 | NoRead : out std_logic; 127 | Write : out std_logic; 128 | RFSH_n : out std_logic; 129 | HALT_n : out std_logic; 130 | BUSAK_n : out std_logic; 131 | A : out std_logic_vector(15 downto 0); 132 | DInst : in std_logic_vector(7 downto 0); 133 | DI : in std_logic_vector(7 downto 0); 134 | DO : out std_logic_vector(7 downto 0); 135 | MC : out std_logic_vector(2 downto 0); 136 | TS : out std_logic_vector(2 downto 0); 137 | IntCycle_n : out std_logic; 138 | IntE : out std_logic; 139 | Stop : out std_logic; 140 | out0 : in std_logic := '0'; -- 0 => OUT(C),0, 1 => OUT(C),255 141 | REG : out std_logic_vector(211 downto 0); -- IFF2, IFF1, IM, IY, HL', DE', BC', IX, HL, DE, BC, PC, SP, R, I, F', A', F, A 142 | 143 | DIRSet : in std_logic := '0'; 144 | DIR : in std_logic_vector(211 downto 0) := (others => '0') -- IFF2, IFF1, IM, IY, HL', DE', BC', IX, HL, DE, BC, PC, SP, R, I, F', A', F, A 145 | ); 146 | end component; 147 | 148 | signal IntCycle_n : std_logic; 149 | signal NoRead : std_logic; 150 | signal Write : std_logic; 151 | signal IORQ : std_logic; 152 | signal DI_Reg : std_logic_vector(7 downto 0); 153 | signal MCycle : std_logic_vector(2 downto 0); 154 | signal TState : std_logic_vector(2 downto 0); 155 | 156 | begin 157 | 158 | u0 : T80 159 | generic map( 160 | Mode => Mode, 161 | IOWait => IOWait) 162 | port map( 163 | CEN => CEN, 164 | M1_n => M1_n, 165 | IORQ => IORQ, 166 | NoRead => NoRead, 167 | Write => Write, 168 | RFSH_n => RFSH_n, 169 | HALT_n => HALT_n, 170 | WAIT_n => Wait_n, 171 | INT_n => INT_n, 172 | NMI_n => NMI_n, 173 | RESET_n => RESET_n, 174 | BUSRQ_n => BUSRQ_n, 175 | BUSAK_n => BUSAK_n, 176 | CLK_n => CLK, 177 | A => A, 178 | DInst => DI, 179 | DI => DI_Reg, 180 | DO => DO, 181 | MC => MCycle, 182 | TS => TState, 183 | OUT0 => OUT0, 184 | IntCycle_n => IntCycle_n 185 | ); 186 | 187 | process (RESET_n, CLK) 188 | begin 189 | if RESET_n = '0' then 190 | RD_n <= '1'; 191 | WR_n <= '1'; 192 | IORQ_n <= '1'; 193 | MREQ_n <= '1'; 194 | DI_Reg <= "00000000"; 195 | elsif rising_edge(CLK) then 196 | if CEN = '1' then 197 | RD_n <= '1'; 198 | WR_n <= '1'; 199 | IORQ_n <= '1'; 200 | MREQ_n <= '1'; 201 | if MCycle = 1 then 202 | if TState = 1 or (TState = 2 and Wait_n = '0') then 203 | RD_n <= not IntCycle_n; 204 | MREQ_n <= not IntCycle_n; 205 | IORQ_n <= IntCycle_n; 206 | end if; 207 | if TState = 3 then 208 | MREQ_n <= '0'; 209 | end if; 210 | else 211 | if (TState = 1 or (TState = 2 and Wait_n = '0')) and NoRead = '0' and Write = '0' then 212 | RD_n <= '0'; 213 | IORQ_n <= not IORQ; 214 | MREQ_n <= IORQ; 215 | end if; 216 | if T2Write = 0 then 217 | if TState = 2 and Write = '1' then 218 | WR_n <= '0'; 219 | IORQ_n <= not IORQ; 220 | MREQ_n <= IORQ; 221 | end if; 222 | else 223 | if (TState = 1 or (TState = 2 and Wait_n = '0')) and Write = '1' then 224 | WR_n <= '0'; 225 | IORQ_n <= not IORQ; 226 | MREQ_n <= IORQ; 227 | end if; 228 | end if; 229 | end if; 230 | if TState = 2 and Wait_n = '1' then 231 | DI_Reg <= DI; 232 | end if; 233 | end if; 234 | end if; 235 | end process; 236 | end; 237 | -------------------------------------------------------------------------------- /src/gpu/sprite_blitter.vhd: -------------------------------------------------------------------------------- 1 | -- Copyright (c) 2019 Josh Bassett 2 | -- 3 | -- Permission is hereby granted, free of charge, to any person obtaining a copy 4 | -- of this software and associated documentation files (the "Software"), to deal 5 | -- in the Software without restriction, including without limitation the rights 6 | -- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | -- copies of the Software, and to permit persons to whom the Software is 8 | -- furnished to do so, subject to the following conditions: 9 | -- 10 | -- The above copyright notice and this permission notice shall be included in all 11 | -- copies or substantial portions of the Software. 12 | -- 13 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | -- SOFTWARE. 20 | 21 | library ieee; 22 | use ieee.std_logic_1164.all; 23 | use ieee.numeric_std.all; 24 | 25 | use work.common.all; 26 | 27 | -- The sprite blitter copies sprite data from the tile ROM to the frame buffer. 28 | -- 29 | -- A blit operation is requested by setting the sprite descriptor and asserting 30 | -- the start signal. Once all the pixels have been copied to the frame buffer, 31 | -- the ready signal is again asserted by the blitter. 32 | entity sprite_blitter is 33 | port ( 34 | -- clock 35 | clk : in std_logic; 36 | cen_6 : in std_logic; 37 | 38 | -- sprite descriptor 39 | sprite : in sprite_t; 40 | 41 | -- The ready signal is asserted when the blitter is ready to execute a blit 42 | -- operation. 43 | ready : out std_logic; 44 | 45 | -- A blit operation is requested when the start signal is asserted. 46 | start : in std_logic; 47 | 48 | -- sprite ROM 49 | rom_addr : out unsigned(SPRITE_ROM_ADDR_WIDTH-1 downto 0); 50 | rom_data : in std_logic_vector(SPRITE_ROM_DATA_WIDTH-1 downto 0); 51 | 52 | -- frame buffer 53 | frame_buffer_addr : out unsigned(FRAME_BUFFER_ADDR_WIDTH-1 downto 0); 54 | frame_buffer_data : out std_logic_vector(FRAME_BUFFER_DATA_WIDTH-1 downto 0); 55 | frame_buffer_we : out std_logic 56 | ); 57 | end sprite_blitter; 58 | 59 | architecture arch of sprite_blitter is 60 | -- represents the position of a pixel in a sprite 61 | type sprite_pos_t is record 62 | x : unsigned(4 downto 0); 63 | y : unsigned(4 downto 0); 64 | end record sprite_pos_t; 65 | 66 | type state_t is (IDLE, CHECK, PRELOAD, BLIT); 67 | 68 | -- state signals 69 | signal state, next_state : state_t; 70 | 71 | -- tile signals 72 | signal tile_row : tile_row_t; 73 | signal tile_pixel : tile_pixel_t; 74 | 75 | -- position signals 76 | signal src_pos : sprite_pos_t; 77 | signal load_pos : sprite_pos_t; 78 | signal dest_pos : pos_t; 79 | 80 | -- control signals 81 | signal preload_done : std_logic; 82 | signal blit_done : std_logic; 83 | signal visible : std_logic; 84 | begin 85 | -- state machine 86 | fsm : process (state, start, visible, preload_done, blit_done) 87 | begin 88 | next_state <= state; 89 | 90 | case state is 91 | -- this is the default state, we just wait for the start signal 92 | when IDLE => 93 | if start = '1' then 94 | next_state <= CHECK; 95 | end if; 96 | 97 | -- check whether the sprite is visible before we bother to render it 98 | when CHECK => 99 | if visible = '1' then 100 | next_state <= PRELOAD; 101 | else 102 | next_state <= IDLE; 103 | end if; 104 | 105 | -- preload the first row of pixels 106 | when PRELOAD => 107 | if preload_done = '1' then 108 | next_state <= BLIT; 109 | end if; 110 | 111 | -- copy pixels from the source to the destination 112 | when BLIT => 113 | if blit_done = '1' then 114 | next_state <= IDLE; 115 | end if; 116 | end case; 117 | end process; 118 | 119 | -- latch the next state 120 | latch_next_state : process (clk) 121 | begin 122 | if rising_edge(clk) then 123 | if cen_6 = '1' then 124 | state <= next_state; 125 | end if; 126 | end if; 127 | end process; 128 | 129 | -- the source position represents the current pixel offset of the sprite to 130 | -- be copied to the frame buffer 131 | update_src_pos_counter : process (clk) 132 | begin 133 | if rising_edge(clk) then 134 | if cen_6 = '1' then 135 | if state = IDLE then 136 | -- set source position to first pixel 137 | src_pos.x <= (others => '0'); 138 | src_pos.y <= (others => '0'); 139 | elsif state = BLIT then 140 | if src_pos.x = sprite.size-1 then 141 | src_pos.x <= (others => '0'); 142 | 143 | if src_pos.y = sprite.size-1 then 144 | src_pos.y <= (others => '0'); 145 | else 146 | src_pos.y <= src_pos.y + 1; 147 | end if; 148 | else 149 | src_pos.x <= src_pos.x + 1; 150 | end if; 151 | end if; 152 | end if; 153 | end if; 154 | end process; 155 | 156 | -- the load position represents the position of the next pixel to be loaded 157 | update_load_pos_counter : process (clk) 158 | begin 159 | if rising_edge(clk) then 160 | if cen_6 = '1' then 161 | if state = IDLE then 162 | -- set load position to first pixel 163 | load_pos.x <= (others => '0'); 164 | load_pos.y <= (others => '0'); 165 | elsif state = PRELOAD or state = BLIT then 166 | if load_pos.x = sprite.size-1 then 167 | load_pos.x <= (others => '0'); 168 | 169 | if load_pos.y = sprite.size-1 then 170 | load_pos.y <= (others => '0'); 171 | else 172 | load_pos.y <= load_pos.y + 1; 173 | end if; 174 | else 175 | load_pos.x <= load_pos.x + 1; 176 | end if; 177 | end if; 178 | end if; 179 | end if; 180 | end process; 181 | 182 | -- latch the next row from the tile ROM when rendering the last pixel in 183 | -- every row 184 | latch_tile_row : process (clk) 185 | begin 186 | if rising_edge(clk) then 187 | if cen_6 = '1' then 188 | if (state = PRELOAD or state = BLIT) and load_pos.x(2 downto 0) = 7 then 189 | tile_row <= rom_data; 190 | end if; 191 | end if; 192 | end if; 193 | end process; 194 | 195 | -- write to the frame buffer when we're blitting to the visible part of the frame 196 | frame_buffer_we <= '1' when state = BLIT and tile_pixel /= "0000" and dest_pos.x(8) = '0' and dest_pos.y(8) = '0' else '0'; 197 | 198 | -- set ready output 199 | ready <= '1' when state = IDLE else '0'; 200 | 201 | -- the sprite is visible if it is enabled 202 | visible <= '1' when sprite.enable = '1' else '0'; 203 | 204 | -- Set the ROM address. 205 | -- 206 | -- This address points to a row of an 8x8 tile. 207 | rom_addr <= sprite.code(11 downto 4) & 208 | (sprite.code(3 downto 0) or (load_pos.y(4) & load_pos.x(4) & load_pos.y(3) & load_pos.x(3))) & 209 | load_pos.y(2 downto 0); 210 | 211 | -- set destination position and handle X/Y axis flipping 212 | dest_pos.x <= resize(sprite.pos.x+src_pos.x, dest_pos.x'length) when sprite.flip_x = '0' else 213 | resize(sprite.pos.x-src_pos.x+sprite.size-1, dest_pos.x'length); 214 | dest_pos.y <= resize(sprite.pos.y+src_pos.y, dest_pos.y'length) when sprite.flip_y = '0' else 215 | resize(sprite.pos.y-src_pos.y+sprite.size-1, dest_pos.y'length); 216 | 217 | -- the preload is done when the first row of pixels has been loaded 218 | preload_done <= '1' when load_pos.x = 7 else '0'; 219 | 220 | -- the blit is done when all the pixels have been copied 221 | blit_done <= '1' when src_pos.x = sprite.size-1 and src_pos.y = sprite.size-1 else '0'; 222 | 223 | -- decode the pixel from the tile row data 224 | tile_pixel <= decode_tile_row(tile_row, src_pos.x(2 downto 0)); 225 | 226 | -- set frame buffer address 227 | frame_buffer_addr <= dest_pos.y(7 downto 0) & dest_pos.x(7 downto 0); 228 | 229 | -- set frame buffer data 230 | frame_buffer_data <= std_logic_vector(sprite.priority & sprite.color) & tile_pixel; 231 | end architecture arch; 232 | --------------------------------------------------------------------------------