├── .github └── FUNDING.yml ├── .gitignore ├── LICENSE ├── README.md ├── SNES.aseprite ├── build.ps1 ├── docs └── PLL Reconfig.md ├── gateware.json ├── generate.tcl ├── pkg ├── Assets │ └── snes │ │ └── common │ │ └── .gitkeep ├── Cores │ └── agg23.SNES │ │ ├── audio.json │ │ ├── core.json │ │ ├── data.json │ │ ├── icon.bin │ │ ├── info.txt │ │ ├── input.json │ │ ├── interact.json │ │ ├── loader.bin │ │ ├── snes_custom.rev │ │ ├── snes_main.rev │ │ ├── snes_pal.rev │ │ ├── snes_spc.rev │ │ ├── variants.json │ │ └── video.json └── Platforms │ ├── _images │ └── snes.bin │ └── snes.json ├── platform └── pocket │ ├── apf.qip │ ├── apf_constraints.sdc │ ├── apf_top.v │ ├── build_cdf.tcl │ ├── build_id_gen.tcl │ ├── common.v │ ├── io_bridge_peripheral.v │ ├── io_pad_controller.v │ ├── mf_datatable.qip │ ├── mf_datatable.v │ ├── mf_ddio_bidir_12.qip │ ├── mf_ddio_bidir_12.v │ └── pocket.tcl ├── projects ├── snes_pocket.qip ├── snes_pocket.qpf ├── snes_pocket.qsf └── snes_pocket.sdc ├── rtl ├── 65C816 │ ├── 65C816.qip │ ├── ALU.vhd │ ├── AddSubBCD.vhd │ ├── AddrGen.vhd │ ├── BCDAdder.vhd │ ├── MCode.vhd │ ├── P65816_pkg.vhd │ └── P65C816.vhd ├── CEGen.vhd ├── CPU.vhd ├── DSP.vhd ├── DSP_PKG.vhd ├── PPU.vhd ├── PPU_PKG.vhd ├── SMP.vhd ├── SNES.vhd ├── SPC700 │ ├── ALU.vhd │ ├── AddSub.vhd │ ├── AddrGen.vhd │ ├── BCDAdj.vhd │ ├── MCode.vhd │ ├── MulDiv.vhd │ ├── SPC700.qip │ ├── SPC700.vhd │ └── SPC700_pkg.vhd ├── SWRAM.vhd ├── bram.vhd ├── cheatcodes.sv ├── chip │ ├── BSX │ │ ├── BSXMap.vhd │ │ ├── BSX_BS.vhd │ │ ├── BSX_DP.vhd │ │ ├── BSX_MCC.vhd │ │ └── bsx121-124.mif │ ├── CX4 │ │ ├── CX4.vhd │ │ ├── CX4Map.vhd │ │ ├── cx4cache.vhd │ │ └── drom.mif │ ├── DSP │ │ ├── DSP_LHRomMap.vhd │ │ ├── DSPn.vhd │ │ ├── OBC1.vhd │ │ ├── dsp11b23410_d.mif │ │ └── dsp11b23410_p.mif │ ├── GSU │ │ ├── GSU.vhd │ │ ├── GSUMap.vhd │ │ └── GSU_PKG.vhd │ ├── MSU1 │ │ ├── MSU.sv │ │ ├── msu_audio.v │ │ ├── msu_data_store.sv │ │ └── msu_fifo.v │ ├── RTC4513.vhd │ ├── SA1 │ │ ├── SA1.vhd │ │ ├── SA1DIV.vhd │ │ ├── SA1MULT.vhd │ │ └── SA1Map.vhd │ ├── SDD1 │ │ ├── Decoder.vhd │ │ ├── InputMgr.vhd │ │ ├── SDD1.vhd │ │ └── SDD1Map.vhd │ ├── SPC7110 │ │ ├── SPC7110.vhd │ │ ├── SPC7110Map.vhd │ │ ├── SPC7110_DEC.vhd │ │ ├── SPC7110_DEC_PKG.vhd │ │ ├── SPC7110_FIFO.vhd │ │ └── SPC7110_MULDIV.vhd │ ├── SRTC.vhd │ └── chip.qip ├── hps_ext.v ├── ioport.sv ├── lightgun.sv ├── main.v ├── miracle.sv ├── mister_top │ ├── SNES.sv │ ├── rom_parser.sv │ ├── rom_parser_tb.sv │ └── scanline_filler.sv ├── sdram.sv └── snes.qip ├── support ├── check_header.asm ├── loader.asm ├── loader.bin ├── test.bin ├── test_data.json └── util.asm └── target └── pocket ├── core.qip ├── core_bridge_cmd.v ├── core_constraints.sdc ├── core_top.sv ├── data_loader.sv ├── data_unloader.sv ├── mf_pllbase.ppf ├── mf_pllbase.qip ├── mf_pllbase.v ├── mf_pllbase ├── mf_pllbase.mif ├── mf_pllbase_0002.qip └── mf_pllbase_0002.v ├── mf_pllbase_pal.ppf ├── mf_pllbase_pal.qip ├── mf_pllbase_pal.v ├── mf_pllbase_pal ├── mf_pllbase_pal_0002.qip └── mf_pllbase_pal_0002.v ├── pll_reconfig.ppf ├── pll_reconfig.qip ├── pll_reconfig.v ├── pll_reconfig ├── altera_pll_reconfig_core.v ├── altera_pll_reconfig_top.v └── altera_std_synchronizer.v ├── psram.sv ├── save_state_controller.sv ├── sound_i2s.sv ├── stp1.stp └── sync_fifo.sv /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: agg23 2 | patreon: srg320 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.rbf_r 2 | *.zip 3 | dist/**/*.rev 4 | dist/**/*.bin 5 | src/**/*.bin 6 | src/sim/work/ 7 | src/sim/*.hex 8 | src/sim/*.mem 9 | src/sim/*.bin 10 | 11 | # Quartus directories and files 12 | db 13 | greybox_tmp 14 | hps_isw_handoff 15 | incremental_db 16 | output_files 17 | PLLJ_PLLSPE_INFO.txt 18 | simulation 19 | vip 20 | .qsys_edit 21 | *_netlist 22 | *_sim 23 | *.bak 24 | *.bsf 25 | *.cdf 26 | *.cmp 27 | *.csv 28 | *.done 29 | *.f 30 | *.pin 31 | *.pof 32 | *.ptf.* 33 | *.qar 34 | *.qarlog 35 | *.qdf 36 | *.qws 37 | *.rbf 38 | *.rpt 39 | *.sip 40 | *.sld 41 | *.smsg 42 | *.sof 43 | *.sopc_builder 44 | *.sopcinfo 45 | *.spd 46 | *.summary 47 | *.txt 48 | *.xml 49 | *~ 50 | **/.DS_Store 51 | build_id.mif 52 | build_id.v 53 | c5_pin_model_dump.txt 54 | cr_ie_info.json 55 | # Gateman directories and files 56 | !.gateman/* 57 | !gateware.json 58 | !/pkg/* 59 | /pkg/**/*.rom 60 | /pkg/**/*.zip 61 | /staging/* 62 | /release/* 63 | # Editor directories and files 64 | .idea 65 | *.suo 66 | *.ntvs* 67 | *.njsproj 68 | *.sln 69 | *.sw? 70 | # Pocket directories and files 71 | !info.txt 72 | # ROMS Checklist 73 | !checklist.sha1 74 | !checklist.md5 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SNES for Analogue Pocket 2 | 3 | Ported from the original core developed by [srg320](https://github.com/srg320) ([Patreon](https://www.patreon.com/srg320)). Latest upstream available at https://github.com/MiSTer-devel/SNES_MiSTer. 4 | 5 | Please report any issues encountered to this repo. Most likely any problems are a result of my port, not the original core. Issues will be upstreamed as necessary. 6 | 7 | > [!WARNING] 8 | > 9 | > Savestates/Memories/Sleep not supported 10 | > 11 | > Savestates/Memories/Sleep are not supported by any FPGA SNES core. Not this one, not the MiSTer core it's ported from, not the Analogue Super NT one. 12 | > 13 | > **Support for savestates will _not_ be coming** to any of these cores. Do not ask. If you would like to learn more, see [issue #59](https://github.com/agg23/openfpga-SNES/issues/59) and [this discussion on the MiSTer forums](https://misterfpga.org/viewtopic.php?t=4944). 14 | 15 | ## Installation 16 | 17 | ### Easy mode 18 | 19 | I highly recommend the updater tools by [@mattpannella](https://github.com/mattpannella) and [@RetroDriven](https://github.com/RetroDriven). If you're running Windows, use [the RetroDriven GUI](https://github.com/RetroDriven/Pocket_Updater), or if you prefer the CLI, use [the mattpannella tool](https://github.com/mattpannella/pocket_core_autoupdate_net). Either of these will allow you to automatically download and install openFPGA cores onto your Analogue Pocket. Go donate to them if you can 20 | 21 | ### Manual mode 22 | To install the core, copy the `Assets`, `Cores`, and `Platform` folders over to the root of your SD card. Please note that Finder on macOS automatically _replaces_ folders, rather than merging them like Windows does, so you have to manually merge the folders. 23 | 24 | ## Usage 25 | 26 | ROMs should be placed in `/Assets/snes/common`. Both headered and unheadered ROMs are now supported. 27 | 28 | ## Features 29 | 30 | ### Dock Support 31 | 32 | Core supports four players/controllers via the Analogue Dock. To enable four player mode, turn on `Use Multitap` setting. 33 | 34 | ### Expansion Chips 35 | 36 | All original expansion chips supported by MiSTer are also supported on the Pocket. The full list is: 37 | 38 | * SA-1 (Super Mario RPG) 39 | * Super FX/GSU-1/2 (Star Fox) 40 | * DSP (Super Mario Kart) 41 | * CX4 (Mega Man X 2) 42 | * S-DD1 (Star Ocean) 43 | * SPC7110 (Far East of Eden) 44 | * ST1010 (F1 Roc 2) 45 | * BSX (Satellaview) 46 | 47 | The Super Game Boy, ST011 (Hayazashi Nidan Morita Shougi), and ST018 (Hayazashi Nidan Morita Shougi 2) are not supported in the MiSTer core, and therefore are not supported here. Additionally, the homebrew MSU expansion chip is not currently supported. 48 | 49 | #### BSX 50 | 51 | BSX ROMs must be patched to run without BIOS. The BSX BIOS is not currently supported 52 | 53 | ### Savestates/Memories/Sleep 54 | 55 | > **Warning**: Not supported 56 | 57 | Savestates/Memories/Sleep are not supported by any FPGA SNES core. Not this one, not the MiSTer core it's ported from, not the Analogue Super NT one. 58 | 59 | **Support for savestates will _not_ be coming** to any of these cores. Do not ask. If you would like to learn more, see [issue #59](https://github.com/agg23/openfpga-SNES/issues/59) and [this discussion on the MiSTer forums](https://misterfpga.org/viewtopic.php?t=4944). 60 | 61 | ### Video 62 | 63 | * `Square Pixels` - The internal resolution of the SNES is a 8:7 pixel aspect ratio (wide pixels), which roughly corresponds to what users would see on 4:3 display aspect ratio CRTs. Some games are designed to be displayed at 8:7 PAR (the core's default), and others at 1:1 PAR (square pixels). The `Square Pixels` option is provided to switch to a 1:1 pixel aspect ratio 64 | * `Pseudo Transparency` - Enable blending of adjacent pixels, used in some games to simulate transparency 65 | 66 | ### Turbo 67 | 68 | * `CPU Turbo` - Applies a speed increase to the main SNES CPU. **NOTE:** This has different compatibility with different games. See the [MiSTer list of games](https://github.com/MiSTer-devel/SNES_MiSTer/blob/master/SNES_Turbo.md) that this feature works with 69 | * `SuperFX Turbo` - Applies a speed increase to the GSU (SuperFX) chip. Can be used in addition to the `CPU Turbo` option in games like Star Fox to maintain a higher frame rate. 70 | 71 | ### Controller Options 72 | 73 | There are several options provided for selecting which type of controller the core will emulate. 74 | 75 | * `Gamepad` - The standard SNES controller used with most games. 76 | * `Super Scope` - The Super Scope lightgun that's used with most lightgun games. See Lightguns for more details. 77 | * `Justifier` - The Justifier lightgun that's used with Lethal Enforcers. See Lightguns for more details. 78 | * `Mouse` - The SNES mouse that's used with Mario Paint and several other games. See SNES Mouse for more details. 79 | 80 | ### Lightguns 81 | 82 | Core supports virtual lightguns by selecting the `Super Scope` or `Justifier` options under `Controller Options`. Most lightgun games user the Super Scope but Lethal Enforcers uses the Justifier. The crosshair can be controlled with the D-Pad or left joystick, using the A button to fire and the B button to reload. D-Pad aim sensitivity can be adjusted with the `D-Pad Aim Speed` setting. 83 | 84 | **NOTE:** Joystick support for aiming only appears to work when a controller is paired over Bluetooth and not connected to the Analogue Dock directly by USB. 85 | 86 | ### SNES Mouse 87 | 88 | Core supports a virtual SNES mouse by selecting `Mouse` under `Controller Options`. The mouse can be moved with the D-Pad or left joystick and left and right clicks can be performed by pressing the A and B buttons respectively. Mouse D-Pad movement sensitivity can be adjusted with the `D-Pad Aim Speed` setting. 89 | 90 | **NOTE:** The dock firmware doesn't currently support a USB mouse. -------------------------------------------------------------------------------- /SNES.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agg23/openfpga-SNES/05f0587891754e885647915ed42faa52604fc1d5/SNES.aseprite -------------------------------------------------------------------------------- /build.ps1: -------------------------------------------------------------------------------- 1 | if (($args.count -ne 1) -or ($args[0] -eq "")) { 2 | Write-Output "Expected build type arg" 3 | exit 1 4 | } 5 | 6 | $build_type = $args[0] 7 | 8 | quartus_sh -t generate.tcl $build_type 9 | 10 | $exitcode = $LASTEXITCODE 11 | if ($exitcode -ne 0) { 12 | Write-Output "Build failed with $exitcode" 13 | exit $exitcode 14 | } 15 | 16 | $output_file = "snes_main.rev" 17 | 18 | if (($build_type -eq "ntsc") -or ($build_type -eq "none")) { 19 | $output_file = "snes_main.rev" 20 | } elseif (($build_type -eq "pal") -or ($build_type -eq "none_pal")) { 21 | $output_file = "snes_pal.rev" 22 | } elseif ($build_type -eq "ntsc_spc") { 23 | $output_file = "snes_spc.rev" 24 | } 25 | 26 | C:\Users\adam\code\pocket-text\tools\reverse.exe C:\Users\adam\code\fpga\openFPGA\ports\snes\projects\output_files\snes_pocket.rbf "C:\Users\adam\code\fpga\openFPGA\ports\snes\pkg\Cores\agg23.SNES\$output_file"; -------------------------------------------------------------------------------- /docs/PLL Reconfig.md: -------------------------------------------------------------------------------- 1 | # C Counter 2 | 3 | ## C0 4 | 5 | NTSC: 6 | Lo: 3 7 | Hi: 4 8 | Bypass: false 9 | Odd div: true 10 | 11 | 0x020403 12 | 13 | PAL: 14 | Lo: 4 15 | Hi: 4 16 | Bypass: false 17 | Odd div: false 18 | 19 | 0x000404 20 | 21 | ## C1 22 | 23 | NTSC: 24 | Lo: 14 25 | Hi: 14 26 | Bypass: false 27 | Odd div: false 28 | 29 | 0x040E0E 30 | 31 | PAL: 32 | Lo: 16 33 | Hi: 16 34 | Bypass: false 35 | Odd div: false 36 | 37 | 0x041010 38 | 39 | ## C2 40 | 41 | NTSC: 42 | Lo: 28 43 | Hi: 28 44 | Bypass: false 45 | Odd div: false 46 | 47 | 0x081C1C 48 | 49 | PAL: 50 | Lo: 32 51 | Hi: 32 52 | Bypass: false 53 | Odd div: false 54 | 55 | 0x082020 56 | 57 | ## C3 58 | 59 | NTSC: 60 | Lo: 28 61 | Hi: 28 62 | Bypass: false 63 | Odd div: false 64 | 65 | 0x0C1C1C 66 | 67 | PAL: 68 | Lo: 32 69 | Hi: 32 70 | Bypass: false 71 | Odd div: false 72 | 73 | 0x0C2020 74 | 75 | # M Counter 76 | 77 | NTSC: 78 | Lo: 4 79 | Hi: 4 80 | Bypass: false 81 | Odd div: false 82 | 83 | 0x00404 84 | 85 | PAL: 86 | Lo: 4 87 | Hi: 5 88 | Bypass: false 89 | Odd div: true 90 | 91 | 0x20504 92 | 93 | # Fractional division 94 | 95 | NTSC: 425937894 96 | PAL: 737741702 -------------------------------------------------------------------------------- /gateware.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "snes", 3 | "displayName": "snes", 4 | "description": "Super Nintendo and Super Famicom. Nintendo's second major home console", 5 | "author": "agg23", 6 | "version": "0.4.4", 7 | "license": "GPL-3.0-or-later", 8 | "repository": "https://github.com/agg23/openFPGA-SNES", 9 | "keywords": [ 10 | "ecosystem:gateman" 11 | ], 12 | "scripts": { 13 | "verilator": "echo \"Error: no simulation specified\" && exit 1", 14 | "build:pocket": "pwsh build.ps1", 15 | "program:pocket": "quartus_pgm -m jtag -c 1 -o \"p;projects/output_files/nes_pocket.sof@1\"" 16 | }, 17 | "platforms": { 18 | "pocket": "1.3.0" 19 | }, 20 | "modules": {} 21 | } -------------------------------------------------------------------------------- /generate.tcl: -------------------------------------------------------------------------------- 1 | # Run with quartus_sh -t generate.tcl 2 | 3 | # Load Quartus II Tcl Project package 4 | package require ::quartus::project 5 | 6 | # Required for compilation 7 | package require ::quartus::flow 8 | 9 | if { $argc != 1 } { 10 | puts "Exactly 1 argument required" 11 | exit 12 | } 13 | 14 | project_open projects/snes_pocket.qpf 15 | 16 | if { [lindex $argv 0] == "ntsc" } { 17 | puts "NTSC" 18 | set_parameter -name PAL_PLL -entity core_top '0 19 | 20 | set_parameter -name USE_CX4 -entity MAIN_SNES '1 21 | set_parameter -name USE_SDD1 -entity MAIN_SNES '0 22 | set_parameter -name USE_GSU -entity MAIN_SNES '1 23 | set_parameter -name USE_SA1 -entity MAIN_SNES '1 24 | set_parameter -name USE_DSPn -entity MAIN_SNES '1 25 | set_parameter -name USE_SPC7110 -entity MAIN_SNES '0 26 | set_parameter -name USE_BSX -entity MAIN_SNES '0 27 | set_parameter -name USE_MSU -entity MAIN_SNES '0 28 | } elseif { [lindex $argv 0] == "pal" } { 29 | puts "PAL" 30 | set_parameter -name PAL_PLL -entity core_top '1 31 | 32 | set_parameter -name USE_CX4 -entity MAIN_SNES '1 33 | set_parameter -name USE_SDD1 -entity MAIN_SNES '0 34 | set_parameter -name USE_GSU -entity MAIN_SNES '1 35 | set_parameter -name USE_SA1 -entity MAIN_SNES '1 36 | set_parameter -name USE_DSPn -entity MAIN_SNES '1 37 | set_parameter -name USE_SPC7110 -entity MAIN_SNES '0 38 | set_parameter -name USE_BSX -entity MAIN_SNES '0 39 | set_parameter -name USE_MSU -entity MAIN_SNES '0 40 | } elseif { [lindex $argv 0] == "ntsc_spc" } { 41 | puts "NTSC SPC" 42 | set_parameter -name PAL_PLL -entity core_top '0 43 | 44 | set_parameter -name USE_CX4 -entity MAIN_SNES '0 45 | set_parameter -name USE_SDD1 -entity MAIN_SNES '1 46 | set_parameter -name USE_GSU -entity MAIN_SNES '0 47 | set_parameter -name USE_SA1 -entity MAIN_SNES '0 48 | set_parameter -name USE_DSPn -entity MAIN_SNES '0 49 | set_parameter -name USE_SPC7110 -entity MAIN_SNES '1 50 | set_parameter -name USE_BSX -entity MAIN_SNES '1 51 | set_parameter -name USE_MSU -entity MAIN_SNES '0 52 | } elseif { [lindex $argv 0] == "none" } { 53 | puts "NONE" 54 | set_parameter -name PAL_PLL -entity core_top '0 55 | 56 | set_parameter -name USE_CX4 -entity MAIN_SNES '0 57 | set_parameter -name USE_SDD1 -entity MAIN_SNES '0 58 | set_parameter -name USE_GSU -entity MAIN_SNES '0 59 | set_parameter -name USE_SA1 -entity MAIN_SNES '0 60 | set_parameter -name USE_DSPn -entity MAIN_SNES '0 61 | set_parameter -name USE_SPC7110 -entity MAIN_SNES '0 62 | set_parameter -name USE_BSX -entity MAIN_SNES '0 63 | set_parameter -name USE_MSU -entity MAIN_SNES '0 64 | } elseif { [lindex $argv 0] == "none_pal" } { 65 | puts "NONE PAL" 66 | set_parameter -name PAL_PLL -entity core_top '1 67 | 68 | set_parameter -name USE_CX4 -entity MAIN_SNES '0 69 | set_parameter -name USE_SDD1 -entity MAIN_SNES '0 70 | set_parameter -name USE_GSU -entity MAIN_SNES '0 71 | set_parameter -name USE_SA1 -entity MAIN_SNES '0 72 | set_parameter -name USE_DSPn -entity MAIN_SNES '0 73 | set_parameter -name USE_SPC7110 -entity MAIN_SNES '0 74 | set_parameter -name USE_BSX -entity MAIN_SNES '0 75 | set_parameter -name USE_MSU -entity MAIN_SNES '0 76 | } else { 77 | puts "Unknown bitstream type [lindex $argv 0]" 78 | project_close 79 | exit 80 | } 81 | 82 | execute_flow -compile 83 | 84 | project_close -------------------------------------------------------------------------------- /pkg/Assets/snes/common/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agg23/openfpga-SNES/05f0587891754e885647915ed42faa52604fc1d5/pkg/Assets/snes/common/.gitkeep -------------------------------------------------------------------------------- /pkg/Cores/agg23.SNES/audio.json: -------------------------------------------------------------------------------- 1 | { 2 | "audio": { 3 | "magic": "APF_VER_1" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /pkg/Cores/agg23.SNES/core.json: -------------------------------------------------------------------------------- 1 | { 2 | "core": { 3 | "magic": "APF_VER_1", 4 | "metadata": { 5 | "platform_ids": [ 6 | "snes" 7 | ], 8 | "shortname": "SNES", 9 | "description": "Super Nintendo and Super Famicom. Nintendo's second major home console", 10 | "author": "agg23", 11 | "url": "https://github.com/agg23/openfpga-snes", 12 | "version": "0.4.4", 13 | "date_release": "2024-09-16" 14 | }, 15 | "framework": { 16 | "target_product": "Analogue Pocket", 17 | "version_required": "1.1", 18 | "sleep_supported": false, 19 | "dock": { 20 | "supported": true, 21 | "analog_output": false 22 | }, 23 | "hardware": { 24 | "link_port": false, 25 | "cartridge_adapter": -1 26 | }, 27 | "chip32_vm": "loader.bin" 28 | }, 29 | "cores": [ 30 | { 31 | "name": "main", 32 | "id": 0, 33 | "filename": "snes_main.rev" 34 | }, 35 | { 36 | "name": "SPCSDD1", 37 | "id": 1, 38 | "filename": "snes_spc.rev" 39 | }, 40 | { 41 | "name": "PAL", 42 | "id": 2, 43 | "filename": "snes_pal.rev" 44 | } 45 | ] 46 | } 47 | } -------------------------------------------------------------------------------- /pkg/Cores/agg23.SNES/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "magic": "APF_VER_1", 4 | "data_slots": [ 5 | { 6 | "name": "Cartridge", 7 | "id": 0, 8 | "required": true, 9 | "parameters": "0x109", 10 | "extensions": ["smc", "sfc", "bs"], 11 | "address": "0x10000000" 12 | }, 13 | { 14 | "name": "Save", 15 | "id": 10, 16 | "required": false, 17 | "parameters": "0x84", 18 | "nonvolatile": true, 19 | "extensions": ["sav", "srm"], 20 | "address": "0x20000000", 21 | "size_maximum": "0x20000" 22 | } 23 | ] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /pkg/Cores/agg23.SNES/icon.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agg23/openfpga-SNES/05f0587891754e885647915ed42faa52604fc1d5/pkg/Cores/agg23.SNES/icon.bin -------------------------------------------------------------------------------- /pkg/Cores/agg23.SNES/info.txt: -------------------------------------------------------------------------------- 1 | Port by agg23. Core by srg320. 2 | 3 | Super Nintendo Entertainment System (SNES), referred to as the Super Famicom (SFC) in Japan was the second home console produced by Nintendo. A 16-bit console that remains hugely popular to this day due to its expansive library and impressive enhancement chips. 4 | 5 | Core supports 4 controllers (when connected to the Dock), and the SA-1, Super FX (GSU), DSP, CX4, S-DD1, SPC7110, and BSX expansion chips. Please report all issues to agg23, as most likely any issues experienced are issues with the port, not the core. -------------------------------------------------------------------------------- /pkg/Cores/agg23.SNES/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "input": { 3 | "magic": "APF_VER_1", 4 | "controllers": [ 5 | { 6 | "type": "default", 7 | "mappings": [ 8 | { 9 | "id": 0, 10 | "name": "A Button", 11 | "key": "pad_btn_a" 12 | }, 13 | { 14 | "id": 1, 15 | "name": "B Button", 16 | "key": "pad_btn_b" 17 | }, 18 | { 19 | "id": 2, 20 | "name": "X Button", 21 | "key": "pad_btn_x" 22 | }, 23 | { 24 | "id": 3, 25 | "name": "Y Button", 26 | "key": "pad_btn_y" 27 | }, 28 | { 29 | "id": 10, 30 | "name": "Left Trigger", 31 | "key": "pad_trig_l" 32 | }, 33 | { 34 | "id": 11, 35 | "name": "Right Trigger", 36 | "key": "pad_trig_r" 37 | }, 38 | { 39 | "id": 20, 40 | "name": "Start", 41 | "key": "pad_btn_start" 42 | }, 43 | { 44 | "id": 21, 45 | "name": "Select", 46 | "key": "pad_btn_select" 47 | } 48 | ] 49 | } 50 | ] 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /pkg/Cores/agg23.SNES/interact.json: -------------------------------------------------------------------------------- 1 | { 2 | "interact": { 3 | "magic": "APF_VER_1", 4 | "variables": [ 5 | { 6 | "name": "Reset Core", 7 | "id": 10, 8 | "type": "action", 9 | "enabled": true, 10 | "address": "0x50", 11 | "value": 1 12 | }, 13 | { 14 | "name": "CPU Turbo", 15 | "id": 15, 16 | "type": "check", 17 | "enabled": true, 18 | "address": "0x80", 19 | "persist": true, 20 | "writeonly": true, 21 | "defaultval": 0, 22 | "value": 1 23 | }, 24 | { 25 | "name": "SuperFX Turbo", 26 | "id": 16, 27 | "type": "check", 28 | "enabled": true, 29 | "address": "0x84", 30 | "persist": true, 31 | "writeonly": true, 32 | "defaultval": 0, 33 | "value": 1 34 | }, 35 | { 36 | "name": "Use Multitap", 37 | "id": 20, 38 | "type": "check", 39 | "enabled": true, 40 | "address": "0x100", 41 | "persist": true, 42 | "writeonly": true, 43 | "defaultval": 0, 44 | "value": 1 45 | }, 46 | { 47 | "name": "Controller Options", 48 | "id": 30, 49 | "type": "list", 50 | "enabled": true, 51 | "address": "0x104", 52 | "persist": true, 53 | "writeonly": true, 54 | "defaultval": 0, 55 | "options": [ 56 | { 57 | "name": "Gamepad", 58 | "value": 0 59 | }, 60 | { 61 | "name": "Super Scope", 62 | "value": 1 63 | }, 64 | { 65 | "name": "Justifier", 66 | "value": 3 67 | }, 68 | { 69 | "name": "Mouse", 70 | "value": 4 71 | } 72 | ] 73 | }, 74 | { 75 | "name": "D-Pad Aim Speed", 76 | "id": 34, 77 | "type": "slider_u32", 78 | "enabled": true, 79 | "address": "0x108", 80 | "persist": true, 81 | "writeonly": true, 82 | "defaultval": 3, 83 | "graphical": { 84 | "signed": false, 85 | "min": 1, 86 | "max": 10, 87 | "adjust_small": 1, 88 | "adjust_large": 4 89 | } 90 | }, 91 | { 92 | "name": "Joy Deadzone", 93 | "id": 35, 94 | "type": "slider_u32", 95 | "enabled": true, 96 | "address": "0x0000010C", 97 | "persist": true, 98 | "writeonly": true, 99 | "defaultval": 0, 100 | "graphical": { 101 | "signed": false, 102 | "min": 0, 103 | "max": 64, 104 | "adjust_small": 1, 105 | "adjust_large": 10 106 | } 107 | }, 108 | { 109 | "name": "Square Pixels", 110 | "id": 42, 111 | "type": "check", 112 | "enabled": true, 113 | "address": "0x200", 114 | "persist": true, 115 | "writeonly": true, 116 | "defaultval": 0, 117 | "value": 1 118 | }, 119 | { 120 | "name": "Pseudo Transparency", 121 | "id": 41, 122 | "type": "check", 123 | "enabled": true, 124 | "address": "0x204", 125 | "persist": true, 126 | "writeonly": true, 127 | "defaultval": 1, 128 | "value": 1 129 | } 130 | ], 131 | "messages": [] 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /pkg/Cores/agg23.SNES/loader.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agg23/openfpga-SNES/05f0587891754e885647915ed42faa52604fc1d5/pkg/Cores/agg23.SNES/loader.bin -------------------------------------------------------------------------------- /pkg/Cores/agg23.SNES/snes_custom.rev: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agg23/openfpga-SNES/05f0587891754e885647915ed42faa52604fc1d5/pkg/Cores/agg23.SNES/snes_custom.rev -------------------------------------------------------------------------------- /pkg/Cores/agg23.SNES/snes_main.rev: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agg23/openfpga-SNES/05f0587891754e885647915ed42faa52604fc1d5/pkg/Cores/agg23.SNES/snes_main.rev -------------------------------------------------------------------------------- /pkg/Cores/agg23.SNES/snes_pal.rev: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agg23/openfpga-SNES/05f0587891754e885647915ed42faa52604fc1d5/pkg/Cores/agg23.SNES/snes_pal.rev -------------------------------------------------------------------------------- /pkg/Cores/agg23.SNES/snes_spc.rev: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agg23/openfpga-SNES/05f0587891754e885647915ed42faa52604fc1d5/pkg/Cores/agg23.SNES/snes_spc.rev -------------------------------------------------------------------------------- /pkg/Cores/agg23.SNES/variants.json: -------------------------------------------------------------------------------- 1 | { 2 | "variants": { 3 | "magic": "APF_VER_1", 4 | "variant_list": [] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /pkg/Cores/agg23.SNES/video.json: -------------------------------------------------------------------------------- 1 | { 2 | "video": { 3 | "magic": "APF_VER_1", 4 | "scaler_modes": [ 5 | { 6 | "width": 512, 7 | "height": 224, 8 | "aspect_w": 64, 9 | "aspect_h": 49, 10 | "rotation": 0, 11 | "mirror": 0 12 | }, 13 | { 14 | "width": 512, 15 | "height": 224, 16 | "aspect_w": 8, 17 | "aspect_h": 7, 18 | "rotation": 0, 19 | "mirror": 0 20 | }, 21 | { 22 | "width": 512, 23 | "height": 240, 24 | "aspect_w": 128, 25 | "aspect_h": 105, 26 | "rotation": 0, 27 | "mirror": 0 28 | }, 29 | { 30 | "width": 512, 31 | "height": 240, 32 | "aspect_w": 16, 33 | "aspect_h": 15, 34 | "rotation": 0, 35 | "mirror": 0 36 | } 37 | ], 38 | "display_modes": [ 39 | { 40 | "id": "0x10" 41 | }, 42 | { 43 | "id": "0x20" 44 | }, 45 | { 46 | "id": "0x30" 47 | }, 48 | { 49 | "id": "0x40" 50 | }, 51 | { 52 | "id": "0xE0" 53 | }, 54 | { 55 | "id": "0xE1" 56 | } 57 | ] 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /pkg/Platforms/_images/snes.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agg23/openfpga-SNES/05f0587891754e885647915ed42faa52604fc1d5/pkg/Platforms/_images/snes.bin -------------------------------------------------------------------------------- /pkg/Platforms/snes.json: -------------------------------------------------------------------------------- 1 | { 2 | "platform": { 3 | "category": "Console", 4 | "name": "SNES", 5 | "manufacturer": "Nintendo", 6 | "year": 1990 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /platform/pocket/apf.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "apf_top.v"] 2 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "common.v"] 3 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "io_bridge_peripheral.v"] 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "io_pad_controller.v"] 5 | set_global_assignment -name SDC_FILE [file join $::quartus(qip_path) "apf_constraints.sdc"] 6 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) "mf_ddio_bidir_12.qip"] 7 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) "mf_datatable.qip"] 8 | -------------------------------------------------------------------------------- /platform/pocket/apf_constraints.sdc: -------------------------------------------------------------------------------- 1 | # 2 | # APF constraints 3 | # Do not edit this file. 4 | # 5 | # Add your own constraints in the \core_constraints.sdc in the core directory, which will also be loaded. 6 | 7 | create_clock -name clk_74a -period 13.468 [get_ports clk_74a] 8 | create_clock -name clk_74b -period 13.468 [get_ports clk_74b] 9 | create_clock -name bridge_spiclk -period 13.468 [get_ports bridge_spiclk] 10 | 11 | # autogenerate PLL clock names for use down below 12 | derive_pll_clocks 13 | -------------------------------------------------------------------------------- /platform/pocket/build_cdf.tcl: -------------------------------------------------------------------------------- 1 | # ============================================================================== 2 | # SPDX-License-Identifier: CC0-1.0 3 | # SPDX-FileType: SOURCE 4 | # SPDX-FileCopyrightText: (c) 2022, OpenGateware authors and contributors 5 | # ============================================================================== 6 | # @file: build_cd.h 7 | # @brief: Generate a JTAG Chain Description File. 8 | # Create a .cdf file to be used with Quartus Prime Programmer 9 | # ============================================================================== 10 | proc createChainDescriptionFile {revision device outpath project_name} { 11 | set outputFileName "$project_name.cdf" 12 | set outputFile [open $outputFileName "w"] 13 | 14 | puts $outputFile "JedecChain;" 15 | puts $outputFile " FileRevision(JESD32A);" 16 | puts $outputFile " DefaultMfr(6E);" 17 | puts $outputFile "" 18 | puts $outputFile " P ActionCode(Cfg)" 19 | puts $outputFile " Device PartName($device) Path(\"$outpath/\") File(\"$revision.sof\") MfrSpec(OpMask(1));" 20 | puts $outputFile "ChainEnd;" 21 | puts $outputFile "" 22 | puts $outputFile "AlteraBegin;" 23 | puts $outputFile " ChainType(JTAG);" 24 | puts $outputFile "AlteraEnd;" 25 | } 26 | 27 | set project_name [lindex $quartus(args) 1] 28 | set revision [lindex $quartus(args) 2] 29 | 30 | if {[project_exists $project_name]} { 31 | if {[string equal "" $revision]} { 32 | project_open $project_name -revision [get_current_revision $project_name] 33 | } else { 34 | project_open $project_name -revision $revision 35 | } 36 | } else { 37 | post_message -type error "Project $project_name does not exist" 38 | exit 39 | } 40 | 41 | set device [get_global_assignment -name DEVICE] 42 | set outpath [get_global_assignment -name PROJECT_OUTPUT_DIRECTORY] 43 | 44 | if [is_project_open] { 45 | project_close 46 | } 47 | 48 | createChainDescriptionFile $revision $device $outpath $project_name 49 | -------------------------------------------------------------------------------- /platform/pocket/common.v: -------------------------------------------------------------------------------- 1 | // Software License Agreement 2 | 3 | // The software supplied herewith by Analogue Enterprises Limited (the "Company”), 4 | // the Analogue Pocket Framework (“APF”), is provided and licensed to you, the 5 | // Company's customer, solely for use in designing, testing and creating 6 | // applications for use with Company's Products or Services. The software is 7 | // owned by the Company and/or its licensors, and is protected under applicable 8 | // laws, including, but not limited to, U.S. copyright law. All rights are 9 | // reserved. By using the APF code you are agreeing to the terms of the End User 10 | // License Agreement (“EULA”) located at [https://www.analogue.link/pocket-eula] 11 | // and incorporated herein by reference. To the extent any use of the APF requires 12 | // application of the MIT License or the GNU General Public License and terms of 13 | // this APF Software License Agreement and EULA are inconsistent with such license, 14 | // the applicable terms of the MIT License or the GNU General Public License, as 15 | // applicable, will prevail. 16 | 17 | // THE SOFTWARE IS PROVIDED "AS-IS" AND WE EXPRESSLY DISCLAIM ANY IMPLIED 18 | // WARRANTIES TO THE FULLEST EXTENT PROVIDED BY LAW, INCLUDING BUT NOT LIMITED TO, 19 | // ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE OR 20 | // NON-INFRINGEMENT. TO THE EXTENT APPLICABLE LAWS PROHIBIT TERMS OF USE FROM 21 | // DISCLAIMING ANY IMPLIED WARRANTY, SUCH IMPLIED WARRANTY SHALL BE LIMITED TO THE 22 | // MINIMUM WARRANTY PERIOD REQUIRED BY LAW, AND IF NO SUCH PERIOD IS REQUIRED, 23 | // THEN THIRTY (30) DAYS FROM FIRST USE OF THE SOFTWARE. WE CANNOT GUARANTEE AND 24 | // DO NOT PROMISE ANY SPECIFIC RESULTS FROM USE OF THE SOFTWARE. WITHOUT LIMITING 25 | // THE FOREGOING, WE DO NOT WARRANT THAT THE SOFTWARE WILL BE UNINTERRUPTED OR 26 | // ERROR-FREE. IN NO EVENT WILL WE BE LIABLE TO YOU OR ANY OTHER PERSON FOR ANY 27 | // INDIRECT, CONSEQUENTIAL, EXEMPLARY, INCIDENTAL, SPECIAL OR PUNITIVE DAMAGES, 28 | // INCLUDING BUT NOT LIMITED TO, LOST PROFITS ARISING OUT OF YOUR USE, OR 29 | // INABILITY TO USE, THE SOFTWARE, EVEN IF WE HAVE BEEN ADVISED OF THE POSSIBILITY 30 | // OF SUCH DAMAGES. UNDER NO CIRCUMSTANCES SHALL OUR LIABILITY TO YOU FOR ANY 31 | // CLAIM OR CAUSE OF ACTION WHATSOEVER, AND REGARDLESS OF THE FORM OF THE ACTION, 32 | // WHETHER ARISING IN CONTRACT, TORT OR OTHERWISE, EXCEED THE AMOUNT PAID BY YOU 33 | // TO US, IF ANY, DURING THE 90 DAY PERIOD IMMEDIATELY PRECEDING THE DATE ON WHICH 34 | // YOU FIRST ASSERT ANY SUCH CLAIM. THE FOREGOING LIMITATIONS SHALL APPLY TO THE 35 | // FULLEST EXTENT PERMITTED BY APPLICABLE LAW. 36 | // 37 | // 2-stage synchronizer 38 | // 39 | module synch_2 #(parameter WIDTH = 1) ( 40 | input wire [WIDTH-1:0] i, // input signal 41 | output reg [WIDTH-1:0] o, // synchronized output 42 | input wire clk, // clock to synchronize on 43 | output wire rise, // one-cycle rising edge pulse 44 | output wire fall // one-cycle falling edge pulse 45 | ); 46 | 47 | reg [WIDTH-1:0] stage_1; 48 | reg [WIDTH-1:0] stage_2; 49 | reg [WIDTH-1:0] stage_3; 50 | 51 | assign rise = (WIDTH == 1) ? (o & ~stage_2) : 1'b0; 52 | assign fall = (WIDTH == 1) ? (~o & stage_2) : 1'b0; 53 | always @(posedge clk) 54 | {stage_2, o, stage_1} <= {o, stage_1, i}; 55 | 56 | endmodule 57 | 58 | 59 | // 60 | // 3-stage synchronizer 61 | // 62 | module synch_3 #(parameter WIDTH = 1) ( 63 | input wire [WIDTH-1:0] i, // input signal 64 | output reg [WIDTH-1:0] o, // synchronized output 65 | input wire clk, // clock to synchronize on 66 | output wire rise, // one-cycle rising edge pulse 67 | output wire fall // one-cycle falling edge pulse 68 | ); 69 | 70 | reg [WIDTH-1:0] stage_1; 71 | reg [WIDTH-1:0] stage_2; 72 | reg [WIDTH-1:0] stage_3; 73 | 74 | assign rise = (WIDTH == 1) ? (o & ~stage_3) : 1'b0; 75 | assign fall = (WIDTH == 1) ? (~o & stage_3) : 1'b0; 76 | always @(posedge clk) 77 | {stage_3, o, stage_2, stage_1} <= {o, stage_2, stage_1, i}; 78 | 79 | endmodule 80 | 81 | 82 | module bram_block_dp #( 83 | parameter DATA = 32, 84 | parameter ADDR = 7 85 | ) ( 86 | input wire a_clk, 87 | input wire a_wr, 88 | input wire [ADDR-1:0] a_addr, 89 | input wire [DATA-1:0] a_din, 90 | output reg [DATA-1:0] a_dout, 91 | 92 | input wire b_clk, 93 | input wire b_wr, 94 | input wire [ADDR-1:0] b_addr, 95 | input wire [DATA-1:0] b_din, 96 | output reg [DATA-1:0] b_dout 97 | ); 98 | 99 | reg [DATA-1:0] mem [(2**ADDR)-1:0]; 100 | 101 | always @(posedge a_clk) begin 102 | if(a_wr) begin 103 | a_dout <= a_din; 104 | mem[a_addr] <= a_din; 105 | end else 106 | a_dout <= mem[a_addr]; 107 | end 108 | 109 | always @(posedge b_clk) begin 110 | if(b_wr) begin 111 | b_dout <= b_din; 112 | mem[b_addr] <= b_din; 113 | end else 114 | b_dout <= mem[b_addr]; 115 | end 116 | 117 | endmodule 118 | 119 | 120 | module bram_block_dp_nonstd #( 121 | parameter DATA = 32, 122 | parameter ADDR = 7, 123 | parameter DEPTH = 128 124 | ) ( 125 | input wire a_clk, 126 | input wire a_wr, 127 | input wire [ADDR-1:0] a_addr, 128 | input wire [DATA-1:0] a_din, 129 | output reg [DATA-1:0] a_dout, 130 | 131 | input wire b_clk, 132 | input wire b_wr, 133 | input wire [ADDR-1:0] b_addr, 134 | input wire [DATA-1:0] b_din, 135 | output reg [DATA-1:0] b_dout 136 | ); 137 | 138 | reg [DATA-1:0] mem [DEPTH-1:0]; 139 | 140 | always @(posedge a_clk) begin 141 | if(a_wr) begin 142 | a_dout <= a_din; 143 | mem[a_addr] <= a_din; 144 | end else 145 | a_dout <= mem[a_addr]; 146 | end 147 | 148 | always @(posedge b_clk) begin 149 | if(b_wr) begin 150 | b_dout <= b_din; 151 | mem[b_addr] <= b_din; 152 | end else 153 | b_dout <= mem[b_addr]; 154 | end 155 | 156 | endmodule 157 | -------------------------------------------------------------------------------- /platform/pocket/mf_datatable.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name IP_TOOL_NAME "RAM: 2-PORT" 2 | set_global_assignment -name IP_TOOL_VERSION "18.1" 3 | set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{Cyclone V}" 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "mf_datatable.v"] 5 | -------------------------------------------------------------------------------- /platform/pocket/mf_ddio_bidir_12.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name IP_TOOL_NAME "ALTDDIO_BIDIR" 2 | set_global_assignment -name IP_TOOL_VERSION "18.1" 3 | set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{Cyclone V}" 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "mf_ddio_bidir_12.v"] 5 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "mf_ddio_bidir_12.ppf"] 6 | -------------------------------------------------------------------------------- /platform/pocket/mf_ddio_bidir_12.v: -------------------------------------------------------------------------------- 1 | // megafunction wizard: %ALTDDIO_BIDIR% 2 | // GENERATION: STANDARD 3 | // VERSION: WM1.0 4 | // MODULE: ALTDDIO_BIDIR 5 | 6 | // ============================================================ 7 | // File Name: mf_ddio_bidir_12.v 8 | // Megafunction Name(s): 9 | // ALTDDIO_BIDIR 10 | // 11 | // Simulation Library Files(s): 12 | // altera_mf 13 | // ============================================================ 14 | // ************************************************************ 15 | // THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! 16 | // 17 | // 18.1.1 Build 646 04/11/2019 SJ Lite Edition 18 | // ************************************************************ 19 | 20 | 21 | //Copyright (C) 2019 Intel Corporation. All rights reserved. 22 | //Your use of Intel Corporation's design tools, logic functions 23 | //and other software and tools, and any partner logic 24 | //functions, and any output files from any of the foregoing 25 | //(including device programming or simulation files), and any 26 | //associated documentation or information are expressly subject 27 | //to the terms and conditions of the Intel Program License 28 | //Subscription Agreement, the Intel Quartus Prime License Agreement, 29 | //the Intel FPGA IP License Agreement, or other applicable license 30 | //agreement, including, without limitation, that your use is for 31 | //the sole purpose of programming logic devices manufactured by 32 | //Intel and sold by Intel or its authorized distributors. Please 33 | //refer to the applicable agreement for further details, at 34 | //https://fpgasoftware.intel.com/eula. 35 | 36 | 37 | // synopsys translate_off 38 | `timescale 1 ps / 1 ps 39 | // synopsys translate_on 40 | module mf_ddio_bidir_12 ( 41 | datain_h, 42 | datain_l, 43 | inclock, 44 | oe, 45 | outclock, 46 | dataout_h, 47 | dataout_l, 48 | padio); 49 | 50 | input [11:0] datain_h; 51 | input [11:0] datain_l; 52 | input inclock; 53 | input oe; 54 | input outclock; 55 | output [11:0] dataout_h; 56 | output [11:0] dataout_l; 57 | inout [11:0] padio; 58 | 59 | wire [11:0] sub_wire0; 60 | wire [11:0] sub_wire1; 61 | wire [11:0] dataout_h = sub_wire0[11:0]; 62 | wire [11:0] dataout_l = sub_wire1[11:0]; 63 | 64 | altddio_bidir ALTDDIO_BIDIR_component ( 65 | .datain_h (datain_h), 66 | .datain_l (datain_l), 67 | .inclock (inclock), 68 | .oe (oe), 69 | .outclock (outclock), 70 | .padio (padio), 71 | .dataout_h (sub_wire0), 72 | .dataout_l (sub_wire1), 73 | .aclr (1'b0), 74 | .aset (1'b0), 75 | .combout (), 76 | .dqsundelayedout (), 77 | .inclocken (1'b1), 78 | .oe_out (), 79 | .outclocken (1'b1), 80 | .sclr (1'b0), 81 | .sset (1'b0)); 82 | defparam 83 | ALTDDIO_BIDIR_component.extend_oe_disable = "OFF", 84 | ALTDDIO_BIDIR_component.implement_input_in_lcell = "OFF", 85 | ALTDDIO_BIDIR_component.intended_device_family = "Cyclone V", 86 | ALTDDIO_BIDIR_component.invert_output = "OFF", 87 | ALTDDIO_BIDIR_component.lpm_hint = "UNUSED", 88 | ALTDDIO_BIDIR_component.lpm_type = "altddio_bidir", 89 | ALTDDIO_BIDIR_component.oe_reg = "UNREGISTERED", 90 | ALTDDIO_BIDIR_component.power_up_high = "OFF", 91 | ALTDDIO_BIDIR_component.width = 12; 92 | 93 | 94 | endmodule 95 | 96 | // ============================================================ 97 | // CNX file retrieval info 98 | // ============================================================ 99 | // Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all 100 | // Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone V" 101 | // Retrieval info: CONSTANT: EXTEND_OE_DISABLE STRING "OFF" 102 | // Retrieval info: CONSTANT: IMPLEMENT_INPUT_IN_LCELL STRING "OFF" 103 | // Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone V" 104 | // Retrieval info: CONSTANT: INVERT_OUTPUT STRING "OFF" 105 | // Retrieval info: CONSTANT: LPM_HINT STRING "UNUSED" 106 | // Retrieval info: CONSTANT: LPM_TYPE STRING "altddio_bidir" 107 | // Retrieval info: CONSTANT: OE_REG STRING "UNREGISTERED" 108 | // Retrieval info: CONSTANT: POWER_UP_HIGH STRING "OFF" 109 | // Retrieval info: CONSTANT: WIDTH NUMERIC "12" 110 | // Retrieval info: USED_PORT: datain_h 0 0 12 0 INPUT NODEFVAL "datain_h[11..0]" 111 | // Retrieval info: CONNECT: @datain_h 0 0 12 0 datain_h 0 0 12 0 112 | // Retrieval info: USED_PORT: datain_l 0 0 12 0 INPUT NODEFVAL "datain_l[11..0]" 113 | // Retrieval info: CONNECT: @datain_l 0 0 12 0 datain_l 0 0 12 0 114 | // Retrieval info: USED_PORT: dataout_h 0 0 12 0 OUTPUT NODEFVAL "dataout_h[11..0]" 115 | // Retrieval info: CONNECT: dataout_h 0 0 12 0 @dataout_h 0 0 12 0 116 | // Retrieval info: USED_PORT: dataout_l 0 0 12 0 OUTPUT NODEFVAL "dataout_l[11..0]" 117 | // Retrieval info: CONNECT: dataout_l 0 0 12 0 @dataout_l 0 0 12 0 118 | // Retrieval info: USED_PORT: inclock 0 0 0 0 INPUT_CLK_EXT NODEFVAL "inclock" 119 | // Retrieval info: CONNECT: @inclock 0 0 0 0 inclock 0 0 0 0 120 | // Retrieval info: USED_PORT: oe 0 0 0 0 INPUT NODEFVAL "oe" 121 | // Retrieval info: CONNECT: @oe 0 0 0 0 oe 0 0 0 0 122 | // Retrieval info: USED_PORT: outclock 0 0 0 0 INPUT_CLK_EXT NODEFVAL "outclock" 123 | // Retrieval info: CONNECT: @outclock 0 0 0 0 outclock 0 0 0 0 124 | // Retrieval info: USED_PORT: padio 0 0 12 0 BIDIR NODEFVAL "padio[11..0]" 125 | // Retrieval info: CONNECT: padio 0 0 12 0 @padio 0 0 12 0 126 | // Retrieval info: GEN_FILE: TYPE_NORMAL mf_ddio_bidir_12.v TRUE FALSE 127 | // Retrieval info: GEN_FILE: TYPE_NORMAL mf_ddio_bidir_12.qip TRUE FALSE 128 | // Retrieval info: GEN_FILE: TYPE_NORMAL mf_ddio_bidir_12.bsf FALSE TRUE 129 | // Retrieval info: GEN_FILE: TYPE_NORMAL mf_ddio_bidir_12_inst.v FALSE TRUE 130 | // Retrieval info: GEN_FILE: TYPE_NORMAL mf_ddio_bidir_12_bb.v FALSE TRUE 131 | // Retrieval info: GEN_FILE: TYPE_NORMAL mf_ddio_bidir_12.inc FALSE TRUE 132 | // Retrieval info: GEN_FILE: TYPE_NORMAL mf_ddio_bidir_12.cmp FALSE TRUE 133 | // Retrieval info: GEN_FILE: TYPE_NORMAL mf_ddio_bidir_12.ppf TRUE FALSE 134 | // Retrieval info: LIB_FILE: altera_mf 135 | -------------------------------------------------------------------------------- /projects/snes_pocket.qip: -------------------------------------------------------------------------------- 1 | # ============================================================================== 2 | # Quartus Prime Platform Specific Modules File 3 | # Generated by OpenGateware - Gateman CLI v0.1.0 4 | # ============================================================================== 5 | # A single file that contains paths to platform specific third-party modules. 6 | # Quartus will use this file but won't edit it. 7 | # You need to edit it manually to add/remove files here. 8 | # ============================================================================== 9 | 10 | -------------------------------------------------------------------------------- /projects/snes_pocket.qpf: -------------------------------------------------------------------------------- 1 | # ============================================================================== 2 | # Quartus Prime Project File 3 | # Generated by OpenGateware - Gateman CLI v0.1.0 4 | # ============================================================================== 5 | 6 | QUARTUS_VERSION = "18.1" 7 | DATE = "16:33:14 September 23, 2023" 8 | 9 | # Revisions 10 | 11 | PROJECT_REVISION = "snes_pocket" 12 | -------------------------------------------------------------------------------- /projects/snes_pocket.qsf: -------------------------------------------------------------------------------- 1 | # ============================================================================== 2 | # Quartus Prime Settings File 3 | # Generated by OpenGateware - Gateman CLI v0.1.0 4 | # ============================================================================== 5 | # WARNING: DO NOT ADD FILES TO THE PROJECT VIA THE QUARTUS IDE! 6 | # Add them manually to nes_pocket.qip or Quartus will overwrite this file. 7 | # ============================================================================== 8 | 9 | # ============================================================================== 10 | # Project-Wide Assignments 11 | # ============================================================================== 12 | set_global_assignment -name ORIGINAL_QUARTUS_VERSION 18.1.1 13 | set_global_assignment -name LAST_QUARTUS_VERSION "21.1.1 Lite Edition" 14 | set_global_assignment -name TOP_LEVEL_ENTITY apf_top 15 | set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top 16 | set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top 17 | set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top 18 | set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files 19 | 20 | # ============================================================================== 21 | # Compiler Assignments 22 | # ============================================================================== 23 | set_global_assignment -name OPTIMIZATION_MODE "HIGH PERFORMANCE EFFORT" 24 | set_global_assignment -name SAVE_DISK_SPACE OFF 25 | set_global_assignment -name SEED 1 26 | set_global_assignment -name SMART_RECOMPILE ON 27 | 28 | # ============================================================================== 29 | # Analysis & Synthesis Assignments 30 | # ============================================================================== 31 | set_global_assignment -name ADV_NETLIST_OPT_SYNTH_WYSIWYG_REMAP ON 32 | set_global_assignment -name MUX_RESTRUCTURE OFF 33 | set_global_assignment -name OPTIMIZATION_TECHNIQUE SPEED 34 | set_global_assignment -name PRE_MAPPING_RESYNTHESIS ON 35 | set_global_assignment -name SAFE_STATE_MACHINE ON 36 | set_global_assignment -name SYNTH_PROTECT_SDC_CONSTRAINT ON 37 | 38 | # ============================================================================== 39 | # Fitter Assignments 40 | # ============================================================================== 41 | set_global_assignment -name ACTIVE_SERIAL_CLOCK FREQ_100MHZ 42 | set_global_assignment -name CRC_ERROR_OPEN_DRAIN ON 43 | set_global_assignment -name ECO_OPTIMIZE_TIMING ON 44 | set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 256 45 | set_global_assignment -name FITTER_EFFORT "AUTO FIT" 46 | set_global_assignment -name PERIPHERY_TO_CORE_PLACEMENT_AND_ROUTING_OPTIMIZATION ON 47 | set_global_assignment -name PHYSICAL_SYNTHESIS_ASYNCHRONOUS_SIGNAL_PIPELINING ON 48 | set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC ON 49 | set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_DUPLICATION ON 50 | set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_RETIMING ON 51 | set_global_assignment -name ROUTER_CLOCKING_TOPOLOGY_ANALYSIS ON 52 | set_global_assignment -name ROUTER_LCELL_INSERTION_AND_LOGIC_DUPLICATION ON 53 | set_global_assignment -name STRATIXV_CONFIGURATION_SCHEME "PASSIVE SERIAL" 54 | 55 | # ============================================================================== 56 | # Platform/Core Assignments 57 | # ============================================================================== 58 | source ../platform/pocket/pocket.tcl 59 | set_global_assignment -name QIP_FILE snes_pocket.qip 60 | set_global_assignment -name SDC_FILE snes_pocket.sdc 61 | set_global_assignment -name QIP_FILE ../rtl/snes.qip 62 | 63 | # Default values 64 | set_parameter -name USE_CX4 '0 -entity MAIN_SNES 65 | set_parameter -name USE_SDD1 '0 -entity MAIN_SNES 66 | set_parameter -name USE_GSU '0 -entity MAIN_SNES 67 | set_parameter -name USE_SA1 '0 -entity MAIN_SNES 68 | set_parameter -name USE_DSPn '0 -entity MAIN_SNES 69 | set_parameter -name USE_SPC7110 '0 -entity MAIN_SNES 70 | set_parameter -name USE_BSX '0 -entity MAIN_SNES 71 | set_parameter -name USE_MSU '0 -entity MAIN_SNES 72 | set_parameter -name PAL_PLL '0 -entity core_top 73 | 74 | # ============================================================================== 75 | 76 | 77 | set_global_assignment -name FITTER_AGGRESSIVE_ROUTABILITY_OPTIMIZATION ALWAYS 78 | set_global_assignment -name ALM_REGISTER_PACKING_EFFORT LOW 79 | set_global_assignment -name NUM_PARALLEL_PROCESSORS 4 80 | set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top -------------------------------------------------------------------------------- /projects/snes_pocket.sdc: -------------------------------------------------------------------------------- 1 | # ============================================================================== 2 | # Quartus Prime Synopsys Design Constraint File 3 | # Generated by OpenGateware - Gateman CLI v0.1.0 4 | # ============================================================================== 5 | # pocket SDC settings 6 | # Users are recommended to modify this file to match users logic. 7 | # Put your clock groups in here as well as any net assignments. 8 | # ============================================================================== 9 | 10 | # ============================================================================== 11 | # Time Information 12 | # ============================================================================== 13 | 14 | # ============================================================================== 15 | # Create Clock 16 | # ============================================================================== 17 | 18 | # ============================================================================== 19 | # Create Generated Clock 20 | # ============================================================================== 21 | 22 | # ============================================================================== 23 | # Set Clock Latency 24 | # ============================================================================== 25 | 26 | # ============================================================================== 27 | # Set Clock Uncertainty 28 | # ============================================================================== 29 | 30 | # ============================================================================== 31 | # Set Input Delay 32 | # ============================================================================== 33 | 34 | # ============================================================================== 35 | # Set Output Delay 36 | # ============================================================================== 37 | 38 | # ============================================================================== 39 | # Set Clock Groups 40 | # ============================================================================== 41 | 42 | # ============================================================================== 43 | # Set False Path 44 | # ============================================================================== 45 | 46 | # ============================================================================== 47 | # Set Multicycle Path 48 | # ============================================================================== 49 | 50 | # ============================================================================== 51 | # Set Maximum Delay 52 | # ============================================================================== 53 | 54 | # ============================================================================== 55 | # Set Minimum Delay 56 | # ============================================================================== 57 | 58 | # ============================================================================== 59 | # Set Input Transition 60 | # ============================================================================== 61 | 62 | -------------------------------------------------------------------------------- /rtl/65C816/65C816.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) P65816_pkg.vhd ] 2 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) AddrGen.vhd ] 3 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) BCDAdder.vhd ] 4 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) AddSubBCD.vhd ] 5 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) ALU.vhd ] 6 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) MCode.vhd ] 7 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) P65C816.vhd ] 8 | -------------------------------------------------------------------------------- /rtl/65C816/ALU.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | library work; 5 | use work.P65816_pkg.all; 6 | 7 | entity ALU is 8 | port( 9 | L : in std_logic_vector(15 downto 0); 10 | R : in std_logic_vector(15 downto 0); 11 | CTRL : in ALUCtrl_r; 12 | w16 : in std_logic; 13 | BCD : in std_logic; 14 | CI : in std_logic; 15 | VI : in std_logic; 16 | SI : in std_logic; 17 | CO : out std_logic; 18 | VO : out std_logic; 19 | SO : out std_logic; 20 | ZO : out std_logic; 21 | RES : out std_logic_vector(15 downto 0); 22 | IntR : out std_logic_vector(15 downto 0) 23 | ); 24 | end ALU; 25 | 26 | architecture rtl of ALU is 27 | 28 | signal IntR16 : std_logic_vector(15 downto 0); 29 | signal IntR8 : std_logic_vector(7 downto 0); 30 | signal CR8, CR16, CR, ZR : std_logic; 31 | signal CIIn, ADDIn, BCDIn: std_logic; 32 | 33 | signal AddR : std_logic_vector(15 downto 0); 34 | signal AddCO, AddVO : std_logic; 35 | signal Result16 : std_logic_vector(15 downto 0); 36 | signal Result8 : std_logic_vector(7 downto 0); 37 | 38 | begin 39 | 40 | process(CTRL, CI, R) 41 | begin 42 | CR8 <= CI; 43 | CR16 <= CI; 44 | case CTRL.fstOp is 45 | when "000" => 46 | CR8 <= R(7); 47 | CR16 <= R(15); 48 | IntR8 <= R(6 downto 0) & "0"; 49 | IntR16 <= R(14 downto 0) & "0"; 50 | when "001"=> 51 | CR8 <= R(7); 52 | CR16 <= R(15); 53 | IntR8 <= R(6 downto 0) & CI; 54 | IntR16 <= R(14 downto 0) & CI; 55 | when "010" => 56 | CR8 <= R(0); 57 | CR16 <= R(0); 58 | IntR8 <= "0" & R(7 downto 1); 59 | IntR16 <= "0" & R(15 downto 1); 60 | when "011" => 61 | CR8 <= R(0); 62 | CR16 <= R(0); 63 | IntR8 <= CI & R(7 downto 1); 64 | IntR16 <= CI & R(15 downto 1); 65 | when "100" => 66 | IntR8 <= R(7 downto 0); 67 | IntR16 <= R; 68 | when "101" => 69 | IntR8 <= R(15 downto 8); 70 | IntR16 <= R(7 downto 0) & R(15 downto 8); 71 | when "110" => 72 | IntR8 <= std_logic_vector(unsigned(R(7 downto 0)) - 1); -- INC/DEC 73 | IntR16 <= std_logic_vector(unsigned(R) - 1); -- INC/DEC 74 | when "111" => 75 | IntR8 <= std_logic_vector(unsigned(R(7 downto 0)) + 1); -- INC/DEC 76 | IntR16 <= std_logic_vector(unsigned(R) + 1); -- INC/DEC 77 | when others => null; 78 | end case; 79 | end process; 80 | 81 | CR <= CR8 when w16 = '0' else CR16; 82 | 83 | CIIn <= CR or not CTRL.secOp(0); 84 | ADDIn <= not CTRL.secOp(2); 85 | BCDIn <= BCD and CTRL.secOp(0); 86 | 87 | AddSub: entity work.AddSubBCD 88 | port map ( 89 | A => L, 90 | B => R, 91 | CI => CIIn, 92 | ADD => ADDIn, 93 | BCD => BCDIn, 94 | w16 => w16, 95 | S => AddR, 96 | CO => AddCO, 97 | VO => AddVO 98 | ); 99 | 100 | process(CTRL, w16, CR, IntR8, IntR16, L, AddCO, AddR) 101 | variable temp8 : std_logic_vector(7 downto 0); 102 | variable temp16 : std_logic_vector(15 downto 0); 103 | begin 104 | ZR <= '0'; 105 | case CTRL.secOp is 106 | when "000" => 107 | CO <= CR; 108 | Result8 <= L(7 downto 0) or IntR8; 109 | Result16 <= L or IntR16; 110 | when "001"=> 111 | CO <= CR; 112 | Result8 <= L(7 downto 0) and IntR8; 113 | Result16 <= L and IntR16; 114 | when "010" => 115 | CO <= CR; 116 | Result8 <= L(7 downto 0) xor IntR8; 117 | Result16 <= L xor IntR16; 118 | when "011" | "110" | "111" => 119 | CO <= AddCO; 120 | Result8 <= AddR(7 downto 0); 121 | Result16 <= AddR; 122 | when "100" => 123 | CO <= CR; 124 | Result8 <= IntR8; 125 | Result16 <= IntR16; 126 | when "101" => --TRB,TSB 127 | CO <= CR; 128 | if CTRL.fc = '0' then 129 | Result8 <= IntR8 and (not L(7 downto 0)); 130 | Result16 <= IntR16 and (not L); 131 | else 132 | Result8 <= IntR8 or L(7 downto 0); 133 | Result16 <= IntR16 or L; 134 | end if; 135 | 136 | temp8 := IntR8 and L(7 downto 0); 137 | temp16 := IntR16 and L; 138 | if (temp8 = x"00" and w16 = '0') or 139 | (temp16 = x"0000" and w16 = '1') then 140 | ZR <= '1'; 141 | end if; 142 | when others => null; 143 | end case; 144 | end process; 145 | 146 | process(CTRL, w16, VI, SI, IntR8, IntR16, Result8, Result16, AddVO) 147 | begin 148 | VO <= VI; 149 | if w16 = '0' then 150 | SO <= Result8(7); 151 | else 152 | SO <= Result16(15); 153 | end if; 154 | case CTRL.secOp is 155 | when "001" => 156 | if CTRL.fc = '1' then 157 | if w16 = '0' then 158 | VO <= IntR8(6); -- Set V to 6th bit for BIT 159 | SO <= IntR8(7); 160 | else 161 | VO <= IntR16(14); -- Set V to 14th bit for BIT 162 | SO <= IntR16(15); 163 | end if; 164 | end if; 165 | when "011" => 166 | VO <= AddVO; -- ADC always sets V. 167 | when "101" => --TRB,TSB 168 | SO <= SI; 169 | when "111" => 170 | if CTRL.fc = '1' then 171 | VO <= AddVO; -- Only SBC sets V. 172 | end if; 173 | when others => null; 174 | end case; 175 | end process; 176 | 177 | 178 | ZO <= ZR when CTRL.secOp = "101" else 179 | '1' when (w16 = '0' and Result8 = x"00") or (w16 = '1' and Result16 = x"0000") else 180 | '0'; 181 | 182 | RES <= x"00"&Result8 when w16 = '0' else Result16; 183 | IntR <= x"00"&IntR8 when w16 = '0' else IntR16; 184 | 185 | end rtl; -------------------------------------------------------------------------------- /rtl/65C816/AddSubBCD.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | library work; 5 | use work.P65816_pkg.all; 6 | 7 | entity AddSubBCD is 8 | port( 9 | A : in std_logic_vector(15 downto 0); 10 | B : in std_logic_vector(15 downto 0); 11 | CI : in std_logic; 12 | ADD : in std_logic; 13 | BCD : in std_logic; 14 | w16 : in std_logic; 15 | S : out std_logic_vector(15 downto 0); 16 | CO : out std_logic; 17 | VO : out std_logic 18 | ); 19 | end AddSubBCD; 20 | 21 | architecture rtl of AddSubBCD is 22 | 23 | signal VO1, VO3 : std_logic; 24 | signal CO0, CO1, CO2, CO3 : std_logic; 25 | 26 | begin 27 | 28 | add0 : entity work.BCDAdder 29 | port map ( 30 | A => A(3 downto 0), 31 | B => B(3 downto 0), 32 | CI => CI, 33 | 34 | S => S(3 downto 0), 35 | CO => CO0, 36 | 37 | ADD => ADD, 38 | BCD => BCD 39 | ); 40 | 41 | add1 : entity work.BCDAdder 42 | port map ( 43 | A => A(7 downto 4), 44 | B => B(7 downto 4), 45 | CI => CO0, 46 | 47 | S => S(7 downto 4), 48 | CO => CO1, 49 | VO => VO1, 50 | 51 | ADD => ADD, 52 | BCD => BCD 53 | ); 54 | 55 | add2 : entity work.BCDAdder 56 | port map ( 57 | A => A(11 downto 8), 58 | B => B(11 downto 8), 59 | CI => CO1, 60 | 61 | S => S(11 downto 8), 62 | CO => CO2, 63 | 64 | ADD => ADD, 65 | BCD => BCD 66 | ); 67 | 68 | add3 : entity work.BCDAdder 69 | port map ( 70 | A => A(15 downto 12), 71 | B => B(15 downto 12), 72 | CI => CO2, 73 | 74 | S => S(15 downto 12), 75 | CO => CO3, 76 | VO => VO3, 77 | 78 | ADD => ADD, 79 | BCD => BCD 80 | ); 81 | 82 | 83 | VO <= VO1 when w16 = '0' else VO3; 84 | CO <= CO1 when w16 = '0' else CO3; 85 | 86 | end rtl; -------------------------------------------------------------------------------- /rtl/65C816/BCDAdder.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.STD_LOGIC_1164.ALL; 3 | library STD; 4 | use IEEE.NUMERIC_STD.ALL; 5 | library work; 6 | 7 | entity bit_adder is 8 | port( 9 | A : in std_logic; 10 | B : in std_logic; 11 | CI : in std_logic; 12 | S : out std_logic; 13 | CO : out std_logic 14 | ); 15 | end bit_adder; 16 | 17 | architecture rtl of bit_adder is 18 | 19 | begin 20 | 21 | S <= (not A and not B and CI) or 22 | (not A and B and not CI) or 23 | ( A and not B and not CI) or 24 | ( A and B and CI); 25 | 26 | CO <= (not A and B and CI) or 27 | ( A and not B and CI) or 28 | ( A and B and not CI) or 29 | ( A and B and CI); 30 | 31 | end rtl; 32 | 33 | 34 | 35 | library IEEE; 36 | use IEEE.STD_LOGIC_1164.ALL; 37 | library STD; 38 | use IEEE.NUMERIC_STD.ALL; 39 | library work; 40 | 41 | entity adder4 is 42 | port( 43 | A : in std_logic_vector(3 downto 0); 44 | B : in std_logic_vector(3 downto 0); 45 | CI : in std_logic; 46 | S : out std_logic_vector(3 downto 0); 47 | CO : out std_logic 48 | ); 49 | end adder4; 50 | 51 | architecture rtl of adder4 is 52 | 53 | component bit_adder is 54 | port( 55 | A : in std_logic; 56 | B : in std_logic; 57 | CI : in std_logic; 58 | S : out std_logic; 59 | CO : out std_logic 60 | ); 61 | end component; 62 | 63 | signal CO0, CO1, CO2 : std_logic; 64 | 65 | begin 66 | 67 | b_add0: bit_adder port map (A(0), B(0), CI, S(0), CO0); 68 | b_add1: bit_adder port map (A(1), B(1), CO0, S(1), CO1); 69 | b_add2: bit_adder port map (A(2), B(2), CO1, S(2), CO2); 70 | b_add3: bit_adder port map (A(3), B(3), CO2, S(3), CO); 71 | 72 | end rtl; 73 | 74 | 75 | library IEEE; 76 | use IEEE.STD_LOGIC_1164.ALL; 77 | library STD; 78 | use IEEE.NUMERIC_STD.ALL; 79 | library work; 80 | 81 | entity BCDAdder is 82 | port( 83 | A : in std_logic_vector(3 downto 0); 84 | B : in std_logic_vector(3 downto 0); 85 | CI : in std_logic; 86 | 87 | S : out std_logic_vector(3 downto 0); 88 | CO : out std_logic; 89 | VO : out std_logic; 90 | 91 | ADD : in std_logic; 92 | BCD : in std_logic 93 | ); 94 | end BCDAdder; 95 | 96 | architecture rtl of BCDAdder is 97 | 98 | signal B2 : std_logic_vector(3 downto 0); 99 | signal BIN_S : std_logic_vector(3 downto 0); 100 | signal BIN_CO : std_logic; 101 | signal BCD_B : std_logic_vector(3 downto 0); 102 | signal BCD_CO : std_logic; 103 | 104 | begin 105 | 106 | B2 <= B xor (3 downto 0 => not ADD); 107 | 108 | bin_adder : entity work.adder4 109 | port map( 110 | A => A, 111 | B => B2, 112 | CI => CI, 113 | S => BIN_S, 114 | CO => BIN_CO 115 | ); 116 | 117 | 118 | BCD_CO <= (((BIN_S(3) and BIN_S(2)) or (BIN_S(3) and BIN_S(1))) and ADD) or (not (BIN_CO xor ADD)); 119 | BCD_B <= not ADD & ((BCD_CO and BCD) xor not ADD) & ((BCD_CO and BCD) xor not ADD) & not ADD; 120 | 121 | bcd_corr_adder : entity work.adder4 122 | port map( 123 | A => BIN_S, 124 | B => BCD_B, 125 | CI => not ADD, 126 | S => S 127 | ); 128 | 129 | CO <= BIN_CO when BCD = '0' else BCD_CO xor not ADD; 130 | VO <= (not (A(3) xor B2(3))) and (A(3) xor BIN_S(3)); 131 | 132 | end rtl; 133 | -------------------------------------------------------------------------------- /rtl/65C816/P65816_pkg.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | 5 | package P65816_pkg is 6 | 7 | type MicroInst_r is record 8 | stateCtrl : std_logic_vector(2 downto 0); 9 | addrBus : std_logic_vector(2 downto 0); 10 | addrInc : std_logic_vector(1 downto 0); 11 | loadP : std_logic_vector(2 downto 0); 12 | loadT : std_logic_vector(1 downto 0); 13 | muxCtrl : std_logic_vector(1 downto 0); 14 | addrCtrl : std_logic_vector(7 downto 0); 15 | loadPC : std_logic_vector(2 downto 0); 16 | loadSP : std_logic_vector(2 downto 0); 17 | regAXY : std_logic_vector(2 downto 0); 18 | loadDKB : std_logic_vector(1 downto 0); 19 | busCtrl : std_logic_vector(5 downto 0); 20 | ALUCtrl : std_logic_vector(4 downto 0); 21 | byteSel : std_logic_vector(1 downto 0); 22 | outBus : std_logic_vector(2 downto 0); 23 | va : std_logic_vector(1 downto 0); 24 | end record; 25 | 26 | type ALUCtrl_r is record 27 | fstOp : std_logic_vector(2 downto 0); 28 | secOp : std_logic_vector(2 downto 0); 29 | fc : std_logic; 30 | w16 : std_logic; 31 | end record; 32 | 33 | type MCode_r is record 34 | ALU_CTRL : ALUCtrl_r; 35 | STATE_CTRL : std_logic_vector(2 downto 0); 36 | ADDR_BUS : std_logic_vector(2 downto 0); 37 | ADDR_INC : std_logic_vector(1 downto 0); 38 | IND_CTRL : std_logic_vector(1 downto 0); 39 | ADDR_CTRL : std_logic_vector(7 downto 0); 40 | LOAD_PC : std_logic_vector(2 downto 0); 41 | LOAD_SP : std_logic_vector(2 downto 0); 42 | LOAD_AXY : std_logic_vector(2 downto 0); 43 | LOAD_P : std_logic_vector(2 downto 0); 44 | LOAD_T : std_logic_vector(1 downto 0); 45 | LOAD_DKB : std_logic_vector(1 downto 0); 46 | BUS_CTRL : std_logic_vector(5 downto 0); 47 | BYTE_SEL : std_logic_vector(1 downto 0); 48 | OUT_BUS : std_logic_vector(2 downto 0); 49 | VA : std_logic_vector(1 downto 0); 50 | end record; 51 | 52 | type addrIncTab_t is array(0 to 3) of unsigned(15 downto 0); 53 | constant INC_TAB: addrIncTab_t := (x"0000", x"0001", x"0002", x"0003"); 54 | 55 | end P65816_pkg; 56 | 57 | package body P65816_pkg is 58 | 59 | 60 | end package body P65816_pkg; 61 | -------------------------------------------------------------------------------- /rtl/CEGen.vhd: -------------------------------------------------------------------------------- 1 | LIBRARY ieee; 2 | USE ieee.std_logic_1164.all; 3 | 4 | ENTITY CEGen IS 5 | PORT 6 | ( 7 | CLK : in STD_LOGIC; 8 | RST_N : in STD_LOGIC; 9 | 10 | IN_CLK : in integer; 11 | OUT_CLK : in integer; 12 | 13 | CE : out STD_LOGIC 14 | ); 15 | END CEGen; 16 | 17 | ARCHITECTURE SYN OF CEGen IS 18 | BEGIN 19 | process( RST_N, CLK ) 20 | variable CLK_SUM : integer; 21 | begin 22 | if RST_N = '0' then 23 | CLK_SUM := 0; 24 | CE <= '0'; 25 | elsif falling_edge(CLK) then 26 | CE <= '0'; 27 | CLK_SUM := CLK_SUM + OUT_CLK; 28 | if CLK_SUM >= IN_CLK then 29 | CLK_SUM := CLK_SUM - IN_CLK; 30 | CE <= '1'; 31 | end if; 32 | end if; 33 | end process; 34 | END SYN; 35 | -------------------------------------------------------------------------------- /rtl/SPC700/ALU.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | library work; 5 | use work.SPC700_pkg.all; 6 | 7 | entity SPC700_ALU is 8 | port( 9 | CLK : in std_logic; 10 | RST_N : in std_logic; 11 | EN : in std_logic; 12 | L : in std_logic_vector(7 downto 0); 13 | R : in std_logic_vector(7 downto 0); 14 | CTRL : in ALUCtrl_r; 15 | CI : in std_logic; 16 | VI : in std_logic; 17 | SI : in std_logic; 18 | ZI : in std_logic; 19 | HI : in std_logic; 20 | DivZI : in std_logic; 21 | DivVI : in std_logic; 22 | DivHI : in std_logic; 23 | DivSI : in std_logic; 24 | CO : out std_logic; 25 | VO : out std_logic; 26 | SO : out std_logic; 27 | ZO : out std_logic; 28 | HO : out std_logic; 29 | RES : out std_logic_vector(7 downto 0) 30 | ); 31 | end SPC700_ALU; 32 | 33 | architecture rtl of SPC700_ALU is 34 | 35 | signal tIntR : std_logic_vector(7 downto 0); 36 | signal CR, COut, HOut, VOut, SOut, tZ, SaveC : std_logic; 37 | signal CIIn, ADDIn: std_logic; 38 | 39 | signal AddR, BCDR : std_logic_vector(7 downto 0); 40 | signal AddCO, AddVO, AddHO : std_logic; 41 | signal BCDCO : std_logic; 42 | signal tResult : std_logic_vector(7 downto 0); 43 | 44 | begin 45 | 46 | process(CTRL, CI, R) 47 | begin 48 | CR <= CI; 49 | case CTRL.fstOp is 50 | when "000" => 51 | CR <= R(7); 52 | tIntR <= R(6 downto 0) & "0"; 53 | when "001"=> 54 | CR <= R(7); 55 | tIntR <= R(6 downto 0) & CI; 56 | when "010" => 57 | CR <= R(0); 58 | tIntR <= "0" & R(7 downto 1); 59 | when "011" => 60 | CR <= R(0); 61 | tIntR <= CI & R(7 downto 1); 62 | when "100" => 63 | tIntR <= x"00"; 64 | when "101" => --INC,DEC 65 | tIntR <= x"01"; 66 | when "110" => 67 | tIntR <= R; 68 | when "111" => 69 | tIntR <= not R; 70 | when others => null; 71 | end case; 72 | end process; 73 | 74 | process(CLK, RST_N) 75 | begin 76 | if RST_N = '0' then 77 | SaveC <= '0'; 78 | elsif rising_edge(CLK) then 79 | if EN = '1' then 80 | if CTRL.secOp(3) = '1' then 81 | SaveC <= AddCO; 82 | end if; 83 | end if; 84 | end if; 85 | end process; 86 | 87 | CIIn <= SaveC when CTRL.intC = '1' else 88 | CI when CTRL.secOp(0) = '0' else 89 | CTRL.secOp(1); 90 | 91 | ADDIn <= not CTRL.secOp(1); 92 | 93 | AddSub: entity work.SPC700_AddSub 94 | port map ( 95 | A => L, 96 | B => tIntR, 97 | CI => CIIn, 98 | ADD => ADDIn, 99 | S => AddR, 100 | CO => AddCO, 101 | VO => AddVO, 102 | HO => AddHO 103 | ); 104 | 105 | BCD: entity work.SPC700_BCDAdj 106 | port map ( 107 | A => L, 108 | ADD => CTRL.secOp(0), 109 | CI => CI, 110 | HI => HI, 111 | R => BCDR, 112 | CO => BCDCO 113 | ); 114 | 115 | process(CTRL, CR, tIntR, L, AddCO, AddHO, BCDCO, AddR, BCDR, DivHI) 116 | begin 117 | HOut <= '0'; 118 | COut <= CR; 119 | case CTRL.secOp is 120 | when "0000" => 121 | tResult <= L or tIntR; 122 | when "0001"=> 123 | tResult <= L and tIntR; 124 | when "0010" => 125 | tResult <= L xor tIntR; 126 | when "0011" => 127 | tResult <= tIntR; 128 | when "0100" => --TCLR1 129 | tResult <= tIntR and (not L); 130 | when "0101" => --TSET1 131 | tResult <= tIntR or L; 132 | when "0110" => --XCN 133 | tResult <= tIntR(3 downto 0) & tIntR(7 downto 4); 134 | when "1000" | "1010" | "1001" | "1011" => --ADC,SBC, ADD,SUB 135 | tResult <= AddR; 136 | COut <= AddCO; 137 | HOut <= AddHO; 138 | when "1100" | "1101" => --DAA,DAS 139 | tResult <= BCDR; 140 | COut <= BCDCO; 141 | when "1110" => --MUL 142 | tResult <= tIntR; 143 | when "1111" => --DIV 144 | tResult <= tIntR; 145 | HOut <= DivHI; 146 | when others => 147 | tResult <= x"00"; 148 | end case; 149 | end process; 150 | 151 | process(CTRL, VI, AddVO, DivVI) 152 | begin 153 | VOut <= VI; 154 | case CTRL.secOp is 155 | when "1000" | "1001" => --ADC,ADD 156 | VOut <= AddVO; 157 | when "1010" | "1011" => --SBC,SUB 158 | VOut <= AddVO; 159 | when "1111" => --DIV 160 | VOut <= DivVI; 161 | when others => null; 162 | end case; 163 | end process; 164 | 165 | process(CTRL, SI, tResult, DivSI) 166 | begin 167 | SOut <= SI; 168 | case CTRL.secOp is 169 | when "1110" => --MUL 170 | SOut <= DivSI; 171 | when "1111" => --DIV 172 | SOut <= DivSI; 173 | when others => 174 | SOut <= tResult(7); 175 | end case; 176 | end process; 177 | 178 | tZ <= DivZI when CTRL.secOp(3 downto 1) = "111" else 179 | '1' when tResult = x"00" else '0'; 180 | ZO <= ZI and tZ when CTRL.w = '1' else tZ; 181 | CO <= COut when CTRL.chgCO = '1' else CI; 182 | VO <= VOut when CTRL.chgVO = '1' else VI; 183 | HO <= HOut when CTRL.chgHO = '1' else HI; 184 | SO <= SOut; 185 | 186 | RES <= tResult; 187 | 188 | end rtl; -------------------------------------------------------------------------------- /rtl/SPC700/AddSub.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | library work; 5 | use work.SPC700_pkg.all; 6 | 7 | entity SPC700_AddSub is 8 | port( 9 | A : in std_logic_vector(7 downto 0); 10 | B : in std_logic_vector(7 downto 0); 11 | CI : in std_logic; 12 | ADD : in std_logic; 13 | S : out std_logic_vector(7 downto 0); 14 | CO : out std_logic; 15 | VO : out std_logic; 16 | HO : out std_logic 17 | ); 18 | end SPC700_AddSub; 19 | 20 | architecture rtl of SPC700_AddSub is 21 | 22 | signal tempB : std_logic_vector(7 downto 0); 23 | signal res : unsigned(7 downto 0); 24 | signal C7 : std_logic; 25 | 26 | begin 27 | 28 | tempB <= B when ADD = '1' else B xor x"FF"; 29 | 30 | process(A, tempB, CI, ADD) 31 | variable temp0, temp1 : unsigned(4 downto 0); 32 | begin 33 | temp0 := ('0' & unsigned(A(3 downto 0))) + ('0' & unsigned(tempB(3 downto 0))) + ("0000" & CI); 34 | temp1 := ('0' & unsigned(A(7 downto 4))) + ('0' & unsigned(tempB(7 downto 4))) + ("0000" & temp0(4)); 35 | 36 | res <= temp1(3 downto 0) & temp0(3 downto 0); 37 | C7 <= temp1(4); 38 | end process; 39 | 40 | S <= std_logic_vector(res); 41 | VO <= (not (A(7) xor tempB(7))) and (A(7) xor res(7)); 42 | HO <= (A(4) xor B(4) xor res(4)) xor not ADD; 43 | CO <= C7; 44 | 45 | end rtl; -------------------------------------------------------------------------------- /rtl/SPC700/AddrGen.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | library work; 5 | use work.SPC700_pkg.all; 6 | 7 | entity SPC700_AddrGen is 8 | port( 9 | CLK : in std_logic; 10 | RST_N : in std_logic; 11 | EN : in std_logic; 12 | ADDR_CTRL : in std_logic_vector(5 downto 0); 13 | LOAD_PC : in std_logic_vector(2 downto 0); 14 | GotInterrupt : in std_logic; 15 | D_IN : in std_logic_vector(7 downto 0); 16 | X : in std_logic_vector(7 downto 0); 17 | Y : in std_logic_vector(7 downto 0); 18 | S : in std_logic_vector(7 downto 0); 19 | T : in std_logic_vector(7 downto 0); 20 | P : in std_logic; 21 | PC : out std_logic_vector(15 downto 0); 22 | AX : out std_logic_vector(15 downto 0); 23 | ALCarry : out std_logic; 24 | 25 | REG_DAT : in std_logic_vector(15 downto 0); 26 | REG_SET : in std_logic 27 | ); 28 | end SPC700_AddrGen; 29 | 30 | architecture rtl of SPC700_AddrGen is 31 | 32 | signal AL, AH : std_logic_vector(7 downto 0); 33 | signal SavedCarry : std_logic; 34 | 35 | signal NewAL, NewAH : std_logic_vector(8 downto 0); 36 | signal NewAHWithCarry : std_logic_vector(7 downto 0); 37 | signal NextAX : std_logic_vector(15 downto 0); 38 | 39 | signal DR : std_logic_vector(7 downto 0); 40 | signal PCr: std_logic_vector(15 downto 0); 41 | signal NextPC, NewPCWithOffset: std_logic_vector(15 downto 0); 42 | 43 | signal ALCtrl : std_logic_vector(1 downto 0); 44 | signal AHCtrl : std_logic_vector(1 downto 0); 45 | signal MuxCtrl : std_logic_vector(1 downto 0); 46 | 47 | begin 48 | 49 | ALCtrl <= ADDR_CTRL(5 downto 4); 50 | AHCtrl <= ADDR_CTRL(3 downto 2); 51 | MuxCtrl <= ADDR_CTRL(1 downto 0); 52 | 53 | NewPCWithOffset <= std_logic_vector(unsigned(PCr) + unsigned((7 downto 0 => DR(7)) & DR)); 54 | 55 | process(LOAD_PC, PCr, D_IN, DR, NewPCWithOffset, AL, AH, GotInterrupt) 56 | begin 57 | case LOAD_PC is 58 | when "000" => 59 | NextPC <= PCr; 60 | when "001" => 61 | if GotInterrupt = '0' then 62 | NextPC <= std_logic_vector(unsigned(PCr) + 1); 63 | else 64 | NextPC <= PCr; 65 | end if; 66 | when "010"=> 67 | NextPC <= D_IN & DR; 68 | when "011" => 69 | NextPC <= NewPCWithOffset; 70 | when "100" => 71 | NextPC <= AH & AL; 72 | when "101" => 73 | NextPC <= x"FF" & AL; 74 | when others => 75 | NextPC <= PCr; 76 | end case; 77 | end process; 78 | 79 | process(CLK, RST_N) 80 | begin 81 | if RST_N = '0' then 82 | PCr <= (others=>'0'); 83 | DR <= (others=>'0'); 84 | elsif rising_edge(CLK) then 85 | if REG_SET = '1' then 86 | PCr <= REG_DAT; 87 | elsif EN = '0' then 88 | 89 | else 90 | DR <= D_IN; 91 | PCr <= NextPC; 92 | end if; 93 | end if; 94 | end process; 95 | 96 | 97 | process(MuxCtrl, AL, X, Y, DR) 98 | begin 99 | case MuxCtrl is 100 | when "00" => 101 | NewAL <= std_logic_vector(unsigned("0" & AL) + unsigned("0" & X)); 102 | when "01" => 103 | NewAL <= std_logic_vector(unsigned("0" & AL) + unsigned("0" & Y)); 104 | when "10"=> 105 | NewAL <= "0" & DR; 106 | when "11" => 107 | NewAL <= std_logic_vector(unsigned("0" & DR) + unsigned("0" & Y)); 108 | when others => null; 109 | end case; 110 | end process; 111 | 112 | NewAHWithCarry <= std_logic_vector(unsigned(AH) + ("0000000"&SavedCarry)); 113 | NextAX <= std_logic_vector((unsigned(AH) & unsigned(AL)) + 1); 114 | 115 | process(CLK, RST_N) 116 | begin 117 | if RST_N = '0' then 118 | AL <= (others=>'0'); 119 | AH <= (others=>'0'); 120 | SavedCarry <= '0'; 121 | elsif rising_edge(CLK) then 122 | if EN = '1' then 123 | case ALCtrl is 124 | when "00" => SavedCarry <= '0'; 125 | when "01" => AL <= NewAL(7 downto 0); SavedCarry <= NewAL(8); 126 | when "10" => 127 | case MuxCtrl is 128 | when "00" => AL <= D_IN; 129 | when "01" => AL <= X; 130 | when "10" => AL <= Y; 131 | when others => null; 132 | end case; 133 | SavedCarry <= '0'; 134 | when "11" => AL <= std_logic_vector(NextAX(7 downto 0)); SavedCarry <= '0'; 135 | when others => null; 136 | end case; 137 | 138 | case AHCtrl is 139 | when "00" => null; 140 | when "01" => AH <= "0000000"&P; 141 | when "10" => AH <= D_IN; 142 | when "11" => 143 | if ALCtrl /= "11" then 144 | AH <= NewAHWithCarry; 145 | else 146 | AH <= std_logic_vector(NextAX(15 downto 8)); 147 | end if; 148 | when others => null; 149 | end case; 150 | 151 | end if; 152 | end if; 153 | end process; 154 | 155 | ALCarry <= NewAL(8); 156 | AX <= AH & AL; 157 | PC <= PCr; 158 | 159 | end rtl; -------------------------------------------------------------------------------- /rtl/SPC700/BCDAdj.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | library work; 5 | use work.SPC700_pkg.all; 6 | 7 | entity SPC700_BCDAdj is 8 | port( 9 | A : in std_logic_vector(7 downto 0); 10 | ADD : in std_logic; 11 | CI : in std_logic; 12 | HI : in std_logic; 13 | R : out std_logic_vector(7 downto 0); 14 | CO : out std_logic 15 | ); 16 | end SPC700_BCDAdj; 17 | 18 | architecture rtl of SPC700_BCDAdj is 19 | 20 | signal res : unsigned(7 downto 0); 21 | signal tempC : std_logic; 22 | 23 | begin 24 | 25 | process(A, CI, HI, ADD) 26 | variable temp0, temp1 : unsigned(7 downto 0); 27 | begin 28 | temp0 := unsigned(A); 29 | tempC <= CI; 30 | 31 | temp1 := temp0; 32 | if CI = not ADD or temp0 > x"99" then 33 | if ADD = '0' then 34 | temp1 := temp0 + x"60"; 35 | else 36 | temp1 := temp0 - x"60"; 37 | end if; 38 | tempC <= not ADD; 39 | end if; 40 | 41 | res <= temp1; 42 | if HI = not ADD or temp1(3 downto 0) > x"9" then 43 | if ADD = '0' then 44 | res <= temp1 + x"06"; 45 | else 46 | res <= temp1 - x"06"; 47 | end if; 48 | end if; 49 | end process; 50 | 51 | R <= std_logic_vector(res); 52 | CO <= tempC; 53 | 54 | end rtl; -------------------------------------------------------------------------------- /rtl/SPC700/MulDiv.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.std_logic_1164.all; 3 | use ieee.numeric_std.all; 4 | library work; 5 | use work.SPC700_pkg.all; 6 | 7 | 8 | entity MulDiv is 9 | port( 10 | CLK : in std_logic; 11 | RST_N : in std_logic; 12 | EN : in std_logic; 13 | CTRL : in ALUCtrl_r; 14 | A : in std_logic_vector(7 downto 0); 15 | X : in std_logic_vector(7 downto 0); 16 | Y : in std_logic_vector(7 downto 0); 17 | RES : out std_logic_vector(15 downto 0); 18 | ZO : out std_logic; 19 | VO : out std_logic; 20 | HO : out std_logic; 21 | SO : out std_logic 22 | ); 23 | end MulDiv; 24 | 25 | architecture rtl of MulDiv is 26 | 27 | signal tResult : std_logic_vector(15 downto 0); 28 | signal tV, tZ, tS : std_logic; 29 | signal mulRes, mulTemp : unsigned(15 downto 0); 30 | signal mulA : unsigned(15 downto 0); 31 | signal mulY : unsigned(7 downto 0); 32 | signal divt : unsigned(15 downto 0); 33 | signal quotient : unsigned(8 downto 0); 34 | signal remainder : unsigned(15 downto 0); 35 | 36 | begin 37 | 38 | process(CLK, RST_N) 39 | begin 40 | if RST_N = '0' then 41 | mulA <= (others=>'0'); 42 | mulY <= (others=>'0'); 43 | mulRes <= (others=>'0'); 44 | divt <= (others=>'0'); 45 | remainder <= (others=>'0'); 46 | quotient <= (others=>'0'); 47 | elsif rising_edge(CLK) then 48 | if EN = '1' then 49 | if CTRL.secOp = "1110" then 50 | mulRes <= mulTemp; 51 | mulA <= mulA(14 downto 0) & "0"; 52 | mulY <= "0" & mulY(7 downto 1); 53 | elsif CTRL.secOp = "1111" then 54 | if remainder >= divt then 55 | remainder <= remainder - divt; 56 | quotient <= quotient(7 downto 0) & "1"; 57 | else 58 | quotient <= quotient(7 downto 0) & "0"; 59 | end if; 60 | divt <= "0" & divt(15 downto 1); 61 | else 62 | mulA <= unsigned("00000000" & A); 63 | mulY <= unsigned(Y); 64 | mulRes <= (others=>'0'); 65 | divt <= unsigned(X & "00000000"); 66 | remainder <= unsigned(Y & A); 67 | quotient <= (others=>'0'); 68 | end if; 69 | end if; 70 | end if; 71 | end process; 72 | 73 | process(CTRL, mulA, mulY, mulRes, mulTemp, quotient, remainder) 74 | begin 75 | mulTemp <= (others=>'0'); 76 | if CTRL.secOp = "1110" then 77 | if mulY(0) = '1' then 78 | mulTemp <= mulRes + mulA; 79 | else 80 | mulTemp <= mulRes; 81 | end if; 82 | tResult <= std_logic_vector(mulTemp); 83 | if mulTemp(15 downto 8) = 0 then 84 | tZ <= '1'; 85 | else 86 | tZ <= '0'; 87 | end if; 88 | tV <= '0'; 89 | tS <= mulTemp(15); 90 | elsif CTRL.secOp = "1111" then 91 | tResult <= std_logic_vector(remainder(7 downto 0) & quotient(7 downto 0)); 92 | if quotient(7 downto 0) = 0 then 93 | tZ <= '1'; 94 | else 95 | tZ <= '0'; 96 | end if; 97 | tV <= quotient(8); 98 | tS <= quotient(7); 99 | else 100 | tResult <= (others=>'0'); 101 | tZ <= '0'; 102 | tV <= '0'; 103 | tS <= '0'; 104 | end if; 105 | end process; 106 | 107 | RES <= tResult; 108 | ZO <= tZ; 109 | VO <= tV; 110 | SO <= tS; 111 | HO <= '1' when Y(3 downto 0) >= X(3 downto 0) else '0'; 112 | 113 | end rtl; -------------------------------------------------------------------------------- /rtl/SPC700/SPC700.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) SPC700_pkg.vhd ] 2 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) AddrGen.vhd ] 3 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) AddSub.vhd ] 4 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) ALU.vhd ] 5 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) BCDAdj.vhd ] 6 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) MCode.vhd ] 7 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) MulDiv.vhd ] 8 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) SPC700.vhd ] 9 | -------------------------------------------------------------------------------- /rtl/SPC700/SPC700_pkg.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.Std_Logic_1164.all; 3 | 4 | package SPC700_pkg is 5 | 6 | type MicroInst_r is record 7 | stateCtrl : std_logic_vector(1 downto 0); 8 | addrBus : std_logic_vector(1 downto 0); 9 | addrCtrl : std_logic_vector(5 downto 0); 10 | regMode : std_logic_vector(4 downto 0); 11 | regAXY : std_logic_vector(1 downto 0); 12 | busCtrl : std_logic_vector(5 downto 0); 13 | ALUCtrl : std_logic_vector(5 downto 0); 14 | outBus : std_logic_vector(2 downto 0); 15 | end record; 16 | 17 | type ALUCtrl_r is record 18 | fstOp : std_logic_vector(2 downto 0); 19 | secOp : std_logic_vector(3 downto 0); 20 | chgVO : std_logic; 21 | chgHO : std_logic; 22 | intC : std_logic; 23 | chgCO : std_logic; 24 | w : std_logic; 25 | end record; 26 | 27 | type RegCtrl_r is record 28 | loadPC : std_logic_vector(2 downto 0); 29 | loadSP : std_logic_vector(1 downto 0); 30 | loadP : std_logic_vector(2 downto 0); 31 | loadT : std_logic_vector(1 downto 0); 32 | end record; 33 | 34 | type MCode_r is record 35 | ALU_CTRL : ALUCtrl_r; 36 | STATE_CTRL : std_logic_vector(1 downto 0); 37 | ADDR_BUS : std_logic_vector(1 downto 0); 38 | ADDR_CTRL : std_logic_vector(5 downto 0); 39 | LOAD_PC : std_logic_vector(2 downto 0); 40 | LOAD_SP : std_logic_vector(1 downto 0); 41 | LOAD_AXY : std_logic_vector(1 downto 0); 42 | LOAD_P : std_logic_vector(2 downto 0); 43 | LOAD_T : std_logic_vector(1 downto 0); 44 | BUS_CTRL : std_logic_vector(5 downto 0); 45 | OUT_BUS : std_logic_vector(2 downto 0); 46 | end record; 47 | 48 | end SPC700_pkg; 49 | 50 | package body SPC700_pkg is 51 | 52 | 53 | end package body SPC700_pkg; 54 | -------------------------------------------------------------------------------- /rtl/SWRAM.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.STD_LOGIC_1164.ALL; 3 | library STD; 4 | use IEEE.NUMERIC_STD.ALL; 5 | 6 | entity SWRAM is 7 | port( 8 | CLK : in std_logic; 9 | SYSCLK_CE : in std_logic; 10 | RST_N : in std_logic; 11 | ENABLE : in std_logic; 12 | 13 | CA : in std_logic_vector(23 downto 0); 14 | CPURD_N : in std_logic; 15 | CPUWR_N : in std_logic; 16 | RAMSEL_N : in std_logic; 17 | 18 | PA : in std_logic_vector(7 downto 0); 19 | PARD_N : in std_logic; 20 | PAWR_N : in std_logic; 21 | 22 | DI : in std_logic_vector(7 downto 0); 23 | DO : out std_logic_vector(7 downto 0); 24 | 25 | RAM_A : out std_logic_vector(16 downto 0); 26 | RAM_D : out std_logic_vector(7 downto 0); 27 | RAM_Q : in std_logic_vector(7 downto 0); 28 | RAM_WE_N : out std_logic; 29 | RAM_CE_N : out std_logic; 30 | RAM_OE_N : out std_logic 31 | ); 32 | end SWRAM; 33 | 34 | architecture rtl of SWRAM is 35 | 36 | signal WMADD : std_logic_vector(23 downto 0); 37 | 38 | begin 39 | 40 | process( RST_N, CLK ) 41 | begin 42 | if RST_N = '0' then 43 | WMADD <= (others => '0'); 44 | elsif rising_edge(CLK) then 45 | if ENABLE = '1' and SYSCLK_CE = '1' then 46 | if PAWR_N = '0' then 47 | case PA is 48 | when x"80" => 49 | if RAMSEL_N = '1' then --check if DMA use WRAM in ABUS 50 | WMADD <= std_logic_vector(unsigned(WMADD) + 1); 51 | end if; 52 | when x"81" => 53 | WMADD(7 downto 0) <= DI; 54 | when x"82" => 55 | WMADD(15 downto 8) <= DI; 56 | when x"83" => 57 | WMADD(23 downto 16) <= DI; 58 | when others => null; 59 | end case; 60 | elsif PARD_N = '0' then 61 | case PA is 62 | when x"80" => 63 | if RAMSEL_N = '1' then --check if DMA use WRAM in ABUS 64 | WMADD <= std_logic_vector(unsigned(WMADD) + 1); 65 | end if; 66 | when others => null; 67 | end case; 68 | end if; 69 | end if; 70 | end if; 71 | end process; 72 | 73 | DO <= RAM_Q; 74 | RAM_D <= x"FF" when PA = x"80" and RAMSEL_N = '0' else DI; 75 | 76 | RAM_A <= CA(16 downto 0) when RAMSEL_N = '0' else 77 | WMADD(16 downto 0); 78 | 79 | RAM_CE_N <= '0' when ENABLE = '0' else 80 | '0' when RAMSEL_N = '0' else 81 | '0' when PA = x"80" else 82 | '1'; 83 | 84 | RAM_OE_N <= '0' when ENABLE = '0' else 85 | '0' when RAMSEL_N = '0' and CPURD_N = '0' else 86 | '0' when PA = x"80" and PARD_N = '0' and RAMSEL_N = '1' else 87 | '1'; 88 | 89 | RAM_WE_N <= '1' when ENABLE = '0' else 90 | '0' when RAMSEL_N = '0' and CPUWR_N = '0' else 91 | '0' when PA = x"80" and PAWR_N = '0' and RAMSEL_N = '1' else 92 | '1'; 93 | 94 | end rtl; 95 | 96 | -------------------------------------------------------------------------------- /rtl/cheatcodes.sv: -------------------------------------------------------------------------------- 1 | // Cheat Code handling by Kitrinx 2 | // Apr 21, 2019 3 | 4 | // Code layout: 5 | // {clock bit, code flags, 32'b address, 32'b compare, 32'b replace} 6 | // 128 127:96 95:64 63:32 31:0 7 | // Integer values are in BIG endian byte order, so it up to the loader 8 | // or generator of the code to re-arrange them correctly. 9 | 10 | module CODES( 11 | input clk, // Best to not make it too high speed for timing reasons 12 | input reset, // This should only be triggered when a new rom is loaded or before new codes load, not warm reset 13 | input enable, 14 | output available, 15 | input [ADDR_WIDTH - 1:0] addr_in, 16 | input [DATA_WIDTH - 1:0] data_in, 17 | input [128:0] code, 18 | output genie_ovr, 19 | output [DATA_WIDTH - 1:0] genie_data 20 | ); 21 | 22 | parameter ADDR_WIDTH = 16; // Not more than 32 23 | parameter DATA_WIDTH = 8; // Not more than 32 24 | parameter MAX_CODES = 32; 25 | 26 | localparam INDEX_SIZE = $clog2(MAX_CODES-1); // Number of bits for index, must accomodate MAX_CODES 27 | 28 | localparam DATA_S = DATA_WIDTH - 1; 29 | localparam COMP_S = DATA_S + DATA_WIDTH; 30 | localparam ADDR_S = COMP_S + ADDR_WIDTH; 31 | localparam COMP_F_S = ADDR_S + 1; 32 | localparam ENA_F_S = COMP_F_S + 1; 33 | localparam CODE_WIDTH = ENA_F_S + 1; 34 | 35 | reg [ENA_F_S:0] codes[MAX_CODES]; 36 | 37 | wire [ADDR_WIDTH-1: 0] code_addr = code[64+:ADDR_WIDTH]; 38 | wire [DATA_WIDTH-1: 0] code_compare = code[32+:DATA_WIDTH]; 39 | wire [DATA_WIDTH-1: 0] code_data = code[0+:DATA_WIDTH]; 40 | wire code_comp_f = code[96]; 41 | 42 | wire [COMP_F_S:0] code_trimmed = {code_comp_f, code_addr, code_compare, code_data}; 43 | 44 | // If MAX_INDEX is changes, these need to be made larger 45 | wire [INDEX_SIZE-1:0] index, dup_index; 46 | reg [INDEX_SIZE:0] next_index; 47 | wire found_dup; 48 | 49 | assign index = found_dup ? dup_index : next_index[INDEX_SIZE-1:0]; 50 | 51 | // See if the code exists already, so it can be disabled if loaded again 52 | always_comb begin 53 | int x; 54 | dup_index = 0; 55 | found_dup = 0; 56 | 57 | for (x = 0; x < MAX_CODES; x = x + 1) begin 58 | if (codes[x][ADDR_S-:ADDR_WIDTH] == code_addr) begin 59 | dup_index = x[INDEX_SIZE-1:0]; 60 | found_dup = 1; 61 | end 62 | end 63 | end 64 | 65 | assign available = |next_index; 66 | 67 | reg code_change; 68 | always_ff @(posedge clk) begin 69 | int x; 70 | if (reset) begin 71 | next_index <= 0; 72 | code_change <= 0; 73 | for (x = 0; x < MAX_CODES; x = x + 1) codes[x] <= '0; 74 | end else begin 75 | code_change <= code[128]; 76 | if (code[128] && ~code_change && (found_dup || next_index < MAX_CODES)) begin // detect posedge 77 | // replace it enabled if it has the same address, otherwise, add a new code 78 | codes[index] <= {1'b1, code_trimmed}; 79 | if (~found_dup) next_index <= next_index + 1'b1; 80 | end 81 | end 82 | end 83 | 84 | always_comb begin 85 | int x; 86 | genie_ovr = 0; 87 | genie_data = '0; 88 | 89 | if (enable) begin 90 | for (x = 0; x < MAX_CODES; x = x + 1) begin 91 | if (codes[x][ENA_F_S] && codes[x][ADDR_S-:ADDR_WIDTH] == addr_in) begin 92 | if (!codes[x][COMP_F_S] || (codes[x][COMP_S-:DATA_WIDTH] == data_in)) begin 93 | genie_ovr = 1; 94 | genie_data = codes[x][DATA_S-:DATA_WIDTH]; 95 | end 96 | end 97 | end 98 | end 99 | end 100 | 101 | endmodule 102 | -------------------------------------------------------------------------------- /rtl/chip/BSX/BSX_DP.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.STD_LOGIC_1164.ALL; 3 | library STD; 4 | use IEEE.NUMERIC_STD.ALL; 5 | library work; 6 | 7 | entity DATAPAK is 8 | port( 9 | CLK : in std_logic; 10 | RST_N : in std_logic; 11 | ENABLE : in std_logic; 12 | 13 | A : in std_logic_vector(19 downto 0); 14 | DI : in std_logic_vector(7 downto 0); 15 | DO : out std_logic_vector(7 downto 0); 16 | CE_N : in std_logic; 17 | RD_N : in std_logic; 18 | WR_N : in std_logic; 19 | SYSCLKF_CE : in std_logic; 20 | SYSCLKR_CE : in std_logic; 21 | 22 | MEM_ADDR : out std_logic_vector(19 downto 0); 23 | MEM_DI : in std_logic_vector(7 downto 0); 24 | MEM_DO : out std_logic_vector(7 downto 0); 25 | MEM_RD : out std_logic; 26 | MEM_WR : out std_logic 27 | ); 28 | end DATAPAK; 29 | 30 | architecture rtl of DATAPAK is 31 | 32 | signal IO_REG : std_logic_vector(13 downto 0); 33 | signal PREV_COM : std_logic_vector(7 downto 0); 34 | signal CSR : std_logic; 35 | signal ESR : std_logic; 36 | signal VEN : std_logic; 37 | signal BYTE_WRITE : std_logic; 38 | 39 | type FlashStates_t is ( 40 | FS_IDLE, 41 | FS_READ, 42 | FS_WRITE, 43 | FS_ERASE 44 | ); 45 | signal FS : FlashStates_t; 46 | signal WRITE_ADDR : std_logic_vector(19 downto 0); 47 | signal WRITE_DATA : std_logic_vector(7 downto 0); 48 | signal READ_DATA : std_logic_vector(7 downto 0); 49 | signal WRITE_PEND : std_logic; 50 | signal PAGE_ERASE_PEND : std_logic; 51 | signal CHIP_ERASE_PEND : std_logic; 52 | 53 | begin 54 | 55 | process( RST_N, CLK) 56 | begin 57 | if RST_N = '0' then 58 | CSR <= '0'; 59 | ESR <= '0'; 60 | VEN <= '0'; 61 | BYTE_WRITE <= '0'; 62 | PREV_COM <= (others => '0'); 63 | FS <= FS_IDLE; 64 | WRITE_PEND <= '0'; 65 | PAGE_ERASE_PEND <= '0'; 66 | CHIP_ERASE_PEND <= '0'; 67 | elsif rising_edge(CLK) then 68 | if ENABLE = '1' then 69 | if CE_N = '0' and WR_N = '0' and SYSCLKF_CE = '1' then 70 | if BYTE_WRITE = '1' then --Data write 71 | if WRITE_PEND = '0' then 72 | WRITE_ADDR <= A; 73 | WRITE_DATA <= DI; 74 | WRITE_PEND <= '1'; 75 | BYTE_WRITE <= '0'; 76 | end if; 77 | else --Command write 78 | PREV_COM <= DI; 79 | case DI is 80 | when x"00" | x"FF" => --Reset 81 | CSR <= '0'; 82 | ESR <= '0'; 83 | VEN <= '0'; 84 | when x"10" | x"40" => --Byte write 85 | BYTE_WRITE <= '1'; 86 | when x"70" => --CSR enable 87 | CSR <= '1'; 88 | when x"71" => --ESR enable 89 | ESR <= '1'; 90 | when x"75" => --Vendor Info enable 91 | VEN <= '1'; 92 | when x"D0" => --Double Byte Commands 93 | case PREV_COM is 94 | when x"20" => --Page erase 95 | if PAGE_ERASE_PEND = '0' then 96 | WRITE_ADDR <= A(19 downto 16)&x"0000"; 97 | WRITE_DATA <= x"FF"; 98 | PAGE_ERASE_PEND <= '1'; 99 | end if; 100 | when x"A7" => --Chip erase 101 | if CHIP_ERASE_PEND = '0' then 102 | WRITE_ADDR <= (others => '0'); 103 | WRITE_DATA <= x"FF"; 104 | CHIP_ERASE_PEND <= '1'; 105 | end if; 106 | when others => null; 107 | end case; 108 | when others => null; 109 | end case; 110 | end if; 111 | elsif CE_N = '0' and RD_N = '0' and SYSCLKF_CE = '1' then 112 | if ESR = '1' and (A(15 downto 0) = x"0002" or A(15 downto 0) = x"0004") then 113 | 114 | elsif CSR = '1' then 115 | CSR <= '0'; 116 | end if; 117 | end if; 118 | 119 | if SYSCLKR_CE = '1' then 120 | READ_DATA <= MEM_DI; 121 | end if; 122 | 123 | if SYSCLKF_CE = '1' then 124 | case FS is 125 | when FS_IDLE => 126 | if WRITE_PEND = '1' then 127 | FS <= FS_READ; 128 | elsif PAGE_ERASE_PEND = '1' or CHIP_ERASE_PEND = '1' then 129 | FS <= FS_ERASE; 130 | end if; 131 | 132 | when FS_READ => 133 | WRITE_DATA <= WRITE_DATA and READ_DATA; 134 | FS <= FS_WRITE; 135 | 136 | when FS_WRITE => 137 | WRITE_PEND <= '0'; 138 | FS <= FS_IDLE; 139 | 140 | when FS_ERASE => 141 | WRITE_ADDR <= std_logic_vector( unsigned(WRITE_ADDR) + 1 ); 142 | if WRITE_ADDR(15 downto 0) = x"FFFF" and (WRITE_ADDR(19 downto 16) = x"F" or CHIP_ERASE_PEND = '0') then 143 | PAGE_ERASE_PEND <= '0'; 144 | CHIP_ERASE_PEND <= '0'; 145 | FS <= FS_IDLE; 146 | end if; 147 | 148 | when others => null; 149 | end case; 150 | end if; 151 | end if; 152 | end if; 153 | end process; 154 | 155 | MEM_ADDR <= WRITE_ADDR; 156 | MEM_DO <= WRITE_DATA; 157 | MEM_RD <= '1' when FS = FS_READ else '0'; 158 | MEM_WR <= '1' when FS = FS_WRITE or FS = FS_ERASE else '0'; 159 | 160 | 161 | process( RST_N, CLK) 162 | begin 163 | if RST_N = '0' then 164 | DO <= (others => '0'); 165 | elsif rising_edge(CLK) then 166 | if ESR = '1' and A(15 downto 0) = x"0002" then 167 | DO <= x"C0"; 168 | elsif ESR = '1' and A(15 downto 0) = x"0004" then 169 | DO <= not CHIP_ERASE_PEND & "0000010"; 170 | elsif CSR = '1' then 171 | DO <= not (WRITE_PEND or PAGE_ERASE_PEND) & "0000000"; 172 | elsif VEN = '1' and A(14 downto 8) = "1111111" then 173 | case A(7 downto 0) is 174 | when x"00" => DO <= x"4D"; 175 | when x"01" => DO <= x"00"; 176 | when x"02" => DO <= x"50"; 177 | when x"03" => DO <= x"00"; 178 | when x"04" => DO <= x"00"; 179 | when x"05" => DO <= x"00"; 180 | when x"06" => DO <= x"1A"; 181 | when x"07" => DO <= x"00"; 182 | when others =>DO <= x"00"; 183 | end case; 184 | else 185 | DO <= MEM_DI; 186 | end if; 187 | end if; 188 | end process; 189 | 190 | end rtl; -------------------------------------------------------------------------------- /rtl/chip/BSX/BSX_MCC.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.STD_LOGIC_1164.ALL; 3 | library STD; 4 | use IEEE.NUMERIC_STD.ALL; 5 | library work; 6 | 7 | entity MCC is 8 | port( 9 | CLK : in std_logic; 10 | RST_N : in std_logic; 11 | ENABLE : in std_logic; 12 | 13 | CA : in std_logic_vector(23 downto 12); 14 | DI7 : in std_logic; 15 | DO7 : out std_logic; 16 | RD_N : in std_logic; 17 | WR_N : in std_logic; 18 | SYSCLKF_CE : in std_logic; 19 | 20 | BIOS_CE_N : out std_logic; 21 | SRAM_CE_N : out std_logic; 22 | 23 | ADDR : out std_logic_vector(19 downto 15); 24 | PSRAM_CE_N : out std_logic; 25 | EXTMEM_CE_N : out std_logic; 26 | DPAK_CE_N : out std_logic; 27 | DPAK_WR_N : out std_logic; 28 | 29 | IOPORT_CE_N : out std_logic 30 | ); 31 | end MCC; 32 | 33 | architecture rtl of MCC is 34 | 35 | signal IO_REG : std_logic_vector(13 downto 2); 36 | signal REG : std_logic_vector(13 downto 2); 37 | signal ENIRQ : std_logic; 38 | signal MAP_MODE : std_logic; 39 | signal PSRAM_ON : std_logic_vector(1 downto 0); 40 | signal PSRAM_MAP : std_logic_vector(1 downto 0); 41 | signal BIOS_ON : std_logic_vector(1 downto 0); 42 | signal EXT_ON : std_logic_vector(1 downto 0); 43 | signal EXT_MAP : std_logic; 44 | signal EN_DPAK_WR : std_logic; 45 | signal EN_EXT_WR : std_logic; 46 | signal IO_SEL : std_logic; 47 | signal ROM_AREA : std_logic; 48 | 49 | begin 50 | 51 | IO_SEL <= '1' when CA(23 downto 20) = x"0" and CA(15 downto 12) = x"5" else '0'; -- 00:5XXX-0F:5XXX 52 | IOPORT_CE_N <= not IO_SEL; 53 | 54 | process( RST_N, CLK) 55 | begin 56 | if RST_N = '0' then 57 | IO_REG <= "001011111011"; 58 | ENIRQ <= '0'; 59 | MAP_MODE <= '1'; 60 | PSRAM_ON <= "01"; 61 | PSRAM_MAP <= "11"; 62 | BIOS_ON <= "11"; 63 | EXT_ON <= "01"; 64 | EXT_MAP <= '1'; 65 | EN_DPAK_WR <= '0'; 66 | EN_EXT_WR <= '0'; 67 | elsif rising_edge(CLK) then 68 | if ENABLE = '1' then 69 | if IO_SEL = '1' and WR_N = '0' and SYSCLKF_CE = '1' then 70 | case CA(19 downto 16) is 71 | when x"0" => 72 | when x"1" => ENIRQ <= DI7; 73 | when x"2" => IO_REG(2) <= DI7; 74 | when x"3" => IO_REG(3) <= DI7; 75 | when x"4" => IO_REG(4) <= DI7; 76 | when x"5" => IO_REG(5) <= DI7; 77 | when x"6" => IO_REG(6) <= DI7; 78 | when x"7" => IO_REG(7) <= DI7; 79 | when x"8" => IO_REG(8) <= DI7; 80 | when x"9" => IO_REG(9) <= DI7; 81 | when x"A" => IO_REG(10) <= DI7; 82 | when x"B" => IO_REG(11) <= DI7; 83 | when x"C" => IO_REG(12) <= DI7; 84 | when x"D" => IO_REG(13) <= DI7; 85 | when x"E" => 86 | MAP_MODE <= IO_REG(2); 87 | PSRAM_ON <= IO_REG(4 downto 3); 88 | PSRAM_MAP <= IO_REG(6 downto 5); 89 | BIOS_ON <= IO_REG(8 downto 7); 90 | EXT_ON <= IO_REG(10 downto 9); 91 | EXT_MAP <= IO_REG(11); 92 | EN_DPAK_WR <= IO_REG(12); 93 | EN_EXT_WR <= IO_REG(13); 94 | when others => null; 95 | end case; 96 | end if; 97 | end if; 98 | end if; 99 | end process; 100 | 101 | process( RST_N, CLK) 102 | begin 103 | if RST_N = '0' then 104 | DO7 <= '0'; 105 | elsif rising_edge(CLK) then 106 | if IO_SEL = '1' then 107 | case CA(19 downto 16) is 108 | when x"0" => DO7 <= '0'; 109 | when x"1" => DO7 <= ENIRQ; 110 | when x"2" => DO7 <= MAP_MODE; 111 | when x"3" => DO7 <= PSRAM_ON(0); 112 | when x"4" => DO7 <= PSRAM_ON(1); 113 | when x"5" => DO7 <= PSRAM_MAP(1); 114 | when x"6" => DO7 <= PSRAM_MAP(1); 115 | when x"7" => DO7 <= BIOS_ON(0); 116 | when x"8" => DO7 <= BIOS_ON(1); 117 | when x"9" => DO7 <= EXT_ON(0); 118 | when x"A" => DO7 <= EXT_ON(1); 119 | when x"B" => DO7 <= EXT_MAP; 120 | when x"C" => DO7 <= EN_DPAK_WR; 121 | when x"D" => DO7 <= EN_EXT_WR; 122 | when others => DO7 <= '0'; 123 | end case; 124 | else 125 | DO7 <= '0'; 126 | end if; 127 | end if; 128 | end process; 129 | 130 | ROM_AREA <= '0' when CA(23 downto 17) = "0111111" or (CA(22) = '0' and CA(15) = '0') else '1'; 131 | 132 | process( CA, ROM_AREA, MAP_MODE, PSRAM_ON, PSRAM_MAP, BIOS_ON, EXT_ON, EXT_MAP ) 133 | begin 134 | BIOS_CE_N <= '1'; 135 | PSRAM_CE_N <= '1'; 136 | EXTMEM_CE_N <= '1'; 137 | DPAK_CE_N <= '1'; 138 | 139 | if MAP_MODE = '0' then 140 | if ((not CA(23) and BIOS_ON(0)) = '1' or (CA(23) and BIOS_ON(1)) = '1') and CA(22) = '0' then 141 | BIOS_CE_N <= not ROM_AREA; 142 | elsif ((not CA(23) and PSRAM_ON(0)) = '1' or (CA(23) and PSRAM_ON(1)) = '1') and CA(22 downto 21) = PSRAM_MAP then 143 | PSRAM_CE_N <= not ROM_AREA; 144 | elsif ((not CA(23) and EXT_ON(0)) = '1' or (CA(23) and EXT_ON(1)) = '1') and CA(22) = EXT_MAP and CA(21) = '0' then 145 | EXTMEM_CE_N <= not ROM_AREA; 146 | else 147 | DPAK_CE_N <= not ROM_AREA; 148 | end if; 149 | 150 | if ((not CA(23) and PSRAM_ON(0)) = '1' or (CA(23) and PSRAM_ON(1)) = '1') and CA(22 downto 20) = "111" and CA(15) = '0' then --70-7D:0000-7FFF,F0-FF:0000-7FFF 151 | PSRAM_CE_N <= not ROM_AREA; 152 | end if; 153 | else 154 | if ((not CA(23) and BIOS_ON(0)) = '1' or (CA(23) and BIOS_ON(1)) = '1') and CA(22) = '0' then 155 | BIOS_CE_N <= not ROM_AREA; 156 | elsif ((not CA(23) and PSRAM_ON(0)) = '1' or (CA(23) and PSRAM_ON(1)) = '1') and CA(21 downto 20) = PSRAM_MAP and CA(19) = '0' then 157 | PSRAM_CE_N <= not ROM_AREA; 158 | elsif ((not CA(23) and EXT_ON(0)) = '1' or (CA(23) and EXT_ON(1)) = '1') and CA(21) = EXT_MAP and CA(20) = '0' then 159 | EXTMEM_CE_N <= not ROM_AREA; 160 | else 161 | DPAK_CE_N <= not ROM_AREA; 162 | end if; 163 | 164 | if CA(22 downto 21) = "01" and CA(15 downto 12) = x"6" then --20-3F:6000-6FFF,A0-BF:6000-6FFF 165 | PSRAM_CE_N <= '0'; 166 | end if; 167 | end if; 168 | 169 | if ((not CA(23) and PSRAM_ON(0)) = '1' or (CA(23) and PSRAM_ON(1)) = '1') and CA(23 downto 19) = "00010" and CA(15 downto 12) = x"5" then --10-17:5000-5FFF 170 | SRAM_CE_N <= '0'; 171 | else 172 | SRAM_CE_N <= '1'; 173 | end if; 174 | end process; 175 | 176 | DPAK_WR_N <= WR_N or not EN_DPAK_WR; 177 | 178 | process( CA, MAP_MODE ) 179 | begin 180 | if MAP_MODE = '0' then 181 | ADDR <= CA(20 downto 16);--LoROM 182 | else 183 | ADDR <= CA(19 downto 15);--HiROM 184 | end if; 185 | end process; 186 | 187 | end rtl; -------------------------------------------------------------------------------- /rtl/chip/CX4/CX4Map.vhd: -------------------------------------------------------------------------------- 1 | library STD; 2 | use STD.TEXTIO.ALL; 3 | library IEEE; 4 | use IEEE.STD_LOGIC_1164.ALL; 5 | use IEEE.NUMERIC_STD.ALL; 6 | use IEEE.STD_LOGIC_UNSIGNED.ALL; 7 | use IEEE.STD_LOGIC_TEXTIO.all; 8 | 9 | entity CX4Map is 10 | port( 11 | MCLK : in std_logic; 12 | RST_N : in std_logic; 13 | ENABLE : in std_logic := '1'; 14 | 15 | CA : in std_logic_vector(23 downto 0); 16 | DI : in std_logic_vector(7 downto 0); 17 | DO : out std_logic_vector(7 downto 0); 18 | CPURD_N : in std_logic; 19 | CPUWR_N : in std_logic; 20 | 21 | PA : in std_logic_vector(7 downto 0); 22 | PARD_N : in std_logic; 23 | PAWR_N : in std_logic; 24 | 25 | ROMSEL_N : in std_logic; 26 | RAMSEL_N : in std_logic; 27 | 28 | SYSCLKF_CE : in std_logic; 29 | SYSCLKR_CE : in std_logic; 30 | REFRESH : in std_logic; 31 | 32 | IRQ_N : out std_logic; 33 | 34 | ROM_ADDR : out std_logic_vector(22 downto 0); 35 | ROM_Q : in std_logic_vector(15 downto 0); 36 | ROM_CE_N : out std_logic; 37 | ROM_OE_N : out std_logic; 38 | ROM_WORD : out std_logic; 39 | 40 | BSRAM_ADDR : out std_logic_vector(19 downto 0); 41 | BSRAM_D : out std_logic_vector(7 downto 0); 42 | BSRAM_Q : in std_logic_vector(7 downto 0); 43 | BSRAM_CE_N : out std_logic; 44 | BSRAM_OE_N : out std_logic; 45 | BSRAM_WE_N : out std_logic; 46 | 47 | MAP_ACTIVE : out std_logic; 48 | MAP_CTRL : in std_logic_vector(7 downto 0); 49 | ROM_MASK : in std_logic_vector(23 downto 0); 50 | BSRAM_MASK : in std_logic_vector(23 downto 0) 51 | ); 52 | end CX4Map; 53 | 54 | architecture rtl of CX4Map is 55 | 56 | signal CX4_A : std_logic_vector(23 downto 0); 57 | signal CX4_DI : std_logic_vector(7 downto 0); 58 | signal SRAM_CE_N, ROM_CE1_N, ROM_CE2_N : std_logic; 59 | signal CART_ADDR : std_logic_vector(21 downto 0); 60 | signal BRAM_ADDR : std_logic_vector(19 downto 0); 61 | signal CX4_CE : std_logic; 62 | signal MAP_SEL : std_logic; 63 | begin 64 | 65 | MAP_SEL <= '1' when MAP_CTRL(7 downto 4) = X"4" else '0'; 66 | MAP_ACTIVE <= MAP_SEL; 67 | 68 | CEGen : entity work.CEGen 69 | port map( 70 | CLK => MCLK, 71 | RST_N => RST_N, 72 | IN_CLK => 2147727, 73 | OUT_CLK => 2000000, 74 | CE => CX4_CE 75 | ); 76 | 77 | CX4 : entity work.CX4 78 | port map( 79 | CLK => MCLK, 80 | CE => CX4_CE, 81 | RST_N => RST_N and MAP_SEL, 82 | ENABLE => ENABLE, 83 | 84 | ADDR => CA, 85 | DO => DO, 86 | DI => DI, 87 | RD_N => CPURD_N, 88 | WR_N => CPUWR_N, 89 | 90 | SYSCLKF_CE => SYSCLKF_CE, 91 | SYSCLKR_CE => SYSCLKR_CE, 92 | 93 | IRQ_N => IRQ_N, 94 | 95 | BUS_A => CX4_A, 96 | BUS_DI => CX4_DI, 97 | BUS_DO => BSRAM_D, 98 | BUS_OE_N => BSRAM_OE_N, 99 | BUS_WE_N => BSRAM_WE_N, 100 | ROM_CE1_N => ROM_CE1_N, 101 | ROM_CE2_N => ROM_CE2_N, 102 | SRAM_CE_N => SRAM_CE_N, 103 | 104 | BUS_RD_N => ROM_OE_N, 105 | 106 | MAPPER => MAP_CTRL(0) 107 | ); 108 | 109 | CART_ADDR <= CX4_A(22) & not ROM_CE2_N & CX4_A(20 downto 16) & CX4_A(14 downto 0); 110 | BRAM_ADDR <= CX4_A(20 downto 16) & CX4_A(14 downto 0); 111 | 112 | ROM_ADDR <= CART_ADDR and ROM_MASK(22 downto 0); 113 | ROM_CE_N <= ROM_CE1_N and ROM_CE2_N; 114 | ROM_WORD <= '0'; 115 | 116 | BSRAM_ADDR <= BRAM_ADDR and BSRAM_MASK(19 downto 0); 117 | BSRAM_CE_N <= SRAM_CE_N; 118 | 119 | CX4_DI <= BSRAM_Q when SRAM_CE_N = '0' else ROM_Q(7 downto 0); 120 | 121 | end rtl; 122 | -------------------------------------------------------------------------------- /rtl/chip/DSP/OBC1.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.STD_LOGIC_1164.ALL; 3 | library STD; 4 | use IEEE.NUMERIC_STD.ALL; 5 | 6 | 7 | entity OBC1 is 8 | port( 9 | CLK : in std_logic; 10 | RST_N : in std_logic; 11 | ENABLE : in std_logic; 12 | 13 | CA : in std_logic_vector(23 downto 0); 14 | DI : in std_logic_vector(7 downto 0); 15 | CPURD_N : in std_logic; 16 | CPUWR_N : in std_logic; 17 | 18 | SYSCLKF_CE : in std_logic; 19 | 20 | CS : in std_logic; 21 | 22 | SRAM_A : out std_logic_vector(12 downto 0); 23 | SRAM_DI : in std_logic_vector(7 downto 0); 24 | SRAM_DO : out std_logic_vector(7 downto 0) 25 | ); 26 | end OBC1; 27 | 28 | architecture rtl of OBC1 is 29 | 30 | signal BASE : std_logic; 31 | signal INDEX : std_logic_vector(6 downto 0); 32 | 33 | signal SRAM_ADDR : std_logic_vector(12 downto 0); 34 | 35 | begin 36 | 37 | process( RST_N, CLK) 38 | begin 39 | if RST_N = '0' then 40 | INDEX <= (others => '0'); 41 | BASE <= '0'; 42 | elsif rising_edge(CLK) then 43 | if ENABLE = '1' and SYSCLKF_CE = '1' then 44 | if CPUWR_N = '0' and CS = '1' and CA(15 downto 4) = x"7FF" then 45 | case CA(3 downto 0) is 46 | when x"5" => 47 | BASE<= DI(0); 48 | when x"6" => 49 | INDEX <= DI(6 downto 0); 50 | when others => null; 51 | end case; 52 | end if; 53 | end if; 54 | end if; 55 | end process; 56 | 57 | process( CA, BASE, INDEX ) 58 | begin 59 | if CA(12 downto 3) = "1111111110" then --7FF0-7FF7 60 | case CA(3 downto 0) is 61 | when x"0" | x"1" | x"2" | x"3" => 62 | SRAM_ADDR <= "11" & not BASE & "0" & INDEX & CA(1 downto 0); 63 | when x"4" => 64 | SRAM_ADDR <= "11" & not BASE & "1" & "0000" & INDEX(6 downto 2); 65 | when others => 66 | SRAM_ADDR <= CA(12 downto 0); 67 | end case; 68 | else 69 | SRAM_ADDR <= CA(12 downto 0); 70 | end if; 71 | end process; 72 | SRAM_A <= SRAM_ADDR; 73 | 74 | process( CA, DI, INDEX, SRAM_DI) 75 | begin 76 | if CA(12 downto 0) = "1111111110100" then --7FF4 77 | case INDEX(1 downto 0) is 78 | when "00" => 79 | SRAM_DO <= SRAM_DI(7 downto 2) & DI(1 downto 0); 80 | when "01" => 81 | SRAM_DO <= SRAM_DI(7 downto 4) & DI(1 downto 0) & SRAM_DI(1 downto 0); 82 | when "10" => 83 | SRAM_DO <= SRAM_DI(7 downto 6) & DI(1 downto 0) & SRAM_DI(3 downto 0); 84 | when others => 85 | SRAM_DO <= DI(1 downto 0) & SRAM_DI(5 downto 0); 86 | end case; 87 | else 88 | SRAM_DO <= DI; 89 | end if; 90 | end process; 91 | 92 | end rtl; 93 | -------------------------------------------------------------------------------- /rtl/chip/GSU/GSUMap.vhd: -------------------------------------------------------------------------------- 1 | library STD; 2 | use STD.TEXTIO.ALL; 3 | library IEEE; 4 | use IEEE.STD_LOGIC_1164.ALL; 5 | use IEEE.NUMERIC_STD.ALL; 6 | use IEEE.STD_LOGIC_UNSIGNED.ALL; 7 | use IEEE.STD_LOGIC_TEXTIO.all; 8 | 9 | entity GSUMap is 10 | port( 11 | MCLK : in std_logic; 12 | RST_N : in std_logic; 13 | ENABLE : in std_logic := '1'; 14 | 15 | CA : in std_logic_vector(23 downto 0); 16 | DI : in std_logic_vector(7 downto 0); 17 | DO : out std_logic_vector(7 downto 0); 18 | CPURD_N : in std_logic; 19 | CPUWR_N : in std_logic; 20 | 21 | PA : in std_logic_vector(7 downto 0); 22 | PARD_N : in std_logic; 23 | PAWR_N : in std_logic; 24 | 25 | ROMSEL_N : in std_logic; 26 | RAMSEL_N : in std_logic; 27 | 28 | SYSCLKF_CE : in std_logic; 29 | SYSCLKR_CE : in std_logic; 30 | REFRESH : in std_logic; 31 | 32 | IRQ_N : out std_logic; 33 | 34 | ROM_ADDR : out std_logic_vector(22 downto 0); 35 | ROM_Q : in std_logic_vector(15 downto 0); 36 | ROM_CE_N : out std_logic; 37 | ROM_OE_N : out std_logic; 38 | ROM_WORD : out std_logic; 39 | 40 | BSRAM_ADDR : out std_logic_vector(19 downto 0); 41 | BSRAM_D : out std_logic_vector(7 downto 0); 42 | BSRAM_Q : in std_logic_vector(7 downto 0); 43 | BSRAM_CE_N : out std_logic; 44 | BSRAM_OE_N : out std_logic; 45 | BSRAM_WE_N : out std_logic; 46 | 47 | MAP_ACTIVE : out std_logic; 48 | MAP_CTRL : in std_logic_vector(7 downto 0); 49 | ROM_MASK : in std_logic_vector(23 downto 0); 50 | BSRAM_MASK : in std_logic_vector(23 downto 0); 51 | 52 | TURBO : in std_logic 53 | ); 54 | end GSUMap; 55 | 56 | architecture rtl of GSUMap is 57 | 58 | signal ROM_A : std_logic_vector(20 downto 0); 59 | signal RAM_A : std_logic_vector(16 downto 0); 60 | signal RAM_WE_N : std_logic; 61 | signal MAP_SEL : std_logic; 62 | 63 | begin 64 | 65 | MAP_SEL <= '1' when MAP_CTRL(7 downto 4) = X"7" else '0'; 66 | MAP_ACTIVE <= MAP_SEL; 67 | 68 | GSU : entity work.GSU 69 | port map( 70 | CLK => MCLK, 71 | RST_N => RST_N and MAP_SEL, 72 | ENABLE => ENABLE, 73 | 74 | ADDR => CA, 75 | DO => DO, 76 | DI => DI, 77 | RD_N => CPURD_N, 78 | WR_N => CPUWR_N, 79 | 80 | SYSCLKF_CE => SYSCLKF_CE, 81 | SYSCLKR_CE => SYSCLKR_CE, 82 | 83 | IRQ_N => IRQ_N, 84 | 85 | ROM_A => ROM_A, 86 | ROM_DI => ROM_Q(7 downto 0), 87 | ROM_RD_N => ROM_OE_N, 88 | 89 | RAM_A => RAM_A, 90 | RAM_DI => BSRAM_Q, 91 | RAM_DO => BSRAM_D, 92 | RAM_WE_N => RAM_WE_N, 93 | RAM_CE_N => BSRAM_CE_N, 94 | 95 | TURBO => TURBO 96 | ); 97 | 98 | ROM_ADDR <= ("00" & ROM_A) and ROM_MASK(22 downto 0); 99 | ROM_CE_N <= '0'; 100 | ROM_WORD <= '0'; 101 | 102 | BSRAM_ADDR <= "0000" & RAM_A(15 downto 0); 103 | BSRAM_OE_N <= not RAM_WE_N; 104 | BSRAM_WE_N <= RAM_WE_N; 105 | 106 | end rtl; -------------------------------------------------------------------------------- /rtl/chip/MSU1/MSU.sv: -------------------------------------------------------------------------------- 1 | // This module is responsible for exposing MSU registers to the SNES for it to control 2 | 3 | module MSU 4 | ( 5 | input CLK, 6 | input RST_N, 7 | input ENABLE, 8 | 9 | input RD_N, 10 | input WR_N, 11 | input SYSCLKF_CE, 12 | 13 | input [23:0] ADDR, 14 | input [7:0] DIN, 15 | output reg [7:0] DOUT, 16 | output MSU_SEL, 17 | 18 | output reg [15:0] track_num, 19 | output track_request, 20 | input track_mounting, 21 | 22 | // Audio player control 23 | output reg [7:0] volume, 24 | input status_track_missing, 25 | output reg status_audio_repeat, 26 | output reg status_audio_playing, 27 | input audio_stop, 28 | 29 | // Data track read 30 | output reg [31:0] data_addr, 31 | input [7:0] data, 32 | input data_ack, 33 | output reg data_seek, 34 | output reg data_req 35 | ); 36 | 37 | 38 | // Read 'registers' 39 | // MSU_STATUS - $2000 40 | // Status bits 41 | localparam [2:0] status_revision = 3'b001; 42 | wire [7:0] MSU_STATUS = { 43 | status_data_busy, 44 | status_audio_busy, 45 | status_audio_repeat, 46 | status_audio_playing, 47 | status_track_missing, 48 | status_revision 49 | }; 50 | 51 | // Write registers 52 | reg [31:0] MSU_SEEK; // $2000 - $2003 53 | reg [15:0] MSU_TRACK; // $2004 - $2005 54 | 55 | // banks 00-3F and 80-BF, address 2000-2007 56 | assign MSU_SEL = ENABLE && !ADDR[22] && (ADDR[15:4] == 'h200) && !ADDR[3]; 57 | 58 | wire status_audio_busy = track_request; 59 | 60 | reg data_ack_1 = 1'b0; 61 | reg status_data_busy = 1'b0; 62 | reg track_mounting_old = 0; 63 | 64 | reg data_rd_old; 65 | wire data_rd = MSU_SEL && !RD_N && ADDR[2:0] == 1 && !status_data_busy; 66 | 67 | always @(posedge CLK) begin 68 | if (~RST_N) begin 69 | MSU_SEEK <= 0; 70 | data_addr <= 0; 71 | MSU_TRACK <= 0; 72 | track_num <= 0; 73 | track_request <= 0; 74 | volume <= 0; 75 | status_audio_playing <= 0; 76 | status_audio_repeat <= 0; 77 | status_data_busy <= 0; 78 | track_mounting_old <= 0; 79 | data_req <= 0; 80 | data_seek <= 0; 81 | end 82 | else begin 83 | // Reset our request trigger for pulsing 84 | data_req <= 0; 85 | 86 | // Falling edge of data busy 87 | data_ack_1 <= data_ack; 88 | if (!data_ack_1 && data_ack) begin 89 | status_data_busy <= 0; 90 | data_seek <= 0; 91 | end 92 | 93 | // Falling edge of track mounting 94 | track_mounting_old <= track_mounting; 95 | if (track_mounting_old && !track_mounting) track_request <= 0; 96 | 97 | if (audio_stop) status_audio_playing <= 0; 98 | 99 | // Register writes 100 | if (MSU_SEL & SYSCLKF_CE & ~WR_N) begin 101 | case (ADDR[2:0]) 102 | 0: MSU_SEEK[7:0] <= DIN; // Data seek address. MSU_SEEK, LSB byte 103 | 1: MSU_SEEK[15:8] <= DIN; // Data seek address. MSU_SEEK. 104 | 2: MSU_SEEK[23:16] <= DIN; // Data seek address. MSU_SEEK. 105 | 3: begin 106 | MSU_SEEK[31:24] <= DIN; // Data seek address. MSU_SEEK, MSB byte 107 | data_addr <= {DIN, MSU_SEEK[23:0]}; 108 | data_seek <= 1; 109 | status_data_busy <= 1; 110 | end 111 | 112 | 4: MSU_TRACK[7:0] <= DIN; // MSU_Track LSB 113 | 5: begin 114 | MSU_TRACK[15:8] <= DIN; // MSU_Track MSB 115 | track_num <= {DIN, MSU_TRACK[7:0]}; 116 | track_request <= 1; 117 | end 118 | 119 | 6: volume <= DIN; // MSU Audio Volume 120 | 121 | // MSU Audio state control 122 | 7: begin 123 | status_audio_repeat <= DIN[1]; 124 | status_audio_playing <= DIN[0]; 125 | end 126 | endcase 127 | end 128 | 129 | // Advance data pointer after read 130 | data_rd_old <= data_rd; 131 | if (data_rd_old & ~data_rd) begin 132 | data_addr <= data_addr + 1; 133 | data_req <= 1'b1; 134 | end 135 | 136 | case (ADDR[2:0]) 137 | 0: DOUT <= MSU_STATUS; 138 | 1: DOUT <= data; 139 | 2: DOUT <= "S"; 140 | 3: DOUT <= "-"; 141 | 4: DOUT <= "M"; 142 | 5: DOUT <= "S"; 143 | 6: DOUT <= "U"; 144 | 7: DOUT <= "1"; 145 | endcase 146 | end 147 | end 148 | 149 | endmodule 150 | -------------------------------------------------------------------------------- /rtl/chip/MSU1/msu_data_store.sv: -------------------------------------------------------------------------------- 1 | // 2 | // msu_data_store.v 3 | // Copyright (c) 2022 Alexey Melnikov 4 | // 5 | // 6 | // This source file is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This source file is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // 20 | 21 | module msu_data_store 22 | ( 23 | input DDRAM_CLK, 24 | 25 | input DDRAM_BUSY, 26 | output [7:0] DDRAM_BURSTCNT, 27 | output [28:0] DDRAM_ADDR, 28 | input [63:0] DDRAM_DOUT, 29 | input DDRAM_DOUT_READY, 30 | output DDRAM_RD, 31 | output [63:0] DDRAM_DIN, 32 | output [7:0] DDRAM_BE, 33 | output DDRAM_WE, 34 | 35 | input clk_sys, 36 | input [31:0] base_addr, 37 | 38 | input rd_next, 39 | input rd_seek, 40 | output reg rd_seek_done, 41 | input [31:0] rd_addr, 42 | output [7:0] rd_dout 43 | ); 44 | 45 | assign DDRAM_BURSTCNT = ram_burst; 46 | assign DDRAM_BE = 8'hFF; 47 | assign DDRAM_ADDR = ram_address; 48 | assign DDRAM_RD = ram_read; 49 | assign DDRAM_DIN = 0; 50 | assign DDRAM_WE = 0; 51 | 52 | wire [28:0] ph_addr = base_addr[31:3] + rd_addr[31:3]; 53 | wire [28:0] ph_addr_curr = ph_addr + ((ph_addr >= 'h4400000) ? 29'h100000 : 29'h0); 54 | wire [28:0] ph_addr_next = ph_addr + ((ph_addr >= 'h43FFFFF) ? 29'h100001 : 29'h1); 55 | 56 | assign rd_dout = ram_q[{rd_addr[2:0], 3'b000} +:8]; 57 | 58 | reg [7:0] ram_burst; 59 | reg [63:0] ram_q, next_q; 60 | reg [63:0] ram_data; 61 | reg [28:0] ram_address, cache_addr; 62 | reg ram_read = 0; 63 | 64 | reg [1:0] state = 0; 65 | 66 | always @(posedge DDRAM_CLK) begin 67 | reg old_seek; 68 | reg old_rd; 69 | 70 | if(~rd_seek) old_seek <= 0; 71 | 72 | if(!DDRAM_BUSY) begin 73 | 74 | ram_read <= 0; 75 | old_rd <= rd_next; 76 | 77 | case(state) 78 | 0: if(~old_seek & rd_seek) begin 79 | old_seek <= 1; 80 | rd_seek_done<= 0; 81 | ram_address <= ph_addr_curr; 82 | cache_addr <= ph_addr_next; // seek to 'h21FFFFF8 will return wrong second dword 83 | ram_read <= 1; 84 | ram_burst <= 2; 85 | state <= 1; 86 | end 87 | else if(~old_rd & rd_next) begin 88 | if(cache_addr == ph_addr_curr) begin 89 | ram_q <= next_q; 90 | ram_address <= ph_addr_next; 91 | cache_addr <= ph_addr_next; 92 | ram_read <= 1; 93 | ram_burst <= 1; 94 | state <= 2; 95 | end 96 | end 97 | 98 | 1: if(DDRAM_DOUT_READY) begin 99 | ram_q <= DDRAM_DOUT; 100 | state <= 2; 101 | end 102 | 103 | 2: if(DDRAM_DOUT_READY) begin 104 | next_q <= DDRAM_DOUT; 105 | state <= 0; 106 | rd_seek_done <= 1; 107 | end 108 | endcase 109 | end 110 | end 111 | 112 | endmodule 113 | -------------------------------------------------------------------------------- /rtl/chip/MSU1/msu_fifo.v: -------------------------------------------------------------------------------- 1 | 2 | module msu_fifo #(parameter WIDTH, DEPTH) 3 | ( 4 | input aclr, 5 | 6 | input wrclk, 7 | input wrreq, 8 | input [WIDTH-1:0] data, 9 | output wrfull, 10 | output [DEPTH-1:0] wrusedw, 11 | 12 | input rdclk, 13 | input rdreq, 14 | output [WIDTH-1:0] q, 15 | output rdempty, 16 | output [DEPTH-1:0] rdusedw 17 | ); 18 | 19 | dcfifo dcfifo_component 20 | ( 21 | .aclr (aclr), 22 | .data (data), 23 | .rdclk (rdclk), 24 | .rdreq (rdreq), 25 | .wrclk (wrclk), 26 | .wrreq (wrreq), 27 | .q (q), 28 | .rdempty (rdempty), 29 | .wrfull (wrfull), 30 | .wrusedw (wrusedw), 31 | .eccstatus (), 32 | .rdfull (), 33 | .rdusedw (rdusedw), 34 | .wrempty () 35 | ); 36 | defparam 37 | dcfifo_component.intended_device_family = "Cyclone V", 38 | dcfifo_component.lpm_numwords = 2**DEPTH, 39 | dcfifo_component.lpm_showahead = "ON", 40 | dcfifo_component.lpm_type = "dcfifo", 41 | dcfifo_component.lpm_width = WIDTH, 42 | dcfifo_component.lpm_widthu = DEPTH, 43 | dcfifo_component.overflow_checking = "ON", 44 | dcfifo_component.rdsync_delaypipe = 4, 45 | dcfifo_component.read_aclr_synch = "OFF", 46 | dcfifo_component.underflow_checking = "ON", 47 | dcfifo_component.use_eab = "ON", 48 | dcfifo_component.write_aclr_synch = "OFF", 49 | dcfifo_component.wrsync_delaypipe = 4; 50 | 51 | endmodule 52 | -------------------------------------------------------------------------------- /rtl/chip/SA1/SA1DIV.vhd: -------------------------------------------------------------------------------- 1 | -- megafunction wizard: %LPM_DIVIDE% 2 | -- GENERATION: STANDARD 3 | -- VERSION: WM1.0 4 | -- MODULE: LPM_DIVIDE 5 | 6 | -- ============================================================ 7 | -- File Name: SA1DIV.vhd 8 | -- Megafunction Name(s): 9 | -- LPM_DIVIDE 10 | -- 11 | -- Simulation Library Files(s): 12 | -- lpm 13 | -- ============================================================ 14 | -- ************************************************************ 15 | -- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! 16 | -- 17 | -- 13.1.4 Build 182 03/12/2014 SJ Full Version 18 | -- ************************************************************ 19 | 20 | 21 | --Copyright (C) 1991-2014 Altera Corporation 22 | --Your use of Altera Corporation's design tools, logic functions 23 | --and other software and tools, and its AMPP partner logic 24 | --functions, and any output files from any of the foregoing 25 | --(including device programming or simulation files), and any 26 | --associated documentation or information are expressly subject 27 | --to the terms and conditions of the Altera Program License 28 | --Subscription Agreement, Altera MegaCore Function License 29 | --Agreement, or other applicable license agreement, including, 30 | --without limitation, that your use is for the sole purpose of 31 | --programming logic devices manufactured by Altera and sold by 32 | --Altera or its authorized distributors. Please refer to the 33 | --applicable agreement for further details. 34 | 35 | 36 | LIBRARY ieee; 37 | USE ieee.std_logic_1164.all; 38 | 39 | LIBRARY lpm; 40 | USE lpm.all; 41 | 42 | ENTITY SA1DIV IS 43 | PORT 44 | ( 45 | clock : IN STD_LOGIC ; 46 | denom : IN STD_LOGIC_VECTOR (15 DOWNTO 0); 47 | numer : IN STD_LOGIC_VECTOR (15 DOWNTO 0); 48 | quotient : OUT STD_LOGIC_VECTOR (15 DOWNTO 0); 49 | remain : OUT STD_LOGIC_VECTOR (15 DOWNTO 0) 50 | ); 51 | END SA1DIV; 52 | 53 | 54 | ARCHITECTURE SYN OF sa1div IS 55 | 56 | SIGNAL sub_wire0 : STD_LOGIC_VECTOR (15 DOWNTO 0); 57 | SIGNAL sub_wire1 : STD_LOGIC_VECTOR (15 DOWNTO 0); 58 | 59 | 60 | 61 | COMPONENT lpm_divide 62 | GENERIC ( 63 | lpm_drepresentation : STRING; 64 | lpm_hint : STRING; 65 | lpm_nrepresentation : STRING; 66 | lpm_pipeline : NATURAL; 67 | lpm_type : STRING; 68 | lpm_widthd : NATURAL; 69 | lpm_widthn : NATURAL 70 | ); 71 | PORT ( 72 | clock : IN STD_LOGIC ; 73 | remain : OUT STD_LOGIC_VECTOR (15 DOWNTO 0); 74 | denom : IN STD_LOGIC_VECTOR (15 DOWNTO 0); 75 | numer : IN STD_LOGIC_VECTOR (15 DOWNTO 0); 76 | quotient : OUT STD_LOGIC_VECTOR (15 DOWNTO 0) 77 | ); 78 | END COMPONENT; 79 | 80 | BEGIN 81 | remain <= sub_wire0(15 DOWNTO 0); 82 | quotient <= sub_wire1(15 DOWNTO 0); 83 | 84 | LPM_DIVIDE_component : LPM_DIVIDE 85 | GENERIC MAP ( 86 | lpm_drepresentation => "UNSIGNED", 87 | lpm_hint => "LPM_REMAINDERPOSITIVE=TRUE", 88 | lpm_nrepresentation => "SIGNED", 89 | lpm_pipeline => 6, 90 | lpm_type => "LPM_DIVIDE", 91 | lpm_widthd => 16, 92 | lpm_widthn => 16 93 | ) 94 | PORT MAP ( 95 | clock => clock, 96 | denom => denom, 97 | numer => numer, 98 | remain => sub_wire0, 99 | quotient => sub_wire1 100 | ); 101 | 102 | 103 | 104 | END SYN; 105 | 106 | -- ============================================================ 107 | -- CNX file retrieval info 108 | -- ============================================================ 109 | -- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone III" 110 | -- Retrieval info: PRIVATE: PRIVATE_LPM_REMAINDERPOSITIVE STRING "TRUE" 111 | -- Retrieval info: PRIVATE: PRIVATE_MAXIMIZE_SPEED NUMERIC "-1" 112 | -- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" 113 | -- Retrieval info: PRIVATE: USING_PIPELINE NUMERIC "1" 114 | -- Retrieval info: PRIVATE: VERSION_NUMBER NUMERIC "2" 115 | -- Retrieval info: PRIVATE: new_diagram STRING "1" 116 | -- Retrieval info: LIBRARY: lpm lpm.lpm_components.all 117 | -- Retrieval info: CONSTANT: LPM_DREPRESENTATION STRING "UNSIGNED" 118 | -- Retrieval info: CONSTANT: LPM_HINT STRING "LPM_REMAINDERPOSITIVE=TRUE" 119 | -- Retrieval info: CONSTANT: LPM_NREPRESENTATION STRING "SIGNED" 120 | -- Retrieval info: CONSTANT: LPM_PIPELINE NUMERIC "6" 121 | -- Retrieval info: CONSTANT: LPM_TYPE STRING "LPM_DIVIDE" 122 | -- Retrieval info: CONSTANT: LPM_WIDTHD NUMERIC "16" 123 | -- Retrieval info: CONSTANT: LPM_WIDTHN NUMERIC "16" 124 | -- Retrieval info: USED_PORT: clock 0 0 0 0 INPUT NODEFVAL "clock" 125 | -- Retrieval info: USED_PORT: denom 0 0 16 0 INPUT NODEFVAL "denom[15..0]" 126 | -- Retrieval info: USED_PORT: numer 0 0 16 0 INPUT NODEFVAL "numer[15..0]" 127 | -- Retrieval info: USED_PORT: quotient 0 0 16 0 OUTPUT NODEFVAL "quotient[15..0]" 128 | -- Retrieval info: USED_PORT: remain 0 0 16 0 OUTPUT NODEFVAL "remain[15..0]" 129 | -- Retrieval info: CONNECT: @clock 0 0 0 0 clock 0 0 0 0 130 | -- Retrieval info: CONNECT: @denom 0 0 16 0 denom 0 0 16 0 131 | -- Retrieval info: CONNECT: @numer 0 0 16 0 numer 0 0 16 0 132 | -- Retrieval info: CONNECT: quotient 0 0 16 0 @quotient 0 0 16 0 133 | -- Retrieval info: CONNECT: remain 0 0 16 0 @remain 0 0 16 0 134 | -- Retrieval info: GEN_FILE: TYPE_NORMAL SA1DIV.vhd TRUE 135 | -- Retrieval info: GEN_FILE: TYPE_NORMAL SA1DIV.inc FALSE 136 | -- Retrieval info: GEN_FILE: TYPE_NORMAL SA1DIV.cmp FALSE 137 | -- Retrieval info: GEN_FILE: TYPE_NORMAL SA1DIV.bsf FALSE 138 | -- Retrieval info: GEN_FILE: TYPE_NORMAL SA1DIV_inst.vhd FALSE 139 | -- Retrieval info: LIB_FILE: lpm 140 | -------------------------------------------------------------------------------- /rtl/chip/SA1/SA1MULT.vhd: -------------------------------------------------------------------------------- 1 | -- megafunction wizard: %LPM_MULT% 2 | -- GENERATION: STANDARD 3 | -- VERSION: WM1.0 4 | -- MODULE: lpm_mult 5 | 6 | -- ============================================================ 7 | -- File Name: SA1MULT.vhd 8 | -- Megafunction Name(s): 9 | -- lpm_mult 10 | -- 11 | -- Simulation Library Files(s): 12 | -- lpm 13 | -- ============================================================ 14 | -- ************************************************************ 15 | -- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! 16 | -- 17 | -- 11.1 Build 216 11/23/2011 SP 1 SJ Full Version 18 | -- ************************************************************ 19 | 20 | 21 | --Copyright (C) 1991-2011 Altera Corporation 22 | --Your use of Altera Corporation's design tools, logic functions 23 | --and other software and tools, and its AMPP partner logic 24 | --functions, and any output files from any of the foregoing 25 | --(including device programming or simulation files), and any 26 | --associated documentation or information are expressly subject 27 | --to the terms and conditions of the Altera Program License 28 | --Subscription Agreement, Altera MegaCore Function License 29 | --Agreement, or other applicable license agreement, including, 30 | --without limitation, that your use is for the sole purpose of 31 | --programming logic devices manufactured by Altera and sold by 32 | --Altera or its authorized distributors. Please refer to the 33 | --applicable agreement for further details. 34 | 35 | 36 | LIBRARY ieee; 37 | USE ieee.std_logic_1164.all; 38 | 39 | LIBRARY lpm; 40 | USE lpm.all; 41 | 42 | ENTITY SA1MULT IS 43 | PORT 44 | ( 45 | dataa : IN STD_LOGIC_VECTOR (15 DOWNTO 0); 46 | datab : IN STD_LOGIC_VECTOR (15 DOWNTO 0); 47 | result : OUT STD_LOGIC_VECTOR (31 DOWNTO 0) 48 | ); 49 | END SA1MULT; 50 | 51 | 52 | ARCHITECTURE SYN OF sa1mult IS 53 | 54 | SIGNAL sub_wire0 : STD_LOGIC_VECTOR (31 DOWNTO 0); 55 | 56 | 57 | 58 | COMPONENT lpm_mult 59 | GENERIC ( 60 | lpm_hint : STRING; 61 | lpm_representation : STRING; 62 | lpm_type : STRING; 63 | lpm_widtha : NATURAL; 64 | lpm_widthb : NATURAL; 65 | lpm_widthp : NATURAL 66 | ); 67 | PORT ( 68 | dataa : IN STD_LOGIC_VECTOR (15 DOWNTO 0); 69 | datab : IN STD_LOGIC_VECTOR (15 DOWNTO 0); 70 | result : OUT STD_LOGIC_VECTOR (31 DOWNTO 0) 71 | ); 72 | END COMPONENT; 73 | 74 | BEGIN 75 | result <= sub_wire0(31 DOWNTO 0); 76 | 77 | lpm_mult_component : lpm_mult 78 | GENERIC MAP ( 79 | lpm_hint => "MAXIMIZE_SPEED=5", 80 | lpm_representation => "SIGNED", 81 | lpm_type => "LPM_MULT", 82 | lpm_widtha => 16, 83 | lpm_widthb => 16, 84 | lpm_widthp => 32 85 | ) 86 | PORT MAP ( 87 | dataa => dataa, 88 | datab => datab, 89 | result => sub_wire0 90 | ); 91 | 92 | 93 | 94 | END SYN; 95 | 96 | -- ============================================================ 97 | -- CNX file retrieval info 98 | -- ============================================================ 99 | -- Retrieval info: PRIVATE: AutoSizeResult NUMERIC "1" 100 | -- Retrieval info: PRIVATE: B_isConstant NUMERIC "0" 101 | -- Retrieval info: PRIVATE: ConstantB NUMERIC "0" 102 | -- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone III" 103 | -- Retrieval info: PRIVATE: LPM_PIPELINE NUMERIC "0" 104 | -- Retrieval info: PRIVATE: Latency NUMERIC "0" 105 | -- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" 106 | -- Retrieval info: PRIVATE: SignedMult NUMERIC "1" 107 | -- Retrieval info: PRIVATE: USE_MULT NUMERIC "1" 108 | -- Retrieval info: PRIVATE: ValidConstant NUMERIC "0" 109 | -- Retrieval info: PRIVATE: WidthA NUMERIC "16" 110 | -- Retrieval info: PRIVATE: WidthB NUMERIC "16" 111 | -- Retrieval info: PRIVATE: WidthP NUMERIC "32" 112 | -- Retrieval info: PRIVATE: aclr NUMERIC "0" 113 | -- Retrieval info: PRIVATE: clken NUMERIC "0" 114 | -- Retrieval info: PRIVATE: new_diagram STRING "1" 115 | -- Retrieval info: PRIVATE: optimize NUMERIC "0" 116 | -- Retrieval info: LIBRARY: lpm lpm.lpm_components.all 117 | -- Retrieval info: CONSTANT: LPM_HINT STRING "MAXIMIZE_SPEED=5" 118 | -- Retrieval info: CONSTANT: LPM_REPRESENTATION STRING "SIGNED" 119 | -- Retrieval info: CONSTANT: LPM_TYPE STRING "LPM_MULT" 120 | -- Retrieval info: CONSTANT: LPM_WIDTHA NUMERIC "16" 121 | -- Retrieval info: CONSTANT: LPM_WIDTHB NUMERIC "16" 122 | -- Retrieval info: CONSTANT: LPM_WIDTHP NUMERIC "32" 123 | -- Retrieval info: USED_PORT: dataa 0 0 16 0 INPUT NODEFVAL "dataa[15..0]" 124 | -- Retrieval info: USED_PORT: datab 0 0 16 0 INPUT NODEFVAL "datab[15..0]" 125 | -- Retrieval info: USED_PORT: result 0 0 32 0 OUTPUT NODEFVAL "result[31..0]" 126 | -- Retrieval info: CONNECT: @dataa 0 0 16 0 dataa 0 0 16 0 127 | -- Retrieval info: CONNECT: @datab 0 0 16 0 datab 0 0 16 0 128 | -- Retrieval info: CONNECT: result 0 0 32 0 @result 0 0 32 0 129 | -- Retrieval info: GEN_FILE: TYPE_NORMAL SA1MULT.vhd TRUE 130 | -- Retrieval info: GEN_FILE: TYPE_NORMAL SA1MULT.inc FALSE 131 | -- Retrieval info: GEN_FILE: TYPE_NORMAL SA1MULT.cmp FALSE 132 | -- Retrieval info: GEN_FILE: TYPE_NORMAL SA1MULT.bsf FALSE 133 | -- Retrieval info: GEN_FILE: TYPE_NORMAL SA1MULT_inst.vhd FALSE 134 | -- Retrieval info: LIB_FILE: lpm 135 | -------------------------------------------------------------------------------- /rtl/chip/SA1/SA1Map.vhd: -------------------------------------------------------------------------------- 1 | library STD; 2 | use STD.TEXTIO.ALL; 3 | library IEEE; 4 | use IEEE.STD_LOGIC_1164.ALL; 5 | use IEEE.NUMERIC_STD.ALL; 6 | use IEEE.STD_LOGIC_UNSIGNED.ALL; 7 | use IEEE.STD_LOGIC_TEXTIO.all; 8 | 9 | entity SA1Map is 10 | port( 11 | MCLK : in std_logic; 12 | RST_N : in std_logic; 13 | ENABLE : in std_logic := '1'; 14 | 15 | CA : in std_logic_vector(23 downto 0); 16 | DI : in std_logic_vector(7 downto 0); 17 | DO : out std_logic_vector(7 downto 0); 18 | CPURD_N : in std_logic; 19 | CPUWR_N : in std_logic; 20 | 21 | PA : in std_logic_vector(7 downto 0); 22 | PARD_N : in std_logic; 23 | PAWR_N : in std_logic; 24 | 25 | ROMSEL_N : in std_logic; 26 | RAMSEL_N : in std_logic; 27 | 28 | SYSCLKF_CE : in std_logic; 29 | SYSCLKR_CE : in std_logic; 30 | 31 | REFRESH : in std_logic; 32 | 33 | PAL : in std_logic; 34 | 35 | IRQ_N : out std_logic; 36 | 37 | ROM_ADDR : out std_logic_vector(22 downto 0); 38 | ROM_Q : in std_logic_vector(15 downto 0); 39 | ROM_CE_N : out std_logic; 40 | ROM_OE_N : out std_logic; 41 | ROM_WORD : out std_logic; 42 | 43 | BSRAM_ADDR : out std_logic_vector(19 downto 0); 44 | BSRAM_D : out std_logic_vector(7 downto 0); 45 | BSRAM_Q : in std_logic_vector(7 downto 0); 46 | BSRAM_CE_N : out std_logic; 47 | BSRAM_OE_N : out std_logic; 48 | BSRAM_WE_N : out std_logic; 49 | 50 | MAP_ACTIVE : out std_logic; 51 | MAP_CTRL : in std_logic_vector(7 downto 0); 52 | ROM_MASK : in std_logic_vector(23 downto 0); 53 | BSRAM_MASK : in std_logic_vector(23 downto 0) 54 | ); 55 | end SA1Map; 56 | 57 | architecture rtl of SA1Map is 58 | 59 | signal ROM_A : std_logic_vector(22 downto 0); 60 | signal BWRAM_A : std_logic_vector(17 downto 0); 61 | signal MAP_SEL : std_logic; 62 | 63 | begin 64 | 65 | MAP_SEL <= '1' when MAP_CTRL(7 downto 4) = X"6" else '0'; 66 | MAP_ACTIVE <= MAP_SEL; 67 | 68 | SA1 : entity work.SA1 69 | port map( 70 | CLK => MCLK, 71 | RST_N => RST_N and MAP_SEL, 72 | ENABLE => ENABLE, 73 | 74 | SNES_A => CA, 75 | SNES_DO => DO, 76 | SNES_DI => DI, 77 | SNES_RD_N => CPURD_N, 78 | SNES_WR_N => CPUWR_N, 79 | 80 | SYSCLKF_CE => SYSCLKF_CE, 81 | SYSCLKR_CE => SYSCLKR_CE, 82 | 83 | REFRESH => REFRESH, 84 | 85 | PAL => PAL, 86 | 87 | ROM_A => ROM_A, 88 | ROM_DI => ROM_Q, 89 | ROM_RD_N => ROM_OE_N, 90 | 91 | BWRAM_A => BWRAM_A, 92 | BWRAM_DI => BSRAM_Q, 93 | BWRAM_DO => BSRAM_D, 94 | BWRAM_OE_N => BSRAM_OE_N, 95 | BWRAM_WE_N => BSRAM_WE_N, 96 | 97 | IRQ_N => IRQ_N 98 | ); 99 | 100 | ROM_ADDR <= ROM_A and ROM_MASK(22 downto 0); 101 | ROM_CE_N <= '0'; 102 | ROM_WORD <= '1'; 103 | 104 | BSRAM_ADDR <= ("00" & BWRAM_A) and BSRAM_MASK(19 downto 0); 105 | BSRAM_CE_N <= '0'; 106 | 107 | end rtl; -------------------------------------------------------------------------------- /rtl/chip/SDD1/InputMgr.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.STD_LOGIC_1164.ALL; 3 | use IEEE.STD_LOGIC_ARITH.ALL; 4 | use IEEE.STD_LOGIC_UNSIGNED.ALL; 5 | 6 | entity InputMgr is 7 | port( 8 | RST_N : in std_logic; 9 | CLK : in std_logic; 10 | ENABLE : in std_logic; 11 | 12 | INIT_ADDR : in std_logic_vector(23 downto 0); 13 | 14 | INIT : in std_logic; 15 | DATA_REQ : in std_logic; 16 | 17 | ROM_ADDR : out std_logic_vector(23 downto 0); 18 | ROM_DATA : in std_logic_vector(15 downto 0); 19 | 20 | ROM_RD : in std_logic; 21 | 22 | OUT_DATA : out std_logic_vector(15 downto 0); 23 | HEADER : out std_logic_vector(3 downto 0); 24 | 25 | INIT_DONE : out std_logic 26 | ); 27 | end InputMgr; 28 | 29 | architecture rtl of InputMgr is 30 | 31 | signal LOAD_ADDR : std_logic_vector(23 downto 0); 32 | signal CURR_DATA, NEXT_DATA : std_logic_vector(15 downto 0); 33 | signal BYTE_LOAD : std_logic; 34 | signal INIT_CNT : std_logic_vector(1 downto 0); 35 | signal WAIT_ACCESS: std_logic_vector(1 downto 0); 36 | signal TINIT_DONE : std_logic; 37 | 38 | type DataBuf_t is array(0 to 3) of std_logic_vector(15 downto 0); 39 | signal DATA_BUF: DataBuf_t; 40 | attribute ramstyle : string; 41 | attribute ramstyle of DATA_BUF : signal is "logic"; 42 | signal WR_POS : std_logic_vector(1 downto 0); 43 | signal RD_POS : std_logic_vector(1 downto 0); 44 | begin 45 | 46 | process( RST_N, CLK) 47 | variable READ_REQ : std_logic; 48 | variable WRITE_REQ : std_logic; 49 | begin 50 | if RST_N = '0' then 51 | HEADER <= (others => '0'); 52 | CURR_DATA <= (others => '0'); 53 | NEXT_DATA <= (others => '0'); 54 | LOAD_ADDR <= (others => '0'); 55 | INIT_CNT <= (others => '0'); 56 | BYTE_LOAD <= '0'; 57 | TINIT_DONE <= '0'; 58 | WAIT_ACCESS <= (others => '1'); 59 | WR_POS <= (others => '0'); 60 | RD_POS <= (others => '0'); 61 | elsif rising_edge(CLK) then 62 | if ENABLE = '1' then 63 | if DATA_REQ = '1' and BYTE_LOAD = '1' then 64 | READ_REQ := '1'; 65 | else 66 | READ_REQ := '0'; 67 | end if; 68 | 69 | if ROM_RD = '1' and (WR_POS + 1 /= RD_POS) then 70 | WAIT_ACCESS <= (others => '0'); 71 | elsif WAIT_ACCESS < 3 then 72 | WAIT_ACCESS <= WAIT_ACCESS + 1; 73 | end if; 74 | 75 | if WAIT_ACCESS = 1 then 76 | WRITE_REQ := '1'; 77 | else 78 | WRITE_REQ := '0'; 79 | end if; 80 | 81 | if INIT = '1' then 82 | LOAD_ADDR <= INIT_ADDR; 83 | INIT_CNT <= (others => '0'); 84 | TINIT_DONE <= '0'; 85 | WAIT_ACCESS <= (others => '1'); 86 | WR_POS <= (others => '0'); 87 | RD_POS <= (others => '0'); 88 | else 89 | if TINIT_DONE = '0' and (WR_POS + 1 = RD_POS) then 90 | TINIT_DONE <= '1'; 91 | end if; 92 | 93 | if INIT_CNT < 3 and WRITE_REQ = '1' then 94 | if INIT_CNT = 0 then 95 | if LOAD_ADDR(0) = '0' then 96 | CURR_DATA <= ROM_DATA(7 downto 0) & ROM_DATA(15 downto 8); 97 | HEADER <= ROM_DATA(7 downto 4); 98 | LOAD_ADDR <= LOAD_ADDR + 2; 99 | else 100 | CURR_DATA(15 downto 8) <= ROM_DATA(15 downto 8); 101 | HEADER <= ROM_DATA(15 downto 12); 102 | LOAD_ADDR <= LOAD_ADDR + 1; 103 | end if; 104 | BYTE_LOAD <= LOAD_ADDR(0); 105 | elsif INIT_CNT = 1 then 106 | if BYTE_LOAD = '1' then 107 | CURR_DATA(7 downto 0) <= ROM_DATA(7 downto 0); 108 | end if; 109 | NEXT_DATA <= ROM_DATA; 110 | LOAD_ADDR <= LOAD_ADDR + 2; 111 | end if; 112 | INIT_CNT <= INIT_CNT + 1; 113 | 114 | else 115 | if DATA_REQ = '1' then 116 | BYTE_LOAD <= not BYTE_LOAD; 117 | if BYTE_LOAD = '0' then 118 | CURR_DATA <= CURR_DATA(7 downto 0) & NEXT_DATA(7 downto 0); 119 | else 120 | CURR_DATA <= CURR_DATA(7 downto 0) & NEXT_DATA(15 downto 8); 121 | end if; 122 | end if; 123 | 124 | if READ_REQ = '1' then 125 | NEXT_DATA <= DATA_BUF(conv_integer(RD_POS)); 126 | if RD_POS /= WR_POS then 127 | RD_POS <= RD_POS + 1; 128 | end if; 129 | end if; 130 | 131 | if WRITE_REQ = '1' then 132 | DATA_BUF(conv_integer(WR_POS)) <= ROM_DATA; 133 | LOAD_ADDR <= LOAD_ADDR + 2; 134 | WR_POS <= WR_POS + 1; 135 | end if; 136 | 137 | end if; 138 | end if; 139 | end if; 140 | end if; 141 | end process; 142 | 143 | ROM_ADDR <= LOAD_ADDR; 144 | OUT_DATA <= CURR_DATA; 145 | INIT_DONE <= TINIT_DONE; 146 | 147 | end rtl; 148 | -------------------------------------------------------------------------------- /rtl/chip/SDD1/SDD1Map.vhd: -------------------------------------------------------------------------------- 1 | library STD; 2 | use STD.TEXTIO.ALL; 3 | library IEEE; 4 | use IEEE.STD_LOGIC_1164.ALL; 5 | use IEEE.NUMERIC_STD.ALL; 6 | use IEEE.STD_LOGIC_UNSIGNED.ALL; 7 | use IEEE.STD_LOGIC_TEXTIO.all; 8 | 9 | entity SDD1Map is 10 | port( 11 | MCLK : in std_logic; 12 | RST_N : in std_logic; 13 | ENABLE : in std_logic := '1'; 14 | 15 | CA : in std_logic_vector(23 downto 0); 16 | DI : in std_logic_vector(7 downto 0); 17 | DO : out std_logic_vector(7 downto 0); 18 | CPURD_N : in std_logic; 19 | CPUWR_N : in std_logic; 20 | 21 | PA : in std_logic_vector(7 downto 0); 22 | PARD_N : in std_logic; 23 | PAWR_N : in std_logic; 24 | 25 | ROMSEL_N : in std_logic; 26 | RAMSEL_N : in std_logic; 27 | 28 | SYSCLKF_CE : in std_logic; 29 | SYSCLKR_CE : in std_logic; 30 | REFRESH : in std_logic; 31 | 32 | IRQ_N : out std_logic; 33 | 34 | ROM_ADDR : out std_logic_vector(22 downto 0); 35 | ROM_Q : in std_logic_vector(15 downto 0); 36 | ROM_CE_N : out std_logic; 37 | ROM_OE_N : out std_logic; 38 | ROM_WORD : out std_logic; 39 | 40 | BSRAM_ADDR : out std_logic_vector(19 downto 0); 41 | BSRAM_D : out std_logic_vector(7 downto 0); 42 | BSRAM_Q : in std_logic_vector(7 downto 0); 43 | BSRAM_CE_N : out std_logic; 44 | BSRAM_OE_N : out std_logic; 45 | BSRAM_WE_N : out std_logic; 46 | 47 | MAP_ACTIVE : out std_logic; 48 | MAP_CTRL : in std_logic_vector(7 downto 0); 49 | ROM_MASK : in std_logic_vector(23 downto 0); 50 | BSRAM_MASK : in std_logic_vector(23 downto 0) 51 | ); 52 | end SDD1Map; 53 | 54 | architecture rtl of SDD1Map is 55 | 56 | signal SDD1_ROM_A : std_logic_vector(23 downto 0); 57 | signal BSRAM_CS_N : std_logic; 58 | signal SDD1_DO : std_logic_vector(7 downto 0); 59 | signal MAP_SEL : std_logic; 60 | begin 61 | 62 | MAP_SEL <= '1' when MAP_CTRL(7 downto 4) = X"5" else '0'; 63 | MAP_ACTIVE <= MAP_SEL; 64 | 65 | -- SDD1 66 | SDD1 : entity work.SDD1 67 | port map( 68 | RST_N => RST_N and MAP_SEL, 69 | CLK => MCLK, 70 | ENABLE => ENABLE, 71 | 72 | CA => CA, 73 | CPURD_N => CPURD_N, 74 | CPUWR_N => CPUWR_N, 75 | DO => SDD1_DO, 76 | DI => DI, 77 | ROMSEL_N => ROMSEL_N, 78 | 79 | SYSCLKF_CE => SYSCLKF_CE, 80 | SYSCLKR_CE => SYSCLKR_CE, 81 | 82 | ROM_A => SDD1_ROM_A, 83 | ROM_DO => ROM_Q, 84 | ROM_RD_N => ROM_OE_N 85 | ); 86 | 87 | ROM_ADDR <= SDD1_ROM_A(22 downto 0) and ROM_MASK(22 downto 0); 88 | ROM_CE_N <= '0'; 89 | ROM_WORD <= '1'; 90 | 91 | BSRAM_CS_N <= '0' when CA(23 downto 18) = x"7" & "00" or (CA(22) = '0' and CA(15 downto 13) = "011") else '1'; 92 | BSRAM_ADDR <= ("0" & CA(19 downto 16) & CA(14 downto 0)) and BSRAM_MASK(19 downto 0); 93 | BSRAM_CE_N <= BSRAM_CS_N; 94 | BSRAM_OE_N <= CPURD_N; 95 | BSRAM_WE_N <= CPUWR_N; 96 | BSRAM_D <= DI; 97 | 98 | DO <= BSRAM_Q when BSRAM_CS_N = '0' else SDD1_DO; 99 | 100 | IRQ_N <= '1'; 101 | 102 | end rtl; 103 | -------------------------------------------------------------------------------- /rtl/chip/SPC7110/SPC7110Map.vhd: -------------------------------------------------------------------------------- 1 | library STD; 2 | use STD.TEXTIO.ALL; 3 | library IEEE; 4 | use IEEE.STD_LOGIC_1164.ALL; 5 | use IEEE.NUMERIC_STD.ALL; 6 | use IEEE.STD_LOGIC_UNSIGNED.ALL; 7 | use IEEE.STD_LOGIC_TEXTIO.all; 8 | 9 | entity SPC7110Map is 10 | port( 11 | MCLK : in std_logic; 12 | RST_N : in std_logic; 13 | ENABLE : in std_logic := '1'; 14 | 15 | CA : in std_logic_vector(23 downto 0); 16 | DI : in std_logic_vector(7 downto 0); 17 | DO : out std_logic_vector(7 downto 0); 18 | CPURD_N : in std_logic; 19 | CPUWR_N : in std_logic; 20 | 21 | PA : in std_logic_vector(7 downto 0); 22 | PARD_N : in std_logic; 23 | PAWR_N : in std_logic; 24 | 25 | ROMSEL_N : in std_logic; 26 | RAMSEL_N : in std_logic; 27 | 28 | SYSCLKF_CE : in std_logic; 29 | SYSCLKR_CE : in std_logic; 30 | REFRESH : in std_logic; 31 | 32 | IRQ_N : out std_logic; 33 | 34 | ROM_ADDR : out std_logic_vector(22 downto 0); 35 | ROM_Q : in std_logic_vector(15 downto 0); 36 | ROM_CE_N : out std_logic; 37 | ROM_OE_N : out std_logic; 38 | ROM_WORD : out std_logic; 39 | 40 | BSRAM_ADDR : out std_logic_vector(19 downto 0); 41 | BSRAM_D : out std_logic_vector(7 downto 0); 42 | BSRAM_Q : in std_logic_vector(7 downto 0); 43 | BSRAM_CE_N : out std_logic; 44 | BSRAM_OE_N : out std_logic; 45 | BSRAM_WE_N : out std_logic; 46 | 47 | MAP_ACTIVE : out std_logic; 48 | MAP_CTRL : in std_logic_vector(7 downto 0); 49 | ROM_MASK : in std_logic_vector(23 downto 0); 50 | BSRAM_MASK : in std_logic_vector(23 downto 0); 51 | 52 | EXT_RTC : in std_logic_vector(64 downto 0) 53 | ); 54 | end SPC7110Map; 55 | 56 | architecture rtl of SPC7110Map is 57 | 58 | signal PROM_OE_N : std_logic; 59 | 60 | signal SPC7110_DROM_A : std_logic_vector(22 downto 0); 61 | signal SPC7110_DROM_DO : std_logic_vector(7 downto 0); 62 | signal SPC7110_DROM_OE_N : std_logic; 63 | signal SPC7110_DROM_RDY : std_logic; 64 | signal SNES_DROM_A : std_logic_vector(22 downto 0); 65 | signal SNES_DROM_OE_N : std_logic; 66 | 67 | signal SRAM_CE_N : std_logic; 68 | 69 | signal RTC_DI : std_logic_vector(3 downto 0); 70 | signal RTC_DO : std_logic_vector(3 downto 0); 71 | signal RTC_CE : std_logic; 72 | signal RTC_CK : std_logic; 73 | 74 | signal SPC7110_DO : std_logic_vector(7 downto 0); 75 | signal SNES_ROM_ACTIVE : std_logic; 76 | signal SPC7110_DROM_ACTIVE : std_logic; 77 | signal ROM_RD : std_logic; 78 | signal ROM_RD_LATE : std_logic; 79 | 80 | signal MAP_SEL : std_logic; 81 | 82 | begin 83 | 84 | MAP_SEL <= '1' when MAP_CTRL(7 downto 4) = X"D" else '0'; 85 | MAP_ACTIVE <= MAP_SEL; 86 | 87 | SPC7110 : entity work.SPC7110 88 | port map( 89 | RST_N => RST_N and MAP_SEL, 90 | CLK => MCLK, 91 | ENABLE => ENABLE, 92 | 93 | CA => CA, 94 | DO => SPC7110_DO, 95 | DI => DI, 96 | CPURD_N => CPURD_N, 97 | CPUWR_N => CPUWR_N, 98 | 99 | SYSCLKF_CE => SYSCLKF_CE, 100 | SYSCLKR_CE => SYSCLKR_CE, 101 | 102 | DROM_A => SPC7110_DROM_A, 103 | DROM_OE_N => SPC7110_DROM_OE_N, 104 | DROM_DO => ROM_Q(7 downto 0), 105 | DROM_RDY => SPC7110_DROM_RDY, 106 | 107 | PROM_OE_N => PROM_OE_N, 108 | SNES_DROM_A => SNES_DROM_A, 109 | SNES_DROM_OE_N => SNES_DROM_OE_N, 110 | SRAM_CE_N => SRAM_CE_N, 111 | 112 | RTC_DO => RTC_DI, 113 | RTC_DI => RTC_DO, 114 | RTC_CE => RTC_CE, 115 | RTC_CK => RTC_CK 116 | ); 117 | 118 | RTC : entity work.RTC4513 119 | port map( 120 | CLK => MCLK, 121 | ENABLE => ENABLE, 122 | 123 | DO => RTC_DO, 124 | DI => RTC_DI, 125 | CE => RTC_CE, 126 | CK => RTC_CK, 127 | 128 | EXT_RTC => EXT_RTC 129 | ); 130 | 131 | 132 | process(MCLK, RST_N) 133 | begin 134 | if RST_N = '0' then 135 | SNES_ROM_ACTIVE <= '0'; 136 | SPC7110_DROM_ACTIVE <= '0'; 137 | SPC7110_DROM_RDY <= '0'; 138 | ROM_RD_LATE <= '0'; 139 | elsif rising_edge(MCLK) then 140 | if SYSCLKF_CE = '1' then 141 | SPC7110_DROM_ACTIVE <= not SPC7110_DROM_OE_N; 142 | SNES_ROM_ACTIVE <= '0'; 143 | elsif SYSCLKR_CE = '1' then 144 | SPC7110_DROM_ACTIVE <= '0'; 145 | SNES_ROM_ACTIVE <= '1'; 146 | end if; 147 | 148 | ROM_RD_LATE <= ROM_RD; --waiting for 2 cycles of reading sdram 149 | 150 | SPC7110_DROM_RDY <= '0'; 151 | if SPC7110_DROM_RDY = '0' and ROM_RD_LATE = '1' and SPC7110_DROM_ACTIVE = '1' then 152 | SPC7110_DROM_RDY <= '1'; 153 | end if; 154 | end if; 155 | end process; 156 | 157 | process(MCLK, RST_N) 158 | begin 159 | if RST_N = '0' then 160 | ROM_RD <= '0'; 161 | elsif rising_edge(MCLK) then 162 | ROM_RD <= '0'; 163 | if SYSCLKR_CE = '1' or SYSCLKF_CE = '1' then 164 | ROM_RD <= '1'; 165 | end if; 166 | end if; 167 | end process; 168 | 169 | -- SYSCLK |___|---| 170 | -- 0 - slot for SPC7110 for DROM access if need, else same SNES access (for sdram refresh) 171 | -- 1 - slot for SNES for PROM/DROM access, first 1 MByte - PROM, rest - DROM 172 | process(CA, SPC7110_DROM_A, SNES_DROM_A, SPC7110_DROM_ACTIVE, SNES_DROM_OE_N, SNES_ROM_ACTIVE) 173 | begin 174 | if SNES_ROM_ACTIVE = '0' then 175 | if SPC7110_DROM_ACTIVE = '1' then 176 | ROM_ADDR <= std_logic_vector(unsigned(SPC7110_DROM_A(22 downto 20)) + "001") & SPC7110_DROM_A(19 downto 0); 177 | else 178 | ROM_ADDR <= (not CA(23) and CA(22)) & (not CA(23) and CA(22)) & "0" & CA(19 downto 0); 179 | end if; 180 | else 181 | if SNES_DROM_OE_N = '0' then 182 | ROM_ADDR <= std_logic_vector(unsigned(SNES_DROM_A(22 downto 20)) + "001") & SNES_DROM_A(19 downto 0); 183 | else 184 | ROM_ADDR <= (not CA(23) and CA(22)) & (not CA(23) and CA(22)) & "0" & CA(19 downto 0); 185 | end if; 186 | end if; 187 | end process; 188 | ROM_CE_N <= '0'; 189 | ROM_OE_N <= not ROM_RD; 190 | ROM_WORD <= '0'; 191 | 192 | BSRAM_ADDR <= ("0000000" & CA(12 downto 0)) and BSRAM_MASK(19 downto 0); 193 | BSRAM_D <= DI; 194 | BSRAM_CE_N <= SRAM_CE_N; 195 | BSRAM_OE_N <= CPURD_N; 196 | BSRAM_WE_N <= CPUWR_N; 197 | 198 | DO <= ROM_Q(7 downto 0) when PROM_OE_N = '0' or SNES_DROM_OE_N = '0' else 199 | BSRAM_Q when SRAM_CE_N = '0' else 200 | SPC7110_DO; 201 | 202 | IRQ_N <= '1'; 203 | 204 | end rtl; 205 | -------------------------------------------------------------------------------- /rtl/chip/SRTC.vhd: -------------------------------------------------------------------------------- 1 | library IEEE; 2 | use IEEE.STD_LOGIC_1164.ALL; 3 | library STD; 4 | use IEEE.NUMERIC_STD.ALL; 5 | 6 | entity SRTC is 7 | port( 8 | CLK : in std_logic; 9 | 10 | A0 : in std_logic; 11 | DI : in std_logic_vector(7 downto 0); 12 | DO : out std_logic_vector(7 downto 0); 13 | CS : in std_logic; 14 | CPURD_N : in std_logic; 15 | CPUWR_N : in std_logic; 16 | 17 | SYSCLKF_CE : in std_logic; 18 | 19 | EXT_RTC : in std_logic_vector(64 downto 0) 20 | ); 21 | end SRTC; 22 | 23 | architecture rtl of SRTC is 24 | 25 | type regs_t is array(0 to 12) of std_logic_vector(3 downto 0); 26 | signal REGS : regs_t; 27 | 28 | signal INDEX : integer range 0 to 15 := 15; 29 | signal MODE : integer range 0 to 3 := 0; 30 | 31 | signal SEC_DIV : integer := 0; 32 | signal SEC_TICK : std_logic := '0'; 33 | signal LAST_RTC64 : std_logic := '0'; 34 | 35 | type LastDayOfMonth_t is array(0 to 12) of std_logic_vector(7 downto 0); 36 | constant DAYS_TBL : LastDayOfMonth_t := ( 37 | x"31",--not use 38 | x"31",--01 39 | x"28",--02 40 | x"31",--03 41 | x"30",--04 42 | x"31",--05 43 | x"30",--06 44 | x"31",--07 45 | x"31",--08 46 | x"30",--09 47 | x"31",--10 48 | x"30",--11 49 | x"31" --12 50 | ); 51 | 52 | begin 53 | 54 | process( CLK) 55 | begin 56 | if rising_edge(CLK) then 57 | SEC_TICK <= '0'; 58 | 59 | SEC_DIV <= SEC_DIV + 1; 60 | if SEC_DIV = 21477270-1 then 61 | SEC_DIV <= 0; 62 | SEC_TICK <= '1'; 63 | end if; 64 | end if; 65 | end process; 66 | 67 | process( CLK) 68 | variable DAY_OF_MONTH_L : std_logic_vector(3 downto 0); 69 | variable DAY_OF_MONTH_H : std_logic_vector(3 downto 0); 70 | begin 71 | if rising_edge(CLK) then 72 | DAY_OF_MONTH_H := DAYS_TBL(to_integer(unsigned(REGS(8))))(7 downto 4); 73 | DAY_OF_MONTH_L := DAYS_TBL(to_integer(unsigned(REGS(8))))(3 downto 0); 74 | 75 | if SEC_TICK = '1' then 76 | REGS(0) <= std_logic_vector( unsigned(REGS(0)) + 1 ); --sec low inc 77 | if REGS(0) = x"9" then 78 | REGS(0) <= (others => '0'); 79 | REGS(1) <= std_logic_vector( unsigned(REGS(1)) + 1 ); --sec high inc 80 | if REGS(1) = x"5" then 81 | REGS(1) <= (others => '0'); 82 | REGS(2) <= std_logic_vector( unsigned(REGS(2)) + 1 ); --min low inc 83 | if REGS(2) = x"9" then 84 | REGS(2) <= (others => '0'); 85 | REGS(3) <= std_logic_vector( unsigned(REGS(3)) + 1 ); --min high inc 86 | if REGS(3) = x"5" then 87 | REGS(3) <= (others => '0'); 88 | REGS(4) <= std_logic_vector( unsigned(REGS(4)) + 1 ); --hour low inc 89 | if REGS(4) = x"9" and REGS(5) <= x"2" then 90 | REGS(4) <= (others => '0'); 91 | REGS(5) <= std_logic_vector( unsigned(REGS(5)) + 1 ); --hour high inc 92 | elsif REGS(4) = x"3" and REGS(5) = x"2" then 93 | REGS(4) <= (others => '0'); 94 | REGS(5) <= (others => '0'); 95 | REGS(6) <= std_logic_vector( unsigned(REGS(6)) + 1 ); --day low inc 96 | if REGS(6) = x"9" and REGS(7)(1 downto 0) <= x"2" then 97 | REGS(6) <= (others => '0'); 98 | REGS(7) <= std_logic_vector( unsigned(REGS(7)) + 1 ); --day high inc 99 | elsif REGS(6) = DAY_OF_MONTH_L and REGS(7) = DAY_OF_MONTH_H then 100 | REGS(6) <= x"1"; 101 | REGS(7) <= (others => '0'); 102 | REGS(8) <= std_logic_vector( unsigned(REGS(8)) + 1 ); --month inc 103 | if REGS(8) = x"C" then 104 | REGS(8) <= x"1"; 105 | REGS(9) <= std_logic_vector( unsigned(REGS(9)) + 1 ); --year low inc 106 | if REGS(9) = x"9" then 107 | REGS(9) <= (others => '0'); 108 | REGS(10) <= std_logic_vector( unsigned(REGS(10)) + 1 ); --year high inc 109 | if REGS(10) = x"9" then 110 | REGS(10) <= (others => '0'); 111 | REGS(11) <= std_logic_vector( unsigned(REGS(11)) + 1 ); --century inc 112 | if REGS(11) = x"C" then 113 | REGS(11) <= (others => '0'); 114 | end if; 115 | end if; 116 | end if; 117 | end if; 118 | end if; 119 | REGS(12) <= std_logic_vector( unsigned(REGS(12)) + 1 ); --weeks inc 120 | if REGS(12) = x"6" then 121 | REGS(12) <= (others => '0'); 122 | end if; 123 | end if; 124 | end if; 125 | end if; 126 | end if; 127 | end if; 128 | end if; 129 | 130 | if EXT_RTC(64) /= LAST_RTC64 then 131 | LAST_RTC64 <= EXT_RTC(64); 132 | REGS(0) <= EXT_RTC(3 downto 0); 133 | REGS(1) <= EXT_RTC(7 downto 4); 134 | REGS(2) <= EXT_RTC(11 downto 8); 135 | REGS(3) <= EXT_RTC(15 downto 12); 136 | REGS(4) <= EXT_RTC(19 downto 16); 137 | REGS(5) <= EXT_RTC(23 downto 20); 138 | REGS(6) <= EXT_RTC(27 downto 24); 139 | REGS(7) <= EXT_RTC(31 downto 28); 140 | if EXT_RTC(36) = '0' then 141 | REGS(8) <= EXT_RTC(35 downto 32); 142 | else 143 | REGS(8) <= std_logic_vector( unsigned(EXT_RTC(35 downto 32)) + 10 ); 144 | end if; 145 | REGS(9) <= EXT_RTC(43 downto 40); 146 | REGS(10) <= EXT_RTC(47 downto 44); 147 | REGS(11) <= x"A"; 148 | REGS(12) <= EXT_RTC(51 downto 48); 149 | end if; 150 | 151 | if CS = '1' and SYSCLKF_CE = '1' then 152 | if CPUWR_N = '0' and A0 = '1' then 153 | if DI(3 downto 0) = x"D" then 154 | INDEX <= 15; 155 | MODE <= 0; 156 | elsif DI(3 downto 0) = x"E" then 157 | MODE <= 1; 158 | else 159 | if MODE = 1 then 160 | case DI(3 downto 0) is 161 | when x"0" => 162 | MODE <= 2; 163 | INDEX <= 0; 164 | when others => 165 | MODE <= 3; 166 | end case; 167 | elsif MODE = 2 then 168 | if INDEX < 12 then 169 | REGS(INDEX) <= DI(3 downto 0); 170 | INDEX <= INDEX + 1; 171 | end if; 172 | end if; 173 | end if; 174 | end if; 175 | 176 | if CPURD_N = '0' and A0 = '0' then 177 | if MODE = 0 then 178 | if INDEX = 13 then 179 | INDEX <= 15; 180 | else 181 | INDEX <= INDEX + 1; 182 | end if; 183 | end if; 184 | end if; 185 | end if; 186 | end if; 187 | end process; 188 | 189 | DO <= x"0" & REGS(INDEX) when INDEX <= 12 else x"0F"; 190 | 191 | end rtl; 192 | -------------------------------------------------------------------------------- /rtl/chip/chip.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) CX4/CX4.vhd ] 2 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) CX4/cx4cache.vhd ] 3 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) CX4/CX4Map.vhd ] 4 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) DSP/DSPn.vhd ] 5 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) DSP/DSP_LHRomMap.vhd ] 6 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) DSP/OBC1.vhd ] 7 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) SDD1/InputMgr.vhd ] 8 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) SDD1/Decoder.vhd ] 9 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) SDD1/SDD1.vhd ] 10 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) SDD1/SDD1Map.vhd ] 11 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) GSU/GSU.vhd ] 12 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) GSU/GSU_PKG.vhd ] 13 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) GSU/GSUMap.vhd ] 14 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) SA1/SA1.vhd ] 15 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) SA1/SA1DIV.vhd ] 16 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) SA1/SA1MULT.vhd ] 17 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) SA1/SA1Map.vhd ] 18 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) SPC7110/SPC7110.vhd ] 19 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) SPC7110/SPC7110_DEC.vhd ] 20 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) SPC7110/SPC7110_DEC_PKG.vhd ] 21 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) SPC7110/SPC7110_FIFO.vhd ] 22 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) SPC7110/SPC7110_MULDIV.vhd ] 23 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) SPC7110/SPC7110Map.vhd ] 24 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) BSX/BSX_MCC.vhd ] 25 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) BSX/BSX_DP.vhd ] 26 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) BSX/BSX_BS.vhd ] 27 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) BSX/BSXMap.vhd ] 28 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) MSU1/MSU.sv ] 29 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) MSU1/msu_audio.v ] 30 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) MSU1/msu_fifo.v ] 31 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) MSU1/msu_data_store.sv ] 32 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) RTC4513.vhd ] 33 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) SRTC.vhd ] 34 | -------------------------------------------------------------------------------- /rtl/hps_ext.v: -------------------------------------------------------------------------------- 1 | // 2 | // hps_ext for Mega CD 3 | // 4 | // Copyright (c) 2020 Alexey Melnikov 5 | // 6 | // This source file is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published 8 | // by the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // This source file is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | /////////////////////////////////////////////////////////////////////// 20 | 21 | module hps_ext 22 | ( 23 | input reset, 24 | input clk_sys, 25 | inout [35:0] EXT_BUS, 26 | 27 | output reg msu_enable, 28 | 29 | input [15:0] msu_track_num, 30 | input msu_track_request, 31 | output reg msu_track_mounting, 32 | output reg msu_track_missing, 33 | 34 | output reg [31:0] msu_audio_size, 35 | output reg msu_audio_ack, 36 | input msu_audio_req, 37 | input msu_audio_seek, 38 | input [21:0] msu_audio_sector, 39 | input msu_audio_download, 40 | 41 | output reg [31:0] msu_data_base 42 | ); 43 | 44 | assign EXT_BUS[15:0] = io_dout; 45 | wire [15:0] io_din = EXT_BUS[31:16]; 46 | assign EXT_BUS[32] = dout_en; 47 | wire io_strobe = EXT_BUS[33]; 48 | wire io_enable = EXT_BUS[34]; 49 | 50 | localparam EXT_CMD_MIN = CD_GET; 51 | localparam EXT_CMD_MAX = CD_SET; 52 | 53 | localparam CD_GET = 'h34; 54 | localparam CD_SET = 'h35; 55 | 56 | reg [15:0] io_dout; 57 | reg dout_en = 0; 58 | reg [9:0] byte_cnt; 59 | 60 | always@(posedge clk_sys) begin 61 | reg [15:0] cmd; 62 | reg [7:0] cd_req = 0; 63 | 64 | cd_get <= 0; 65 | if(cd_put) cd_req <= cd_req + 1'd1; 66 | 67 | if(~io_enable) begin 68 | dout_en <= 0; 69 | io_dout <= 0; 70 | byte_cnt <= 0; 71 | if(cmd == 'h35) cd_get <= 1; 72 | end 73 | else if(io_strobe) begin 74 | 75 | io_dout <= 0; 76 | if(~&byte_cnt) byte_cnt <= byte_cnt + 1'd1; 77 | 78 | if(byte_cnt == 0) begin 79 | cmd <= io_din; 80 | dout_en <= (io_din >= EXT_CMD_MIN && io_din <= EXT_CMD_MAX); 81 | if(io_din == CD_GET) io_dout <= cd_req; 82 | end else begin 83 | case(cmd) 84 | CD_GET: 85 | if(!byte_cnt[9:3]) begin 86 | case(byte_cnt[2:0]) 87 | 1: io_dout <= cd_in[15:0]; 88 | 2: io_dout <= cd_in[31:16]; 89 | 3: io_dout <= cd_in[47:32]; 90 | endcase 91 | end 92 | 93 | CD_SET: 94 | if(!byte_cnt[9:3]) begin 95 | case(byte_cnt[2:0]) 96 | 1: cd_out[15:0] <= io_din; 97 | 2: cd_out[31:16] <= io_din; 98 | 3: cd_out[47:32] <= io_din; 99 | endcase 100 | end 101 | endcase 102 | end 103 | end 104 | end 105 | 106 | reg [47:0] cd_in; 107 | reg [47:0] cd_out; 108 | reg cd_put, cd_get; 109 | 110 | always @(posedge clk_sys) begin 111 | reg reset_old = 0; 112 | reg msu_audio_req_old = 0; 113 | reg msu_audio_seek_old = 0; 114 | reg msu_track_request_old = 0; 115 | reg msu_audio_download_old = 0; 116 | 117 | cd_put <= 0; 118 | 119 | reset_old <= reset; 120 | if (reset) begin 121 | msu_track_missing <= 0; 122 | msu_track_mounting <= 0; 123 | msu_audio_ack <= 0; 124 | if (!reset_old) begin 125 | cd_in <= 8'hFF; 126 | cd_put <= 1; 127 | end 128 | end 129 | 130 | msu_audio_download_old <= msu_audio_download; 131 | if (!msu_audio_download && msu_audio_download_old) begin 132 | msu_audio_ack <= 0; 133 | end 134 | if (msu_audio_download && !msu_audio_download_old) begin 135 | msu_audio_ack <= 1; 136 | end 137 | 138 | // Outgoing messaging 139 | // Sectors 140 | msu_audio_req_old <= msu_audio_req; 141 | if (!msu_track_request && !msu_audio_req_old && msu_audio_req) begin 142 | cd_in <= 'h34; 143 | cd_put <= 1; 144 | end 145 | 146 | // Jump to a sector 147 | msu_audio_seek_old <= msu_audio_seek; 148 | if (!msu_track_request && !msu_audio_seek_old && msu_audio_seek) begin 149 | cd_in <= { msu_audio_sector, 16'h36 }; 150 | cd_put <= 1; 151 | end 152 | 153 | // Track requests 154 | msu_track_request_old <= msu_track_request; 155 | if (!msu_track_request_old && msu_track_request) begin 156 | cd_in <= { msu_track_num, 16'h35 }; 157 | cd_put <= 1; 158 | msu_track_missing <= 0; 159 | msu_track_mounting <= 1; 160 | end 161 | 162 | if (cd_get) begin 163 | case(cd_out[3:0]) 164 | 1: msu_enable <= cd_out[15]; 165 | 2: {msu_audio_size, msu_track_missing, msu_track_mounting, msu_audio_ack} <= {cd_out[47:16], !cd_out[47:16], 2'b00}; 166 | 3: msu_data_base <= cd_out[47:16]; 167 | endcase 168 | end 169 | end 170 | 171 | endmodule 172 | -------------------------------------------------------------------------------- /rtl/ioport.sv: -------------------------------------------------------------------------------- 1 | 2 | module ioport 3 | ( 4 | input CLK, 5 | 6 | input MULTITAP, 7 | 8 | input PORT_LATCH, 9 | input PORT_CLK, 10 | input PORT_P6, 11 | output [1:0] PORT_DO, 12 | 13 | input [11:0] JOYSTICK1, 14 | input [11:0] JOYSTICK2, 15 | input [11:0] JOYSTICK3, 16 | input [11:0] JOYSTICK4, 17 | 18 | input [7:0] JOY_X, 19 | input [7:0] JOY_Y, 20 | 21 | input [7:0] DPAD_AIM_SPEED, 22 | 23 | input MOUSE_EN 24 | ); 25 | 26 | assign PORT_DO = {(JOY_LATCH1[15] & ~PORT_LATCH) | ~MULTITAP, MOUSE_EN ? MS_LATCH[31] : JOY_LATCH0[15]}; 27 | 28 | wire [11:0] JOYSTICK[4] = '{JOYSTICK1,JOYSTICK2,JOYSTICK3,JOYSTICK4}; 29 | 30 | wire JOYn = ~PORT_P6 & MULTITAP; 31 | 32 | wire [15:0] JOY0 = {JOYSTICK[{JOYn,1'b0}][5], JOYSTICK[{JOYn,1'b0}][7], 33 | JOYSTICK[{JOYn,1'b0}][10], JOYSTICK[{JOYn,1'b0}][11], 34 | JOYSTICK[{JOYn,1'b0}][3], JOYSTICK[{JOYn,1'b0}][2], 35 | JOYSTICK[{JOYn,1'b0}][1], JOYSTICK[{JOYn,1'b0}][0], 36 | JOYSTICK[{JOYn,1'b0}][4], JOYSTICK[{JOYn,1'b0}][6], 37 | JOYSTICK[{JOYn,1'b0}][8], JOYSTICK[{JOYn,1'b0}][9], 4'b0000}; 38 | 39 | wire [15:0] JOY1 = {JOYSTICK[{JOYn,1'b1}][5], JOYSTICK[{JOYn,1'b1}][7], 40 | JOYSTICK[{JOYn,1'b1}][10], JOYSTICK[{JOYn,1'b1}][11], 41 | JOYSTICK[{JOYn,1'b1}][3], JOYSTICK[{JOYn,1'b1}][2], 42 | JOYSTICK[{JOYn,1'b1}][1], JOYSTICK[{JOYn,1'b1}][0], 43 | JOYSTICK[{JOYn,1'b1}][4], JOYSTICK[{JOYn,1'b1}][6], 44 | JOYSTICK[{JOYn,1'b1}][8], JOYSTICK[{JOYn,1'b1}][9], 4'b0000}; 45 | 46 | // Gamepads 47 | reg [15:0] JOY_LATCH0; 48 | always @(posedge CLK) begin 49 | reg old_clk, old_n; 50 | old_clk <= PORT_CLK; 51 | old_n <= JOYn; 52 | if(PORT_LATCH | (~old_n & JOYn)) JOY_LATCH0 <= ~JOY0; 53 | else if (~old_clk & PORT_CLK) JOY_LATCH0 <= JOY_LATCH0 << 1; 54 | end 55 | 56 | reg [15:0] JOY_LATCH1; 57 | always @(posedge CLK) begin 58 | reg old_clk, old_n; 59 | old_clk <= PORT_CLK; 60 | old_n <= JOYn; 61 | if(PORT_LATCH | (~old_n & JOYn)) JOY_LATCH1 <= ~JOY1; 62 | else if (~old_clk & PORT_CLK) JOY_LATCH1 <= JOY_LATCH1 << 1; 63 | end 64 | 65 | // Mouse 66 | wire dpad_mouse_sdy = JOYSTICK1[3]; 67 | wire dpad_mouse_sdx = JOYSTICK1[1]; 68 | wire [6:0] dpad_mouse_dy = JOYSTICK1[3] | JOYSTICK1[2] ? DPAD_AIM_SPEED[6:0] : 7'd0; 69 | wire [6:0] dpad_mouse_dx = JOYSTICK1[0] | JOYSTICK1[1] ? DPAD_AIM_SPEED[6:0] : 7'd0; 70 | wire joy_mouse_sdy = ~JOY_Y[7]; 71 | wire joy_mouse_sdx = ~JOY_X[7]; 72 | wire [6:0] joy_mouse_dy = joy_mouse_sdy ? (8'd128-JOY_Y) >> 4 : (JOY_Y[6:0]) >> 4; 73 | wire [6:0] joy_mouse_dx = joy_mouse_sdx ? (8'd128-JOY_X) >> 4 : (JOY_X[6:0]) >> 4; 74 | wire mouse_left = JOYSTICK1[5]; 75 | wire mouse_right = JOYSTICK1[4]; 76 | 77 | reg joystick_detected = 0; 78 | reg [1:0] speed = 0; 79 | reg [31:0] MS_LATCH; 80 | always @(posedge CLK) begin 81 | reg old_stb, old_clk, old_latch; 82 | reg sdx,sdy; 83 | 84 | old_clk <= PORT_CLK; 85 | old_latch <= PORT_LATCH; 86 | 87 | if (JOY_Y || JOY_X) 88 | joystick_detected <= 1'b1; 89 | 90 | if(old_latch & ~PORT_LATCH) begin 91 | if(joystick_detected && (joy_mouse_dy + joy_mouse_dx > 0)) begin 92 | MS_LATCH <= ~{8'h00, mouse_left, mouse_right, speed, 4'b0001, joy_mouse_sdy, joy_mouse_dy, joy_mouse_sdx, joy_mouse_dx}; 93 | end else begin 94 | MS_LATCH <= ~{8'h00, mouse_left, mouse_right, speed, 4'b0001, dpad_mouse_sdy, dpad_mouse_dy, dpad_mouse_sdx, dpad_mouse_dx}; 95 | end 96 | end 97 | 98 | if(~old_clk & PORT_CLK) begin 99 | if(PORT_LATCH) begin 100 | speed <= speed + 1'd1; 101 | if(speed == 2) speed <= 0; 102 | end 103 | else MS_LATCH <= MS_LATCH << 1; 104 | end 105 | end 106 | 107 | endmodule 108 | -------------------------------------------------------------------------------- /rtl/lightgun.sv: -------------------------------------------------------------------------------- 1 | 2 | module lightgun 3 | ( 4 | input CLK, 5 | input RESET, 6 | 7 | //input [24:0] MOUSE, 8 | //input MOUSE_XY, 9 | 10 | input [7:0] JOY_X,JOY_Y, 11 | input F,C,T,P, 12 | 13 | input UP, 14 | input DOWN, 15 | input LEFT, 16 | input RIGHT, 17 | input [7:0] DPAD_AIM_SPEED, 18 | 19 | input HDE,VDE, 20 | input CLKPIX, 21 | 22 | output [2:0] TARGET, 23 | input SIZE, 24 | input GUN_TYPE, 25 | 26 | input PORT_LATCH, 27 | input PORT_CLK, 28 | output PORT_P6, 29 | output [1:0] PORT_DO 30 | ); 31 | 32 | parameter CROSS_SZ = 8'd4; 33 | 34 | assign PORT_DO = {1'b1, GUN_TYPE ? JUSTIFIER_LATCH[31] : JOY_LATCH0[7]}; 35 | assign TARGET = {{2{~Ttr & ~offscreen & draw}}, Ttr & ~offscreen & draw}; 36 | 37 | reg Ttr; // 0 - one-shot fire. 1 - continous fire. 38 | reg Fb = 0, Pb = 0; 39 | 40 | reg [2:0] reload_pend; 41 | reg [2:0] reload; 42 | 43 | reg [7:0] JOY_LATCH0; 44 | reg [31:0] JUSTIFIER_LATCH; 45 | always @(posedge CLK) begin 46 | reg old_clk, old_f, old_p, old_t, old_latch; 47 | old_clk <= PORT_CLK; 48 | 49 | old_latch <= PORT_LATCH; 50 | if(old_latch & ~PORT_LATCH) begin 51 | Pb <= 0; 52 | if(~Ttr) Fb <= 0; 53 | end 54 | 55 | old_t <= T; 56 | if(~old_t & T) Ttr <=~Ttr; 57 | if(RESET) Ttr <= 1; 58 | 59 | old_f <= F; 60 | if(~old_f & F) Fb <= 1; 61 | if(old_f & ~F) Fb <= 0; 62 | 63 | old_p <= P; 64 | if(~old_p & P) Pb <= 1; 65 | 66 | if(PORT_LATCH) begin 67 | JOY_LATCH0 <= ~{Fb,C,Ttr,Pb,2'b00,offscreen,1'b0}; 68 | JUSTIFIER_LATCH <= ~{24'b000000000000111001010101, reload ? 1'b1 : (reload_pend ? 1'b0 : F), 1'b0, P, 1'b0, 4'b1000}; 69 | end 70 | else if (~old_clk & PORT_CLK) begin 71 | JOY_LATCH0 <= JOY_LATCH0 << 1; 72 | JUSTIFIER_LATCH <= JUSTIFIER_LATCH << 1; 73 | end 74 | end 75 | 76 | reg [8:0] lg_x, lg_y, x, y; 77 | 78 | wire [9:0] new_x = {lg_x[8],lg_x};// + {{2{MOUSE[4]}},MOUSE[15:8]}; 79 | wire [9:0] new_y = {lg_y[8],lg_y};// - {{2{MOUSE[5]}},MOUSE[23:16]}; 80 | 81 | reg [7:0] old_joy_x; 82 | reg [7:0] old_joy_y; 83 | reg [8:0] j_x; 84 | reg [8:0] j_y; 85 | 86 | reg offscreen = 0, draw = 0; 87 | reg [21:0] port_p6_sr; 88 | always @(posedge CLK) begin 89 | reg old_pix, old_hde, old_vde, old_ms; 90 | reg [8:0] hcnt, vcnt; 91 | reg [8:0] vtotal; 92 | reg [15:0] hde_d; 93 | reg [8:0] xm,xp,ym,yp; 94 | reg reload_pressed; 95 | reg [16:0] jy1,jy2; 96 | 97 | jy1 <= {8'd0, j_y} * vtotal; 98 | jy2 <= jy1; 99 | 100 | /*old_ms <= MOUSE[24]; 101 | if(MOUSE_XY) begin 102 | if(old_ms ^ MOUSE[24]) begin 103 | if(new_x[9]) lg_x <= 0; 104 | else if(new_x[8]) lg_x <= 255; 105 | else lg_x <= new_x[8:0]; 106 | 107 | if(new_y[9]) lg_y <= 0; 108 | else if(new_y > vtotal) lg_y <= vtotal; 109 | else lg_y <= new_y[8:0]; 110 | end 111 | end 112 | else begin*/ 113 | lg_x <= j_x; 114 | lg_y <= jy2[16:8]; 115 | if(jy2[16:8] > vtotal) lg_y <= vtotal; 116 | //end 117 | 118 | old_pix <= CLKPIX; 119 | if(~old_pix & CLKPIX) begin 120 | hde_d <= {hde_d[14:0],HDE}; 121 | old_hde <= hde_d[15]; 122 | if(~&hcnt) hcnt <= hcnt + 1'd1; 123 | if(~old_hde & ~HDE) hcnt <= 0; 124 | if(old_hde & ~hde_d[15]) begin 125 | if(~VDE) begin 126 | vcnt <= 0; 127 | if(vcnt) vtotal <= vcnt - 1'd1; 128 | end 129 | else if(~&vcnt) vcnt <= vcnt + 1'd1; 130 | end 131 | 132 | old_vde <= VDE; 133 | if(~old_vde & VDE) begin 134 | 135 | old_joy_x <= JOY_X; 136 | old_joy_y <= JOY_Y; 137 | if(old_joy_x != JOY_X || old_joy_y != JOY_Y) begin 138 | j_x <= JOY_X[7:0]; 139 | j_y <= JOY_Y[7:0]; 140 | end else begin 141 | if(LEFT) begin 142 | if (j_x >= DPAD_AIM_SPEED) j_x <= j_x - DPAD_AIM_SPEED; 143 | else j_x <= 0; 144 | end 145 | if(RIGHT) begin 146 | if(lg_x <= 8'd255 - DPAD_AIM_SPEED) j_x <= j_x + DPAD_AIM_SPEED; 147 | else j_x <= 8'd255; 148 | end 149 | if(UP) begin 150 | if (j_y >= DPAD_AIM_SPEED) j_y <= j_y - DPAD_AIM_SPEED; 151 | else j_y <= 0; 152 | end 153 | if(DOWN) begin 154 | if (j_y < vtotal - DPAD_AIM_SPEED) j_y <= j_y + DPAD_AIM_SPEED; 155 | else j_y <= vtotal; 156 | end 157 | end 158 | 159 | x <= lg_x; 160 | y <= lg_y; 161 | xm <= lg_x - CROSS_SZ; 162 | xp <= lg_x + CROSS_SZ; 163 | ym <= lg_y - CROSS_SZ; 164 | yp <= lg_y + CROSS_SZ; 165 | offscreen <= !lg_y[7:1] || lg_y >= (vtotal-1'd1) || !lg_x[7:1] || &lg_x[7:1] || reload_pend || reload; 166 | 167 | if(reload_pend && !reload) begin 168 | reload_pend <= reload_pend - 3'd1; 169 | if (reload_pend == 3'd1) reload <= 3'd5; 170 | end 171 | else if (reload) reload <= reload - 3'd1; 172 | end 173 | 174 | port_p6_sr <= {port_p6_sr[20:0], ~(HDE && VDE && x == hcnt && y == vcnt) || offscreen }; 175 | end 176 | 177 | reload_pressed <= C; 178 | if (GUN_TYPE && C && ~reload_pressed) reload_pend <= 3'd5; 179 | 180 | PORT_P6 <= port_p6_sr[21]; 181 | draw <= (((SIZE || ($signed(hcnt) >= $signed(xm) && hcnt <= xp)) && y == vcnt) || 182 | ((SIZE || ($signed(vcnt) >= $signed(ym) && vcnt <= yp)) && x == hcnt)); 183 | end 184 | 185 | endmodule 186 | -------------------------------------------------------------------------------- /rtl/mister_top/rom_parser_tb.sv: -------------------------------------------------------------------------------- 1 | `timescale 1 ns / 10 ps // time-unit = 1 ns, precision = 10 ps 2 | 3 | module rom_parser_tb; 4 | reg clk_74a = 0; 5 | 6 | localparam period = 20; 7 | localparam half_period = period / 2; 8 | 9 | reg [31:0] rom_file_size; 10 | 11 | reg [24:0] addr; 12 | reg [15:0] data; 13 | reg downloading; 14 | 15 | wire [2:0] parsed_rom_type; 16 | 17 | rom_parser rom_parser ( 18 | .clk_mem(clk_74a), 19 | 20 | .rom_file_size(rom_file_size), 21 | 22 | .addr(addr), 23 | .data(data), 24 | .downloading(downloading), 25 | 26 | .parsed_rom_type(parsed_rom_type) 27 | ); 28 | 29 | always begin 30 | #half_period clk_74a = ~clk_74a; 31 | end 32 | 33 | integer fd; 34 | integer value; 35 | 36 | reg div; 37 | 38 | initial begin 39 | fd = $fopen("Super Mario Kart.smc", "rb"); 40 | rom_file_size = 'h100000; 41 | downloading = 1; 42 | 43 | if (!fd) begin 44 | $error("Could not open file"); 45 | end 46 | 47 | addr = 0; 48 | 49 | value = $fgetc(fd); 50 | div = 1; 51 | data[7:0] = value; 52 | 53 | while (value != -1) begin 54 | value = $fgetc(fd); 55 | 56 | if (div) begin 57 | data[15:8] = value; 58 | 59 | // Send data 60 | #period; 61 | 62 | addr += 2; 63 | end else begin 64 | data[7:0] = value; 65 | end 66 | 67 | div = ~div; 68 | end 69 | 70 | #period; 71 | 72 | downloading = 0; 73 | 74 | #(10 * period); 75 | 76 | $stop; 77 | end 78 | 79 | endmodule 80 | -------------------------------------------------------------------------------- /rtl/mister_top/scanline_filler.sv: -------------------------------------------------------------------------------- 1 | module scanline_filler #( 2 | parameter int SNAP_COUNT = 1, 3 | parameter int SNAP_POINTS[SNAP_COUNT] = '{240}, 4 | parameter int HSYNC_DELAY = 6 5 | ) ( 6 | input wire clk, 7 | 8 | input wire hsync_in, 9 | input wire vsync_in, 10 | 11 | input wire vblank_in, 12 | input wire hblank_in, 13 | 14 | input wire [23:0] rgb_in, 15 | 16 | output reg hsync, 17 | output wire vsync, 18 | 19 | output reg de, 20 | output reg [23:0] rgb, 21 | output wire [7:0] snap_index, 22 | output wire [8:0] snap_point 23 | ); 24 | reg prev_de = 0; 25 | reg prev_hsync = 0; 26 | reg prev_vsync = 0; 27 | reg [2:0] hs_delay = 0; 28 | 29 | reg [8:0] output_line_count = 0; 30 | reg [8:0] visible_line_count = 0; 31 | // reg [9:0] clks_since_hsync_count = 0; 32 | // reg [8:0] black_pixel_count = 0; 33 | 34 | reg drawing_line = 0 /* synthesis noprune */; 35 | reg drawing_black = 0 /* synthesis noprune */; 36 | 37 | wire extended_vblank = vblank_in && ~(output_line_count < snap_point && output_line_count > 0) /* synthesis keep */; 38 | wire de_blanks = ~(hblank_in || extended_vblank); 39 | 40 | always @(posedge clk) begin 41 | prev_hsync <= hsync_in; 42 | prev_vsync <= vsync_in; 43 | prev_de <= de_blanks; 44 | 45 | hsync <= 0; 46 | de <= 0; 47 | rgb <= 0; 48 | // clks_since_hsync_count <= clks_since_hsync_count + 1; 49 | 50 | if (vsync_in && ~prev_vsync) begin 51 | // Reset line count on start of vsync 52 | output_line_count <= 0; 53 | visible_line_count <= 0; 54 | end 55 | 56 | if (de_blanks && ~prev_de) begin 57 | // We're drawing on this line 58 | drawing_line <= 1; 59 | drawing_black <= 0; 60 | end 61 | // else if (output_line_count < snap_point && ~drawing_line && 62 | // clks_since_hsync_count > CLKS_UNTIL_BLANK_LINE[9:0] && 63 | // black_pixel_count < horizontal_width) begin 64 | // // No data to render for this line, but we haven't met the snap point, so fill black 65 | // de <= 1; 66 | // rgb <= 0; 67 | // black_pixel_count <= black_pixel_count + 1; 68 | // drawing_black <= 1; 69 | // end 70 | 71 | if (de_blanks) begin 72 | de <= 1; 73 | if (vblank_in) begin 74 | // Extended blanking 75 | rgb <= 0; 76 | drawing_black <= 1; 77 | end else begin 78 | // Normal pixels 79 | rgb <= rgb_in; 80 | end 81 | end else if (~de_blanks && prev_de) begin 82 | // Falling edge of drawing 83 | output_line_count <= output_line_count + 1; 84 | if (~drawing_black) begin 85 | // If we drew black this line, it's not visible 86 | visible_line_count <= visible_line_count + 1; 87 | end 88 | end 89 | 90 | // Move hsync to not collide with vsync 91 | // ------------ 92 | if (hs_delay > 0) begin 93 | hs_delay <= hs_delay - 1; 94 | end 95 | 96 | if (hs_delay == 1) begin 97 | hsync <= 1; 98 | // clks_since_hsync_count <= 0; 99 | // black_pixel_count <= 0; 100 | // drawing_black <= 0; 101 | drawing_line <= 0; 102 | end 103 | 104 | if (hsync_in && ~prev_hsync) begin 105 | if (HSYNC_DELAY <= 1) begin 106 | hsync <= 1; 107 | // clks_since_hsync_count <= 0; 108 | // black_pixel_count <= 0; 109 | // drawing_black <= 0; 110 | drawing_line <= 0; 111 | end else begin 112 | hs_delay <= HSYNC_DELAY[2:0]; 113 | end 114 | end 115 | end 116 | 117 | always @(posedge clk) begin 118 | for (int i = 0; i < SNAP_COUNT; i = i + 1) begin 119 | if (visible_line_count <= SNAP_POINTS[i][8:0]) begin 120 | snap_index <= i[7:0]; 121 | snap_point <= SNAP_POINTS[i][8:0]; 122 | end 123 | end 124 | 125 | end 126 | 127 | assign vsync = vsync_in && ~prev_vsync; 128 | 129 | endmodule 130 | -------------------------------------------------------------------------------- /rtl/snes.qip: -------------------------------------------------------------------------------- 1 | # ============================================================================== 2 | # RTL 3 | # ============================================================================== 4 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "mister_top/SNES.sv"] 5 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "mister_top/rom_parser.sv"] 6 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "mister_top/scanline_filler.sv"] 7 | set_global_assignment -name MIF_FILE [file join $::quartus(qip_path) "chip/DSP/dsp11b23410_p.mif"] 8 | set_global_assignment -name MIF_FILE [file join $::quartus(qip_path) "chip/DSP/dsp11b23410_d.mif"] 9 | set_global_assignment -name MIF_FILE [file join $::quartus(qip_path) "chip/CX4/drom.mif"] 10 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) "SPC700/SPC700.qip"] 11 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) "65C816/65C816.qip"] 12 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "SWRAM.vhd"] 13 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "SNES.vhd"] 14 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "SMP.vhd"] 15 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "sdram.sv"] 16 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "PPU_PKG.vhd"] 17 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "PPU.vhd"] 18 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "miracle.sv"] 19 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "main.v"] 20 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "lightgun.sv"] 21 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "ioport.sv"] 22 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "hps_ext.v"] 23 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "DSP_PKG.vhd"] 24 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "DSP.vhd"] 25 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "CPU.vhd"] 26 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "cheatcodes.sv"] 27 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "CEGen.vhd"] 28 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "bram.vhd"] 29 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) "chip/chip.qip"] 30 | 31 | # ============================================================================== 32 | # MODULES 33 | # ============================================================================== 34 | 35 | -------------------------------------------------------------------------------- /support/loader.asm: -------------------------------------------------------------------------------- 1 | architecture chip32.vm 2 | output "loader.bin", create 3 | 4 | constant DEBUG = 0 5 | 6 | constant rom_dataslot = 0 7 | constant save_dataslot = 10 8 | 9 | // Host init command 10 | constant host_init = 0x4002 11 | 12 | // Addresses 13 | constant rom_file_size = 0x1000 14 | constant header_offset_addr = 0x1004 15 | 16 | constant lorom_header_seek = 0x007FBD 17 | constant hirom_header_seek = 0x00FFBD 18 | constant exhirom_header_seek = 0x40FFBD 19 | 20 | constant lorom_output = 0x1A00 21 | constant hirom_output = 0x1A10 22 | constant exhirom_output = 0x1A20 23 | 24 | constant romsz_addr = 0x1800 25 | 26 | // Error vector (0x0) 27 | jp error_handler 28 | 29 | // Init vector (0x2) 30 | jp start 31 | 32 | /// Includes /// 33 | include "util.asm" 34 | align(2) 35 | 36 | include "check_header.asm" 37 | align(2) 38 | 39 | start: 40 | ld r1,#rom_dataslot // populate data slot 41 | open r1,r2 42 | 43 | ld.l (rom_file_size),r2 44 | and r2,#0x200 // AND with 0x200, which implies SMC header 45 | jp z, no_header // If empty, no header 46 | log_string("File has header") 47 | jp store_header 48 | 49 | no_header: 50 | log_string("File doesn't have header") 51 | 52 | store_header: 53 | ld.w (header_offset_addr),r2 // Store header offset 54 | 55 | // Calculate romsz 56 | ld r1,#15 57 | ld r2,#0x1000000 // Max ROM size 58 | ld.l r3,(rom_file_size) // ROM file size 59 | ld.w r4,(header_offset_addr) // Header offset 60 | sub r3,r4 // Remove header offset from size for calculation 61 | 62 | rom_size_loop: 63 | cmp r1,#0 64 | jp z, finished_rom_size // If romsz == 0 65 | cmp r2,r3 66 | jp c, finished_rom_size // If size > r2 67 | asl r3,#1 // Else shift size left 1 68 | sub r1,#1 // Subtract 1 from rom size 69 | jp rom_size_loop 70 | 71 | finished_rom_size: 72 | ld.b (romsz_addr),r1 73 | log_string("Calculated ROM size:") 74 | hex.b r1 75 | 76 | check_header(lorom_header_seek, lorom_output) 77 | 78 | // Check headers at 0xFFBD 79 | ld.l r2,(rom_file_size) 80 | cmp r2,#0xFFFF 81 | jp c, finished_checking_headers // If ROM is smaller than 0xFFFF 82 | check_header(hirom_header_seek, hirom_output) 83 | 84 | // Check headers at 0x40FFBD 85 | ld.l r2,(rom_file_size) 86 | ld r3,#0x40 87 | asl r3,#16 // Shift left 16 times 88 | or r3,#0xFFFF // We now have 0x40FFFF in r3 89 | cmp r2,r3 90 | jp c, finished_checking_headers // If ROM is smaller than 0x40FFFF 91 | 92 | check_header(exhirom_header_seek, exhirom_output) 93 | 94 | // All headers checked, compare scores 95 | finished_checking_headers: 96 | close // Close file since we won't be seeking anymore 97 | 98 | ld.b r1,(lorom_output) // Get LoROM score 99 | ld.b r2,(hirom_output) // Get HiROM score 100 | ld.b r3,(exhirom_output) // Get ExHiROM score 101 | jp z,compare_scores // If ExHiROM has a score 102 | add r3,#4 // Add 4 to score to give weight if ExHiROM exists 103 | 104 | compare_scores: 105 | cmp r1,r2 // r1 - r2 106 | jp c, check_hirom_score // Jp if hirom >= lorom 107 | cmp r1,r3 // Else lorom >= hirom, so r1 - r3 108 | jp c, check_hirom_score // jp if exhirom >= lorom 109 | 110 | // LoROM has the highest core 111 | log_string("Choosing LoROM") 112 | ld.b r1,(lorom_output + 1) // Get LoROM chip type 113 | ld.b r2,(lorom_output + 2) // Get RAMSZ 114 | ld.b r3,(lorom_output + 3) // Get PAL 115 | jp set_core 116 | 117 | check_hirom_score: 118 | cmp r2,r3 119 | jp c, score_exhi // jp if exhirom >= hirom 120 | 121 | log_string("Choosing HiROM") 122 | ld.b r1,(hirom_output + 1) // Get HiROM chip type 123 | or r1,#1 // OR 1 to chip_type to mark HiROM 124 | ld.b r2,(hirom_output + 2) // Get RAMSZ 125 | ld.b r3,(hirom_output + 3) // Get PAL 126 | 127 | jp set_core 128 | 129 | score_exhi: 130 | log_string("Choosing ExHiROM") 131 | ld.b r1,(exhirom_output + 1) // Get ExHiROM chip type 132 | or r1,#2 // OR 2 to chip_type to mark ExHiROM 133 | ld.b r2,(exhirom_output + 2) // Get RAMSZ 134 | ld.b r3,(exhirom_output + 3) // Get PAL 135 | 136 | // Set core 137 | set_core: 138 | log_string("Setting core") 139 | ld r4,r1 // Copy chip type to r4 140 | and r4,#0xF0 // Get only the high nibble 141 | 142 | ld r8,#0 143 | core r8 // Default to the main core 144 | 145 | cmp r4,#0xD0 // Check if SPC7110 146 | jp nz, bit_sdd1 147 | log_string("Using SPC7110") 148 | jp expansion_core // It's SPC7110 149 | 150 | bit_sdd1: 151 | cmp r4,#0x50 // Check if SDD1 152 | jp nz, bit_bsx 153 | log_string("Using SDD1") 154 | jp expansion_core // It's SDD1 155 | 156 | bit_bsx: 157 | cmp r4,#0x30 // Check if BSX 158 | jp nz, check_pal 159 | log_string("Using BSX") 160 | // It's BSX 161 | 162 | expansion_core: 163 | ld r8,#1 164 | core r8 // Boot SPC7110/SDD1/BSX core 165 | jp send_chip 166 | 167 | check_pal: 168 | cmp r3,#1 // Check if PAL 169 | jp nz, send_chip 170 | // It's PAL 171 | ld r8,#2 172 | core r8 173 | 174 | send_chip: 175 | log_string("Sending chip type") 176 | ld r8,#8 177 | pmpw r8,r1 178 | 179 | log_string("Sending ROM size") 180 | ld.b r7,(romsz_addr) 181 | ld r8,#4 // Load address of ROM size 182 | pmpw r8,r7 // Send ROM size to FPGA 183 | 184 | log_string("Sending RAMSZ") 185 | ld r8,#0xC 186 | pmpw r8,r2 187 | 188 | log_string("Sending PAL") 189 | ld r8,#0x10 190 | pmpw r8,r3 191 | 192 | log_string("Booting") 193 | ld r1,#0 // Set address for write 194 | ld r2,#1 // Downloading start 195 | pmpw r1,r2 // Write ioctl_download = 1 196 | 197 | ld r1,#rom_dataslot 198 | ld.w r2,(header_offset_addr) // Get header offset 199 | adjfo r1,r2 // Offset by header offset 200 | loadf r1 // Load ROM 201 | 202 | ld r1,#0 // Set address for write 203 | ld r2,#0 // Downloading end 204 | pmpw r1,r2 // Write ioctl_download = 0 205 | 206 | // Load save 207 | ld r1,#0 // Set address for write 208 | ld r2,#1 // Downloading start 209 | pmpw r1,r2 // Write ioctl_download = 1 210 | 211 | ld r1,#save_dataslot 212 | loadf r1 // Load Save 213 | 214 | ld r1,#0 // Set address for write 215 | ld r2,#0 // Downloading end 216 | pmpw r1,r2 // Write ioctl_download = 0 217 | 218 | // Start core 219 | ld r0,#host_init 220 | host r0,r0 221 | 222 | exit 0 223 | 224 | error_handler: 225 | ld r14,#test_err_msg 226 | 227 | print: 228 | printf r14 229 | exit 1 230 | 231 | test_err_msg: 232 | db "Error",0 233 | align(2) 234 | -------------------------------------------------------------------------------- /support/loader.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agg23/openfpga-SNES/05f0587891754e885647915ed42faa52604fc1d5/support/loader.bin -------------------------------------------------------------------------------- /support/test.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agg23/openfpga-SNES/05f0587891754e885647915ed42faa52604fc1d5/support/test.bin -------------------------------------------------------------------------------- /support/test_data.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "magic": "APF_VER_1", 4 | "data_slots": [ 5 | { 6 | "name": "SMC", 7 | "id": 0, 8 | "filename": "C:/Users/adam/Downloads/SNES/Super Mario World (U) [!].smc", 9 | "required": true, 10 | "parameters": "0x109", 11 | "extensions": ["smc", "sfc"], 12 | "address": "0x10000000" 13 | }, 14 | { 15 | "name": "SMC", 16 | "id": 0, 17 | "filename": "C:/Users/adam/Downloads/SNES/Super Mario World With Header.smc", 18 | "required": true, 19 | "parameters": "0x109", 20 | "extensions": ["smc", "sfc"], 21 | "address": "0x10000000" 22 | }, 23 | { 24 | "name": "SMC", 25 | "id": 0, 26 | "filename": "C:/Users/adam/Downloads/SNES/Super Mario World 2 - Yoshi's Island.smc", 27 | "required": true, 28 | "parameters": "0x109", 29 | "extensions": ["smc", "sfc"], 30 | "address": "0x10000000" 31 | }, 32 | { 33 | "name": "SMC", 34 | "id": 0, 35 | "filename": "C:/Users/adam/Downloads/SNES/Pilotwings (U) [!].smc", 36 | "required": true, 37 | "parameters": "0x109", 38 | "extensions": ["smc", "sfc"], 39 | "address": "0x10000000" 40 | }, 41 | { 42 | "name": "SMC", 43 | "id": 0, 44 | "filename": "C:/Users/adam/Downloads/SNES/Asterix (Europe) (En,Fr,De,Es).sfc", 45 | "required": true, 46 | "parameters": "0x109", 47 | "extensions": ["smc", "sfc"], 48 | "address": "0x10000000" 49 | }, 50 | { 51 | "name": "SMC", 52 | "id": 0, 53 | "filename": "C:/Users/adam/Downloads/SNES/Super Mario Kart.smc", 54 | "required": true, 55 | "parameters": "0x109", 56 | "extensions": ["smc", "sfc"], 57 | "address": "0x10000000" 58 | }, 59 | { 60 | "name": "SMC", 61 | "id": 0, 62 | "filename": "C:/Users/adam/Downloads/SNES/Tales of Phantasia.smc", 63 | "required": true, 64 | "parameters": "0x109", 65 | "extensions": ["smc", "sfc"], 66 | "address": "0x10000000" 67 | }, 68 | { 69 | "name": "SMC", 70 | "id": 0, 71 | "filename": "C:/Users/adam/Downloads/SNES/Star Ocean (J) [!].smc", 72 | "required": true, 73 | "parameters": "0x109", 74 | "extensions": ["smc", "sfc"], 75 | "address": "0x10000000" 76 | }, 77 | { 78 | "name": "SMC", 79 | "id": 0, 80 | "filename": "C:/Users/adam/Downloads/SNES/Far East of Eden Zero (J).smc", 81 | "required": true, 82 | "parameters": "0x109", 83 | "extensions": ["smc", "sfc"], 84 | "address": "0x10000000" 85 | }, 86 | { 87 | "name": "SMC", 88 | "id": 0, 89 | "filename": "C:/Users/adam/Downloads/SNES/SDD1/Star Ocean Eng Patched.sfc", 90 | "required": true, 91 | "parameters": "0x109", 92 | "extensions": ["smc", "sfc"], 93 | "address": "0x10000000" 94 | } 95 | ] 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /support/util.asm: -------------------------------------------------------------------------------- 1 | /// Util Functions /// 2 | 3 | // Seek function 4 | // Input: location - r1 5 | // Clobbers Z 6 | macro seek() { 7 | seek r1 8 | jp z, seek_end 9 | 10 | // Failed to seek 11 | ld r14,#seek_err 12 | printf r14 13 | hex.l r1 14 | exit 1 15 | 16 | seek_end: 17 | } 18 | 19 | // Read function 20 | // Input: length - r1 21 | // Input: ouput memory address - r2 22 | // Clobbers Z 23 | macro read() { 24 | read r2,r1 25 | jp z, read_end 26 | 27 | // Failed to read 28 | ld r14,#read_err 29 | printf r14 30 | hex.l r1 31 | exit 1 32 | 33 | read_end: 34 | } 35 | 36 | macro align(size) { 37 | while (pc() % {size}) { 38 | db 0 39 | } 40 | } 41 | 42 | macro log_string(value) { 43 | if DEBUG { 44 | ld r15,#+ 45 | printf r15 46 | jp ++ 47 | 48 | +; 49 | db {value},0 50 | align(2) 51 | +; 52 | } 53 | } 54 | 55 | macro log_hex(value) { 56 | if DEBUG { 57 | ld r15,#{value} 58 | hex.l r15 59 | } 60 | } 61 | 62 | macro log_dec(value) { 63 | if DEBUG { 64 | ld r15,#{value} 65 | dec.l r15 66 | } 67 | } 68 | 69 | /// Messages /// 70 | 71 | seek_err: 72 | db "Seek fail 0x",0 73 | 74 | read_err: 75 | db "Read fail length 0x",0 76 | -------------------------------------------------------------------------------- /target/pocket/core.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "core_top.sv"] 2 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "core_bridge_cmd.v"] 3 | set_global_assignment -name SDC_FILE [file join $::quartus(qip_path) "core_constraints.sdc"] 4 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "data_loader.sv"] 5 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "data_unloader.sv"] 6 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "psram.sv"] 7 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "save_state_controller.sv"] 8 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "sound_i2s.sv"] 9 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "sync_fifo.sv"] 10 | 11 | set_global_assignment -name SIGNALTAP_FILE [file join $::quartus(qip_path) "stp1.stp"] 12 | 13 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) "mf_pllbase.qip"] 14 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) "mf_pllbase_pal.qip"] 15 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) "pll_reconfig.qip"] 16 | -------------------------------------------------------------------------------- /target/pocket/core_constraints.sdc: -------------------------------------------------------------------------------- 1 | # 2 | # user core constraints 3 | # 4 | # put your clock groups in here as well as any net assignments 5 | # 6 | 7 | set_clock_groups -asynchronous \ 8 | -group { bridge_spiclk } \ 9 | -group { clk_74a } \ 10 | -group { clk_74b } \ 11 | -group { ic|mp1|mf_pllbase_inst|altera_pll_i|*[0].*|divclk \ 12 | ic|mp1|mf_pllbase_inst|altera_pll_i|*[1].*|divclk } \ 13 | -group { ic|mp1|mf_pllbase_inst|altera_pll_i|*[2].*|divclk } \ 14 | -group { ic|mp1|mf_pllbase_inst|altera_pll_i|*[3].*|divclk } \ 15 | -group { ic|audio_mixer|audio_pll|mf_audio_pll_inst|altera_pll_i|general[0].gpll~PLL_OUTPUT_COUNTER|divclk \ 16 | ic|audio_mixer|audio_pll|mf_audio_pll_inst|altera_pll_i|general[1].gpll~PLL_OUTPUT_COUNTER|divclk } 17 | 18 | derive_clock_uncertainty 19 | 20 | set_multicycle_path -from {ic|nes|sdram|*} -to [get_clocks {ic|mp1|mf_pllbase_inst|altera_pll_i|*[1].*|divclk}] -start -setup 2 21 | set_multicycle_path -from {ic|nes|sdram|*} -to [get_clocks {ic|mp1|mf_pllbase_inst|altera_pll_i|*[1].*|divclk}] -start -hold 1 22 | 23 | set_multicycle_path -from [get_clocks {ic|mp1|mf_pllbase_inst|altera_pll_i|*[1].*|divclk}] -to {ic|nes|sdram|*} -setup 2 24 | set_multicycle_path -from [get_clocks {ic|mp1|mf_pllbase_inst|altera_pll_i|*[1].*|divclk}] -to {ic|nes|sdram|*} -hold 1 25 | 26 | set_false_path -from {ic|nes|mapper_flags*} 27 | #set_false_path -from {ic|nes|downloading*} 28 | -------------------------------------------------------------------------------- /target/pocket/mf_pllbase.ppf: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /target/pocket/mf_pllbase/mf_pllbase_0002.qip: -------------------------------------------------------------------------------- 1 | set_instance_assignment -name PLL_COMPENSATION_MODE NORMAL -to "*mf_pllbase_0002*|altera_pll:altera_pll_i*|*" 2 | set_instance_assignment -name PLL_CHANNEL_SPACING "0.0 KHz" -to "*mf_pllbase_0002*|altera_pll:altera_pll_i*|*" 3 | set_instance_assignment -name PLL_AUTO_RESET OFF -to "*mf_pllbase_0002*|altera_pll:altera_pll_i*|*" 4 | set_instance_assignment -name PLL_BANDWIDTH_PRESET AUTO -to "*mf_pllbase_0002*|altera_pll:altera_pll_i*|*" 5 | -------------------------------------------------------------------------------- /target/pocket/mf_pllbase/mf_pllbase_0002.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/10ps 2 | module mf_pllbase_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 'outclk2' 17 | output wire outclk_2, 18 | 19 | // interface 'outclk3' 20 | output wire outclk_3, 21 | 22 | // interface 'locked' 23 | output wire locked 24 | ); 25 | 26 | altera_pll #( 27 | .fractional_vco_multiplier("true"), 28 | .reference_clock_frequency("74.25 MHz"), 29 | .operation_mode("normal"), 30 | .number_of_clocks(4), 31 | .output_clock_frequency0("85.909080 MHz"), 32 | .phase_shift0("0 ps"), 33 | .duty_cycle0(50), 34 | .output_clock_frequency1("21.477270 MHz"), 35 | .phase_shift1("0 ps"), 36 | .duty_cycle1(50), 37 | .output_clock_frequency2("10.738635 MHz"), 38 | .phase_shift2("0 ps"), 39 | .duty_cycle2(50), 40 | .output_clock_frequency3("10.738635 MHz"), 41 | .phase_shift3("23280 ps"), 42 | .duty_cycle3(50), 43 | .output_clock_frequency4("0 MHz"), 44 | .phase_shift4("0 ps"), 45 | .duty_cycle4(50), 46 | .output_clock_frequency5("0 MHz"), 47 | .phase_shift5("0 ps"), 48 | .duty_cycle5(50), 49 | .output_clock_frequency6("0 MHz"), 50 | .phase_shift6("0 ps"), 51 | .duty_cycle6(50), 52 | .output_clock_frequency7("0 MHz"), 53 | .phase_shift7("0 ps"), 54 | .duty_cycle7(50), 55 | .output_clock_frequency8("0 MHz"), 56 | .phase_shift8("0 ps"), 57 | .duty_cycle8(50), 58 | .output_clock_frequency9("0 MHz"), 59 | .phase_shift9("0 ps"), 60 | .duty_cycle9(50), 61 | .output_clock_frequency10("0 MHz"), 62 | .phase_shift10("0 ps"), 63 | .duty_cycle10(50), 64 | .output_clock_frequency11("0 MHz"), 65 | .phase_shift11("0 ps"), 66 | .duty_cycle11(50), 67 | .output_clock_frequency12("0 MHz"), 68 | .phase_shift12("0 ps"), 69 | .duty_cycle12(50), 70 | .output_clock_frequency13("0 MHz"), 71 | .phase_shift13("0 ps"), 72 | .duty_cycle13(50), 73 | .output_clock_frequency14("0 MHz"), 74 | .phase_shift14("0 ps"), 75 | .duty_cycle14(50), 76 | .output_clock_frequency15("0 MHz"), 77 | .phase_shift15("0 ps"), 78 | .duty_cycle15(50), 79 | .output_clock_frequency16("0 MHz"), 80 | .phase_shift16("0 ps"), 81 | .duty_cycle16(50), 82 | .output_clock_frequency17("0 MHz"), 83 | .phase_shift17("0 ps"), 84 | .duty_cycle17(50), 85 | .pll_type("General"), 86 | .pll_subtype("General") 87 | ) altera_pll_i ( 88 | .rst (rst), 89 | .outclk ({outclk_3, outclk_2, outclk_1, outclk_0}), 90 | .locked (locked), 91 | .fboutclk ( ), 92 | .fbclk (1'b0), 93 | .refclk (refclk) 94 | ); 95 | endmodule 96 | 97 | -------------------------------------------------------------------------------- /target/pocket/mf_pllbase_pal.ppf: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /target/pocket/mf_pllbase_pal/mf_pllbase_pal_0002.qip: -------------------------------------------------------------------------------- 1 | set_instance_assignment -name PLL_COMPENSATION_MODE DIRECT -to "*mf_pllbase_pal_0002*|altera_pll:altera_pll_i*|*" 2 | set_instance_assignment -name PLL_CHANNEL_SPACING "0.0 KHz" -to "*mf_pllbase_pal_0002*|altera_pll:altera_pll_i*|*" 3 | set_instance_assignment -name PLL_AUTO_RESET OFF -to "*mf_pllbase_pal_0002*|altera_pll:altera_pll_i*|*" 4 | set_instance_assignment -name PLL_BANDWIDTH_PRESET AUTO -to "*mf_pllbase_pal_0002*|altera_pll:altera_pll_i*|*" 5 | -------------------------------------------------------------------------------- /target/pocket/mf_pllbase_pal/mf_pllbase_pal_0002.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns/10ps 2 | module mf_pllbase_pal_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 'outclk2' 17 | output wire outclk_2, 18 | 19 | // interface 'outclk3' 20 | output wire outclk_3, 21 | 22 | // interface 'locked' 23 | output wire locked 24 | ); 25 | 26 | altera_pll #( 27 | .fractional_vco_multiplier("true"), 28 | .reference_clock_frequency("74.25 MHz"), 29 | .operation_mode("direct"), 30 | .number_of_clocks(4), 31 | .output_clock_frequency0("85.125480 MHz"), 32 | .phase_shift0("0 ps"), 33 | .duty_cycle0(50), 34 | .output_clock_frequency1("21.281370 MHz"), 35 | .phase_shift1("0 ps"), 36 | .duty_cycle1(50), 37 | .output_clock_frequency2("10.640685 MHz"), 38 | .phase_shift2("0 ps"), 39 | .duty_cycle2(50), 40 | .output_clock_frequency3("10.640685 MHz"), 41 | .phase_shift3("23495 ps"), 42 | .duty_cycle3(50), 43 | .output_clock_frequency4("0 MHz"), 44 | .phase_shift4("0 ps"), 45 | .duty_cycle4(50), 46 | .output_clock_frequency5("0 MHz"), 47 | .phase_shift5("0 ps"), 48 | .duty_cycle5(50), 49 | .output_clock_frequency6("0 MHz"), 50 | .phase_shift6("0 ps"), 51 | .duty_cycle6(50), 52 | .output_clock_frequency7("0 MHz"), 53 | .phase_shift7("0 ps"), 54 | .duty_cycle7(50), 55 | .output_clock_frequency8("0 MHz"), 56 | .phase_shift8("0 ps"), 57 | .duty_cycle8(50), 58 | .output_clock_frequency9("0 MHz"), 59 | .phase_shift9("0 ps"), 60 | .duty_cycle9(50), 61 | .output_clock_frequency10("0 MHz"), 62 | .phase_shift10("0 ps"), 63 | .duty_cycle10(50), 64 | .output_clock_frequency11("0 MHz"), 65 | .phase_shift11("0 ps"), 66 | .duty_cycle11(50), 67 | .output_clock_frequency12("0 MHz"), 68 | .phase_shift12("0 ps"), 69 | .duty_cycle12(50), 70 | .output_clock_frequency13("0 MHz"), 71 | .phase_shift13("0 ps"), 72 | .duty_cycle13(50), 73 | .output_clock_frequency14("0 MHz"), 74 | .phase_shift14("0 ps"), 75 | .duty_cycle14(50), 76 | .output_clock_frequency15("0 MHz"), 77 | .phase_shift15("0 ps"), 78 | .duty_cycle15(50), 79 | .output_clock_frequency16("0 MHz"), 80 | .phase_shift16("0 ps"), 81 | .duty_cycle16(50), 82 | .output_clock_frequency17("0 MHz"), 83 | .phase_shift17("0 ps"), 84 | .duty_cycle17(50), 85 | .pll_type("General"), 86 | .pll_subtype("General") 87 | ) altera_pll_i ( 88 | .rst (rst), 89 | .outclk ({outclk_3, outclk_2, outclk_1, outclk_0}), 90 | .locked (locked), 91 | .fboutclk ( ), 92 | .fbclk (1'b0), 93 | .refclk (refclk) 94 | ); 95 | endmodule 96 | 97 | -------------------------------------------------------------------------------- /target/pocket/pll_reconfig.ppf: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /target/pocket/pll_reconfig.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -entity "pll_reconfig" -library "pll_reconfig" -name IP_TOOL_NAME "altera_pll_reconfig" 2 | set_global_assignment -entity "pll_reconfig" -library "pll_reconfig" -name IP_TOOL_VERSION "21.1" 3 | set_global_assignment -entity "pll_reconfig" -library "pll_reconfig" -name IP_TOOL_ENV "mwpim" 4 | set_global_assignment -library "pll_reconfig" -name MISC_FILE [file join $::quartus(qip_path) "pll_reconfig.cmp"] 5 | set_global_assignment -entity "pll_reconfig" -library "pll_reconfig" -name IP_TARGETED_DEVICE_FAMILY "Cyclone V" 6 | set_global_assignment -entity "pll_reconfig" -library "pll_reconfig" -name IP_GENERATED_DEVICE_FAMILY "{Cyclone V}" 7 | set_global_assignment -entity "pll_reconfig" -library "pll_reconfig" -name IP_QSYS_MODE "UNKNOWN" 8 | set_global_assignment -name SYNTHESIS_ONLY_QIP ON 9 | set_global_assignment -entity "pll_reconfig" -library "pll_reconfig" -name IP_COMPONENT_NAME "cGxsX3JlY29uZmln" 10 | set_global_assignment -entity "pll_reconfig" -library "pll_reconfig" -name IP_COMPONENT_DISPLAY_NAME "UExMIFJlY29uZmlnIEludGVsIEZQR0EgSVA=" 11 | set_global_assignment -entity "pll_reconfig" -library "pll_reconfig" -name IP_COMPONENT_REPORT_HIERARCHY "Off" 12 | set_global_assignment -entity "pll_reconfig" -library "pll_reconfig" -name IP_COMPONENT_INTERNAL "Off" 13 | set_global_assignment -entity "pll_reconfig" -library "pll_reconfig" -name IP_COMPONENT_AUTHOR "SW50ZWwgQ29ycG9yYXRpb24=" 14 | set_global_assignment -entity "pll_reconfig" -library "pll_reconfig" -name IP_COMPONENT_VERSION "MjEuMQ==" 15 | set_global_assignment -entity "pll_reconfig" -library "pll_reconfig" -name IP_COMPONENT_DESCRIPTION "SW50ZWwgUGhhc2UtTG9ja2VkIExvb3AgUmVjb25maWd1cmF0aW9uIEJsb2Nr" 16 | set_global_assignment -entity "pll_reconfig" -library "pll_reconfig" -name IP_COMPONENT_PARAMETER "RU5BQkxFX0JZVEVFTkFCTEU=::ZmFsc2U=::QWRkIGJ5dGVlbmFibGUgcG9ydA==" 17 | set_global_assignment -entity "pll_reconfig" -library "pll_reconfig" -name IP_COMPONENT_PARAMETER "QllURUVOQUJMRV9XSURUSA==::NA==::QllURUVOQUJMRV9XSURUSA==" 18 | set_global_assignment -entity "pll_reconfig" -library "pll_reconfig" -name IP_COMPONENT_PARAMETER "UkVDT05GSUdfQUREUl9XSURUSA==::Ng==::UkVDT05GSUdfQUREUl9XSURUSA==" 19 | set_global_assignment -entity "pll_reconfig" -library "pll_reconfig" -name IP_COMPONENT_PARAMETER "UkVDT05GSUdfREFUQV9XSURUSA==::MzI=::UkVDT05GSUdfREFUQV9XSURUSA==" 20 | set_global_assignment -entity "pll_reconfig" -library "pll_reconfig" -name IP_COMPONENT_PARAMETER "cmVjb25mX3dpZHRo::NjQ=::cmVjb25mX3dpZHRo" 21 | set_global_assignment -entity "pll_reconfig" -library "pll_reconfig" -name IP_COMPONENT_PARAMETER "V0FJVF9GT1JfTE9DSw==::dHJ1ZQ==::V0FJVF9GT1JfTE9DSw==" 22 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_reconfig" -name IP_COMPONENT_NAME "YWx0ZXJhX3BsbF9yZWNvbmZpZ190b3A=" 23 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_reconfig" -name IP_COMPONENT_DISPLAY_NAME "UExMIFJlY29uZmlnIEludGVsIEZQR0EgSVA=" 24 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_reconfig" -name IP_COMPONENT_REPORT_HIERARCHY "Off" 25 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_reconfig" -name IP_COMPONENT_INTERNAL "Off" 26 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_reconfig" -name IP_COMPONENT_AUTHOR "SW50ZWwgQ29ycG9yYXRpb24=" 27 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_reconfig" -name IP_COMPONENT_VERSION "MjEuMQ==" 28 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_reconfig" -name IP_COMPONENT_DESCRIPTION "SW50ZWwgUGhhc2UtTG9ja2VkIExvb3AgUmVjb25maWd1cmF0aW9uIEJsb2Nr" 29 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_reconfig" -name IP_COMPONENT_PARAMETER "ZGV2aWNlX2ZhbWlseQ==::Q3ljbG9uZSBW::ZGV2aWNlX2ZhbWlseQ==" 30 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_reconfig" -name IP_COMPONENT_PARAMETER "RU5BQkxFX01JRg==::ZmFsc2U=::RW5hYmxlIE1JRiBTdHJlYW1pbmc=" 31 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_reconfig" -name IP_COMPONENT_PARAMETER "RU5BQkxFX0JZVEVFTkFCTEU=::ZmFsc2U=::QWRkIGJ5dGVlbmFibGUgcG9ydA==" 32 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_reconfig" -name IP_COMPONENT_PARAMETER "QllURUVOQUJMRV9XSURUSA==::NA==::QllURUVOQUJMRV9XSURUSA==" 33 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_reconfig" -name IP_COMPONENT_PARAMETER "UkVDT05GSUdfQUREUl9XSURUSA==::Ng==::UkVDT05GSUdfQUREUl9XSURUSA==" 34 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_reconfig" -name IP_COMPONENT_PARAMETER "UkVDT05GSUdfREFUQV9XSURUSA==::MzI=::UkVDT05GSUdfREFUQV9XSURUSA==" 35 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_reconfig" -name IP_COMPONENT_PARAMETER "cmVjb25mX3dpZHRo::NjQ=::cmVjb25mX3dpZHRo" 36 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_reconfig" -name IP_COMPONENT_PARAMETER "V0FJVF9GT1JfTE9DSw==::dHJ1ZQ==::V0FJVF9GT1JfTE9DSw==" 37 | 38 | set_global_assignment -library "pll_reconfig" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_reconfig.v"] 39 | set_global_assignment -library "pll_reconfig" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_reconfig/altera_pll_reconfig_top.v"] 40 | set_global_assignment -library "pll_reconfig" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_reconfig/altera_pll_reconfig_core.v"] 41 | set_global_assignment -library "pll_reconfig" -name VERILOG_FILE [file join $::quartus(qip_path) "pll_reconfig/altera_std_synchronizer.v"] 42 | 43 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_reconfig" -name IP_TOOL_NAME "altera_pll_reconfig" 44 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_reconfig" -name IP_TOOL_VERSION "21.1" 45 | set_global_assignment -entity "altera_pll_reconfig_top" -library "pll_reconfig" -name IP_TOOL_ENV "mwpim" 46 | -------------------------------------------------------------------------------- /target/pocket/pll_reconfig.v: -------------------------------------------------------------------------------- 1 | // megafunction wizard: %PLL Reconfig Intel FPGA IP v21.1% 2 | // GENERATION: XML 3 | // pll_reconfig.v 4 | 5 | // Generated using ACDS version 21.1 850 6 | 7 | `timescale 1 ps / 1 ps 8 | module pll_reconfig #( 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 (""), 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_reconfig_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_reconfig.vo 86 | // RELATED_FILES: pll_reconfig.v, altera_pll_reconfig_top.v, altera_pll_reconfig_core.v, altera_std_synchronizer.v 87 | -------------------------------------------------------------------------------- /target/pocket/pll_reconfig/altera_std_synchronizer.v: -------------------------------------------------------------------------------- 1 | // (C) 2001-2022 Intel Corporation. All rights reserved. 2 | // Your use of Intel Corporation's design tools, logic functions and other 3 | // software and tools, and its AMPP partner logic functions, and any output 4 | // files from any of the foregoing (including device programming or simulation 5 | // files), and any associated documentation or information are expressly subject 6 | // to the terms and conditions of the Intel Program License Subscription 7 | // Agreement, Intel FPGA IP License Agreement, or other applicable 8 | // license agreement, including, without limitation, that your use is for the 9 | // sole purpose of programming logic devices manufactured by Intel and sold by 10 | // Intel or its authorized distributors. Please refer to the applicable 11 | // agreement for further details. 12 | 13 | 14 | // $Id: //acds/rel/21.1std/ip/sopc/components/primitives/altera_std_synchronizer/altera_std_synchronizer.v#1 $ 15 | // $Revision: #1 $ 16 | // $Date: 2020/06/22 $ 17 | // $Author: psgswbuild $ 18 | //----------------------------------------------------------------------------- 19 | // 20 | // File: altera_std_synchronizer.v 21 | // 22 | // Abstract: Single bit clock domain crossing synchronizer. 23 | // Composed of two or more flip flops connected in series. 24 | // Random metastable condition is simulated when the 25 | // __ALTERA_STD__METASTABLE_SIM macro is defined. 26 | // Use +define+__ALTERA_STD__METASTABLE_SIM argument 27 | // on the Verilog simulator compiler command line to 28 | // enable this mode. In addition, dfine the macro 29 | // __ALTERA_STD__METASTABLE_SIM_VERBOSE to get console output 30 | // with every metastable event generated in the synchronizer. 31 | // 32 | // Copyright (C) Altera Corporation 2009, All Rights Reserved 33 | //----------------------------------------------------------------------------- 34 | 35 | `timescale 1ns / 1ns 36 | 37 | module altera_std_synchronizer ( 38 | clk, 39 | reset_n, 40 | din, 41 | dout 42 | ); 43 | 44 | parameter depth = 3; // This value must be >= 2 ! 45 | 46 | input clk; 47 | input reset_n; 48 | input din; 49 | output dout; 50 | 51 | // QuartusII synthesis directives: 52 | // 1. Preserve all registers ie. do not touch them. 53 | // 2. Do not merge other flip-flops with synchronizer flip-flops. 54 | // QuartusII TimeQuest directives: 55 | // 1. Identify all flip-flops in this module as members of the synchronizer 56 | // to enable automatic metastability MTBF analysis. 57 | // 2. Cut all timing paths terminating on data input pin of the first flop din_s1. 58 | 59 | (* altera_attribute = {"-name ADV_NETLIST_OPT_ALLOWED NEVER_ALLOW; -name SYNCHRONIZER_IDENTIFICATION FORCED_IF_ASYNCHRONOUS; -name DONT_MERGE_REGISTER ON; -name PRESERVE_REGISTER ON; -name SDC_STATEMENT \"set_false_path -to [get_keepers {*altera_std_synchronizer:*|din_s1}]\" "} *) reg din_s1; 60 | 61 | (* altera_attribute = {"-name ADV_NETLIST_OPT_ALLOWED NEVER_ALLOW; -name SYNCHRONIZER_IDENTIFICATION FORCED_IF_ASYNCHRONOUS; -name DONT_MERGE_REGISTER ON; -name PRESERVE_REGISTER ON"} *) reg [depth-2:0] dreg; 62 | 63 | //synthesis translate_off 64 | initial begin 65 | if (depth <2) begin 66 | $display("%m: Error: synchronizer length: %0d less than 2.", depth); 67 | end 68 | end 69 | 70 | // the first synchronizer register is either a simple D flop for synthesis 71 | // and non-metastable simulation or a D flop with a method to inject random 72 | // metastable events resulting in random delay of [0,1] cycles 73 | 74 | `ifdef __ALTERA_STD__METASTABLE_SIM 75 | 76 | reg[31:0] RANDOM_SEED = 123456; 77 | wire next_din_s1; 78 | wire dout; 79 | reg din_last; 80 | reg random; 81 | event metastable_event; // hook for debug monitoring 82 | 83 | initial begin 84 | $display("%m: Info: Metastable event injection simulation mode enabled"); 85 | end 86 | 87 | always @(posedge clk) begin 88 | if (reset_n == 0) 89 | random <= $random(RANDOM_SEED); 90 | else 91 | random <= $random; 92 | end 93 | 94 | assign next_din_s1 = (din_last ^ din) ? random : din; 95 | 96 | always @(posedge clk or negedge reset_n) begin 97 | if (reset_n == 0) 98 | din_last <= 1'b0; 99 | else 100 | din_last <= din; 101 | end 102 | 103 | always @(posedge clk or negedge reset_n) begin 104 | if (reset_n == 0) 105 | din_s1 <= 1'b0; 106 | else 107 | din_s1 <= next_din_s1; 108 | end 109 | 110 | `else 111 | 112 | //synthesis translate_on 113 | always @(posedge clk or negedge reset_n) begin 114 | if (reset_n == 0) 115 | din_s1 <= 1'b0; 116 | else 117 | din_s1 <= din; 118 | end 119 | //synthesis translate_off 120 | 121 | `endif 122 | 123 | `ifdef __ALTERA_STD__METASTABLE_SIM_VERBOSE 124 | always @(*) begin 125 | if (reset_n && (din_last != din) && (random != din)) begin 126 | $display("%m: Verbose Info: metastable event @ time %t", $time); 127 | ->metastable_event; 128 | end 129 | end 130 | `endif 131 | 132 | //synthesis translate_on 133 | 134 | // the remaining synchronizer registers form a simple shift register 135 | // of length depth-1 136 | generate 137 | if (depth < 3) begin 138 | always @(posedge clk or negedge reset_n) begin 139 | if (reset_n == 0) 140 | dreg <= {depth-1{1'b0}}; 141 | else 142 | dreg <= din_s1; 143 | end 144 | end else begin 145 | always @(posedge clk or negedge reset_n) begin 146 | if (reset_n == 0) 147 | dreg <= {depth-1{1'b0}}; 148 | else 149 | dreg <= {dreg[depth-3:0], din_s1}; 150 | end 151 | end 152 | endgenerate 153 | 154 | assign dout = dreg[depth-2]; 155 | 156 | endmodule 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /target/pocket/sound_i2s.sv: -------------------------------------------------------------------------------- 1 | // MIT License 2 | 3 | // Copyright (c) 2022 Adam Gastineau 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 | // 23 | //////////////////////////////////////////////////////////////////////////////// 24 | 25 | // A very simple audio i2s bridge to APF, based on their example code 26 | module sound_i2s #( 27 | parameter CHANNEL_WIDTH = 15, 28 | parameter SIGNED_INPUT = 0 29 | ) ( 30 | input wire clk_74a, 31 | input wire clk_audio, 32 | 33 | // Left and right audio channels. Can be in an arbitrary clock domain 34 | input wire [CHANNEL_WIDTH - 1:0] audio_l, 35 | input wire [CHANNEL_WIDTH - 1:0] audio_r, 36 | 37 | output reg audio_mclk, 38 | output reg audio_lrck, 39 | output reg audio_dac 40 | ); 41 | // 42 | // audio i2s generator 43 | // 44 | 45 | reg audgen_nextsamp; 46 | 47 | // generate MCLK = 12.288mhz with fractional accumulator 48 | reg [21:0] audgen_accum = 0; 49 | localparam [20:0] CYCLE_48KHZ = 21'd122880 * 2; 50 | always @(posedge clk_74a) begin 51 | audgen_accum <= audgen_accum + CYCLE_48KHZ; 52 | if (audgen_accum >= 21'd742500) begin 53 | audio_mclk <= ~audio_mclk; 54 | audgen_accum <= audgen_accum - 21'd742500 + CYCLE_48KHZ; 55 | end 56 | end 57 | 58 | // generate SCLK = 3.072mhz by dividing MCLK by 4 59 | reg [1:0] aud_mclk_divider; 60 | reg prev_audio_mclk; 61 | wire audgen_sclk = aud_mclk_divider[1] /* synthesis keep*/; 62 | 63 | always @(posedge clk_74a) begin 64 | if (audio_mclk && ~prev_audio_mclk) begin 65 | aud_mclk_divider <= aud_mclk_divider + 1'b1; 66 | end 67 | 68 | prev_audio_mclk <= audio_mclk; 69 | end 70 | 71 | // shift out audio data as I2S 72 | // 32 total bits per channel, but only 16 active bits at the start and then 16 dummy bits 73 | // 74 | // synchronize audio samples coming from the core 75 | 76 | localparam CHANNEL_LEFT_HIGH = SIGNED_INPUT ? 16 : 15; 77 | localparam CHANNEL_RIGHT_HIGH = 16 + CHANNEL_LEFT_HIGH; 78 | 79 | // Width of channel with signed component 80 | localparam SIGNED_CHANNEL_WIDTH = SIGNED_INPUT ? CHANNEL_WIDTH : CHANNEL_WIDTH + 1; 81 | 82 | wire [31:0] audgen_sampdata; 83 | 84 | assign audgen_sampdata[CHANNEL_LEFT_HIGH-1:CHANNEL_LEFT_HIGH-CHANNEL_WIDTH] = audio_l; 85 | assign audgen_sampdata[CHANNEL_RIGHT_HIGH-1:CHANNEL_RIGHT_HIGH-CHANNEL_WIDTH] = audio_r; 86 | 87 | generate 88 | if (!SIGNED_INPUT) begin 89 | // If not signed, make sure high bit is 0 90 | assign audgen_sampdata[31] = 0; 91 | assign audgen_sampdata[15] = 0; 92 | end 93 | endgenerate 94 | 95 | generate 96 | if (15 - SIGNED_CHANNEL_WIDTH > 0) begin 97 | assign audgen_sampdata[31-SIGNED_CHANNEL_WIDTH:16] = 0; 98 | assign audgen_sampdata[15-SIGNED_CHANNEL_WIDTH:0] = 0; 99 | end 100 | endgenerate 101 | 102 | sync_fifo #( 103 | .WIDTH(32) 104 | ) sync_fifo ( 105 | .clk_write(clk_audio), 106 | .clk_read (clk_74a), 107 | 108 | .write_en(write_en), 109 | .data(audgen_sampdata), 110 | .data_s(audgen_sampdata_s) 111 | ); 112 | 113 | reg write_en = 0; 114 | reg [CHANNEL_WIDTH - 1:0] prev_left; 115 | reg [CHANNEL_WIDTH - 1:0] prev_right; 116 | 117 | // Mark write when necessary 118 | always @(posedge clk_audio) begin 119 | prev_left <= audio_l; 120 | prev_right <= audio_r; 121 | 122 | write_en <= 0; 123 | 124 | if (audio_l != prev_left || audio_r != prev_right) begin 125 | write_en <= 1; 126 | end 127 | end 128 | 129 | wire [31:0] audgen_sampdata_s; 130 | 131 | reg [31:0] audgen_sampshift; 132 | reg [4:0] audio_lrck_cnt; 133 | reg prev_audgen_sclk; 134 | always @(posedge clk_74a) begin 135 | if (prev_audgen_sclk && ~audgen_sclk) begin 136 | // output the next bit 137 | audio_dac <= audgen_sampshift[31]; 138 | 139 | // 48khz * 64 140 | audio_lrck_cnt <= audio_lrck_cnt + 1'b1; 141 | if (audio_lrck_cnt == 31) begin 142 | // switch channels 143 | audio_lrck <= ~audio_lrck; 144 | 145 | // Reload sample shifter 146 | if (~audio_lrck) begin 147 | audgen_sampshift <= audgen_sampdata_s; 148 | end 149 | end else if (audio_lrck_cnt < 16) begin 150 | // only shift for 16 clocks per channel 151 | audgen_sampshift <= {audgen_sampshift[30:0], 1'b0}; 152 | end 153 | end 154 | 155 | prev_audgen_sclk <= audgen_sclk; 156 | end 157 | 158 | initial begin 159 | // Verify parameters 160 | if (CHANNEL_WIDTH > 16) begin 161 | $error("CHANNEL_WIDTH must be <= 16. Received %d", CHANNEL_WIDTH); 162 | end 163 | 164 | if (SIGNED_INPUT != 0 && SIGNED_INPUT != 1) begin 165 | $error("SIGNED_INPUT must be 0 or 1. Received %d", SIGNED_INPUT); 166 | end 167 | 168 | if (CHANNEL_WIDTH == 16 && SIGNED_INPUT == 0) begin 169 | $error("Cannot have CHANNEL_WIDTH of 16 and an unsigned input"); 170 | end 171 | end 172 | endmodule 173 | -------------------------------------------------------------------------------- /target/pocket/sync_fifo.sv: -------------------------------------------------------------------------------- 1 | // MIT License 2 | 3 | // Copyright (c) 2022 Adam Gastineau 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 | // 23 | //////////////////////////////////////////////////////////////////////////////// 24 | 25 | // An easily reusable method for synchronizing multiple bits across clock domains 26 | // Uses a shallow depth (4 entries) FIFO, so make sure to empty it quickly 27 | module sync_fifo #( 28 | parameter WIDTH = 2 29 | ) ( 30 | input wire clk_write, 31 | input wire clk_read, 32 | 33 | input wire write_en, 34 | input wire [WIDTH - 1:0] data, 35 | output reg [WIDTH - 1:0] data_s = 0, 36 | output reg write_en_s = 0 37 | ); 38 | 39 | reg read_req = 0; 40 | wire empty; 41 | 42 | wire [WIDTH - 1:0] fifo_out; 43 | 44 | dcfifo dcfifo_component ( 45 | .data(data), 46 | .rdclk(clk_read), 47 | .rdreq(read_req), 48 | .wrclk(clk_write), 49 | .wrreq(write_en), 50 | .q(fifo_out), 51 | .rdempty(empty), 52 | .aclr(), 53 | .eccstatus(), 54 | .rdfull(), 55 | .rdusedw(), 56 | .wrempty(), 57 | .wrfull(), 58 | .wrusedw() 59 | ); 60 | defparam dcfifo_component.intended_device_family = "Cyclone V", dcfifo_component.lpm_numwords = 4, 61 | dcfifo_component.lpm_showahead = "OFF", dcfifo_component.lpm_type = "dcfifo", 62 | dcfifo_component.lpm_width = WIDTH, dcfifo_component.lpm_widthu = 2, 63 | dcfifo_component.overflow_checking = "ON", dcfifo_component.rdsync_delaypipe = 5, 64 | dcfifo_component.underflow_checking = "ON", dcfifo_component.use_eab = "ON", 65 | dcfifo_component.wrsync_delaypipe = 5; 66 | 67 | reg [1:0] read_state = 0; 68 | 69 | localparam READ_DELAY = 1; 70 | localparam READ_WRITE = 2; 71 | 72 | always @(posedge clk_read) begin 73 | read_req <= 0; 74 | write_en_s <= 0; 75 | 76 | if (~empty) begin 77 | read_state <= READ_DELAY; 78 | read_req <= 1; 79 | end 80 | 81 | case (read_state) 82 | READ_DELAY: begin 83 | read_state <= READ_WRITE; 84 | end 85 | READ_WRITE: begin 86 | read_state <= 0; 87 | 88 | data_s <= fifo_out; 89 | write_en_s <= 1; 90 | end 91 | endcase 92 | end 93 | 94 | endmodule 95 | --------------------------------------------------------------------------------