├── .github
├── FUNDING.yml
└── ISSUE_TEMPLATE
│ ├── BUG_REPORT.yml
│ └── QUESTION.yml
├── .gitignore
├── LICENSE
├── README.md
├── assets
└── pce.aseprite
├── pkg
├── Assets
│ └── pce
│ │ └── common
│ │ └── .gitkeep
├── Cores
│ └── agg23.PC Engine
│ │ ├── audio.json
│ │ ├── chip32.bin
│ │ ├── core.json
│ │ ├── data.json
│ │ ├── icon.bin
│ │ ├── info.txt
│ │ ├── input.json
│ │ ├── interact.json
│ │ ├── variants.json
│ │ └── video.json
└── Platforms
│ ├── _images
│ └── pce.bin
│ └── pce.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
├── pce_pocket.qip
├── pce_pocket.qpf
├── pce_pocket.qsf
└── pce_pocket.sdc
├── rtl
├── main.sv
├── pce.qip
├── pce
│ ├── CEGen.vhd
│ ├── HUC6280
│ │ ├── AddSubBCD.vhd
│ │ ├── HUC6280.qip
│ │ ├── HUC6280.vhd
│ │ ├── HUC6280_AG.vhd
│ │ ├── HUC6280_ALU.vhd
│ │ ├── HUC6280_CPU.vhd
│ │ ├── HUC6280_MC.vhd
│ │ ├── HUC6280_PKG.vhd
│ │ ├── psg.vhd
│ │ └── voltab.mif
│ ├── arcade.sv
│ ├── cache_2way.sv
│ ├── cd
│ │ ├── CDDA_FIFO.vhd
│ │ ├── MSM5205.vhd
│ │ ├── SCSI.vhd
│ │ ├── SCSI_FIFO.vhd
│ │ ├── cd.qip
│ │ └── cd.vhd
│ ├── cheatcodes.sv
│ ├── color_mix.sv
│ ├── ddram.sv
│ ├── dpram.vhd
│ ├── hps_ext.v
│ ├── huc6202.vhd
│ ├── huc6260.vhd
│ ├── huc6260_palette_init.mif
│ ├── huc6270.vhd
│ ├── mb128.sv
│ ├── palette.mif
│ ├── pce_top.vhd
│ ├── sdram.sv
│ └── xe1ap.v
└── sys
│ └── iir_filter.v
├── support
└── chip32.asm
└── target
└── pocket
├── audio.sv
├── core.qip
├── core_bridge_cmd.v
├── core_constraints.sdc
├── core_top.v
├── data_loader.sv
├── data_unloader.sv
├── linebuffer.v
├── mf_pllbase.ppf
├── mf_pllbase.qip
├── mf_pllbase.v
├── mf_pllbase
├── mf_pllbase_0002.qip
└── mf_pllbase_0002.v
├── pin_ddio_clk.ppf
├── pin_ddio_clk.qip
├── pin_ddio_clk.v
├── sound_i2s.sv
├── stp1.stp
└── sync_fifo.sv
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: agg23
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/BUG_REPORT.yml:
--------------------------------------------------------------------------------
1 | #####################################################################
2 | # SPDX-License-Identifier: CC0-1.0
3 | # SPDX-FileType: OTHER
4 | # SPDX-FileCopyrightText: (c) 2022, OpenGateware authors and contributors, Adam Gastineau
5 | #####################################################################
6 | name: "Bug Report"
7 | description: "Let us know about an unexpected error, a crash, or incorrect behavior."
8 | labels:
9 | - bug
10 | body:
11 | - type: markdown
12 | attributes:
13 | value: |
14 | Please note that the issue tracker is intended for bug reports.
15 | Make sure to [search for existing issues](https://github.com/agg23/openfpga-pcengine/issues) before filing a new one!
16 |
17 | - type: input
18 | id: version
19 | attributes:
20 | label: Version (or build number)
21 | placeholder: "0.1.0"
22 | description: |
23 | You can find the version in the About section, when you open the core.
24 |
25 | If you are not running the latest version, please try upgrading before reporting issues.
26 | validations:
27 | required: true
28 |
29 | - type: textarea
30 | id: steps
31 | attributes:
32 | label: Steps to reproduce
33 | description: |
34 | Please list the full steps required to reproduce the issue
35 | placeholder: |
36 | - Be precise
37 | - Include exact data used during testing for easy reference
38 | - The steps have to be in the exact order
39 | - Mention pre-requisites when applicable
40 | validations:
41 | required: false
42 |
43 | - type: textarea
44 | id: expected_behavior
45 | attributes:
46 | label: Expected Behavior
47 | description: If you want to include screenshots, paste them into the markdown editor below or follow up with a separate comment.
48 | placeholder: What were you expecting?
49 | validations:
50 | required: false
51 |
52 | - type: textarea
53 | id: actual_behavior
54 | attributes:
55 | label: Actual Behavior
56 | placeholder: What happened instead?
57 | validations:
58 | required: true
59 |
60 | - type: textarea
61 | id: bug_context
62 | attributes:
63 | label: Additional Context
64 | description: |
65 | Are there anything unusual about your situation that we should know?
66 | validations:
67 | required: false
68 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/QUESTION.yml:
--------------------------------------------------------------------------------
1 | #####################################################################
2 | # SPDX-License-Identifier: CC0-1.0
3 | # SPDX-FileType: OTHER
4 | # SPDX-FileCopyrightText: (c) 2022, OpenGateware authors and contributors, Adam Gastineau
5 | #####################################################################
6 | name: "Question"
7 | description: "Ask a question about the project."
8 | labels:
9 | - question
10 | body:
11 | - type: markdown
12 | attributes:
13 | value: |
14 | Please note that the issue tracker is intended for bug reports.
15 | Make sure to [search for existing issues](https://github.com/agg23/openfpga-pcengine/issues) before filing a new one!
16 |
17 | - type: textarea
18 | id: question
19 | attributes:
20 | label: Ask a question
21 | placeholder: |
22 | Ask your question here! Please keep the questions related to the core only.
23 | validations:
24 | required: true
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist/**/chip32.bin
2 | support/*.bin
3 |
4 | *.zip
5 | *.rbf_r
6 | *.rev
7 | *.wlf
8 | *.vcd
9 | db
10 | greybox_tmp
11 | hps_isw_handoff
12 | incremental_db
13 | output_files
14 | PLLJ_PLLSPE_INFO.txt
15 | simulation
16 | vip
17 | .qsys_edit
18 | *_netlist
19 | *_sim
20 | *.bak
21 | *.bsf
22 | *.cdf
23 | *.cmp
24 | *.csv
25 | *.done
26 | *.f
27 | *.pin
28 | *.pof
29 | *.ptf.*
30 | *.qar
31 | *.qarlog
32 | *.qdf
33 | *.qws
34 | *.rbf
35 | *.rpt
36 | *.sip
37 | *.sld
38 | *.smsg
39 | *.sof
40 | *.sopc_builder
41 | *.sopcinfo
42 | *.spd
43 | *.summary
44 | *.xml
45 | *~
46 | **/.DS_Store
47 | build_id.mif
48 | build_id.v
49 | c5_pin_model_dump.txt
50 | cr_ie_info.json
51 | # Gateman directories and files
52 | !.gateman/*
53 | !gateware.json
54 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PC Engine for Analogue Pocket
2 |
3 | Ported from the core originally developed by [Gregory Estrade](https://github.com/Torlus/FPGAPCE) and heavily modified by [@srg320](https://github.com/srg320) and [@greyrogue](https://github.com/greyrogue). Core icon based on TG-16 icon by [spiritualized1997](https://github.com/spiritualized1997). Latest upstream available at https://github.com/MiSTer-devel/TurboGrafx16_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 | ## Installation
8 |
9 | ### Easy mode
10 |
11 | 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
12 |
13 | ### Manual mode
14 | Download the core by clicking Releases on the right side of this page, then download the `agg23.*.zip` file from the latest release.
15 |
16 | 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.
17 |
18 | ## Usage
19 |
20 | ROMs should be placed in `/Assets/pce/common`
21 |
22 | SuperGrafix games **_MUST_** have the `.sgx` extension, as otherwise there's no way for the core to tell that it uses the SuperGrafx hardware.
23 |
24 | Please note that CD games are not currently supported. Support will be added in a future update.
25 |
26 | ## Features
27 |
28 | ### Dock Support
29 |
30 | Core supports four players/controllers via the Analogue Dock. To enable four player mode, turn on `Use Turbo Tap` setting.
31 |
32 | ### 6 button controller
33 |
34 | Some games support a 6 button controller. For those games, enable the `Use 6 Button Ctrl` option in `Core Settings`. Please note that this option can break games that don't support the 6 button controller, so turn it off if you're not using it.
35 |
36 | ### Controller Turbo
37 |
38 | Like the original PC Engine controllers, this core supports multiple turbo modes. Adjust the `I` and `II` button turbo modes, and use the `X` and `Y` buttons (by default) as your turbo buttons. Note that the original PCE controllers had the turbo on the `I` and `II` buttons directly, rather than having separate buttons, but since the Pocket has more than just two, we use them for the turbo.
39 |
40 | ### Video Modes
41 |
42 | The PC Engine is unique in that it can arbitrarily decide what resolution to display at. The Pocket is more limited, requiring fixed resolutions at all times. I've tried to compromise and cover the most common resolutions output by the PCE, but some are better supported than others. You should see the video centered on the screen with surrounding black bars on some resolutions, but the aspect ratios should be correct.
43 |
44 | ### Video Options
45 |
46 | * `Extra Sprites` - Allows extra sprites to be displayed on each line. Will decrease flickering in some games
47 | * `Raw RGB Color` - Use the raw RGB color palette output by the HUC6260. If disabled, will use the composite color palette
48 |
49 | ### Audio Options
50 |
51 | The core can be quiet in some games, so there are options to boost the master audio (`Master Audio Boost`) and ADPCM channels (`PCM Audio Boost`).
52 |
53 | ### Memory Cards
54 |
55 | Instead of sharing a memory card (as you would in real life), each game gets its own save file and therefore memory card. Some games don't have the ability to initialize a memory card, so each newly created save file is pre-initialized for use.
56 |
57 | ## Licensing
58 |
59 | All source included in this project from me or the [MiSTer project](https://github.com/MiSTer-devel/TurboGrafx16_MiSTer) is licensed as GPLv2, unless otherwise noted. The original source for [FPGAPCE](https://github.com/Torlus/FPGAPCE), the project this core is based off of, is [public domain](https://twitter.com/Torlus/status/1582663978068893696). The contents of the public domain tweet are reproduced here:
60 |
61 | > Indeed. The main reason why I haven't provided a license is that I didn't know how to deal with the different licenses attached to parts of the cores.
62 | Anyway, consider *my own* source code as public domain, i.e do what you want with it, for any use you want. (1/2)
63 |
64 | [Additionally, he wrote](https://twitter.com/Torlus/status/1582664299973341184):
65 |
66 | > If stated otherwise in the comments at the beginning of a given source file, the license attached prevails. That applies to my FPGAPCE project (https://github.com/Torlus/FPGAPCE).
--------------------------------------------------------------------------------
/assets/pce.aseprite:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agg23/openfpga-pcengine/8810ed6283c7080013b69db843b5601f170c77c2/assets/pce.aseprite
--------------------------------------------------------------------------------
/pkg/Assets/pce/common/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agg23/openfpga-pcengine/8810ed6283c7080013b69db843b5601f170c77c2/pkg/Assets/pce/common/.gitkeep
--------------------------------------------------------------------------------
/pkg/Cores/agg23.PC Engine/audio.json:
--------------------------------------------------------------------------------
1 | {
2 | "audio": {
3 | "magic": "APF_VER_1"
4 | }
5 | }
--------------------------------------------------------------------------------
/pkg/Cores/agg23.PC Engine/chip32.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agg23/openfpga-pcengine/8810ed6283c7080013b69db843b5601f170c77c2/pkg/Cores/agg23.PC Engine/chip32.bin
--------------------------------------------------------------------------------
/pkg/Cores/agg23.PC Engine/core.json:
--------------------------------------------------------------------------------
1 | {
2 | "core": {
3 | "magic": "APF_VER_1",
4 | "metadata": {
5 | "platform_ids": [
6 | "pce"
7 | ],
8 | "shortname": "PC Engine",
9 | "description": "PC Engine (known as TurboGrafx-16 in the US) by NEC",
10 | "author": "agg23",
11 | "url": "https://github.com/agg23/openfpga-pcengine/",
12 | "version": "1.0.1",
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": "chip32.bin"
28 | },
29 | "cores": [
30 | {
31 | "name": "default",
32 | "id": 0,
33 | "filename": "pce.rev"
34 | }
35 | ]
36 | }
37 | }
--------------------------------------------------------------------------------
/pkg/Cores/agg23.PC Engine/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": ["pce", "sgx"],
11 | "address": "0x10000000"
12 | },
13 | {
14 | "name": "Save",
15 | "id": 1,
16 | "required": false,
17 | "parameters": "0x84",
18 | "nonvolatile": true,
19 | "extensions": ["sav"],
20 | "address": "0x20000000",
21 | "size_maximum": "0x4000"
22 | }
23 | ]
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/pkg/Cores/agg23.PC Engine/icon.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agg23/openfpga-pcengine/8810ed6283c7080013b69db843b5601f170c77c2/pkg/Cores/agg23.PC Engine/icon.bin
--------------------------------------------------------------------------------
/pkg/Cores/agg23.PC Engine/info.txt:
--------------------------------------------------------------------------------
1 | Port by agg23. Core by Gregory Estrade, srg320, and greyrogue
2 |
3 | PC Engine (PCE), known as TurboGrafx-16 in the United States, was created by NEC and was the first 4th generation console to reach the market. Therefore, even though it came out in the late 80s, it has significantly better graphics than 8-bit systems that were being sold at the time, such as the NES.
4 |
5 | Currently supports standard PC Engine/TurboGrafx and SuperGrafx ROMs. CD support is coming sometime in the future. Please report all issues to agg23, as most likely any issues experienced are issues with the port, not the core.
--------------------------------------------------------------------------------
/pkg/Cores/agg23.PC Engine/input.json:
--------------------------------------------------------------------------------
1 | {
2 | "input": {
3 | "magic": "APF_VER_1",
4 | "controllers": [
5 | {
6 | "type": "default",
7 | "mappings": [
8 | {
9 | "id": 0,
10 | "name": "I Button",
11 | "key": "pad_btn_a"
12 | },
13 | {
14 | "id": 1,
15 | "name": "II Button",
16 | "key": "pad_btn_b"
17 | },
18 | {
19 | "id": 2,
20 | "name": "III/Turbo I Button",
21 | "key": "pad_btn_x"
22 | },
23 | {
24 | "id": 3,
25 | "name": "IV/Turbo II Button",
26 | "key": "pad_btn_y"
27 | },
28 | {
29 | "id": 4,
30 | "name": "V Button",
31 | "key": "pad_trig_l"
32 | },
33 | {
34 | "id": 5,
35 | "name": "VI Button",
36 | "key": "pad_trig_r"
37 | },
38 | {
39 | "id": 20,
40 | "name": "Run",
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.PC Engine/interact.json:
--------------------------------------------------------------------------------
1 | {
2 | "interact": {
3 | "magic": "APF_VER_1",
4 | "variables": [
5 | {
6 | "name": "Reset core",
7 | "id": 1,
8 | "type": "action",
9 | "enabled": true,
10 | "address": "0x00000050",
11 | "value": 1
12 | },
13 | {
14 | "name": "Use Turbo Tap",
15 | "id": 20,
16 | "type": "check",
17 | "enabled": true,
18 | "address": "0x00000100",
19 | "persist": true,
20 | "writeonly": true,
21 | "defaultval": 0,
22 | "value": 1
23 | },
24 | {
25 | "name": "Use 6 Button Ctrl",
26 | "id": 21,
27 | "type": "check",
28 | "enabled": true,
29 | "address": "0x00000104",
30 | "persist": true,
31 | "writeonly": true,
32 | "defaultval": 0,
33 | "value": 1
34 | },
35 | {
36 | "name": "Button I Turbo",
37 | "id": 22,
38 | "type": "slider_u32",
39 | "enabled": true,
40 | "address": "0x00000108",
41 | "persist": true,
42 | "writeonly": true,
43 | "defaultval": 0,
44 | "graphical": {
45 | "min": 0,
46 | "max": 2,
47 | "adjust_small": 1,
48 | "adjust_large": 1
49 | }
50 | },
51 | {
52 | "name": "Button II Turbo",
53 | "id": 23,
54 | "type": "slider_u32",
55 | "enabled": true,
56 | "address": "0x0000010C",
57 | "persist": true,
58 | "writeonly": true,
59 | "defaultval": 0,
60 | "graphical": {
61 | "min": 0,
62 | "max": 2,
63 | "adjust_small": 1,
64 | "adjust_large": 1
65 | }
66 | },
67 | {
68 | "name": "Extra Sprites",
69 | "id": 41,
70 | "type": "check",
71 | "enabled": true,
72 | "address": "0x00000204",
73 | "persist": true,
74 | "writeonly": true,
75 | "defaultval": 0,
76 | "value": 1
77 | },
78 | {
79 | "name": "Raw RGB Color",
80 | "id": 42,
81 | "type": "check",
82 | "enabled": true,
83 | "address": "0x00000208",
84 | "persist": true,
85 | "writeonly": true,
86 | "defaultval": 0,
87 | "value": 1
88 | },
89 | {
90 | "name": "Master Audio Boost",
91 | "id": 60,
92 | "type": "list",
93 | "enabled": true,
94 | "address": "0x00000300",
95 | "persist": true,
96 | "writeonly": true,
97 | "defaultval": 0,
98 | "options": [
99 | {
100 | "name": "No Boost",
101 | "value": 0
102 | },
103 | {
104 | "name": "2x Boost",
105 | "value": 1
106 | },
107 | {
108 | "name": "4x Boost",
109 | "value": 2
110 | }
111 | ]
112 | },
113 | {
114 | "name": "PCM Audio Boost",
115 | "id": 61,
116 | "type": "check",
117 | "enabled": true,
118 | "address": "0x00000304",
119 | "persist": true,
120 | "writeonly": true,
121 | "defaultval": 0,
122 | "value": 1
123 | }
124 | ],
125 | "messages": []
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/pkg/Cores/agg23.PC Engine/variants.json:
--------------------------------------------------------------------------------
1 | {
2 | "variants": {
3 | "magic": "APF_VER_1",
4 | "variant_list": []
5 | }
6 | }
--------------------------------------------------------------------------------
/pkg/Cores/agg23.PC Engine/video.json:
--------------------------------------------------------------------------------
1 | {
2 | "video": {
3 | "magic": "APF_VER_1",
4 | "scaler_modes": [
5 | {
6 | "width": 256,
7 | "height": 240,
8 | "aspect_w": 128,
9 | "aspect_h": 105,
10 | "rotation": 0,
11 | "mirror": 0
12 | },
13 | {
14 | "width": 256,
15 | "height": 224,
16 | "aspect_w": 64,
17 | "aspect_h": 49,
18 | "rotation": 0,
19 | "mirror": 0
20 | },
21 | {
22 | "width": 360,
23 | "height": 240,
24 | "aspect_w": 128,
25 | "aspect_h": 105,
26 | "rotation": 0,
27 | "mirror": 0
28 | },
29 | {
30 | "width": 360,
31 | "height": 224,
32 | "aspect_w": 64,
33 | "aspect_h": 49,
34 | "rotation": 0,
35 | "mirror": 0
36 | },
37 | {
38 | "width": 512,
39 | "height": 240,
40 | "aspect_w": 128,
41 | "aspect_h": 105,
42 | "rotation": 0,
43 | "mirror": 0
44 | },
45 | {
46 | "width": 512,
47 | "height": 224,
48 | "aspect_w": 64,
49 | "aspect_h": 49,
50 | "rotation": 0,
51 | "mirror": 0
52 | }
53 | ],
54 | "display_modes": [
55 | {
56 | "id": "0x71"
57 | },
58 | {
59 | "id": "0x72"
60 | },
61 | {
62 | "id": "0x10"
63 | },
64 | {
65 | "id": "0x20"
66 | },
67 | {
68 | "id": "0x30"
69 | },
70 | {
71 | "id": "0x40"
72 | },
73 | {
74 | "id": "0xE0"
75 | },
76 | {
77 | "id": "0xE1"
78 | }
79 | ]
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/pkg/Platforms/_images/pce.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/agg23/openfpga-pcengine/8810ed6283c7080013b69db843b5601f170c77c2/pkg/Platforms/_images/pce.bin
--------------------------------------------------------------------------------
/pkg/Platforms/pce.json:
--------------------------------------------------------------------------------
1 | {
2 | "platform": {
3 | "category": "Console",
4 | "name": "PC Engine",
5 | "year": 1987,
6 | "manufacturer": "NEC Home Electronics"
7 | }
8 | }
--------------------------------------------------------------------------------
/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/build_id_gen.tcl:
--------------------------------------------------------------------------------
1 | # ================================================================================
2 | # (c) 2011 Altera Corporation. All rights reserved.
3 | # Altera products are protected under numerous U.S. and foreign patents, maskwork
4 | # rights, copyrights and other intellectual property laws.
5 | #
6 | # This reference design file, and your use thereof, is subject to and governed
7 | # by the terms and conditions of the applicable Altera Reference Design License
8 | # Agreement (either as signed by you, agreed by you upon download or as a
9 | # "click-through" agreement upon installation andor found at www.altera.com).
10 | # By using this reference design file, you indicate your acceptance of such terms
11 | # and conditions between you and Altera Corporation. In the event that you do
12 | # not agree with such terms and conditions, you may not use the reference design
13 | # file and please promptly destroy any copies you have made.
14 | #
15 | # This reference design file is being provided on an "as-is" basis and as an
16 | # accommodation and therefore all warranties, representations or guarantees of
17 | # any kind (whether express, implied or statutory) including, without limitation,
18 | # warranties of merchantability, non-infringement, or fitness for a particular
19 | # purpose, are specifically disclaimed. By making this reference design file
20 | # available, Altera expressly does not recommend, suggest or require that this
21 | # reference design file be used in combination with any other product not
22 | # provided by Altera.
23 | # ================================================================================
24 | #
25 | # Build ID Verilog Module Script
26 | # Jeff Wiencrot - 8/1/2011
27 | #
28 | # Generates a Verilog module that contains a timestamp, physical address, and host name
29 | # from the current build. These values are available from the build_date, build_time,
30 | # physical_address, and host_name output ports of the build_id module in the build_id.v
31 | # Verilog source file.
32 | #
33 | # The format for each value is as follows:
34 | # Date - 32-bit decimal number of the format mmddyyyy
35 | # Time - 32-bit decimal number of the format hhmmss
36 | # Phyiscal Address - 48-bit hexadecimal number
37 | # Host name - 120-bit hexadecimal number with pairs of digits equal to the
38 | # hexadecimal code for the first 15 ASCII characters of the host
39 | # name. For added clarity, host names that have fewer than 30
40 | # hexadecimal digits (15 characters) are padded on the left with
41 | # zeros.
42 | #
43 | # Usage:
44 | #
45 | # To manually execute this script, source this file using the following Tcl commands:
46 | # source build_id_verilog.tcl
47 | #
48 | # To have this script automatically execute each time your project is built, use the
49 | # following command (see: http://www.altera.com/support/examples/tcl/auto_processing.html):
50 | # set_global_assignment -name PRE_FLOW_SCRIPT_FILE quartus_sh:build_id_verilog.tcl
51 | #
52 | # Comment out the last line to prevent the process from automatically executing when
53 | # the file is sourced. The process can then be executed with the following command:
54 | # generateBuildID_Verilog
55 | #
56 | #
57 | # For more information, see "build_identification.pdf"
58 | #
59 | # ================================================================================
60 | #
61 | # 2021-01-21 Analogue
62 | #
63 | # Only care about generating build date/time, so the rest was removed.
64 | # The original can be downloaded from the Intel resource page
65 | #
66 |
67 | proc generateBuildID_Verilog {} {
68 |
69 | # Get the timestamp (see: http://www.altera.com/support/examples/tcl/tcl-date-time-stamp.html)
70 | set buildDate [ clock format [ clock seconds ] -format %Y%m%d ]
71 | set buildTime [ clock format [ clock seconds ] -format %H%M%S ]
72 |
73 | # Create a Verilog file for output
74 | set outputFileName "../platform/pocket/build_id.v"
75 | set outputFile [open $outputFileName "w"]
76 |
77 | # Output the Verilog source
78 | puts $outputFile "// Build ID Verilog Module"
79 | puts $outputFile "//"
80 | puts $outputFile "// Note - these are stored as binary coded decimal"
81 | puts $outputFile "// Date: $buildDate"
82 | puts $outputFile "// Time: $buildTime"
83 | puts $outputFile ""
84 | puts $outputFile "module build_id"
85 | puts $outputFile "("
86 | puts $outputFile " output \[31:0\] build_date,"
87 | puts $outputFile " output \[31:0\] build_time"
88 | puts $outputFile ");"
89 | puts $outputFile ""
90 | puts $outputFile " assign build_date = 32'h$buildDate;"
91 | puts $outputFile " assign build_time = 32'h$buildTime;"
92 | puts $outputFile ""
93 | puts $outputFile "endmodule"
94 | close $outputFile
95 |
96 |
97 |
98 | # Send confirmation message to the Messages window
99 | #post_message "APF core build date/time generated: [pwd]/$outputFileName"
100 | #post_message "Date: $buildDate"
101 | #post_message "Time: $buildTime"
102 | }
103 |
104 |
105 | proc generateBuildID_MIF {} {
106 |
107 | # Get the timestamp (see: http://www.altera.com/support/examples/tcl/tcl-date-time-stamp.html)
108 | set buildDate [ clock format [ clock seconds ] -format %Y%m%d ]
109 | set buildTime [ clock format [ clock seconds ] -format %H%M%S ]
110 | set buildUnique [expr {int(rand()*(4294967295))}]
111 |
112 | set buildDateNoLeadingZeros [string trimleft $buildDate "0"]
113 | set buildTimeNoLeadingZeros [string trimleft $buildTime "0"]
114 | set buildDate4Byte [format "%08d" $buildDateNoLeadingZeros]
115 | set buildTime4Byte [format "%08d" $buildTimeNoLeadingZeros]
116 | set buildUnique4Byte [format "%08x" $buildUnique]
117 |
118 | #set buildDate4Byte \
119 | [concat [string range $buildDate 0 1] \
120 | [string range $buildDate 2 3] \
121 | [string range $buildDate 4 5] \
122 | [string range $buildDate 6 7] ]
123 |
124 |
125 | set buildDateNumBytes 4
126 | set buildTimeNumBytes 4
127 |
128 | # Calculate depth of the memory (8-bit) words
129 | set memoryDepth [expr $buildDateNumBytes + $buildTimeNumBytes]
130 |
131 | # Create a Memory Initialization File for output
132 | set outputFileName "../platform/pocket/build_id.mif"
133 | set outputFile [open $outputFileName "w"]
134 |
135 | # Output the MIF header (see: http://quartushelp.altera.com/current/mergedProjects/reference/glossary/def_mif.htm)
136 | puts $outputFile "-- Build ID Memory Initialization File"
137 | puts $outputFile "--"
138 | puts $outputFile ""
139 | puts $outputFile "DEPTH = 256;"
140 | puts $outputFile "WIDTH = 32;"
141 | puts $outputFile "ADDRESS_RADIX = HEX;"
142 | puts $outputFile "DATA_RADIX = HEX;"
143 | puts $outputFile ""
144 | puts $outputFile "CONTENT"
145 | puts $outputFile "BEGIN"
146 | puts $outputFile ""
147 | puts $outputFile " 0E0 : $buildDate4Byte;"
148 | puts $outputFile " 0E1 : $buildTime4Byte;"
149 | puts $outputFile " 0E2 : $buildUnique4Byte;"
150 | puts $outputFile ""
151 | puts $outputFile "END;"
152 |
153 | # Close file to complete write
154 | close $outputFile
155 |
156 | # Send confirmation message to the Messages window
157 | post_message "APF core build date/time generated: [pwd]/$outputFileName"
158 | }
159 |
160 | generateBuildID_MIF
161 |
162 | # 2021-01-21 Analogue
163 | #
164 | # There are some circumstances where you want all parts of a FPGA flow to be deterministic, especially
165 | # when trying to hash out timing issues.
166 | # You should comment this line out and temporarily bypass buildid generation so that synthesis/par
167 | # have consistent working input. MIF bram contents like above won't affect the random seed or trigger
168 | # recompilation.
169 | # Don't forget to re-enable before you release.
170 | #
171 | # generateBuildID_Verilog
172 |
--------------------------------------------------------------------------------
/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/pce_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/pce_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 = "11:27:04 February 28, 2023"
8 |
9 | # Revisions
10 |
11 | PROJECT_REVISION = "pce_pocket"
12 |
--------------------------------------------------------------------------------
/projects/pce_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 camera_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 NUM_PARALLEL_PROCESSORS 6
24 | set_global_assignment -name OPTIMIZATION_MODE "HIGH PERFORMANCE EFFORT"
25 | set_global_assignment -name SAVE_DISK_SPACE OFF
26 | set_global_assignment -name SEED 1
27 | set_global_assignment -name SMART_RECOMPILE ON
28 |
29 | # ==============================================================================
30 | # Analysis & Synthesis Assignments
31 | # ==============================================================================
32 | set_global_assignment -name ADV_NETLIST_OPT_SYNTH_WYSIWYG_REMAP ON
33 | set_global_assignment -name MUX_RESTRUCTURE OFF
34 | set_global_assignment -name OPTIMIZATION_TECHNIQUE SPEED
35 | set_global_assignment -name PRE_MAPPING_RESYNTHESIS ON
36 | set_global_assignment -name SAFE_STATE_MACHINE ON
37 | set_global_assignment -name SYNTH_PROTECT_SDC_CONSTRAINT ON
38 |
39 | # ==============================================================================
40 | # Fitter Assignments
41 | # ==============================================================================
42 | set_global_assignment -name ACTIVE_SERIAL_CLOCK FREQ_100MHZ
43 | set_global_assignment -name CRC_ERROR_OPEN_DRAIN ON
44 | set_global_assignment -name ECO_OPTIMIZE_TIMING ON
45 | set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 256
46 | set_global_assignment -name FITTER_EFFORT "AUTO FIT"
47 | set_global_assignment -name PERIPHERY_TO_CORE_PLACEMENT_AND_ROUTING_OPTIMIZATION ON
48 | set_global_assignment -name PHYSICAL_SYNTHESIS_ASYNCHRONOUS_SIGNAL_PIPELINING ON
49 | set_global_assignment -name PHYSICAL_SYNTHESIS_COMBO_LOGIC ON
50 | set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_DUPLICATION ON
51 | set_global_assignment -name PHYSICAL_SYNTHESIS_REGISTER_RETIMING ON
52 | set_global_assignment -name ROUTER_CLOCKING_TOPOLOGY_ANALYSIS ON
53 | set_global_assignment -name ROUTER_LCELL_INSERTION_AND_LOGIC_DUPLICATION ON
54 | set_global_assignment -name STRATIXV_CONFIGURATION_SCHEME "PASSIVE SERIAL"
55 |
56 | # ==============================================================================
57 | # Platform/Core Assignments
58 | # ==============================================================================
59 | source ../platform/pocket/pocket.tcl
60 | set_global_assignment -name QIP_FILE pce_pocket.qip
61 | set_global_assignment -name SDC_FILE pce_pocket.sdc
62 | set_global_assignment -name QIP_FILE ../rtl/pce.qip
63 |
64 | # ==============================================================================
65 |
66 |
67 | set_global_assignment -name TIMING_ANALYZER_MULTICORNER_ANALYSIS ON
68 | set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0
69 | set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85
70 | set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "23 MM HEAT SINK WITH 200 LFPM AIRFLOW"
71 | set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)"
72 | set_global_assignment -name ENABLE_SIGNALTAP ON
73 | set_global_assignment -name USE_SIGNALTAP_FILE stp1.stp
74 | set_global_assignment -name SIGNALTAP_FILE stp1.stp
75 | set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
--------------------------------------------------------------------------------
/projects/pce_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/pce.qip:
--------------------------------------------------------------------------------
1 | # ==============================================================================
2 | # Quartus Prime QIP Index File
3 | # ==============================================================================
4 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) "pce/cd/cd.qip"]
5 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) "pce/HUC6280/HUC6280.qip"]
6 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "pce/arcade.sv"]
7 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "pce/cache_2way.sv"]
8 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "pce/CEGen.vhd"]
9 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "pce/cheatcodes.sv"]
10 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "pce/color_mix.sv"]
11 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "pce/ddram.sv"]
12 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "pce/dpram.vhd"]
13 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "pce/hps_ext.v"]
14 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "pce/huc6202.vhd"]
15 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "pce/huc6260.vhd"]
16 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "pce/huc6270.vhd"]
17 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "pce/mb128.sv"]
18 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "pce/pce_top.vhd"]
19 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "pce/sdram.sv"]
20 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "pce/xe1ap.v"]
21 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "sys/iir_filter.v"]
22 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "main.sv"]
--------------------------------------------------------------------------------
/rtl/pce/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 rising_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/pce/HUC6280/AddSubBCD.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 | signal CI2 : std_logic;
105 |
106 | begin
107 |
108 | B2 <= B xor (3 downto 0 => not ADD);
109 |
110 | bin_adder : entity work.adder4
111 | port map(
112 | A => A,
113 | B => B2,
114 | CI => CI,
115 | S => BIN_S,
116 | CO => BIN_CO
117 | );
118 |
119 | BCD_CO <= (BIN_S(3) and BIN_S(2)) or (BIN_S(3) and BIN_S(1)) or (BIN_CO xor not ADD);
120 | BCD_B <= not ADD & ((BCD_CO and BCD) xor not ADD) & ((BCD_CO and BCD) xor not ADD) & not ADD;
121 |
122 | CI2 <= not ADD;
123 | bcd_corr_adder : entity work.adder4
124 | port map(
125 | A => BIN_S,
126 | B => BCD_B,
127 | CI => CI2,
128 | S => S
129 | );
130 |
131 | CO <= BIN_CO when BCD = '0' else BCD_CO xor not ADD;
132 | VO <= (not (A(3) xor B2(3))) and (A(3) xor BIN_S(3));
133 |
134 | end rtl;
135 |
136 |
137 | library IEEE;
138 | use IEEE.std_logic_1164.all;
139 | use ieee.numeric_std.all;
140 | library work;
141 |
142 | entity AddSubBCD is
143 | port(
144 | A : in std_logic_vector(7 downto 0);
145 | B : in std_logic_vector(7 downto 0);
146 | CI : in std_logic;
147 | ADD : in std_logic;
148 | BCD : in std_logic;
149 | S : out std_logic_vector(7 downto 0);
150 | CO : out std_logic;
151 | VO : out std_logic
152 | );
153 | end AddSubBCD;
154 |
155 | architecture rtl of AddSubBCD is
156 |
157 | signal VO1 : std_logic;
158 | signal CO0, CO1 : std_logic;
159 |
160 | begin
161 |
162 | add0 : entity work.BCDAdder
163 | port map (
164 | A => A(3 downto 0),
165 | B => B(3 downto 0),
166 | CI => CI,
167 |
168 | S => S(3 downto 0),
169 | CO => CO0,
170 |
171 | ADD => ADD,
172 | BCD => BCD
173 | );
174 |
175 | add1 : entity work.BCDAdder
176 | port map (
177 | A => A(7 downto 4),
178 | B => B(7 downto 4),
179 | CI => CO0,
180 |
181 | S => S(7 downto 4),
182 | CO => CO1,
183 | VO => VO1,
184 |
185 | ADD => ADD,
186 | BCD => BCD
187 | );
188 |
189 |
190 | VO <= VO1;
191 | CO <= CO1;
192 |
193 | end rtl;
--------------------------------------------------------------------------------
/rtl/pce/HUC6280/HUC6280.qip:
--------------------------------------------------------------------------------
1 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) HUC6280.vhd ]
2 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) HUC6280_CPU.vhd ]
3 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) HUC6280_PKG.vhd ]
4 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) HUC6280_MC.vhd ]
5 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) HUC6280_ALU.vhd ]
6 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) HUC6280_AG.vhd ]
7 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) AddSubBCD.vhd ]
8 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) psg.vhd ]
9 |
10 |
11 |
--------------------------------------------------------------------------------
/rtl/pce/HUC6280/HUC6280.vhd:
--------------------------------------------------------------------------------
1 | library IEEE;
2 | use IEEE.std_logic_1164.all;
3 | use ieee.numeric_std.all;
4 | library work;
5 | use work.HUC6280_PKG.all;
6 |
7 | entity HUC6280 is
8 | port(
9 | CLK : in std_logic;
10 | RST_N : in std_logic;
11 | WAIT_N : in std_logic;
12 |
13 | A : out std_logic_vector(20 downto 0);
14 | DI : in std_logic_vector(7 downto 0);
15 | DO : out std_logic_vector(7 downto 0);
16 | WR_N : out std_logic;
17 | RD_N : out std_logic;
18 | RDY : in std_logic;
19 | NMI_N : in std_logic;
20 | IRQ1_N : in std_logic;
21 | IRQ2_N : in std_logic;
22 |
23 | CE : out std_logic;
24 | CEK_N : out std_logic;
25 | CE7_N : out std_logic;
26 | CER_N : out std_logic;
27 | PRE_RD : out std_logic; -- for MiSTer sdram/ddram read
28 | PRE_WR : out std_logic;
29 |
30 | HSM : out std_logic;
31 |
32 | O : out std_logic_vector(7 downto 0);
33 | K : in std_logic_vector(7 downto 0);
34 |
35 | VDCNUM : in std_logic;
36 |
37 | AUD_LDATA: out std_logic_vector(23 downto 0);
38 | AUD_RDATA: out std_logic_vector(23 downto 0)
39 | );
40 | end HUC6280;
41 |
42 | architecture rtl of HUC6280 is
43 |
44 | signal CPU_CE : std_logic;
45 | signal CPU_CER : std_logic;
46 | signal IO_CE : std_logic;
47 | signal EN : std_logic;
48 |
49 | signal CPU_DI : std_logic_vector(7 downto 0);
50 | signal CPU_DO : std_logic_vector(7 downto 0);
51 | signal CPU_A : std_logic_vector(20 downto 0);
52 | signal CPU_WE_N : std_logic;
53 | signal CPU_CS : std_logic;
54 | signal CPU_MCYCLE : std_logic;
55 | signal CPU_IRQ1_N : std_logic;
56 | signal CPU_IRQ2_N : std_logic;
57 | signal CPU_IRQT_N : std_logic;
58 | signal CPU_RDY : std_logic;
59 |
60 | signal CPU_CLK_CNT : unsigned(4 downto 0);
61 | signal IO_CLK_CNT : unsigned(2 downto 0);
62 | signal VDC_SEL_OLD : std_logic;
63 |
64 | --IO
65 | signal IO_BUF : std_logic_vector(7 downto 0);
66 | signal RAM_SEL : std_logic;
67 | signal VDC_SEL : std_logic;
68 | signal VCE_SEL : std_logic;
69 | signal IOP_SEL : std_logic;
70 | signal PSG_SEL : std_logic;
71 | signal TMR_SEL : std_logic;
72 | signal INT_SEL : std_logic;
73 | signal IO_SEL : std_logic;
74 |
75 | signal INT_MASK_PRE : std_logic_vector(2 downto 0);
76 | signal INT_MASK : std_logic_vector(2 downto 0);
77 | signal TMR_PRE_CNT : unsigned(9 downto 0);
78 | signal TMR_VALUE : std_logic_vector(6 downto 0);
79 | signal TMR_LATCH : std_logic_vector(6 downto 0);
80 | signal TMR_EN : std_logic;
81 | signal TMR_RELOAD : std_logic;
82 | signal TMR_IRQ : std_logic;
83 | signal TMR_IRQ_ACK : std_logic;
84 |
85 | begin
86 |
87 |
88 | process(CLK, RST_N)
89 | begin
90 | if RST_N = '0' then
91 | CPU_CLK_CNT <= (others=>'0');
92 | CPU_CE <= '0';
93 | CPU_CER <= '0';
94 | IO_CLK_CNT <= (others=>'0');
95 | IO_CE <= '0';
96 | elsif rising_edge(CLK) then
97 | CPU_CE <= '0';
98 | if (CPU_CLK_CNT = 5 and CPU_CS = '1') or (CPU_CLK_CNT = 23 and CPU_CS = '0') then
99 | if WAIT_N = '1' then
100 | CPU_CLK_CNT <= (others=>'0');
101 | CPU_CE <= '1';
102 | end if;
103 | else
104 | CPU_CLK_CNT <= CPU_CLK_CNT + 1;
105 | end if;
106 |
107 | CPU_CER <= '0';
108 | if CPU_CLK_CNT = 1 then
109 | CPU_CER <= '1';
110 | end if;
111 |
112 | IO_CE <= '0';
113 | IO_CLK_CNT <= IO_CLK_CNT + 1;
114 | if IO_CLK_CNT = 5 then
115 | IO_CLK_CNT <= (others=>'0');
116 | IO_CE <= '1';
117 | end if;
118 | end if;
119 | end process;
120 |
121 | CE <= CPU_CE and CPU_RDY;
122 |
123 | EN <= CPU_CE and CPU_RDY;
124 |
125 |
126 | CORE : entity work.HUC6280_CPU
127 | port map (
128 | CLK => CLK,
129 | RST_N => RST_N,
130 | CE => CPU_CE,
131 |
132 | A_OUT => CPU_A,
133 | DI => CPU_DI,
134 | DO => CPU_DO,
135 | WE_N => CPU_WE_N,
136 | RDY => CPU_RDY,
137 | IRQ1_N => CPU_IRQ1_N,
138 | IRQ2_N => CPU_IRQ2_N,
139 | IRQT_N => CPU_IRQT_N,
140 | NMI_N => NMI_N,
141 | MCYCLE => CPU_MCYCLE,
142 | CS => CPU_CS,
143 | VDCNUM => VDCNUM
144 | );
145 |
146 | CPU_IRQ1_N <= IRQ1_N or INT_MASK(1);
147 | CPU_IRQ2_N <= IRQ2_N or INT_MASK(0);
148 | CPU_IRQT_N <= not TMR_IRQ or INT_MASK(2);
149 |
150 | RAM_SEL <= '1' when CPU_A(20 downto 15) = "111110" else '0'; -- RAM : Page $F8 - $FB
151 | VDC_SEL <= '1' when CPU_A(20 downto 13) = x"FF" and CPU_A(12 downto 10) = "000" else '0'; -- VDC : $0000 - $03FF
152 | VCE_SEL <= '1' when CPU_A(20 downto 13) = x"FF" and CPU_A(12 downto 10) = "001" else '0'; -- VCE : $0400 - $07FF
153 |
154 | process(CLK, RST_N)
155 | begin
156 | if RST_N = '0' then
157 | WR_N <= '1';
158 | RD_N <= '1';
159 | CPU_RDY <= '1';
160 | VDC_SEL_OLD <= '0';
161 | elsif rising_edge(CLK) then
162 | if CPU_CER = '1' then
163 | if CPU_MCYCLE = '1' then
164 | WR_N <= CPU_WE_N;
165 | RD_N <= not CPU_WE_N;
166 | end if;
167 |
168 | VDC_SEL_OLD <= VDC_SEL or VCE_SEL;
169 | if (VDC_SEL = '1' or VCE_SEL = '1') and VDC_SEL_OLD = '0' then
170 | CPU_RDY <= '0';
171 | end if;
172 | elsif CPU_CE = '1' then
173 | if CPU_RDY = '1' then
174 | WR_N <= '1';
175 | RD_N <= '1';
176 | end if;
177 | CPU_RDY <= RDY;
178 | end if;
179 | end if;
180 | end process;
181 |
182 | PRE_RD <= CPU_WE_N and CPU_MCYCLE and RST_N;
183 | PRE_WR <= not CPU_WE_N and CPU_MCYCLE and RST_N;
184 |
185 | A <= CPU_A;
186 | DO <= CPU_DO;
187 | CER_N <= not RAM_SEL;
188 | CE7_N <= not VDC_SEL;
189 | CEK_N <= not VCE_SEL;
190 | HSM <= CPU_CS;
191 |
192 |
193 |
194 | --KO port
195 | IOP_SEL <= '1' when CPU_A(20 downto 13) = x"FF" and CPU_A(12 downto 10) = "100" else '0'; -- IOP : $1000 - $13FF
196 | process(CLK, RST_N)
197 | begin
198 | if RST_N = '0' then
199 | O <= (others=>'0');
200 | elsif rising_edge(CLK) then
201 | if EN = '1' then
202 | if IOP_SEL = '1' and CPU_WE_N = '0' then
203 | O <= CPU_DO;
204 | end if;
205 | end if;
206 | end if;
207 | end process;
208 |
209 | --Interrupts register
210 | INT_SEL <= '1' when CPU_A(20 downto 13) = x"FF" and CPU_A(12 downto 10) = "101" else '0'; -- INT : $1400 - $17FF
211 | process(CLK, RST_N)
212 | begin
213 | if RST_N = '0' then
214 | INT_MASK_PRE <= (others=>'0');
215 | TMR_IRQ_ACK <= '0';
216 | elsif rising_edge(CLK) then
217 | TMR_IRQ_ACK <= '0';
218 |
219 | if CPU_CE = '1' then
220 | INT_MASK <= INT_MASK_PRE; -- Delay interrupt mask usage until 1 cycle after it is updated
221 | end if;
222 |
223 | if INT_SEL = '1' and CPU_CER = '1' then
224 | if CPU_WE_N = '0' then
225 | case CPU_A(1 downto 0) is
226 | when "10" =>
227 | INT_MASK_PRE <= CPU_DO(2 downto 0);
228 | when "11" =>
229 | TMR_IRQ_ACK <= '1';
230 | when others => null;
231 | end case;
232 | end if;
233 | end if;
234 | end if;
235 | end process;
236 |
237 |
238 | -- Timer
239 | TMR_SEL <= '1' when CPU_A(20 downto 13) = x"FF" and CPU_A(12 downto 10) = "011" else '0'; -- TMR : $0C00 - $0FFF
240 | process( CLK, RST_N )
241 | begin
242 | if RST_N = '0' then
243 | TMR_VALUE <= (others => '0');
244 | TMR_PRE_CNT <= (others => '1');
245 | TMR_LATCH <= (others => '0');
246 | TMR_EN <= '0';
247 | TMR_RELOAD <= '0';
248 | TMR_IRQ <= '0';
249 | elsif rising_edge(CLK) then
250 | if TMR_SEL = '1' and CPU_WE_N = '0' and CPU_CER = '1' then
251 | if CPU_A(0) = '0' then
252 | -- Timer latch
253 | TMR_LATCH <= CPU_DO(6 downto 0);
254 | else
255 | -- Timer enable
256 | TMR_EN <= CPU_DO(0);
257 | if TMR_EN = '0' and CPU_DO(0) = '1' then
258 | TMR_VALUE <= TMR_LATCH;
259 | TMR_PRE_CNT <= (others => '1');
260 | end if;
261 | end if;
262 | end if;
263 |
264 | if TMR_IRQ_ACK = '1' then
265 | TMR_IRQ <= '0';
266 | end if;
267 |
268 | if IO_CE = '1' then
269 | TMR_RELOAD <= '0';
270 | if TMR_EN = '1' then
271 | TMR_PRE_CNT <= TMR_PRE_CNT - 1;
272 | if TMR_PRE_CNT = 0 then
273 | TMR_VALUE <= std_logic_vector( unsigned(TMR_VALUE) - 1 );
274 | if TMR_VALUE = "0000000" then
275 | TMR_RELOAD <= '1';
276 | TMR_IRQ <= '1';
277 | end if;
278 | end if;
279 | end if;
280 |
281 | if TMR_RELOAD = '1' then
282 | TMR_VALUE <= TMR_LATCH;
283 | end if;
284 | end if;
285 | end if;
286 | end process;
287 |
288 | -- PSG
289 | PSG_SEL <= '1' when CPU_A(20 downto 13) = x"FF" and CPU_A(12 downto 10) = "010" else '0'; -- PSG : $0800 - $0BFF
290 | PSG : entity work.psg port map (
291 | CLK => CLK,
292 | CLKEN => IO_CE, -- 7.16 Mhz clock
293 | RESET_N => RST_N,
294 |
295 | DI => CPU_DO,
296 | A => CPU_A(3 downto 0),
297 | WE => not CPU_WE_N and EN and PSG_SEL,
298 |
299 | DAC_LATCH=> '1',
300 | LDATA => AUD_LDATA,
301 | RDATA => AUD_RDATA
302 | );
303 |
304 | IO_SEL <= IOP_SEL or INT_SEL or TMR_SEL or PSG_SEL;
305 | process(CLK, RST_N)
306 | begin
307 | if RST_N = '0' then
308 | IO_BUF <= (others=>'1');
309 | elsif rising_edge(CLK) then
310 | if EN = '1' then
311 | if IO_SEL = '1' then
312 | if CPU_WE_N = '0' then
313 | IO_BUF <= CPU_DO;
314 | else
315 | IO_BUF <= CPU_DI;
316 | end if;
317 | end if;
318 | end if;
319 | end if;
320 | end process;
321 |
322 | process(CLK)
323 | begin
324 | if rising_edge(CLK) then
325 | if IO_SEL = '0' then
326 | CPU_DI <= DI;
327 | elsif PSG_SEL = '1' then
328 | CPU_DI <= x"00";
329 | elsif IOP_SEL = '1' then
330 | CPU_DI <= K;
331 | elsif INT_SEL = '1' then
332 | case CPU_A(1 downto 0) is
333 | when "10" =>
334 | CPU_DI <= IO_BUF(7 downto 3) & INT_MASK;
335 | when "11" =>
336 | CPU_DI <= IO_BUF(7 downto 3) & TMR_IRQ & not IRQ1_N & not IRQ2_N;
337 | when others =>
338 | CPU_DI <= IO_BUF;
339 | end case;
340 | elsif TMR_SEL = '1' then
341 | CPU_DI <= IO_BUF(7) & TMR_VALUE;
342 | else
343 | CPU_DI <= IO_BUF;
344 | end if;
345 | end if;
346 | end process;
347 |
348 | end rtl;
349 |
--------------------------------------------------------------------------------
/rtl/pce/HUC6280/HUC6280_AG.vhd:
--------------------------------------------------------------------------------
1 | library IEEE;
2 | use IEEE.std_logic_1164.all;
3 | use ieee.numeric_std.all;
4 | library work;
5 |
6 | entity HUC6280_AG is
7 | port(
8 | CLK : in std_logic;
9 | RST_N : in std_logic;
10 | CE : in std_logic;
11 | PC_CTRL : in std_logic_vector(2 downto 0);
12 | ADDR_CTRL : in std_logic_vector(5 downto 0);
13 | GOT_INT : in std_logic;
14 | DI : 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 | DR : in std_logic_vector(7 downto 0);
18 |
19 | PC : out std_logic_vector(15 downto 0);
20 | AA : out std_logic_vector(15 downto 0)
21 | );
22 | end HUC6280_AG;
23 |
24 | architecture rtl of HUC6280_AG is
25 |
26 | signal AAL, AAH : std_logic_vector(7 downto 0);
27 | signal SavedCarry : std_logic;
28 |
29 | signal NewAAL : std_logic_vector(8 downto 0);
30 | signal NewAAH : std_logic_vector(7 downto 0);
31 |
32 | signal PCr: std_logic_vector(15 downto 0);
33 | signal NextPC, NewPCWithOffset: std_logic_vector(15 downto 0);
34 |
35 | begin
36 |
37 | NewPCWithOffset <= std_logic_vector(unsigned(PCr) + unsigned((7 downto 0 => AAL(7)) & AAL));
38 |
39 | process(CLK, RST_N, PC_CTRL, PCr, DI, DR, GOT_INT, NewPCWithOffset, AAH, AAL )
40 | begin
41 | case PC_CTRL is
42 | when "000" =>
43 | NextPC <= PCr;
44 | when "001" =>
45 | if GOT_INT = '0' then
46 | NextPC <= std_logic_vector(unsigned(PCr) + 1);
47 | else
48 | NextPC <= PCr;
49 | end if;
50 | when "010"=>
51 | NextPC <= PCr(15 downto 8) & DI;
52 | when "011" =>
53 | NextPC <= DI & PCr(7 downto 0);
54 | when "100" =>
55 | NextPC <= NewPCWithOffset;
56 | when "110" =>
57 | NextPC <= AAH & AAL;
58 | when others =>
59 | NextPC <= PCr;
60 | end case;
61 |
62 | if RST_N = '0' then
63 | PCr <= (others=>'0');
64 | elsif rising_edge(CLK) then
65 | if CE = '1' then
66 | PCr <= NextPC;
67 | end if;
68 | end if;
69 | end process;
70 |
71 | process(ADDR_CTRL, AAL, AAH, X, Y, DI, DR, SavedCarry)
72 | begin
73 | case ADDR_CTRL(5 downto 3) is
74 | when "000"=>
75 | NewAAL <= "0" & AAL;
76 | when "001"=>
77 | NewAAL <= "0" & DI;
78 | when "010" =>
79 | NewAAL <= std_logic_vector(unsigned("0" & AAL) + 1);
80 | when "011" =>
81 | NewAAL <= std_logic_vector(unsigned("0" & AAL) + unsigned("0" & X));
82 | when "100" =>
83 | NewAAL <= std_logic_vector(unsigned("0" & AAL) + unsigned("0" & Y));
84 | when "101" =>
85 | NewAAL <= "0" & DR;
86 | when "110" =>
87 | NewAAL <= std_logic_vector(unsigned("0" & DR) + unsigned("0" & Y));
88 | when others =>
89 | NewAAL <= "0" & X;
90 | end case;
91 |
92 | case ADDR_CTRL(2 downto 0) is
93 | when "000"=>
94 | NewAAH <= AAH;
95 | when "001"=>
96 | NewAAH <= DI;
97 | when "010" =>
98 | NewAAH <= std_logic_vector(unsigned(AAH) + 1);
99 | when "011" =>
100 | NewAAH <= std_logic_vector(unsigned(AAH) + ("0000000"&SavedCarry));
101 | when others =>
102 | NewAAH <= AAH;
103 | end case;
104 | end process;
105 |
106 |
107 | process(CLK, RST_N)
108 | begin
109 | if RST_N = '0' then
110 | AAL <= (others=>'0');
111 | AAH <= (others=>'0');
112 | SavedCarry <= '0';
113 | elsif rising_edge(CLK) then
114 | if CE = '1' then
115 | AAL <= NewAAL(7 downto 0);
116 | SavedCarry <= NewAAL(8);
117 | AAH <= NewAAH(7 downto 0);
118 | end if;
119 | end if;
120 | end process;
121 |
122 | AA <= AAH & AAL;
123 | PC <= PCr;
124 |
125 | end rtl;
--------------------------------------------------------------------------------
/rtl/pce/HUC6280/HUC6280_ALU.vhd:
--------------------------------------------------------------------------------
1 | library IEEE;
2 | use IEEE.std_logic_1164.all;
3 | use ieee.numeric_std.all;
4 | library work;
5 | use work.HUC6280_PKG.all;
6 |
7 | entity ALU is
8 | port(
9 | CLK : in std_logic;
10 | EN : in std_logic;
11 | L : in std_logic_vector(7 downto 0);
12 | R : in std_logic_vector(7 downto 0);
13 | CTRL : in ALUCtrl_r;
14 | BCD : in std_logic;
15 | CI : in std_logic;
16 | VI : in std_logic;
17 | NI : in std_logic;
18 | CO : out std_logic;
19 | VO : out std_logic;
20 | NO : out std_logic;
21 | ZO : out std_logic;
22 | RES : out std_logic_vector(7 downto 0)
23 | );
24 | end ALU;
25 |
26 | architecture rtl of ALU is
27 |
28 | signal IntL : std_logic_vector(7 downto 0);
29 | signal IntR : std_logic_vector(7 downto 0);
30 | signal CR : std_logic;
31 | signal ADDIn : std_logic;
32 | signal BCDIn : std_logic;
33 | signal CIIn : std_logic;
34 | signal SavedC : std_logic;
35 |
36 | signal AddS : std_logic_vector(7 downto 0);
37 | signal AddCO : std_logic;
38 | signal AddVO : std_logic;
39 | signal Result : std_logic_vector(7 downto 0);
40 |
41 | begin
42 |
43 | process(CTRL, CI, L, R, BCD, SavedC)
44 | begin
45 | CR <= CI;
46 | BCDIn <= '0';
47 | case CTRL.fstOp is
48 | when "000" =>
49 | CR <= L(7);
50 | IntL <= L(6 downto 0) & "0";
51 | IntR <= x"00";
52 | when "001"=>
53 | CR <= L(7);
54 | IntL <= L(6 downto 0) & CI;
55 | IntR <= x"00";
56 | when "010" =>
57 | CR <= L(0);
58 | IntL <= "0" & L(7 downto 1);
59 | IntR <= x"00";
60 | when "011" =>
61 | CR <= L(0);
62 | IntL <= CI & L(7 downto 1);
63 | IntR <= x"00";
64 | when "100" =>
65 | IntL <= L;
66 | IntR <= R;
67 | BCDIn <= BCD and CTRL.secOp(1) and CTRL.secOp(0);
68 | when "101" =>
69 | IntL <= L;
70 | IntR <= R;
71 | when "110" => -- INC/DEC LSB
72 | IntL <= L;
73 | IntR <= x"01";
74 | CR <= CTRL.secOp(2);
75 | when "111" => -- INC/DEC MSB
76 | IntL <= L;
77 | IntR <= x"00";
78 | CR <= SavedC;
79 | when others => null;
80 | end case;
81 | end process;
82 |
83 | CIIn <= CR or not CTRL.secOp(0);
84 | ADDIn <= not CTRL.secOp(2);
85 |
86 | AddSub: entity work.AddSubBCD
87 | port map (
88 | A => IntL,
89 | B => IntR,
90 | CI => CIIn,
91 | ADD => ADDIn,
92 | BCD => BCDIn,
93 | S => AddS,
94 | CO => AddCO,
95 | VO => AddVO
96 | );
97 |
98 | process(CLK)
99 | begin
100 | if rising_edge(CLK) then
101 | if EN = '1' then
102 | SavedC <= AddCO;
103 | end if;
104 | end if;
105 | end process;
106 |
107 | process(CTRL, CR, IntL, IntR, AddCO, AddS)
108 | begin
109 | case CTRL.secOp is
110 | when "000" =>
111 | CO <= CR;
112 | Result <= IntL or IntR;
113 | when "001"=>
114 | CO <= CR;
115 | Result <= IntL and IntR;
116 | when "010" =>
117 | CO <= CR;
118 | Result <= IntL xor IntR;
119 | when "011" | "110" | "111" =>
120 | CO <= AddCO;
121 | Result <= AddS;
122 | when "100" =>
123 | CO <= CR;
124 | Result <= IntL;
125 | when "101" => --TRB,TSB
126 | CO <= CR;
127 | if CTRL.fc = '0' then
128 | Result <= IntR and (not IntL);
129 | else
130 | Result <= IntR or IntL;
131 | end if;
132 | when others => null;
133 | end case;
134 | end process;
135 |
136 | process(CTRL, VI, NI, IntR, Result, AddVO, BCDIn)
137 | begin
138 | VO <= VI;
139 | NO <= Result(7);
140 | case CTRL.secOp is
141 | when "001" => --AND
142 | if CTRL.fc = '1' then --BIT
143 | VO <= IntR(6);
144 | NO <= IntR(7);
145 | end if;
146 | when "011" => -- ADC
147 | if BCDIn = '0' then
148 | VO <= AddVO;
149 | end if;
150 | when "101" => --TRB,TSB
151 | VO <= IntR(6);
152 | NO <= IntR(7);
153 | when "111" => -- SBC
154 | if BCDIn = '0' then
155 | VO <= AddVO;
156 | end if;
157 | when others => null;
158 | end case;
159 | end process;
160 |
161 |
162 | ZO <= '1' when Result = x"00" else '0';
163 |
164 | RES <= Result;
165 |
166 | end rtl;
--------------------------------------------------------------------------------
/rtl/pce/HUC6280/HUC6280_PKG.vhd:
--------------------------------------------------------------------------------
1 | library IEEE;
2 | use IEEE.std_logic_1164.all;
3 | use ieee.numeric_std.all;
4 |
5 | package HUC6280_PKG is
6 |
7 | type MicroInst_r is record
8 | STATE_CTRL : std_logic_vector(1 downto 0);
9 | ADDR_BUS : std_logic_vector(2 downto 0);
10 | LOAD_SDLH : std_logic_vector(1 downto 0);
11 | LOAD_P : std_logic_vector(2 downto 0);
12 | LOAD_T : std_logic_vector(2 downto 0);
13 | ADDR_CTRL : std_logic_vector(5 downto 0);
14 | LOAD_PC : std_logic_vector(2 downto 0);
15 | LOAD_SP : std_logic_vector(2 downto 0);
16 | AXY_CTRL : std_logic_vector(2 downto 0);
17 | ALUBUS_CTRL : std_logic_vector(3 downto 0);
18 | ALUCtrl : std_logic_vector(4 downto 0);
19 | OUT_BUS : std_logic_vector(3 downto 0);
20 | MEM_CYCLE : std_logic;
21 | end record;
22 |
23 | type ALUCtrl_r is record
24 | fstOp : std_logic_vector(2 downto 0);
25 | secOp : std_logic_vector(2 downto 0);
26 | fc : std_logic;
27 | end record;
28 |
29 | type MCode_r is record
30 | STATE_CTRL : std_logic_vector(1 downto 0);
31 | ADDR_BUS : std_logic_vector(2 downto 0);
32 | LOAD_SDLH : std_logic_vector(1 downto 0);
33 | LOAD_P : std_logic_vector(2 downto 0);
34 | LOAD_T : std_logic_vector(2 downto 0);
35 | ADDR_CTRL : std_logic_vector(5 downto 0);
36 | LOAD_PC : std_logic_vector(2 downto 0);
37 | LOAD_SP : std_logic_vector(2 downto 0);
38 | AXY_CTRL : std_logic_vector(2 downto 0);
39 | ALUBUS_CTRL : std_logic_vector(3 downto 0);
40 | OUT_BUS : std_logic_vector(3 downto 0);
41 | MEM_CYCLE : std_logic;
42 | ALU_CTRL : ALUCtrl_r;
43 | end record;
44 |
45 | constant FLAG_C : integer := 0;
46 | constant FLAG_Z : integer := 1;
47 | constant FLAG_I : integer := 2;
48 | constant FLAG_D : integer := 3;
49 | constant FLAG_B : integer := 4;
50 | constant FLAG_T : integer := 5;
51 | constant FLAG_V : integer := 6;
52 | constant FLAG_N : integer := 7;
53 |
54 | type MPR_t is array(0 to 7) of std_logic_vector(7 downto 0);
55 |
56 | end HUC6280_PKG;
57 |
58 | package body HUC6280_PKG is
59 |
60 |
61 | end package body HUC6280_PKG;
62 |
--------------------------------------------------------------------------------
/rtl/pce/arcade.sv:
--------------------------------------------------------------------------------
1 | //
2 | // Arcade Card
3 | // Copyright (c) 2020 Alexey Melnikov
4 | //
5 | // This source file is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published
7 | // by the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // This source file is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with this program. If not, see .
17 | //
18 |
19 | module ARCADE_CARD
20 | (
21 | input CLK,
22 | input RST_N,
23 |
24 | input EN,
25 | input WR_N,
26 | input RD_N,
27 | input [20:0] A,
28 | input [7:0] DI,
29 | output [7:0] DO,
30 | output SEL_N,
31 |
32 | output RAM_CS_N,
33 | output [20:0] RAM_A
34 | );
35 |
36 |
37 | typedef struct packed
38 | {
39 | reg [23:0] base;
40 | reg [15:0] offset;
41 | reg [15:0] increment;
42 | reg [6:0] control;
43 | reg [20:0] addr;
44 | } port_t;
45 |
46 | port_t port[4];
47 | wire [1:0] p;
48 |
49 | reg ena;
50 | reg [31:0] shift_latch;
51 | reg [7:0] shift_bits;
52 | reg [7:0] rotate_bits;
53 |
54 | assign SEL_N = ~(EN && &A[20:13] && (A[12:8] == 'h1A));
55 | assign RAM_A = port[p].addr;
56 |
57 | always_comb begin
58 | DO = 8'hFF;
59 | RAM_CS_N = 1;
60 |
61 | if(A[20:15] == 16) begin // pages 0x40-0x43
62 | p = A[14:13];
63 | RAM_CS_N = ~EN | ~ena;
64 | end
65 | else begin
66 | p = A[5:4];
67 |
68 | if(!A[7]) begin
69 |
70 | case(A[3:0])
71 | 0,1: RAM_CS_N = SEL_N;
72 |
73 | 2: DO = port[p].base[7:0];
74 | 3: DO = port[p].base[15:8];
75 | 4: DO = port[p].base[23:16];
76 | 5: DO = port[p].offset[7:0];
77 | 6: DO = port[p].offset[15:8];
78 | 7: DO = port[p].increment[7:0];
79 | 8: DO = port[p].increment[15:8];
80 | 9: DO = port[p].control;
81 | default:;
82 | endcase
83 | end
84 | else if(&A[6:5]) begin
85 |
86 | case (A[4:0])
87 | 0: DO = shift_latch[7:0];
88 | 1: DO = shift_latch[15:8];
89 | 2: DO = shift_latch[23:16];
90 | 3: DO = shift_latch[31:24];
91 | 4: DO = shift_bits;
92 | 5: DO = rotate_bits;
93 |
94 | 'h1C: DO = 0;
95 | 'h1D: DO = 0;
96 |
97 | 'h1E: DO = 8'h10;
98 | 'h1F: DO = 8'h51;
99 | default:;
100 | endcase
101 | end
102 | end
103 | end
104 |
105 | always @(posedge CLK) begin
106 | for(int i=0; i<4; i++) begin
107 | port[i].addr = port[i].base[20:0] + (port[i].control[1] ? {{5{port[i].control[3]}}, port[i].offset} : 21'd0);
108 | end
109 | end
110 |
111 | wire [3:0] rot = DI[3] ? (4'd8 - DI[2:0]) : DI[2:0];
112 | wire acc = ~(WR_N & RD_N);
113 |
114 | always @(posedge CLK) begin
115 | reg old_acc;
116 |
117 | old_acc <= acc;
118 |
119 | if(~RST_N) begin
120 | for(int i=0; i<4; i++) begin
121 | port[i].base <= 0;
122 | port[i].offset <= 0;
123 | port[i].increment <= 0;
124 | port[i].control <= 0;
125 | end
126 | ena <= 0;
127 | shift_latch <= 0;
128 | shift_bits <= 0;
129 | rotate_bits <= 0;
130 | end
131 | else if(~old_acc & acc) begin
132 |
133 | if(~SEL_N & ~WR_N) begin
134 | if(!A[7]) begin
135 |
136 | ena <= 1;
137 | case(A[3:0])
138 | 2: port[p].base[7:0] <= DI;
139 | 3: port[p].base[15:8] <= DI;
140 | 4: port[p].base[23:16] <= DI;
141 | 5: begin
142 | port[p].offset[7:0] <= DI;
143 | if(port[p].control[6:5] == 1) port[p].base <= port[p].base + {{8{port[p].control[3]}}, port[p].offset[15:8], DI};
144 | end
145 | 6: begin
146 | port[p].offset[15:8] <= DI;
147 | if(port[p].control[6:5] == 2) port[p].base <= port[p].base + {{8{port[p].control[3]}}, DI, port[p].offset[7:0]};
148 | end
149 | 7: port[p].increment[7:0] <= DI;
150 | 8: port[p].increment[15:8] <= DI;
151 | 9: port[p].control <= DI[6:0];
152 | 10: if(port[p].control[6:5] == 3) port[p].base <= port[p].base + {{8{port[p].control[3]}}, port[p].offset};
153 | endcase
154 | end
155 | else if(&A[6:5]) begin
156 |
157 | case (A[4:0])
158 | 0: shift_latch[7:0] <= DI;
159 | 1: shift_latch[15:8] <= DI;
160 | 2: shift_latch[23:16] <= DI;
161 | 3: shift_latch[31:24] <= DI;
162 | 4: begin
163 | shift_bits <= DI[3:0];
164 | shift_latch <= DI[3] ? (shift_latch >> (8 - DI[2:0])) : (shift_latch << DI[2:0]);
165 | end
166 | 5: begin
167 | rotate_bits <= DI[3:0];
168 | if(DI[3]) shift_latch <= (shift_latch >> rot) | (shift_latch << (32 - rot));
169 | else shift_latch <= (shift_latch << rot) | ((shift_latch >> (32 - rot)) & ((32'd1 << rot) - 1'd1));
170 | end
171 | endcase
172 | end
173 | end
174 |
175 | if(~RAM_CS_N & port[p].control[0]) begin
176 | if(port[p].control[4]) port[p].base <= port[p].base + port[p].increment;
177 | else port[p].offset <= port[p].offset + port[p].increment;
178 | end
179 | end
180 | end
181 |
182 | endmodule
183 |
--------------------------------------------------------------------------------
/rtl/pce/cd/CDDA_FIFO.vhd:
--------------------------------------------------------------------------------
1 | -- megafunction wizard: %FIFO%
2 | -- GENERATION: STANDARD
3 | -- VERSION: WM1.0
4 | -- MODULE: scfifo
5 |
6 | -- ============================================================
7 | -- File Name: CDDA_FIFO.vhd
8 | -- Megafunction Name(s):
9 | -- scfifo
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 | -- 17.0.0 Build 595 04/25/2017 SJ Lite Edition
18 | -- ************************************************************
19 |
20 |
21 | --Copyright (C) 2017 Intel Corporation. All rights reserved.
22 | --Your use of Intel 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 Intel Program License
28 | --Subscription Agreement, the Intel Quartus Prime License Agreement,
29 | --the Intel MegaCore Function License Agreement, or other
30 | --applicable license agreement, including, without limitation,
31 | --that your use is for the sole purpose of programming logic
32 | --devices manufactured by Intel and sold by Intel or its
33 | --authorized distributors. Please refer to the applicable
34 | --agreement for further details.
35 |
36 |
37 | LIBRARY ieee;
38 | USE ieee.std_logic_1164.all;
39 |
40 | LIBRARY altera_mf;
41 | USE altera_mf.all;
42 |
43 | ENTITY CDDA_FIFO IS
44 | PORT
45 | (
46 | clock : IN STD_LOGIC ;
47 | data : IN STD_LOGIC_VECTOR (31 DOWNTO 0);
48 | rdreq : IN STD_LOGIC ;
49 | sclr : IN STD_LOGIC ;
50 | wrreq : IN STD_LOGIC ;
51 | empty : OUT STD_LOGIC ;
52 | full : OUT STD_LOGIC ;
53 | q : OUT STD_LOGIC_VECTOR (31 DOWNTO 0)
54 | );
55 | END CDDA_FIFO;
56 |
57 |
58 | ARCHITECTURE SYN OF cdda_fifo IS
59 |
60 | SIGNAL sub_wire0 : STD_LOGIC ;
61 | SIGNAL sub_wire1 : STD_LOGIC ;
62 | SIGNAL sub_wire2 : STD_LOGIC_VECTOR (31 DOWNTO 0);
63 |
64 |
65 |
66 | COMPONENT scfifo
67 | GENERIC (
68 | add_ram_output_register : STRING;
69 | intended_device_family : STRING;
70 | lpm_numwords : NATURAL;
71 | lpm_showahead : STRING;
72 | lpm_type : STRING;
73 | lpm_width : NATURAL;
74 | lpm_widthu : NATURAL;
75 | overflow_checking : STRING;
76 | underflow_checking : STRING;
77 | use_eab : STRING
78 | );
79 | PORT (
80 | clock : IN STD_LOGIC ;
81 | data : IN STD_LOGIC_VECTOR (31 DOWNTO 0);
82 | rdreq : IN STD_LOGIC ;
83 | sclr : IN STD_LOGIC ;
84 | wrreq : IN STD_LOGIC ;
85 | empty : OUT STD_LOGIC ;
86 | full : OUT STD_LOGIC ;
87 | q : OUT STD_LOGIC_VECTOR (31 DOWNTO 0)
88 | );
89 | END COMPONENT;
90 |
91 | BEGIN
92 | empty <= sub_wire0;
93 | full <= sub_wire1;
94 | q <= sub_wire2(31 DOWNTO 0);
95 |
96 | scfifo_component : scfifo
97 | GENERIC MAP (
98 | add_ram_output_register => "OFF",
99 | intended_device_family => "Cyclone V",
100 | lpm_numwords => 4096,
101 | lpm_showahead => "ON",
102 | lpm_type => "scfifo",
103 | lpm_width => 32,
104 | lpm_widthu => 12,
105 | overflow_checking => "ON",
106 | underflow_checking => "ON",
107 | use_eab => "ON"
108 | )
109 | PORT MAP (
110 | clock => clock,
111 | data => data,
112 | rdreq => rdreq,
113 | sclr => sclr,
114 | wrreq => wrreq,
115 | empty => sub_wire0,
116 | full => sub_wire1,
117 | q => sub_wire2
118 | );
119 |
120 |
121 |
122 | END SYN;
123 |
124 | -- ============================================================
125 | -- CNX file retrieval info
126 | -- ============================================================
127 | -- Retrieval info: PRIVATE: AlmostEmpty NUMERIC "0"
128 | -- Retrieval info: PRIVATE: AlmostEmptyThr NUMERIC "-1"
129 | -- Retrieval info: PRIVATE: AlmostFull NUMERIC "0"
130 | -- Retrieval info: PRIVATE: AlmostFullThr NUMERIC "-1"
131 | -- Retrieval info: PRIVATE: CLOCKS_ARE_SYNCHRONIZED NUMERIC "1"
132 | -- Retrieval info: PRIVATE: Clock NUMERIC "0"
133 | -- Retrieval info: PRIVATE: Depth NUMERIC "4096"
134 | -- Retrieval info: PRIVATE: Empty NUMERIC "1"
135 | -- Retrieval info: PRIVATE: Full NUMERIC "1"
136 | -- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone V"
137 | -- Retrieval info: PRIVATE: LE_BasedFIFO NUMERIC "0"
138 | -- Retrieval info: PRIVATE: LegacyRREQ NUMERIC "0"
139 | -- Retrieval info: PRIVATE: MAX_DEPTH_BY_9 NUMERIC "0"
140 | -- Retrieval info: PRIVATE: OVERFLOW_CHECKING NUMERIC "0"
141 | -- Retrieval info: PRIVATE: Optimize NUMERIC "2"
142 | -- Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0"
143 | -- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0"
144 | -- Retrieval info: PRIVATE: UNDERFLOW_CHECKING NUMERIC "0"
145 | -- Retrieval info: PRIVATE: UsedW NUMERIC "0"
146 | -- Retrieval info: PRIVATE: Width NUMERIC "32"
147 | -- Retrieval info: PRIVATE: dc_aclr NUMERIC "0"
148 | -- Retrieval info: PRIVATE: diff_widths NUMERIC "1"
149 | -- Retrieval info: PRIVATE: msb_usedw NUMERIC "0"
150 | -- Retrieval info: PRIVATE: output_width NUMERIC "32"
151 | -- Retrieval info: PRIVATE: rsEmpty NUMERIC "1"
152 | -- Retrieval info: PRIVATE: rsFull NUMERIC "0"
153 | -- Retrieval info: PRIVATE: rsUsedW NUMERIC "0"
154 | -- Retrieval info: PRIVATE: sc_aclr NUMERIC "0"
155 | -- Retrieval info: PRIVATE: sc_sclr NUMERIC "1"
156 | -- Retrieval info: PRIVATE: wsEmpty NUMERIC "0"
157 | -- Retrieval info: PRIVATE: wsFull NUMERIC "1"
158 | -- Retrieval info: PRIVATE: wsUsedW NUMERIC "0"
159 | -- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
160 | -- Retrieval info: CONSTANT: ADD_RAM_OUTPUT_REGISTER STRING "OFF"
161 | -- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone V"
162 | -- Retrieval info: CONSTANT: LPM_NUMWORDS NUMERIC "4096"
163 | -- Retrieval info: CONSTANT: LPM_SHOWAHEAD STRING "ON"
164 | -- Retrieval info: CONSTANT: LPM_TYPE STRING "scfifo"
165 | -- Retrieval info: CONSTANT: LPM_WIDTH NUMERIC "32"
166 | -- Retrieval info: CONSTANT: LPM_WIDTHU NUMERIC "12"
167 | -- Retrieval info: CONSTANT: OVERFLOW_CHECKING STRING "ON"
168 | -- Retrieval info: CONSTANT: UNDERFLOW_CHECKING STRING "ON"
169 | -- Retrieval info: CONSTANT: USE_EAB STRING "ON"
170 | -- Retrieval info: USED_PORT: clock 0 0 0 0 INPUT NODEFVAL "clock"
171 | -- Retrieval info: USED_PORT: data 0 0 32 0 INPUT NODEFVAL "data[31..0]"
172 | -- Retrieval info: USED_PORT: empty 0 0 0 0 OUTPUT NODEFVAL "empty"
173 | -- Retrieval info: USED_PORT: full 0 0 0 0 OUTPUT NODEFVAL "full"
174 | -- Retrieval info: USED_PORT: q 0 0 32 0 OUTPUT NODEFVAL "q[31..0]"
175 | -- Retrieval info: USED_PORT: rdreq 0 0 0 0 INPUT NODEFVAL "rdreq"
176 | -- Retrieval info: USED_PORT: sclr 0 0 0 0 INPUT NODEFVAL "sclr"
177 | -- Retrieval info: USED_PORT: wrreq 0 0 0 0 INPUT NODEFVAL "wrreq"
178 | -- Retrieval info: CONNECT: @clock 0 0 0 0 clock 0 0 0 0
179 | -- Retrieval info: CONNECT: @data 0 0 32 0 data 0 0 32 0
180 | -- Retrieval info: CONNECT: @rdreq 0 0 0 0 rdreq 0 0 0 0
181 | -- Retrieval info: CONNECT: @sclr 0 0 0 0 sclr 0 0 0 0
182 | -- Retrieval info: CONNECT: @wrreq 0 0 0 0 wrreq 0 0 0 0
183 | -- Retrieval info: CONNECT: empty 0 0 0 0 @empty 0 0 0 0
184 | -- Retrieval info: CONNECT: full 0 0 0 0 @full 0 0 0 0
185 | -- Retrieval info: CONNECT: q 0 0 32 0 @q 0 0 32 0
186 | -- Retrieval info: GEN_FILE: TYPE_NORMAL CDDA_FIFO.vhd TRUE
187 | -- Retrieval info: GEN_FILE: TYPE_NORMAL CDDA_FIFO.inc FALSE
188 | -- Retrieval info: GEN_FILE: TYPE_NORMAL CDDA_FIFO.cmp FALSE
189 | -- Retrieval info: GEN_FILE: TYPE_NORMAL CDDA_FIFO.bsf FALSE
190 | -- Retrieval info: GEN_FILE: TYPE_NORMAL CDDA_FIFO_inst.vhd FALSE
191 | -- Retrieval info: LIB_FILE: altera_mf
192 |
--------------------------------------------------------------------------------
/rtl/pce/cd/MSM5205.vhd:
--------------------------------------------------------------------------------
1 | library STD;
2 | use STD.TEXTIO.ALL;
3 | library IEEE;
4 | use IEEE.STD_LOGIC_1164.ALL;
5 | use IEEE.STD_LOGIC_TEXTIO.all;
6 | use IEEE.NUMERIC_STD.ALL;
7 |
8 | entity MSM5205 is
9 | port(
10 | CLK : in std_logic;
11 | RST_N : in std_logic;
12 |
13 | XTI : in std_logic;
14 | D : in std_logic_vector(3 downto 0);
15 | VCK_R : out std_logic;
16 | VCK_F : out std_logic;
17 |
18 | SOUT : out signed(15 downto 0)
19 | );
20 | end MSM5205;
21 |
22 | architecture rtl of MSM5205 is
23 |
24 | type DeltaTable_t is array (0 to 391) of unsigned(11 downto 0);
25 | constant DT : DeltaTable_t :=
26 | (x"002", x"006", x"00A", x"00E", x"012", x"016", x"01A", x"01E",
27 | x"002", x"006", x"00A", x"00E", x"013", x"017", x"01B", x"01F",
28 | x"002", x"006", x"00B", x"00F", x"015", x"019", x"01E", x"022",
29 | x"002", x"007", x"00C", x"011", x"017", x"01C", x"021", x"026",
30 | x"002", x"007", x"00D", x"012", x"019", x"01E", x"024", x"029",
31 | x"003", x"009", x"00F", x"015", x"01C", x"022", x"028", x"02E",
32 | x"003", x"00A", x"011", x"018", x"01F", x"026", x"02D", x"034",
33 | x"003", x"00A", x"012", x"019", x"022", x"029", x"031", x"038",
34 | x"004", x"00C", x"015", x"01D", x"026", x"02E", x"037", x"03F",
35 | x"004", x"00D", x"016", x"01F", x"029", x"032", x"03B", x"044",
36 | x"005", x"00F", x"019", x"023", x"02E", x"038", x"042", x"04C",
37 | x"005", x"010", x"01B", x"026", x"032", x"03D", x"048", x"053",
38 | x"006", x"012", x"01F", x"02B", x"038", x"044", x"051", x"05D",
39 | x"006", x"013", x"021", x"02E", x"03D", x"04A", x"058", x"065",
40 | x"007", x"016", x"025", x"034", x"043", x"052", x"061", x"070",
41 | x"008", x"018", x"029", x"039", x"04A", x"05A", x"06B", x"07B",
42 | x"009", x"01B", x"02D", x"03F", x"052", x"064", x"076", x"088",
43 | x"00A", x"01E", x"032", x"046", x"05A", x"06E", x"082", x"096",
44 | x"00B", x"021", x"037", x"04D", x"063", x"079", x"08F", x"0A5",
45 | x"00C", x"024", x"03C", x"054", x"06D", x"085", x"09D", x"0B5",
46 | x"00D", x"027", x"042", x"05C", x"078", x"092", x"0AD", x"0C7",
47 | x"00E", x"02B", x"049", x"066", x"084", x"0A1", x"0BF", x"0DC",
48 | x"010", x"030", x"051", x"071", x"092", x"0B2", x"0D3", x"0F3",
49 | x"011", x"034", x"058", x"07B", x"0A0", x"0C3", x"0E7", x"10A",
50 | x"013", x"03A", x"061", x"088", x"0B0", x"0D7", x"0FE", x"125",
51 | x"015", x"040", x"06B", x"096", x"0C2", x"0ED", x"118", x"143",
52 | x"017", x"046", x"076", x"0A5", x"0D5", x"104", x"134", x"163",
53 | x"01A", x"04E", x"082", x"0B6", x"0EB", x"11F", x"153", x"187",
54 | x"01C", x"055", x"08F", x"0C8", x"102", x"13B", x"175", x"1AE",
55 | x"01F", x"05E", x"09D", x"0DC", x"11C", x"15B", x"19A", x"1D9",
56 | x"022", x"067", x"0AD", x"0F2", x"139", x"17E", x"1C4", x"209",
57 | x"026", x"072", x"0BF", x"10B", x"159", x"1A5", x"1F2", x"23E",
58 | x"02A", x"07E", x"0D2", x"126", x"17B", x"1CF", x"223", x"277",
59 | x"02E", x"08A", x"0E7", x"143", x"1A1", x"1FD", x"25A", x"2B6",
60 | x"033", x"099", x"0FF", x"165", x"1CB", x"231", x"297", x"2FD",
61 | x"038", x"0A8", x"118", x"188", x"1F9", x"269", x"2D9", x"349",
62 | x"03D", x"0B8", x"134", x"1AF", x"22B", x"2A6", x"322", x"39D",
63 | x"044", x"0CC", x"154", x"1DC", x"264", x"2EC", x"374", x"3FC",
64 | x"04A", x"0DF", x"175", x"20A", x"2A0", x"335", x"3CB", x"460",
65 | x"052", x"0F6", x"19B", x"23F", x"2E4", x"388", x"42D", x"4D1",
66 | x"05A", x"10F", x"1C4", x"279", x"32E", x"3E3", x"498", x"54D",
67 | x"063", x"12A", x"1F1", x"2B8", x"37F", x"446", x"50D", x"5D4",
68 | x"06D", x"148", x"223", x"2FE", x"3D9", x"4B4", x"58F", x"66A",
69 | x"078", x"168", x"259", x"349", x"43B", x"52B", x"61C", x"70C",
70 | x"084", x"18D", x"296", x"39F", x"4A8", x"5B1", x"6BA", x"7C3",
71 | x"091", x"1B4", x"2D8", x"3FB", x"51F", x"642", x"766", x"889",
72 | x"0A0", x"1E0", x"321", x"461", x"5A2", x"6E2", x"823", x"963",
73 | x"0B0", x"210", x"371", x"4D1", x"633", x"793", x"8F4", x"A54",
74 | x"0C2", x"246", x"3CA", x"54E", x"6D2", x"856", x"9DA", x"B5E");
75 |
76 | type StepIndexTable_t is array (0 to 3) of unsigned(3 downto 0);
77 | constant SIT : StepIndexTable_t := ("0010","0100","0110","1000");
78 |
79 |
80 | signal CLK_CNT : unsigned(5 downto 0);
81 | signal SAMPLE_RCE : std_logic;
82 | signal SAMPLE_FCE : std_logic;
83 |
84 | signal DEC_DATA : unsigned(3 downto 0);
85 | signal DEC_EXEC : std_logic;
86 |
87 | signal SAMPLE : unsigned(15 downto 0);
88 | signal STEP : unsigned(5 downto 0);
89 |
90 | begin
91 |
92 | process( CLK )
93 | begin
94 | if rising_edge(CLK) then
95 | SAMPLE_RCE <= '0';
96 | SAMPLE_FCE <= '0';
97 | if XTI = '1' then
98 | CLK_CNT <= CLK_CNT + 1;
99 | if CLK_CNT = 24-1 then
100 | SAMPLE_RCE <= '1';
101 | end if;
102 | if CLK_CNT = 48-1 then
103 | CLK_CNT <= (others => '0');
104 | SAMPLE_FCE <= '1';
105 | end if;
106 | end if;
107 | end if;
108 | end process;
109 |
110 | VCK_R <= SAMPLE_RCE;
111 | VCK_F <= SAMPLE_FCE;
112 |
113 | process( RST_N, CLK )
114 | variable DELTA : unsigned(11 downto 0);
115 | variable NEXT_STEP : unsigned(6 downto 0);
116 | variable NEXT_SAMPLE : unsigned(15 downto 0);
117 | begin
118 | if RST_N = '0' then
119 | DEC_DATA <= (others => '0');
120 | DEC_EXEC <= '0';
121 | STEP <= (others => '0');
122 | SAMPLE <= x"0000";
123 | elsif rising_edge(CLK) then
124 | DEC_EXEC <= '0';
125 | if SAMPLE_FCE = '1' then
126 | DEC_DATA <= unsigned(D);
127 | DEC_EXEC <= '1';
128 | end if;
129 |
130 | if DEC_EXEC = '1' then
131 | DELTA := DT(to_integer(STEP&DEC_DATA(2 downto 0)));
132 | if DEC_DATA(3) = '1' then
133 | NEXT_SAMPLE := SAMPLE - DELTA;
134 | else
135 | NEXT_SAMPLE := SAMPLE + DELTA;
136 | end if;
137 |
138 | if NEXT_SAMPLE(12 downto 11) = "01" then
139 | NEXT_SAMPLE := x"07FF";
140 | elsif NEXT_SAMPLE(12 downto 11) = "10" then
141 | NEXT_SAMPLE := x"F800";
142 | end if;
143 |
144 | SAMPLE <= NEXT_SAMPLE;
145 |
146 | if DEC_DATA(2) = '1' then
147 | NEXT_STEP := ("0"&STEP) + SIT(to_integer(DEC_DATA(1 downto 0)));
148 | else
149 | NEXT_STEP := ("0"&STEP) - 1;
150 | end if;
151 |
152 | if NEXT_STEP(6) = '1' then
153 | STEP <= "000000";
154 | elsif NEXT_STEP > 48 then
155 | STEP <= "110000";
156 | else
157 | STEP <= NEXT_STEP(5 downto 0);
158 | end if;
159 | end if;
160 | end if;
161 | end process;
162 |
163 | SOUT <= signed(SAMPLE(11 downto 0)) & x"0";
164 |
165 | end rtl;
--------------------------------------------------------------------------------
/rtl/pce/cd/SCSI.vhd:
--------------------------------------------------------------------------------
1 | library STD;
2 | use STD.TEXTIO.ALL;
3 | library IEEE;
4 | use IEEE.STD_LOGIC_1164.ALL;
5 | use IEEE.STD_LOGIC_TEXTIO.all;
6 | use IEEE.NUMERIC_STD.ALL;
7 |
8 | entity SCSI is
9 | port(
10 | RESET_N : in std_logic;
11 | CLK : in std_logic;
12 |
13 | DBI : in std_logic_vector(7 downto 0);
14 | DBO : out std_logic_vector(7 downto 0);
15 | SEL_N : in std_logic;
16 | ACK_N : in std_logic;
17 | RST_N : in std_logic;
18 | BSY_N : out std_logic;
19 | REQ_N : out std_logic;
20 | MSG_N : out std_logic;
21 | CD_N : out std_logic;
22 | IO_N : out std_logic;
23 |
24 | STATUS : in std_logic_vector(7 downto 0);
25 | MESSAGE : in std_logic_vector(7 downto 0);
26 | STAT_GET : in std_logic;
27 |
28 | COMMAND : out std_logic_vector(95 downto 0);
29 | COMM_SEND : out std_logic;
30 |
31 | DOUT_REQ : in std_logic;
32 | DOUT : out std_logic_vector(79 downto 0);
33 | DOUT_SEND : out std_logic;
34 |
35 | CD_DATA : in std_logic_vector(7 downto 0);
36 | CD_WR : in std_logic;
37 | CD_DATA_END : out std_logic;
38 | STOP_CD_SND : out std_logic;
39 |
40 | DBG_DATAIN_CNT: out unsigned(15 downto 0)
41 | );
42 | end SCSI;
43 |
44 | architecture rtl of SCSI is
45 |
46 | type SCSIPhase_t is (
47 | SP_FREE,
48 | SP_COMM_START,
49 | SP_COMM_END,
50 | SP_STAT_START,
51 | SP_STAT_END,
52 | SP_MSGIN_START,
53 | SP_MSGIN_END,
54 | SP_DATAIN_START,
55 | SP_DATAIN_END,
56 | SP_DATAOUT_START,
57 | SP_DATAOUT_END
58 | );
59 | signal SP : SCSIPhase_t;
60 |
61 | signal BSY_Nr : std_logic;
62 | signal MSG_Nr : std_logic;
63 | signal CD_Nr : std_logic;
64 | signal IO_Nr : std_logic;
65 | signal REQ_Nr : std_logic;
66 | -- signal TR_DONE : std_logic;
67 | -- signal TR_RDY : std_logic;
68 |
69 | type CommBuf_t is array (0 to 11) of std_logic_vector(7 downto 0);
70 | signal COMM : CommBuf_t;
71 | signal COMM_POS : unsigned(3 downto 0);
72 | signal COMM_OUT : std_logic;
73 | type CommLen_t is array (0 to 15) of unsigned(3 downto 0);
74 | constant COMM_LEN : CommLen_t :=
75 | ("0110", "0110", "1010", "1010", "1010", "1010", "1010", "1010", "1010", "1010", "1100", "1100", "1010", "1010", "1010", "1010");
76 |
77 | type DataBuf_t is array (0 to 9) of std_logic_vector(7 downto 0);
78 | signal DATA_BUF : DataBuf_t;
79 | signal DATA_POS : unsigned(3 downto 0);
80 | signal DATA_OUT : std_logic;
81 |
82 | signal FULL : std_logic;
83 | signal EMPTY : std_logic;
84 | signal FIFO_RD_REQ: std_logic;
85 | signal FIFO_WR_REQ: std_logic;
86 | signal FIFO_D : std_logic_vector(7 downto 0);
87 | signal FIFO_Q : std_logic_vector(7 downto 0);
88 | signal CD_WR_OLD : std_logic;
89 | signal STAT_PEND : std_logic;
90 | signal DOUT_PEND: std_logic;
91 |
92 | signal DATAIN_CNT : unsigned(15 downto 0);
93 |
94 | signal STAT_COUNT : unsigned(15 downto 0);
95 |
96 | begin
97 |
98 | process( RESET_N, CLK )
99 | begin
100 | if RESET_N = '0' then
101 | FIFO_D <= (others => '0');
102 | FIFO_WR_REQ <= '0';
103 | --CD_WR_OLD <= '0';
104 | elsif rising_edge(CLK) then
105 | FIFO_WR_REQ <= '0';
106 | -- if EN = '1' then
107 | CD_WR_OLD <= CD_WR;
108 | if CD_WR = '1' and CD_WR_OLD = '0' then
109 | FIFO_D <= CD_DATA;
110 | if FULL = '0' then
111 | FIFO_WR_REQ <= '1';
112 | end if;
113 | end if;
114 | -- end if;
115 | end if;
116 | end process;
117 |
118 |
119 | FIFO : entity work.SCSI_FIFO
120 | port map(
121 | aclr => not RESET_N,
122 |
123 | wrclk => CLK,
124 | data => FIFO_D,
125 | wrreq => FIFO_WR_REQ,
126 | wrfull => FULL,
127 |
128 | rdclk => CLK,
129 | rdreq => FIFO_RD_REQ,
130 | rdempty => EMPTY,
131 | q => FIFO_Q
132 | );
133 |
134 | process( CLK, RESET_N ) begin
135 | if RESET_N = '0' then
136 | DBO <= (others => '0');
137 | BSY_Nr <= '1';
138 | MSG_Nr <= '1';
139 | CD_Nr <= '1';
140 | IO_Nr <= '1';
141 | REQ_Nr <= '1';
142 | COMM <= (others => (others => '0'));
143 | COMM_POS <= (others => '0');
144 | DATA_BUF <= (others => (others => '0'));
145 | DATA_POS <= (others => '0');
146 | SP <= SP_FREE;
147 | STOP_CD_SND <= '0';
148 |
149 | COMM_OUT <= '0';
150 | DATA_OUT <= '0';
151 | CD_DATA_END <= '0';
152 | STAT_PEND <= '0';
153 | DOUT_PEND <= '0';
154 | FIFO_RD_REQ <= '0';
155 |
156 | STAT_COUNT <= (others => '0');
157 |
158 | DATAIN_CNT <= (others => '0');
159 |
160 | elsif rising_edge( CLK ) then
161 | if STAT_GET = '1' then
162 | STAT_PEND <= '1';
163 | end if;
164 |
165 | if DOUT_REQ = '1' then
166 | DOUT_PEND <= '1';
167 | end if;
168 |
169 |
170 | COMM_OUT <= '0';
171 | DATA_OUT <= '0';
172 | CD_DATA_END <= '0';
173 | FIFO_RD_REQ <= '0';
174 |
175 | if RST_N = '0' then
176 | BSY_Nr <= '1';
177 | MSG_Nr <= '1';
178 | CD_Nr <= '1';
179 | IO_Nr <= '1';
180 | REQ_Nr <= '1';
181 | else
182 | case SP is
183 | when SP_FREE =>
184 | if SEL_N = '0' then
185 | BSY_Nr <= '0';
186 | MSG_Nr <= '1';
187 | CD_Nr <= '0';
188 | IO_Nr <= '1';
189 | REQ_Nr <= '0';
190 | SP <= SP_COMM_START;
191 | DATAIN_CNT <= (others => '0');
192 | elsif STAT_PEND = '1' then
193 | STAT_COUNT <= STAT_COUNT + 1;
194 |
195 | if (STAT_COUNT = 45000) then -- CLK is 42.95 MHz; this gives ~1.05 millisec delay.
196 | -- this is empirical and may not be correct but it solves
197 | -- the Sailor Moon hang issue
198 | STAT_COUNT <= (others => '0');
199 | STAT_PEND <= '0';
200 | DBO <= STATUS;
201 | BSY_Nr <= '0';
202 | MSG_Nr <= '1';
203 | CD_Nr <= '0';
204 | IO_Nr <= '0';
205 | REQ_Nr <= '0';
206 | SP <= SP_STAT_START;
207 | end if;
208 | elsif EMPTY = '0' then
209 | DBO <= FIFO_Q;
210 | BSY_Nr <= '0';
211 | MSG_Nr <= '1';
212 | CD_Nr <= '1';
213 | IO_Nr <= '0';
214 | REQ_Nr <= '0';
215 | FIFO_RD_REQ <= '1';
216 | SP <= SP_DATAIN_START;
217 | elsif DOUT_PEND = '1' then
218 | DOUT_PEND <= '0';
219 | BSY_Nr <= '0';
220 | MSG_Nr <= '1';
221 | CD_Nr <= '1';
222 | IO_Nr <= '1';
223 | REQ_Nr <= '0';
224 | SP <= SP_DATAOUT_START;
225 | end if;
226 |
227 | when SP_COMM_START =>
228 | if REQ_Nr = '0' and ACK_N = '0' then
229 | REQ_Nr <= '1';
230 | COMM(to_integer(COMM_POS)) <= DBI;
231 | COMM_POS <= COMM_POS + 1;
232 | SP <= SP_COMM_END;
233 | end if;
234 |
235 | when SP_COMM_END =>
236 | if REQ_Nr = '1' and ACK_N = '1' then
237 | if COMM_POS = COMM_LEN(to_integer(unsigned(COMM(0)(7 downto 4)))) then
238 | COMM_POS <= (others => '0');
239 | COMM_OUT <= '1';
240 | CD_Nr <= '1';
241 | SP <= SP_FREE;
242 | if ((COMM(0) = x"08") or (COMM(0) = x"DA")) then -- READ6 and PAUSE commands should mute sound, but still drain FIFO
243 | STOP_CD_SND <= '1';
244 | end if;
245 | if ((COMM(0) = x"D8") or (COMM(0) = x"D9")) then -- SAPSP and SAPEP commands should unmute sound (FIFO should be empty by now)
246 | STOP_CD_SND <= '0';
247 | end if;
248 | else
249 | REQ_Nr <= '0';
250 | SP <= SP_COMM_START;
251 | end if;
252 | end if;
253 |
254 | when SP_STAT_START =>
255 | if REQ_Nr = '0' and ACK_N = '0' then
256 | REQ_Nr <= '1';
257 | SP <= SP_STAT_END;
258 | end if;
259 |
260 | when SP_STAT_END =>
261 | if REQ_Nr = '1' and ACK_N = '1' then
262 | DBO <= MESSAGE;
263 | BSY_Nr <= '0';
264 | MSG_Nr <= '0';
265 | CD_Nr <= '0';
266 | IO_Nr <= '0';
267 | REQ_Nr <= '0';
268 | SP <= SP_MSGIN_START;
269 | end if;
270 |
271 | when SP_MSGIN_START =>
272 | if REQ_Nr = '0' and ACK_N = '0' then
273 | REQ_Nr <= '1';
274 | SP <= SP_MSGIN_END;
275 | end if;
276 |
277 | when SP_MSGIN_END =>
278 | if REQ_Nr = '1' and ACK_N = '1' then
279 | BSY_Nr <= '1';
280 | MSG_Nr <= '1';
281 | CD_Nr <= '1';
282 | IO_Nr <= '1';
283 | REQ_Nr <= '1';
284 | SP <= SP_FREE;
285 | end if;
286 |
287 | when SP_DATAIN_START =>
288 | if REQ_Nr = '0' and ACK_N = '0' then
289 | REQ_Nr <= '1';
290 | SP <= SP_DATAIN_END;
291 | STOP_CD_SND <= '0'; -- unmute
292 | end if;
293 |
294 | when SP_DATAIN_END =>
295 | if REQ_Nr = '1' and ACK_N = '1' then
296 | if EMPTY = '0' then
297 | DBO <= FIFO_Q;
298 | REQ_Nr <= '0';
299 | FIFO_RD_REQ <= '1';
300 | SP <= SP_DATAIN_START;
301 | else
302 | CD_DATA_END <= '1';
303 | SP <= SP_FREE;
304 | end if;
305 | DATAIN_CNT <= DATAIN_CNT + 1;
306 | end if;
307 |
308 | when SP_DATAOUT_START =>
309 | if REQ_Nr = '0' and ACK_N = '0' then
310 | REQ_Nr <= '1';
311 | DATA_BUF(to_integer(DATA_POS)) <= DBI;
312 | DATA_POS <= DATA_POS + 1;
313 | SP <= SP_DATAOUT_END;
314 | end if;
315 |
316 | when SP_DATAOUT_END =>
317 | if REQ_Nr = '1' and ACK_N = '1' then
318 | if DATA_POS = 10 then
319 | DATA_POS <= (others => '0');
320 | DATA_OUT <= '1';
321 | SP <= SP_FREE;
322 | else
323 | REQ_Nr <= '0';
324 | SP <= SP_DATAOUT_START;
325 | end if;
326 | end if;
327 |
328 | when others => null;
329 | end case;
330 | end if;
331 | end if;
332 | end process;
333 |
334 | BSY_N <= BSY_Nr;
335 | MSG_N <= MSG_Nr;
336 | CD_N <= CD_Nr;
337 | IO_N <= IO_Nr;
338 | REQ_N <= REQ_Nr;
339 |
340 | COMMAND <= COMM(11) & COMM(10) & COMM(9) & COMM(8) & COMM(7) & COMM(6) & COMM(5) & COMM(4) & COMM(3) & COMM(2) & COMM(1) & COMM(0);
341 | COMM_SEND <= COMM_OUT;
342 |
343 | DOUT <= DATA_BUF(9) & DATA_BUF(8) & DATA_BUF(7) & DATA_BUF(6) & DATA_BUF(5) & DATA_BUF(4) & DATA_BUF(3) & DATA_BUF(2) & DATA_BUF(1) & DATA_BUF(0);
344 | DOUT_SEND <= DATA_OUT;
345 |
346 | DBG_DATAIN_CNT <= DATAIN_CNT;
347 |
348 | end rtl;
349 |
--------------------------------------------------------------------------------
/rtl/pce/cd/SCSI_FIFO.vhd:
--------------------------------------------------------------------------------
1 | -- megafunction wizard: %FIFO%
2 | -- GENERATION: STANDARD
3 | -- VERSION: WM1.0
4 | -- MODULE: dcfifo_mixed_widths
5 |
6 | -- ============================================================
7 | -- File Name: SCSI_FIFO.vhd
8 | -- Megafunction Name(s):
9 | -- dcfifo_mixed_widths
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 | -- 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 altera_mf;
40 | USE altera_mf.all;
41 |
42 | ENTITY SCSI_FIFO IS
43 | PORT
44 | (
45 | aclr : IN STD_LOGIC := '0';
46 | data : IN STD_LOGIC_VECTOR (7 DOWNTO 0);
47 | rdclk : IN STD_LOGIC ;
48 | rdreq : IN STD_LOGIC ;
49 | wrclk : IN STD_LOGIC ;
50 | wrreq : IN STD_LOGIC ;
51 | q : OUT STD_LOGIC_VECTOR (7 DOWNTO 0);
52 | rdempty : OUT STD_LOGIC ;
53 | wrfull : OUT STD_LOGIC
54 | );
55 | END SCSI_FIFO;
56 |
57 |
58 | ARCHITECTURE SYN OF scsi_fifo IS
59 |
60 | SIGNAL sub_wire0 : STD_LOGIC ;
61 | SIGNAL sub_wire1 : STD_LOGIC_VECTOR (7 DOWNTO 0);
62 | SIGNAL sub_wire2 : STD_LOGIC ;
63 |
64 |
65 |
66 | COMPONENT dcfifo_mixed_widths
67 | GENERIC (
68 | intended_device_family : STRING;
69 | lpm_numwords : NATURAL;
70 | lpm_showahead : STRING;
71 | lpm_type : STRING;
72 | lpm_width : NATURAL;
73 | lpm_widthu : NATURAL;
74 | lpm_widthu_r : NATURAL;
75 | lpm_width_r : NATURAL;
76 | overflow_checking : STRING;
77 | rdsync_delaypipe : NATURAL;
78 | read_aclr_synch : STRING;
79 | underflow_checking : STRING;
80 | use_eab : STRING;
81 | write_aclr_synch : STRING;
82 | wrsync_delaypipe : NATURAL
83 | );
84 | PORT (
85 | aclr : IN STD_LOGIC ;
86 | data : IN STD_LOGIC_VECTOR (7 DOWNTO 0);
87 | rdclk : IN STD_LOGIC ;
88 | rdreq : IN STD_LOGIC ;
89 | wrfull : OUT STD_LOGIC ;
90 | q : OUT STD_LOGIC_VECTOR (7 DOWNTO 0);
91 | rdempty : OUT STD_LOGIC ;
92 | wrclk : IN STD_LOGIC ;
93 | wrreq : IN STD_LOGIC
94 | );
95 | END COMPONENT;
96 |
97 | BEGIN
98 | wrfull <= sub_wire0;
99 | q <= sub_wire1(7 DOWNTO 0);
100 | rdempty <= sub_wire2;
101 |
102 | dcfifo_mixed_widths_component : dcfifo_mixed_widths
103 | GENERIC MAP (
104 | intended_device_family => "Cyclone V",
105 | lpm_numwords => 4096,
106 | lpm_showahead => "ON",
107 | lpm_type => "dcfifo_mixed_widths",
108 | lpm_width => 8,
109 | lpm_widthu => 12,
110 | lpm_widthu_r => 12,
111 | lpm_width_r => 8,
112 | overflow_checking => "ON",
113 | rdsync_delaypipe => 4,
114 | read_aclr_synch => "OFF",
115 | underflow_checking => "ON",
116 | use_eab => "ON",
117 | write_aclr_synch => "OFF",
118 | wrsync_delaypipe => 4
119 | )
120 | PORT MAP (
121 | aclr => aclr,
122 | data => data,
123 | rdclk => rdclk,
124 | rdreq => rdreq,
125 | wrclk => wrclk,
126 | wrreq => wrreq,
127 | wrfull => sub_wire0,
128 | q => sub_wire1,
129 | rdempty => sub_wire2
130 | );
131 |
132 |
133 |
134 | END SYN;
135 |
136 | -- ============================================================
137 | -- CNX file retrieval info
138 | -- ============================================================
139 | -- Retrieval info: PRIVATE: AlmostEmpty NUMERIC "0"
140 | -- Retrieval info: PRIVATE: AlmostEmptyThr NUMERIC "-1"
141 | -- Retrieval info: PRIVATE: AlmostFull NUMERIC "0"
142 | -- Retrieval info: PRIVATE: AlmostFullThr NUMERIC "-1"
143 | -- Retrieval info: PRIVATE: CLOCKS_ARE_SYNCHRONIZED NUMERIC "0"
144 | -- Retrieval info: PRIVATE: Clock NUMERIC "4"
145 | -- Retrieval info: PRIVATE: Depth NUMERIC "4096"
146 | -- Retrieval info: PRIVATE: Empty NUMERIC "1"
147 | -- Retrieval info: PRIVATE: Full NUMERIC "1"
148 | -- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone V"
149 | -- Retrieval info: PRIVATE: LE_BasedFIFO NUMERIC "0"
150 | -- Retrieval info: PRIVATE: LegacyRREQ NUMERIC "0"
151 | -- Retrieval info: PRIVATE: MAX_DEPTH_BY_9 NUMERIC "0"
152 | -- Retrieval info: PRIVATE: OVERFLOW_CHECKING NUMERIC "0"
153 | -- Retrieval info: PRIVATE: Optimize NUMERIC "0"
154 | -- Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0"
155 | -- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0"
156 | -- Retrieval info: PRIVATE: UNDERFLOW_CHECKING NUMERIC "0"
157 | -- Retrieval info: PRIVATE: UsedW NUMERIC "0"
158 | -- Retrieval info: PRIVATE: Width NUMERIC "8"
159 | -- Retrieval info: PRIVATE: dc_aclr NUMERIC "1"
160 | -- Retrieval info: PRIVATE: diff_widths NUMERIC "1"
161 | -- Retrieval info: PRIVATE: msb_usedw NUMERIC "0"
162 | -- Retrieval info: PRIVATE: output_width NUMERIC "8"
163 | -- Retrieval info: PRIVATE: rsEmpty NUMERIC "1"
164 | -- Retrieval info: PRIVATE: rsFull NUMERIC "0"
165 | -- Retrieval info: PRIVATE: rsUsedW NUMERIC "0"
166 | -- Retrieval info: PRIVATE: sc_aclr NUMERIC "0"
167 | -- Retrieval info: PRIVATE: sc_sclr NUMERIC "0"
168 | -- Retrieval info: PRIVATE: wsEmpty NUMERIC "0"
169 | -- Retrieval info: PRIVATE: wsFull NUMERIC "1"
170 | -- Retrieval info: PRIVATE: wsUsedW NUMERIC "0"
171 | -- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
172 | -- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone V"
173 | -- Retrieval info: CONSTANT: LPM_NUMWORDS NUMERIC "4096"
174 | -- Retrieval info: CONSTANT: LPM_SHOWAHEAD STRING "ON"
175 | -- Retrieval info: CONSTANT: LPM_TYPE STRING "dcfifo_mixed_widths"
176 | -- Retrieval info: CONSTANT: LPM_WIDTH NUMERIC "8"
177 | -- Retrieval info: CONSTANT: LPM_WIDTHU NUMERIC "12"
178 | -- Retrieval info: CONSTANT: LPM_WIDTHU_R NUMERIC "12"
179 | -- Retrieval info: CONSTANT: LPM_WIDTH_R NUMERIC "8"
180 | -- Retrieval info: CONSTANT: OVERFLOW_CHECKING STRING "ON"
181 | -- Retrieval info: CONSTANT: RDSYNC_DELAYPIPE NUMERIC "4"
182 | -- Retrieval info: CONSTANT: READ_ACLR_SYNCH STRING "OFF"
183 | -- Retrieval info: CONSTANT: UNDERFLOW_CHECKING STRING "ON"
184 | -- Retrieval info: CONSTANT: USE_EAB STRING "ON"
185 | -- Retrieval info: CONSTANT: WRITE_ACLR_SYNCH STRING "OFF"
186 | -- Retrieval info: CONSTANT: WRSYNC_DELAYPIPE NUMERIC "4"
187 | -- Retrieval info: USED_PORT: aclr 0 0 0 0 INPUT GND "aclr"
188 | -- Retrieval info: USED_PORT: data 0 0 8 0 INPUT NODEFVAL "data[7..0]"
189 | -- Retrieval info: USED_PORT: q 0 0 8 0 OUTPUT NODEFVAL "q[7..0]"
190 | -- Retrieval info: USED_PORT: rdclk 0 0 0 0 INPUT NODEFVAL "rdclk"
191 | -- Retrieval info: USED_PORT: rdempty 0 0 0 0 OUTPUT NODEFVAL "rdempty"
192 | -- Retrieval info: USED_PORT: rdreq 0 0 0 0 INPUT NODEFVAL "rdreq"
193 | -- Retrieval info: USED_PORT: wrclk 0 0 0 0 INPUT NODEFVAL "wrclk"
194 | -- Retrieval info: USED_PORT: wrfull 0 0 0 0 OUTPUT NODEFVAL "wrfull"
195 | -- Retrieval info: USED_PORT: wrreq 0 0 0 0 INPUT NODEFVAL "wrreq"
196 | -- Retrieval info: CONNECT: @aclr 0 0 0 0 aclr 0 0 0 0
197 | -- Retrieval info: CONNECT: @data 0 0 8 0 data 0 0 8 0
198 | -- Retrieval info: CONNECT: @rdclk 0 0 0 0 rdclk 0 0 0 0
199 | -- Retrieval info: CONNECT: @rdreq 0 0 0 0 rdreq 0 0 0 0
200 | -- Retrieval info: CONNECT: @wrclk 0 0 0 0 wrclk 0 0 0 0
201 | -- Retrieval info: CONNECT: @wrreq 0 0 0 0 wrreq 0 0 0 0
202 | -- Retrieval info: CONNECT: q 0 0 8 0 @q 0 0 8 0
203 | -- Retrieval info: CONNECT: rdempty 0 0 0 0 @rdempty 0 0 0 0
204 | -- Retrieval info: CONNECT: wrfull 0 0 0 0 @wrfull 0 0 0 0
205 | -- Retrieval info: GEN_FILE: TYPE_NORMAL SCSI_FIFO.vhd TRUE
206 | -- Retrieval info: GEN_FILE: TYPE_NORMAL SCSI_FIFO.inc FALSE
207 | -- Retrieval info: GEN_FILE: TYPE_NORMAL SCSI_FIFO.cmp FALSE
208 | -- Retrieval info: GEN_FILE: TYPE_NORMAL SCSI_FIFO.bsf FALSE
209 | -- Retrieval info: GEN_FILE: TYPE_NORMAL SCSI_FIFO_inst.vhd FALSE
210 | -- Retrieval info: LIB_FILE: altera_mf
211 |
--------------------------------------------------------------------------------
/rtl/pce/cd/cd.qip:
--------------------------------------------------------------------------------
1 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) cd.vhd ]
2 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) CDDA_FIFO.vhd ]
3 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) SCSI.vhd ]
4 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) SCSI_FIFO.vhd ]
5 | set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) MSM5205.vhd ]
6 |
--------------------------------------------------------------------------------
/rtl/pce/cheatcodes.sv:
--------------------------------------------------------------------------------
1 | // Cheat Code handling by Kitrinx
2 | // Apr 21, 2019
3 |
4 | // Code layout:
5 | // {clock bit, 32'bcode 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 |
34 | reg [ENA_F_S:0] codes[MAX_CODES];
35 |
36 | wire [ADDR_WIDTH-1: 0] code_addr = code[64+:ADDR_WIDTH];
37 | wire [DATA_WIDTH-1: 0] code_compare = code[32+:DATA_WIDTH];
38 | wire [DATA_WIDTH-1: 0] code_data = code[0+:DATA_WIDTH];
39 | wire code_comp_f = code[96];
40 |
41 | wire [COMP_F_S:0] code_trimmed = {code_comp_f, code_addr, code_compare, code_data};
42 |
43 | reg [INDEX_SIZE:0] index = '0;
44 |
45 | assign available = |index;
46 |
47 | reg code_change;
48 | always_ff @(posedge clk) begin
49 | int x;
50 | if (reset) begin
51 | index <= 0;
52 | code_change <= 0;
53 | for (x = 0; x < MAX_CODES; x = x + 1) codes[x] <= '0;
54 | end else begin
55 | code_change <= code[128];
56 | if (code[128] && ~code_change && (index < MAX_CODES)) begin // detect posedge
57 | codes[index] <= {1'b1, code_trimmed};
58 | index <= index + 1'b1;
59 | end
60 | end
61 | end
62 |
63 | always_comb begin
64 | int x;
65 | genie_ovr = 0;
66 | genie_data = '0;
67 |
68 | if (enable) begin
69 | for (x = 0; x < MAX_CODES; x = x + 1) begin
70 | if (codes[x][ENA_F_S] && codes[x][ADDR_S-:ADDR_WIDTH] == addr_in) begin
71 | if (!codes[x][COMP_F_S] || (codes[x][COMP_S-:DATA_WIDTH] == data_in)) begin
72 | genie_ovr = 1;
73 | genie_data = codes[x][DATA_S-:DATA_WIDTH];
74 | end
75 | end
76 | end
77 | end
78 | end
79 |
80 | endmodule
81 |
--------------------------------------------------------------------------------
/rtl/pce/color_mix.sv:
--------------------------------------------------------------------------------
1 | //
2 | //
3 | // Copyright (c) 2018 Sorgelig
4 | //
5 | // This program is GPL v2+ Licensed.
6 | //
7 | //
8 | ////////////////////////////////////////////////////////////////////////////////////////////////////////
9 |
10 | module color_mix
11 | (
12 | input clk_vid,
13 | input ce_pix,
14 | input [2:0] mix,
15 |
16 | input [7:0] R_in,
17 | input [7:0] G_in,
18 | input [7:0] B_in,
19 | input HSync_in,
20 | input VSync_in,
21 | input HBlank_in,
22 | input VBlank_in,
23 |
24 | output reg [7:0] R_out,
25 | output reg [7:0] G_out,
26 | output reg [7:0] B_out,
27 | output reg HSync_out,
28 | output reg VSync_out,
29 | output reg HBlank_out,
30 | output reg VBlank_out
31 | );
32 |
33 |
34 | reg [7:0] R,G,B;
35 | reg HBl, VBl, HS, VS;
36 | always @(posedge clk_vid) if(ce_pix) begin
37 | R <= R_in;
38 | G <= G_in;
39 | B <= B_in;
40 | HS <= HSync_in;
41 | VS <= VSync_in;
42 | HBl <= HBlank_in;
43 | VBl <= VBlank_in;
44 | end
45 |
46 | wire [15:0] px = R * 16'd054 + G * 16'd183 + B * 16'd018;
47 |
48 | always @(posedge clk_vid) if(ce_pix) begin
49 | {R_out, G_out, B_out} <= 0;
50 |
51 | case(mix)
52 | 0,
53 | 1: {R_out, G_out, B_out} <= {R, G, B }; // color
54 | 2: { G_out } <= { px[15:8] }; // green
55 | 3: {R_out, G_out } <= {px[15:8], px[15:8] - px[15:10]}; // amber
56 | 4: { G_out, B_out} <= { px[15:8], px[15:8] }; // cyan
57 | 5: {R_out, G_out, B_out} <= {px[15:8], px[15:8], px[15:8] }; // gray
58 | endcase
59 |
60 | HSync_out <= HS;
61 | VSync_out <= VS;
62 | HBlank_out <= HBl;
63 | VBlank_out <= VBl;
64 | end
65 |
66 | endmodule
67 |
--------------------------------------------------------------------------------
/rtl/pce/ddram.sv:
--------------------------------------------------------------------------------
1 | //
2 | // ddram.v
3 | // Copyright (c) 2020 Sorgelig
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 |
22 |
23 | module ddram
24 | (
25 | input DDRAM_CLK,
26 |
27 | input DDRAM_BUSY,
28 | output [7:0] DDRAM_BURSTCNT,
29 | output [28:0] DDRAM_ADDR,
30 | input [63:0] DDRAM_DOUT,
31 | input DDRAM_DOUT_READY,
32 | output DDRAM_RD,
33 | output [63:0] DDRAM_DIN,
34 | output [7:0] DDRAM_BE,
35 | output DDRAM_WE,
36 |
37 | input clkref,
38 |
39 | input [27:0] wraddr,
40 | input [15:0] din,
41 | input we,
42 | output reg we_rdy,
43 | input we_req,
44 | output reg we_ack,
45 |
46 | input [27:0] rdaddr,
47 | output [7:0] dout,
48 | input rd,
49 | output reg rd_rdy
50 | );
51 |
52 | assign DDRAM_BURSTCNT = ram_burst;
53 | assign DDRAM_BE = DDRAM_RD ? 8'hFF : ({6'd0,~b,1'b1} << {ram_addr[2:1],ram_addr[0] & b});
54 | assign DDRAM_ADDR = {4'b0011, ram_addr[27:3]}; // RAM at 0x30000000
55 | assign DDRAM_DIN = ram_data;
56 | assign DDRAM_WE = ram_write;
57 |
58 | assign dout = data;
59 |
60 | reg [7:0] ram_burst;
61 | reg [63:0] ram_data;
62 | reg [27:0] ram_addr;
63 | reg [7:0] data;
64 | reg ram_write = 0;
65 | reg b;
66 | reg start;
67 | reg [1:0] state = 0;
68 |
69 | reg [27:0] addr;
70 |
71 | always @(posedge DDRAM_CLK) begin
72 | reg old_ref;
73 | reg[127:0] ram_q;
74 |
75 | old_ref <= clkref;
76 | start <= ~old_ref & clkref;
77 |
78 | if(start) begin
79 | if(we) we_rdy <= 0;
80 | else if(rd) rd_rdy <= 0;
81 | end
82 |
83 | ram_burst <= 1;
84 | addr <= rdaddr;
85 |
86 | if(!DDRAM_BUSY) begin
87 | ram_write <= 0;
88 | case(state)
89 | 0: begin
90 | we_rdy <= 1;
91 | rd_rdy <= 1;
92 | cache_cs <= 0;
93 | if(we_ack != we_req) begin
94 | we_ack <= we_req;
95 | ram_data <= {4{din}};
96 | ram_addr <= wraddr;
97 | ram_write <= 1;
98 | b <= 0;
99 | end
100 | else if(start) begin
101 | if(we) begin
102 | we_rdy <= 0;
103 | ram_data <= {8{din[7:0]}};
104 | ram_addr <= addr;
105 | ram_write <= 1;
106 | b <= 1;
107 | cache_cs <= 1;
108 | cache_we <= 1;
109 | state <= 1;
110 | end
111 | else if(rd) begin
112 | ram_addr <= addr;
113 | rd_rdy <= 0;
114 | cache_cs <= 1;
115 | cache_we <= 0;
116 | state <= 2;
117 | end
118 | end
119 | end
120 |
121 | 1: if(cache_wrack) begin
122 | cache_cs <= 0;
123 | we_rdy <= 1;
124 | state <= 0;
125 | end
126 |
127 | 2: if(cache_rdack) begin
128 | cache_cs <= 0;
129 | data <= ram_addr[0] ? cache_do[15:8] : cache_do[7:0];
130 | rd_rdy <= 1;
131 | state <= 0;
132 | end
133 | endcase
134 | end
135 | end
136 |
137 | wire [15:0] cache_do;
138 | wire cache_rdack;
139 | wire cache_wrack;
140 | reg cache_cs;
141 | reg cache_we;
142 |
143 | cache_2way cache
144 | (
145 | .clk(DDRAM_CLK),
146 | .rst(we_ack != we_req),
147 |
148 | .cache_enable(1),
149 |
150 | .cpu_cs(cache_cs),
151 | .cpu_adr(addr[27:1]),
152 | .cpu_bs({addr[0],~addr[0]}),
153 | .cpu_we(cache_we),
154 | .cpu_rd(~cache_we),
155 | .cpu_dat_w(ram_data[15:0]),
156 | .cpu_dat_r(cache_do),
157 | .cpu_ack(cache_rdack),
158 | .wb_en(cache_wrack),
159 |
160 | .mem_dat_r(DDRAM_DOUT),
161 | .mem_read_req(DDRAM_RD),
162 | .mem_read_ack(DDRAM_DOUT_READY)
163 | );
164 |
165 | endmodule
166 |
--------------------------------------------------------------------------------
/rtl/pce/dpram.vhd:
--------------------------------------------------------------------------------
1 | LIBRARY ieee;
2 | USE ieee.std_logic_1164.all;
3 |
4 | LIBRARY altera_mf;
5 | USE altera_mf.altera_mf_components.all;
6 |
7 | entity dpram is
8 | generic (
9 | addr_width : integer := 8;
10 | data_width : integer := 8;
11 | mem_init_file : string := " ";
12 | disable_value : std_logic := '1'
13 | );
14 | PORT
15 | (
16 | clock : in STD_LOGIC ;
17 | address_a : in STD_LOGIC_VECTOR (addr_width-1 DOWNTO 0);
18 | data_a : in STD_LOGIC_VECTOR (data_width-1 DOWNTO 0) := (others => '0');
19 | enable_a : in STD_LOGIC := '1';
20 | wren_a : in STD_LOGIC := '0';
21 | q_a : out STD_LOGIC_VECTOR (data_width-1 DOWNTO 0);
22 | cs_a : in std_logic := '1';
23 |
24 | address_b : in STD_LOGIC_VECTOR (addr_width-1 DOWNTO 0) := (others => '0');
25 | data_b : in STD_LOGIC_VECTOR (data_width-1 DOWNTO 0) := (others => '0');
26 | enable_b : in STD_LOGIC := '1';
27 | wren_b : in STD_LOGIC := '0';
28 | q_b : out STD_LOGIC_VECTOR (data_width-1 DOWNTO 0);
29 | cs_b : in std_logic := '1'
30 | );
31 | end entity;
32 |
33 |
34 | ARCHITECTURE SYN OF dpram IS
35 |
36 | signal q0 : std_logic_vector((data_width - 1) downto 0);
37 | signal q1 : std_logic_vector((data_width - 1) downto 0);
38 |
39 | BEGIN
40 | q_a<= q0 when cs_a = '1' else (others => disable_value);
41 | q_b<= q1 when cs_b = '1' else (others => disable_value);
42 |
43 | altsyncram_component : altsyncram
44 | GENERIC MAP (
45 | address_reg_b => "CLOCK1",
46 | clock_enable_input_a => "NORMAL",
47 | clock_enable_input_b => "NORMAL",
48 | clock_enable_output_a => "BYPASS",
49 | clock_enable_output_b => "BYPASS",
50 | indata_reg_b => "CLOCK1",
51 | intended_device_family => "Cyclone V",
52 | lpm_type => "altsyncram",
53 | numwords_a => 2**addr_width,
54 | numwords_b => 2**addr_width,
55 | operation_mode => "BIDIR_DUAL_PORT",
56 | outdata_aclr_a => "NONE",
57 | outdata_aclr_b => "NONE",
58 | outdata_reg_a => "UNREGISTERED",
59 | outdata_reg_b => "UNREGISTERED",
60 | power_up_uninitialized => "FALSE",
61 | read_during_write_mode_port_a => "NEW_DATA_NO_NBE_READ",
62 | read_during_write_mode_port_b => "NEW_DATA_NO_NBE_READ",
63 | init_file => mem_init_file,
64 | widthad_a => addr_width,
65 | widthad_b => addr_width,
66 | width_a => data_width,
67 | width_b => data_width,
68 | width_byteena_a => 1,
69 | width_byteena_b => 1,
70 | wrcontrol_wraddress_reg_b => "CLOCK1"
71 | )
72 | PORT MAP (
73 | address_a => address_a,
74 | address_b => address_b,
75 | clock0 => clock,
76 | clock1 => clock,
77 | clocken0 => enable_a,
78 | clocken1 => enable_b,
79 | data_a => data_a,
80 | data_b => data_b,
81 | wren_a => wren_a and cs_a,
82 | wren_b => wren_b and cs_b,
83 | q_a => q0,
84 | q_b => q1
85 | );
86 |
87 | END SYN;
88 |
89 | LIBRARY ieee;
90 | USE ieee.std_logic_1164.all;
91 |
92 | LIBRARY altera_mf;
93 | USE altera_mf.altera_mf_components.all;
94 |
95 | entity dpram_difclk is
96 | generic (
97 | addr_width_a : integer := 8;
98 | data_width_a : integer := 8;
99 | addr_width_b : integer := 8;
100 | data_width_b : integer := 8;
101 | mem_init_file : string := " "
102 | );
103 | PORT
104 | (
105 | clock0 : in STD_LOGIC;
106 | clock1 : in STD_LOGIC;
107 |
108 | address_a : in STD_LOGIC_VECTOR (addr_width_a-1 DOWNTO 0);
109 | data_a : in STD_LOGIC_VECTOR (data_width_a-1 DOWNTO 0) := (others => '0');
110 | enable_a : in STD_LOGIC := '1';
111 | wren_a : in STD_LOGIC := '0';
112 | q_a : out STD_LOGIC_VECTOR (data_width_a-1 DOWNTO 0);
113 | cs_a : in std_logic := '1';
114 |
115 | address_b : in STD_LOGIC_VECTOR (addr_width_b-1 DOWNTO 0) := (others => '0');
116 | data_b : in STD_LOGIC_VECTOR (data_width_b-1 DOWNTO 0) := (others => '0');
117 | enable_b : in STD_LOGIC := '1';
118 | wren_b : in STD_LOGIC := '0';
119 | q_b : out STD_LOGIC_VECTOR (data_width_b-1 DOWNTO 0);
120 | cs_b : in std_logic := '1'
121 | );
122 | end entity;
123 |
124 |
125 | ARCHITECTURE SYN OF dpram_difclk IS
126 |
127 | signal q0 : std_logic_vector((data_width_a - 1) downto 0);
128 | signal q1 : std_logic_vector((data_width_b - 1) downto 0);
129 |
130 | BEGIN
131 | q_a<= q0 when cs_a = '1' else (others => '1');
132 | q_b<= q1 when cs_b = '1' else (others => '1');
133 |
134 | altsyncram_component : altsyncram
135 | GENERIC MAP (
136 | address_reg_b => "CLOCK1",
137 | clock_enable_input_a => "NORMAL",
138 | clock_enable_input_b => "NORMAL",
139 | clock_enable_output_a => "BYPASS",
140 | clock_enable_output_b => "BYPASS",
141 | indata_reg_b => "CLOCK1",
142 | intended_device_family => "Cyclone V",
143 | lpm_type => "altsyncram",
144 | numwords_a => 2**addr_width_a,
145 | numwords_b => 2**addr_width_b,
146 | operation_mode => "BIDIR_DUAL_PORT",
147 | outdata_aclr_a => "NONE",
148 | outdata_aclr_b => "NONE",
149 | outdata_reg_a => "UNREGISTERED",
150 | outdata_reg_b => "UNREGISTERED",
151 | power_up_uninitialized => "FALSE",
152 | read_during_write_mode_port_a => "NEW_DATA_NO_NBE_READ",
153 | read_during_write_mode_port_b => "NEW_DATA_NO_NBE_READ",
154 | init_file => mem_init_file,
155 | widthad_a => addr_width_a,
156 | widthad_b => addr_width_b,
157 | width_a => data_width_a,
158 | width_b => data_width_b,
159 | width_byteena_a => 1,
160 | width_byteena_b => 1,
161 | wrcontrol_wraddress_reg_b => "CLOCK1"
162 | )
163 | PORT MAP (
164 | address_a => address_a,
165 | address_b => address_b,
166 | clock0 => clock0,
167 | clock1 => clock1,
168 | clocken0 => enable_a,
169 | clocken1 => enable_b,
170 | data_a => data_a,
171 | data_b => data_b,
172 | wren_a => wren_a and cs_a,
173 | wren_b => wren_b and cs_b,
174 | q_a => q0,
175 | q_b => q1
176 | );
177 |
178 | END SYN;
179 |
180 | --------------------------------------------------------------
181 | -- Single port Block RAM
182 | --------------------------------------------------------------
183 |
184 | LIBRARY ieee;
185 | USE ieee.std_logic_1164.all;
186 |
187 | LIBRARY altera_mf;
188 | USE altera_mf.altera_mf_components.all;
189 |
190 | ENTITY spram IS
191 | generic (
192 | addr_width : integer := 8;
193 | data_width : integer := 8;
194 | mem_init_file : string := " ";
195 | mem_name : string := "MEM" -- for InSystem Memory content editor.
196 | );
197 | PORT
198 | (
199 | clock : in STD_LOGIC;
200 | address : in STD_LOGIC_VECTOR (addr_width-1 DOWNTO 0);
201 | data : in STD_LOGIC_VECTOR (data_width-1 DOWNTO 0) := (others => '0');
202 | enable : in STD_LOGIC := '1';
203 | wren : in STD_LOGIC := '0';
204 | q : out STD_LOGIC_VECTOR (data_width-1 DOWNTO 0);
205 | cs : in std_logic := '1'
206 | );
207 | END ENTITY;
208 |
209 | ARCHITECTURE SYN OF spram IS
210 | signal q0 : std_logic_vector((data_width - 1) downto 0);
211 | BEGIN
212 | q<= q0 when cs = '1' else (others => '1');
213 |
214 | altsyncram_component : altsyncram
215 | GENERIC MAP (
216 | clock_enable_input_a => "BYPASS",
217 | clock_enable_output_a => "BYPASS",
218 | intended_device_family => "Cyclone V",
219 | lpm_hint => "ENABLE_RUNTIME_MOD=YES,INSTANCE_NAME="&mem_name,
220 | lpm_type => "altsyncram",
221 | numwords_a => 2**addr_width,
222 | operation_mode => "SINGLE_PORT",
223 | outdata_aclr_a => "NONE",
224 | outdata_reg_a => "UNREGISTERED",
225 | power_up_uninitialized => "FALSE",
226 | read_during_write_mode_port_a => "NEW_DATA_NO_NBE_READ",
227 | init_file => mem_init_file,
228 | widthad_a => addr_width,
229 | width_a => data_width,
230 | width_byteena_a => 1
231 | )
232 | PORT MAP (
233 | address_a => address,
234 | clock0 => clock,
235 | data_a => data,
236 | wren_a => wren and cs,
237 | q_a => q0
238 | );
239 |
240 | END SYN;
241 |
--------------------------------------------------------------------------------
/rtl/pce/hps_ext.v:
--------------------------------------------------------------------------------
1 | //
2 | // hps_ext for TurboGrafx-16 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 clk_sys,
24 | inout [35:0] EXT_BUS,
25 |
26 | // CD interface
27 | input [112:0] cd_in,
28 | output reg [112:0] cd_out
29 | );
30 |
31 | assign EXT_BUS[15:0] = io_dout;
32 | wire [15:0] io_din = EXT_BUS[31:16];
33 | assign EXT_BUS[32] = dout_en;
34 | wire io_strobe = EXT_BUS[33];
35 | wire io_enable = EXT_BUS[34];
36 |
37 | localparam EXT_CMD_MIN = CD_GET;
38 | localparam EXT_CMD_MAX = CD_SET;
39 |
40 | localparam CD_GET = 'h34;
41 | localparam CD_SET = 'h35;
42 |
43 | reg [15:0] io_dout;
44 | reg dout_en = 0;
45 | reg [4:0] byte_cnt;
46 |
47 | always@(posedge clk_sys) begin
48 | reg [15:0] cmd;
49 | reg [7:0] cd_req = 0;
50 | reg old_cd = 0;
51 |
52 | old_cd <= cd_in[112];
53 | if(old_cd ^ cd_in[112]) cd_req <= cd_req + 1'd1;
54 |
55 | if(~io_enable) begin
56 | dout_en <= 0;
57 | io_dout <= 0;
58 | byte_cnt <= 0;
59 | cmd <= 0;
60 | if(cmd == CD_SET) cd_out[112] <= ~cd_out[112];
61 | end
62 | else if(io_strobe) begin
63 |
64 | io_dout <= 0;
65 | if(~&byte_cnt) byte_cnt <= byte_cnt + 1'd1;
66 |
67 | if(byte_cnt == 0) begin
68 | cmd <= io_din;
69 | dout_en <= (io_din >= EXT_CMD_MIN && io_din <= EXT_CMD_MAX);
70 | if(io_din == CD_GET) io_dout <= cd_req;
71 | end else begin
72 |
73 | case(cmd)
74 |
75 | CD_GET: case(byte_cnt)
76 | 1: io_dout <= cd_in[15:0];
77 | 2: io_dout <= cd_in[31:16];
78 | 3: io_dout <= cd_in[47:32];
79 | 4: io_dout <= cd_in[63:48];
80 | 5: io_dout <= cd_in[79:64];
81 | 6: io_dout <= cd_in[95:80];
82 | 7: io_dout <= cd_in[111:96];
83 | endcase
84 |
85 | CD_SET: case(byte_cnt)
86 | 1: cd_out[15:0] <= io_din;
87 | 2: cd_out[31:16] <= io_din;
88 | 3: cd_out[47:32] <= io_din;
89 | 4: cd_out[63:48] <= io_din;
90 | 5: cd_out[79:64] <= io_din;
91 | 6: cd_out[95:80] <= io_din;
92 | 7: cd_out[111:96] <= io_din;
93 | endcase
94 | endcase
95 | end
96 | end
97 | end
98 |
99 | endmodule
100 |
--------------------------------------------------------------------------------
/rtl/pce/huc6202.vhd:
--------------------------------------------------------------------------------
1 | --============================================================================
2 | -- HUC6202
3 | -- Copyright (C) 2018 Sorgelig
4 | --
5 | -- This program is free software; you can redistribute it and/or modify it
6 | -- under the terms of the GNU General Public License as published by the Free
7 | -- Software Foundation; either version 2 of the License, or (at your option)
8 | -- any later version.
9 | --
10 | -- This program is distributed in the hope that it will be useful, but WITHOUT
11 | -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 | -- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 | -- more details.
14 | --
15 | -- You should have received a copy of the GNU General Public License along
16 | -- with this program; if not, write to the Free Software Foundation, Inc.,
17 | -- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 | --============================================================================
19 |
20 | library IEEE;
21 | use IEEE.STD_LOGIC_1164.ALL;
22 | use IEEE.STD_LOGIC_UNSIGNED.ALL;
23 | use IEEE.NUMERIC_STD.ALL;
24 |
25 | entity huc6202 is
26 | port (
27 | CLK : in std_logic;
28 | CLKEN : in std_logic;
29 | RESET_N : in std_logic;
30 |
31 | A : in std_logic_vector(2 downto 0);
32 | WR_N : in std_logic;
33 | DI : in std_logic_vector(7 downto 0);
34 | DO : out std_logic_vector(7 downto 0);
35 |
36 | HS_F : in std_logic;
37 | VDC0_IN : in std_logic_vector(8 downto 0);
38 | VDC1_IN : in std_logic_vector(8 downto 0);
39 | VDC_OUT : out std_logic_vector(8 downto 0);
40 |
41 | SGX : in std_logic;
42 |
43 | VDCNUM : out std_logic
44 | );
45 | end huc6202;
46 |
47 | architecture rtl of huc6202 is
48 |
49 | signal PRI0 : std_logic_vector(7 downto 0);
50 | signal PRI1 : std_logic_vector(7 downto 0);
51 | signal WIN1 : std_logic_vector(9 downto 0);
52 | signal WIN2 : std_logic_vector(9 downto 0);
53 | signal X : std_logic_vector(9 downto 0);
54 | signal PRIN : std_logic_vector(1 downto 0);
55 | signal PRI : std_logic_vector(3 downto 0);
56 |
57 | signal VDC_PRI : std_logic_vector(8 downto 0);
58 |
59 | begin
60 |
61 | PRIN(0) <= '1' when WIN1 <= x"40" or X >= WIN1 else '0';
62 | PRIN(1) <= '1' when WIN2 <= x"40" or X >= WIN2 else '0';
63 | PRI <= PRI0(3 downto 0) when PRIN = "00" else
64 | PRI0(7 downto 4) when PRIN = "01" else
65 | PRI1(3 downto 0) when PRIN = "10" else
66 | PRI1(7 downto 4);
67 |
68 | VDC_PRI <= VDC0_IN when VDC0_IN(3 downto 0) /= "0000" else VDC1_IN;
69 |
70 | process( CLK )
71 | variable VDCDATA : std_logic_vector(8 downto 0);
72 | begin
73 | if rising_edge(CLK) then
74 | if CLKEN = '1' then
75 | X <= X + 1;
76 | if HS_F = '1' then
77 | X <= (others => '0');
78 | end if;
79 |
80 | case PRI(1 downto 0) is
81 | when "00" =>
82 | VDCDATA := (others => '0');
83 | when "01" =>
84 | VDCDATA := VDC0_IN;
85 | when "10" =>
86 | VDCDATA := VDC1_IN;
87 | when others =>
88 | VDCDATA := VDC_PRI;
89 | case PRI(3 downto 2) is
90 | when "01" =>
91 | if VDC1_IN(8) = '1' and VDC0_IN(8) = '0' and VDC1_IN(3 downto 0) /= "0000" then
92 | VDCDATA := VDC1_IN;
93 | end if;
94 | when "10" =>
95 | if VDC1_IN(8) = '0' and VDC0_IN(8) = '1' and VDC1_IN(3 downto 0) /= "0000" then
96 | VDCDATA := VDC1_IN;
97 | end if;
98 | when others => null;
99 | end case;
100 | end case;
101 |
102 | VDC_OUT <= VDCDATA;
103 | end if;
104 | end if;
105 | end process;
106 |
107 | process( CLK ) begin
108 | if rising_edge(CLK) then
109 | if RESET_N = '0' then
110 | PRI0 <= "00010001";
111 | PRI1 <= "00010001";
112 | WIN1 <= (others => '0');
113 | WIN2 <= (others => '0');
114 | VDCNUM <= '0';
115 | DO <= X"FF";
116 | else
117 | if WR_N = '0' then
118 | case A is
119 | when "000" => PRI0 <= DI;
120 | when "001" => PRI1 <= DI;
121 | when "010" => WIN1(7 downto 0) <= DI;
122 | when "011" => WIN1(9 downto 8) <= DI(1 downto 0);
123 | when "100" => WIN2(7 downto 0) <= DI;
124 | when "101" => WIN2(9 downto 8) <= DI(1 downto 0);
125 | when "110" => VDCNUM <= DI(0);
126 | when others => null;
127 | end case;
128 | end if;
129 | case A is
130 | when "000" => DO <= PRI0;
131 | when "001" => DO <= PRI1;
132 | when "010" => DO <= WIN1(7 downto 0);
133 | when "011" => DO <= "000000" & WIN1(9 downto 8);
134 | when "100" => DO <= WIN2(7 downto 0);
135 | when "101" => DO <= "000000" & WIN2(9 downto 8);
136 | when others => DO <= X"00";
137 | end case;
138 | end if;
139 | end if;
140 | end process;
141 |
142 | end rtl;
143 |
--------------------------------------------------------------------------------
/rtl/pce/mb128.sv:
--------------------------------------------------------------------------------
1 | // MB128.v
2 | //
3 | // This executes a compatible protocol to the Memory Base 128
4 | // or Save-kun peripheral as used by the PC Engine
5 | //
6 | // (c) 2020 by David Shadoff
7 | //
8 | //
9 |
10 | module MB128
11 | (
12 | input clk_sys, // system clock
13 | input reset,
14 |
15 | input i_Clk, // Joypad Clr/Reset line, clocks the SPI-like MB128 protocol
16 | input i_Data, // Joypad Sel line, provides data to the SPI-like MB128 protocol
17 |
18 | output o_Active,
19 | output [3:0] o_Data,
20 |
21 | input bk_clk,
22 | input [15:0] bk_address,
23 | input [15:0] bk_din,
24 | output [15:0] bk_dout,
25 | input bk_we,
26 | output bk_written
27 | );
28 |
29 | // constants - STATEs
30 | // STATE GROUP 1 - Request identification
31 | localparam STATE_IDLE = 0;
32 | localparam STATE_A8_A1 = 1;
33 | localparam STATE_A8_A2 = 2;
34 |
35 | // STATE GROUP 2 - Synced; request infromation
36 | localparam STATE_REQ = 3;
37 | localparam STATE_ADDR = 4;
38 | localparam STATE_LEN = 5;
39 |
40 | // STATE GROUP 3 - Synced; in-transfer states
41 | localparam STATE_READ = 6;
42 | localparam STATE_READ_TRAIL = 7;
43 | localparam STATE_WRITE = 8;
44 | localparam STATE_WRITE_TRAIL = 9;
45 |
46 | localparam CMD_WRITE = 0;
47 | localparam CMD_READ = 1;
48 |
49 |
50 | // registers
51 | reg [3:0] r_State = STATE_IDLE;
52 | reg [7:0] r_Register = 0;
53 |
54 | reg r_Req;
55 | reg [19:0] r_Bit_Count;
56 | reg [19:0] r_MB128_Addr;
57 | reg [19:0] r_MB128_Bits;
58 | reg [3:0] r_Data;
59 |
60 | reg clk_prev;
61 |
62 | reg ram_din;
63 | reg ram_we;
64 | wire ram_dout;
65 |
66 | //
67 | // master storage - should be backed by permanent storage like SDCard
68 | //
69 | dpram_difclk #(20,1,16,16) back128_l
70 | (
71 | // Port A for MB128 access
72 | //
73 | .clock0(clk_sys),
74 | .address_a(r_MB128_Addr),
75 | .data_a(ram_din),
76 | .wren_a(ram_we),
77 | .q_a(ram_dout),
78 |
79 | // Port B save/load
80 | //
81 | .clock1(bk_clk),
82 | .address_b(bk_address),
83 | .data_b(bk_din),
84 | .wren_b(bk_we),
85 | .q_b(bk_dout)
86 | );
87 |
88 |
89 | always @(posedge clk_sys) begin
90 |
91 | if(bk_address[15:10] == 2) bk_written <= 0;
92 |
93 | ram_we <= 0;
94 | if (ram_we) r_MB128_Addr <= r_MB128_Addr + 1'b1;
95 |
96 | clk_prev <= i_Clk;
97 |
98 | if (reset) begin
99 | r_State <= STATE_IDLE;
100 | r_Bit_Count <= 0;
101 | end
102 | else if (~clk_prev & i_Clk) begin // drive the SPI-like protocol based on this signal's positive edge
103 |
104 | r_Data <= 0;
105 |
106 | case (r_State)
107 | STATE_IDLE:
108 | begin
109 | if (r_Bit_Count <= 7) r_Bit_Count <= r_Bit_Count + 1'b1;
110 | r_Register <= {i_Data, r_Register[7:1]};
111 | if (({i_Data, r_Register[7:1]} == 8'hA8) && (r_Bit_Count >= 7)) r_State <= STATE_A8_A1;
112 | end
113 |
114 | STATE_A8_A1:
115 | begin
116 | r_State <= STATE_A8_A2;
117 | end
118 |
119 | STATE_A8_A2:
120 | begin
121 | // Note that IDENT actually takes the value sent in data
122 | r_Data[2] <= i_Data;
123 | r_State <= STATE_REQ;
124 | end
125 |
126 | STATE_REQ:
127 | begin
128 | r_Req <= i_Data;
129 |
130 | r_MB128_Addr <= 0;
131 | r_MB128_Bits <= 0;
132 | r_Bit_Count <= 0;
133 |
134 | r_State <= STATE_ADDR;
135 | end
136 |
137 | STATE_ADDR:
138 | begin
139 | // 10 address bits come in LSB signifies 128 bytes of offset
140 | r_MB128_Addr <= {i_Data, r_MB128_Addr[19:1]};
141 |
142 | r_Bit_Count <= r_Bit_Count + 1'b1;
143 | if (r_Bit_Count == 9) begin
144 | r_Bit_Count <= 0;
145 | r_State <= STATE_LEN;
146 | end
147 | end
148 |
149 | STATE_LEN:
150 | begin
151 | // 20 bits come in identifying # of bits
152 | r_MB128_Bits <= {i_Data, r_MB128_Bits[19:1]};
153 |
154 | r_Bit_Count <= r_Bit_Count + 1'b1;
155 | if (r_Bit_Count == 19) begin
156 |
157 | r_Data[0] <= r_Req;
158 | r_State <= (r_Req == CMD_WRITE) ? STATE_WRITE : STATE_READ;
159 | r_Bit_Count <= 1;
160 |
161 | if (!{i_Data, r_MB128_Bits[19:1]}) begin
162 | r_Bit_Count <= 0;
163 | r_State <= (r_Req == CMD_WRITE) ? STATE_WRITE_TRAIL : STATE_READ_TRAIL;
164 | end
165 | end
166 | end
167 |
168 | STATE_READ:
169 | begin
170 | r_Bit_Count <= r_Bit_Count + 1'b1;
171 | r_Data[0] <= ram_dout;
172 | r_MB128_Addr <= r_MB128_Addr + 1'b1;
173 |
174 | if (r_Bit_Count == r_MB128_Bits) begin
175 | r_Bit_Count <= 0;
176 | r_State <= STATE_READ_TRAIL;
177 | end
178 | end
179 |
180 | STATE_READ_TRAIL:
181 | begin
182 | r_Bit_Count <= r_Bit_Count + 1'b1;
183 | if (r_Bit_Count == 2) begin
184 | r_Bit_Count <= 0;
185 | r_State <= STATE_IDLE;
186 | end
187 | end
188 |
189 | STATE_WRITE:
190 | begin
191 | r_Bit_Count <= r_Bit_Count + 1'b1;
192 | ram_din <= i_Data;
193 | ram_we <= 1;
194 | bk_written <= 1;
195 |
196 | if (r_Bit_Count == r_MB128_Bits) begin
197 | r_Bit_Count <= 0;
198 | r_State <= STATE_WRITE_TRAIL;
199 | end
200 | end
201 |
202 | STATE_WRITE_TRAIL:
203 | begin
204 | r_Bit_Count <= r_Bit_Count + 1'b1;
205 |
206 | if (r_Bit_Count == 4) begin
207 | r_Bit_Count <= 0;
208 | r_State <= STATE_IDLE;
209 | end
210 | end
211 | endcase
212 | end
213 | end
214 |
215 | assign o_Active = r_State != STATE_IDLE;
216 | assign o_Data = r_Data;
217 |
218 | endmodule
219 |
--------------------------------------------------------------------------------
/rtl/pce/sdram.sv:
--------------------------------------------------------------------------------
1 | //
2 | // sdram.v
3 | //
4 | // sdram controller implementation
5 | // Copyright (c) 2018 Sorgelig
6 | //
7 | // Based on sdram module by Till Harbaum
8 | //
9 | // This source file is free software: you can redistribute it and/or modify
10 | // it under the terms of the GNU General Public License as published
11 | // by the Free Software Foundation, either version 3 of the License, or
12 | // (at your option) any later version.
13 | //
14 | // This source file is distributed in the hope that it will be useful,
15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | // GNU General Public License for more details.
18 | //
19 | // You should have received a copy of the GNU General Public License
20 | // along with this program. If not, see .
21 | //
22 |
23 | module sdram
24 | (
25 |
26 | // interface to the MT48LC16M16 chip
27 | inout reg [15:0] SDRAM_DQ, // 16 bit bidirectional data bus
28 | output reg [12:0] SDRAM_A, // 13 bit multiplexed address bus
29 | output SDRAM_DQML, // byte mask
30 | output SDRAM_DQMH, // byte mask
31 | output reg [1:0] SDRAM_BA, // two banks
32 | output SDRAM_nCS, // a single chip select
33 | output reg SDRAM_nWE, // write enable
34 | output reg SDRAM_nRAS, // row address select
35 | output reg SDRAM_nCAS, // columns address select
36 | output SDRAM_CLK,
37 | output SDRAM_CKE,
38 |
39 | // cpu/chipset interface
40 | input init, // init signal after FPGA config to initialize RAM
41 | input clk, // sdram is accessed at up to 128MHz
42 | input clkref, // reference clock to sync to
43 |
44 | input [24:0] raddr, // 25 bit byte address
45 | input rd, // cpu/chipset requests read
46 | output reg rd_rdy = 0,
47 | output reg [7:0] dout, // data output to chipset/cpu
48 |
49 | input [24:0] waddr, // 25 bit byte address
50 | input [15:0] din, // data input from chipset/cpu
51 | input we, // cpu/chipset write
52 | input we_req, // cpu/chipset requests write
53 | output reg we_ack = 0
54 | );
55 |
56 | assign SDRAM_nCS = 0;
57 | assign SDRAM_CKE = 1;
58 | assign {SDRAM_DQMH,SDRAM_DQML} = SDRAM_A[12:11];
59 |
60 | // no burst configured
61 | localparam RASCAS_DELAY = 3'd2; // tRCD=20ns -> 3 cycles@128MHz
62 | localparam BURST_LENGTH = 3'b000; // 000=1, 001=2, 010=4, 011=8
63 | localparam ACCESS_TYPE = 1'b0; // 0=sequential, 1=interleaved
64 | localparam CAS_LATENCY = 3'd2; // 2/3 allowed
65 | localparam OP_MODE = 2'b00; // only 00 (standard operation) allowed
66 | localparam NO_WRITE_BURST = 1'b1; // 0= write burst enabled, 1=only single access write
67 |
68 | localparam MODE = { 3'b000, NO_WRITE_BURST, OP_MODE, CAS_LATENCY, ACCESS_TYPE, BURST_LENGTH};
69 |
70 | localparam STATE_IDLE = 4'd0; // first state in cycle
71 | localparam STATE_START = 4'd1; // state in which a new command can be started
72 | localparam STATE_CONT = STATE_START+RASCAS_DELAY; // 4 command can be continued
73 | localparam STATE_LAST = 4'd7; // last state in cycle
74 | localparam STATE_READY = STATE_CONT+CAS_LATENCY+2;
75 |
76 |
77 | reg [3:0] q;
78 | reg [22:0] a;
79 | reg [1:0] bank;
80 | reg [15:0] data;
81 | reg wr;
82 | reg b;
83 | reg ram_req=0;
84 |
85 | // access manager
86 | always @(posedge clk) begin
87 | reg old_ref;
88 |
89 | old_ref<=clkref;
90 |
91 | if(q==STATE_IDLE) begin
92 | rd_rdy <= 1;
93 | ram_req <= 0;
94 | wr <= 0;
95 |
96 | if(we_ack != we_req || we) begin
97 | ram_req <= 1;
98 | wr <= 1;
99 | {bank,a} <= waddr;
100 | data <= din;
101 | b <= we;
102 | end
103 | else
104 | if(rd) begin
105 | rd_rdy <= 0;
106 | ram_req <= 1;
107 | wr <= 0;
108 | {bank,a} <= raddr;
109 | b <= 0;
110 | end
111 | end
112 |
113 | if (q == STATE_READY && ram_req) begin
114 | if(wr) we_ack <= we_req;
115 | else rd_rdy <= 1;
116 | end
117 |
118 | q <= q + 1'd1;
119 | if(~old_ref & clkref) q <= 0;
120 | end
121 |
122 | localparam MODE_NORMAL = 2'b00;
123 | localparam MODE_RESET = 2'b01;
124 | localparam MODE_LDM = 2'b10;
125 | localparam MODE_PRE = 2'b11;
126 |
127 | // initialization
128 | reg [1:0] mode;
129 | always @(posedge clk) begin
130 | reg [4:0] reset=5'h1f;
131 | reg init_old=0;
132 | init_old <= init;
133 |
134 | if(init_old & ~init) reset <= 5'h1f;
135 | else if(q == STATE_LAST) begin
136 | if(reset != 0) begin
137 | reset <= reset - 5'd1;
138 | if(reset == 14) mode <= MODE_PRE;
139 | else if(reset == 3) mode <= MODE_LDM;
140 | else mode <= MODE_RESET;
141 | end
142 | else mode <= MODE_NORMAL;
143 | end
144 | end
145 |
146 | localparam CMD_NOP = 3'b111;
147 | localparam CMD_BURST_TERMINATE = 3'b110;
148 | localparam CMD_READ = 3'b101;
149 | localparam CMD_WRITE = 3'b100;
150 | localparam CMD_ACTIVE = 3'b011;
151 | localparam CMD_PRECHARGE = 3'b010;
152 | localparam CMD_AUTO_REFRESH = 3'b001;
153 | localparam CMD_LOAD_MODE = 3'b000;
154 |
155 | // SDRAM state machines
156 | always @(posedge clk) begin
157 | reg [15:0] data_reg;
158 |
159 | SDRAM_DQ <= 16'hZZZZ;
160 | casex({ram_req,wr,mode,q})
161 | {2'b1X, MODE_NORMAL, STATE_START}: {SDRAM_nRAS, SDRAM_nCAS, SDRAM_nWE} <= CMD_ACTIVE;
162 | {2'b11, MODE_NORMAL, STATE_CONT }: {SDRAM_nRAS, SDRAM_nCAS, SDRAM_nWE, SDRAM_DQ} <= {CMD_WRITE, data};
163 | {2'b10, MODE_NORMAL, STATE_CONT }: {SDRAM_nRAS, SDRAM_nCAS, SDRAM_nWE} <= CMD_READ;
164 | {2'b0X, MODE_NORMAL, STATE_START}: {SDRAM_nRAS, SDRAM_nCAS, SDRAM_nWE} <= CMD_AUTO_REFRESH;
165 |
166 | // init
167 | {2'bXX, MODE_LDM, STATE_START}: {SDRAM_nRAS, SDRAM_nCAS, SDRAM_nWE} <= CMD_LOAD_MODE;
168 | {2'bXX, MODE_PRE, STATE_START}: {SDRAM_nRAS, SDRAM_nCAS, SDRAM_nWE} <= CMD_PRECHARGE;
169 |
170 | default: {SDRAM_nRAS, SDRAM_nCAS, SDRAM_nWE} <= CMD_NOP;
171 | endcase
172 |
173 | if(mode == MODE_NORMAL) begin
174 | casex(q)
175 | STATE_START: SDRAM_A <= a[21:9];
176 | STATE_CONT: SDRAM_A <= {~a[0]&wr&b,a[0]&wr&b,2'b10, a[22], a[8:1]};
177 | endcase;
178 | end
179 | else if(mode == MODE_LDM && q == STATE_START) SDRAM_A <= MODE;
180 | else if(mode == MODE_PRE && q == STATE_START) SDRAM_A <= 13'b0010000000000;
181 | else SDRAM_A <= 0;
182 |
183 | data_reg <= SDRAM_DQ;
184 | if(q == STATE_START) SDRAM_BA <= (mode == MODE_NORMAL) ? bank : 2'b00;
185 | if(q == STATE_READY && ~wr && ram_req) dout <= a[0] ? data_reg[15:8] : data_reg[7:0];
186 | end
187 |
188 | altddio_out
189 | #(
190 | .extend_oe_disable("OFF"),
191 | .intended_device_family("Cyclone V"),
192 | .invert_output("OFF"),
193 | .lpm_hint("UNUSED"),
194 | .lpm_type("altddio_out"),
195 | .oe_reg("UNREGISTERED"),
196 | .power_up_high("OFF"),
197 | .width(1)
198 | )
199 | sdramclk_ddr
200 | (
201 | .datain_h(1'b0),
202 | .datain_l(1'b1),
203 | .outclock(clk),
204 | .dataout(SDRAM_CLK),
205 | .aclr(1'b0),
206 | .aset(1'b0),
207 | .oe(1'b1),
208 | .outclocken(1'b1),
209 | .sclr(1'b0),
210 | .sset(1'b0)
211 | );
212 |
213 | endmodule
214 |
--------------------------------------------------------------------------------
/rtl/pce/xe1ap.v:
--------------------------------------------------------------------------------
1 | // Code your design here
2 | module XE1AP
3 | #(parameter CLKPERUSEC=50) // we need fixed time intervals in microseconds;
4 | // clk_sys may vary from core to core; this is
5 | // the number of clk_sys cycles in a microsecond
6 | (input clk_sys,
7 | input reset,
8 | input [31:0] joystick_0, // 3 = up, 2 = down, 1 = left, 0 = right
9 | // 7 = run, 6 = select, 5 = button 2, 4 - button 1
10 | input [15:0] joystick_l_analog_0, // [15:8] is up/down, range +/- 127 (up is minus)
11 | // [7:0] is left/right, range +/- 127 (left is minus)
12 | input [15:0] joystick_r_analog_0,
13 |
14 | input req, // signal requesting response from XE-1AP (on return to high)
15 | // pin 8 on original 9-pin connector
16 |
17 | output reg trg1, // pin 6 on original 9-pin connector
18 | output reg trg2, // pin 7 on original 9-pin connector
19 |
20 | output reg [3:0] data, // Data[3] = pin 4 on original 9-pin connector
21 | // Data[2] = pin 3 on original 9-pin connector
22 | // Data[1] = pin 2 on original 9-pin connector
23 | // Data[0] = pin 1 on original 9-pin connector
24 |
25 | output reg run_btn, // need to send back for the XHE-3 PC Engine attachment
26 | output reg select_btn // need to send back for the XHE-3 PC Engine attachment
27 | );
28 |
29 | // Note that output data is sent 4 bits at a time, with trg2 == LOW signalling "data ready"
30 | //
31 | // The sequence of data (and bit-order) is as follows (from original joystick):
32 | // (Note that not all buttons are currently mapped for PC-Engine implementation)
33 | //
34 | // All values are low when pressed, high when not pressed
35 | //
36 | // 1: Buttons A, B, C, D - (Note: A is pressed if either A or A' is pressed; same with B or B')
37 | // 2: Buttons E1, E2, Start(F), Select (G)
38 | // 3: Top 4 bits of 'channel 0' (Y-axis; limit up = 0x00, limit down = 0xFF)
39 | // 4: Top 4 bits of 'channel 1' (X-axis; limit left = 0x00, limit right = 0xFF)
40 | // 5: Top 4 bits of 'channel 2' (Throttle; limit up = 0xFF, limit down = 0x00)
41 | // 6: 0000 (unused)
42 | // 7: Bottom 4 bits of 'channel 0' (Y-axis)
43 | // 8: Bottom 4 bits of 'channel 1' (X-axis)
44 | // 9: Bottom 4 bits of 'channel 2' (Throttle)
45 | // 10: 0000 (unused)
46 | // 11: Buttons A, B, A', B' (This can differentiate between the buttons, whereas scan #1 merges them)
47 | // 12: 1111 (all high)
48 | //
49 |
50 | // registers
51 |
52 | reg [6:0] clks_per_usec = CLKPERUSEC;
53 |
54 | reg [6:0] clk_counter = 0;
55 | reg [6:0] usec_counter = 0;
56 | reg [6:0] usec_counter_ff = 0;
57 | reg [47:0] shift_output = 48'h0;
58 |
59 | reg active = 1'b0;
60 | reg req_ff = 1'b1;
61 | reg req_fff = 1'b1;
62 |
63 | reg [2:0] cycle_count = 3'b0; // 0 = wait before pulse train
64 | // 1-6 = normal pulse cycles
65 | // 7 = cycle train completed
66 |
67 | always @(posedge clk_sys)
68 | begin
69 |
70 | req_ff <= req;
71 | req_fff <= req_ff;
72 |
73 | if (reset == 1'b1) begin
74 | active <= 1'b0;
75 | trg1 <= 1'b0;
76 | trg2 <= 1'b1;
77 | cycle_count <= 3'b0;
78 | clk_counter <= 0;
79 | usec_counter <= 0;
80 | end
81 |
82 | if (active == 1'b0) begin
83 | trg1 <= 1'b0;
84 | trg2 <= 1'b1;
85 | if ((req_fff == 0) && (req_ff == 1))
86 | begin
87 | active <= 1'b1;
88 | cycle_count <= 3'b0;
89 | clk_counter <= 0;
90 | usec_counter <= 0;
91 | run_btn <= ~joystick_0[7];
92 | select_btn <= ~joystick_0[6];
93 |
94 | shift_output <= { 4'b1111, // Need to put first nybble as least-significant
95 | ~joystick_0[4], ~joystick_0[5], 2'b11, // A, B, A', B'
96 | 4'b0000,
97 | ~joystick_r_analog_0[11:8], // throttle[3:0]
98 | joystick_l_analog_0[3:0], // x[3:0]
99 | joystick_l_analog_0[11:8], // y[3:0]
100 | 4'b0000,
101 | joystick_r_analog_0[15], ~joystick_r_analog_0[14:12], // throttle[7:4]
102 | ~joystick_l_analog_0[7], joystick_l_analog_0[6:4], // x[7:4]
103 | ~joystick_l_analog_0[15], joystick_l_analog_0[14:12], // y[7:4]
104 | 2'b11, ~joystick_0[7], ~joystick_0[6], // E1, E2, start, select
105 | ~joystick_0[4], ~joystick_0[5], 2'b11 }; // A, B, C, D
106 | end
107 | end
108 |
109 | else if (active == 1) begin
110 | usec_counter_ff <= usec_counter;
111 | clk_counter <= clk_counter + 1;
112 | if (clk_counter == clks_per_usec)
113 | begin
114 | clk_counter <= 0;
115 | usec_counter <= usec_counter + 1;
116 | end
117 |
118 | if (cycle_count == 0) begin // first cycle needs 68 microseconds until output
119 | if ((usec_counter > usec_counter_ff) && (usec_counter == 68)) begin
120 | data[3:0] <= shift_output[3:0];
121 | shift_output[43:0] <= shift_output[47:4];
122 | trg2 <= 1'b0;
123 | cycle_count <= 1;
124 | usec_counter <= 0;
125 | end
126 | end
127 |
128 | else if ((cycle_count >= 1) && (cycle_count <= 6)) begin // normal 6 cycles of data output
129 | if ((usec_counter > usec_counter_ff) && (usec_counter == 13)) begin
130 | trg1 <= 1'b1;
131 | trg2 <= 1'b1;
132 | end
133 |
134 | else if ((usec_counter > usec_counter_ff) && (usec_counter == 17)) begin
135 | data[3:0] <= shift_output[3:0];
136 | shift_output[43:0] <= shift_output[47:4];
137 | trg2 <= 1'b0;
138 | end
139 |
140 | else if ((usec_counter > usec_counter_ff) && (usec_counter == 30)) begin
141 | trg2 <= 1'b1;
142 | end
143 |
144 | else if ((usec_counter > usec_counter_ff) && (usec_counter == 34)) begin
145 | trg1 <= 1'b0;
146 | if (cycle_count == 6)
147 | begin
148 | cycle_count <= 7;
149 | end
150 | end
151 |
152 | else if ((usec_counter > usec_counter_ff) && (usec_counter == 50)) begin
153 | data[3:0] <= shift_output[3:0];
154 | shift_output[43:0] <= shift_output[47:4];
155 | trg2 <= 1'b0;
156 | cycle_count <= cycle_count + 1;
157 | usec_counter <= 0;
158 | end
159 | end
160 |
161 | else if (cycle_count == 7) // Data train completed; ready to reset
162 | begin
163 | active <= 1'b0;
164 | trg1 <= 1'b0;
165 | trg2 <= 1'b1;
166 | data[3:0] <= 4'b1111;
167 | cycle_count <= 3'b0;
168 | clk_counter <= 0;
169 | usec_counter <= 0;
170 | end
171 |
172 | end
173 | end
174 |
175 | endmodule
176 |
--------------------------------------------------------------------------------
/rtl/sys/iir_filter.v:
--------------------------------------------------------------------------------
1 |
2 | // 3-tap IIR filter for 2 channels.
3 | // Copyright (C) 2020 Sorgelig
4 | //
5 | // This program is free software; you can redistribute it and/or modify it
6 | // under the terms of the GNU General Public License as published by the Free
7 | // Software Foundation; either version 2 of the License, or (at your option)
8 | // any later version.
9 | //
10 | // This program is distributed in the hope that it will be useful, but WITHOUT
11 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 | // more details.
14 | //
15 | // You should have received a copy of the GNU General Public License along
16 | // with this program; if not, write to the Free Software Foundation, Inc.,
17 | // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 |
19 | //
20 | // Can be converted to 2-tap (coeff_x2 = 0, coeff_y2 = 0) or 1-tap (coeff_x1,2 = 0, coeff_y1,2 = 0)
21 | //
22 | module IIR_filter
23 | #(
24 | parameter use_params = 1, // set to 1 to use following parameters, 0 for input port variables.
25 | parameter stereo = 1, // 0 for mono (input_l)
26 |
27 | parameter coeff_x = 0.00000774701983513660, // Base gain value for X. Float. Range: 0.0 ... 0.999(9)
28 | parameter coeff_x0 = 3, // Gain scale factor for X0. Integer. Range -7 ... +7
29 | parameter coeff_x1 = 3, // Gain scale factor for X1. Integer. Range -7 ... +7
30 | parameter coeff_x2 = 1, // Gain scale factor for X2. Integer. Range -7 ... +7
31 | parameter coeff_y0 = -2.96438150626551080000, // Coefficient for Y0. Float. Range -3.999(9) ... 3.999(9)
32 | parameter coeff_y1 = 2.92939452735121100000, // Coefficient for Y1. Float. Range -3.999(9) ... 3.999(9)
33 | parameter coeff_y2 = -0.96500747158831091000 // Coefficient for Y2. Float. Range -3.999(9) ... 3.999(9)
34 | )
35 | (
36 | input clk,
37 | input reset,
38 |
39 | input ce, // must be double of calculated rate for stereo!
40 | input sample_ce, // desired output sample rate
41 |
42 | input [39:0] cx,
43 | input [7:0] cx0,
44 | input [7:0] cx1,
45 | input [7:0] cx2,
46 | input [23:0] cy0,
47 | input [23:0] cy1,
48 | input [23:0] cy2,
49 |
50 | input [15:0] input_l, input_r, // signed samples
51 | output [15:0] output_l, output_r // signed samples
52 | );
53 |
54 | localparam [39:0] pcoeff_x = coeff_x * 40'h8000000000;
55 | localparam [31:0] pcoeff_y0 = coeff_y0 * 24'h200000;
56 | localparam [31:0] pcoeff_y1 = coeff_y1 * 24'h200000;
57 | localparam [31:0] pcoeff_y2 = coeff_y2 * 24'h200000;
58 |
59 | wire [39:0] vcoeff = use_params ? pcoeff_x : cx;
60 | wire [23:0] vcoeff_y0 = use_params ? pcoeff_y0[23:0] : cy0;
61 | wire [23:0] vcoeff_y1 = use_params ? pcoeff_y1[23:0] : cy1;
62 | wire [23:0] vcoeff_y2 = use_params ? pcoeff_y2[23:0] : cy2;
63 |
64 | wire [59:0] inp_mul = $signed(inp) * $signed(vcoeff);
65 |
66 | wire [39:0] x = inp_mul[59:20];
67 | wire [39:0] y = x + tap0;
68 |
69 | wire [39:0] tap0;
70 | iir_filter_tap iir_tap_0
71 | (
72 | .clk(clk),
73 | .reset(reset),
74 | .ce(ce),
75 | .ch(ch),
76 | .cx(use_params ? coeff_x0[7:0] : cx0),
77 | .cy(vcoeff_y0),
78 | .x(x),
79 | .y(y),
80 | .z(tap1),
81 | .tap(tap0)
82 | );
83 |
84 | wire [39:0] tap1;
85 | iir_filter_tap iir_tap_1
86 | (
87 | .clk(clk),
88 | .reset(reset),
89 | .ce(ce),
90 | .ch(ch),
91 | .cx(use_params ? coeff_x1[7:0] : cx1),
92 | .cy(vcoeff_y1),
93 | .x(x),
94 | .y(y),
95 | .z(tap2),
96 | .tap(tap1)
97 | );
98 |
99 | wire [39:0] tap2;
100 | iir_filter_tap iir_tap_2
101 | (
102 | .clk(clk),
103 | .reset(reset),
104 | .ce(ce),
105 | .ch(ch),
106 | .cx(use_params ? coeff_x2[7:0] : cx2),
107 | .cy(vcoeff_y2),
108 | .x(x),
109 | .y(y),
110 | .z(0),
111 | .tap(tap2)
112 | );
113 |
114 | wire [15:0] y_clamp = (~y[39] & |y[38:35]) ? 16'h7FFF : (y[39] & ~&y[38:35]) ? 16'h8000 : y[35:20];
115 |
116 | reg ch = 0;
117 | reg [15:0] out_l, out_r, out_m;
118 | reg [15:0] inp, inp_m;
119 | always @(posedge clk) if (ce) begin
120 | if(!stereo) begin
121 | ch <= 0;
122 | inp <= input_l;
123 | out_l <= y_clamp;
124 | out_r <= y_clamp;
125 | end
126 | else begin
127 | ch <= ~ch;
128 | if(ch) begin
129 | out_m <= y_clamp;
130 | inp <= inp_m;
131 | end
132 | else begin
133 | out_l <= out_m;
134 | out_r <= y_clamp;
135 | inp <= input_l;
136 | inp_m <= input_r;
137 | end
138 | end
139 | end
140 |
141 | reg [31:0] out;
142 | always @(posedge clk) if (sample_ce) out <= {out_l, out_r};
143 |
144 | assign {output_l, output_r} = out;
145 |
146 | endmodule
147 |
148 | module iir_filter_tap
149 | (
150 | input clk,
151 | input reset,
152 |
153 | input ce,
154 | input ch,
155 |
156 | input [7:0] cx,
157 | input [23:0] cy,
158 |
159 | input [39:0] x,
160 | input [39:0] y,
161 | input [39:0] z,
162 | output [39:0] tap
163 | );
164 |
165 | wire signed [60:0] y_mul = $signed(y[36:0]) * $signed(cy);
166 |
167 | function [39:0] x_mul;
168 | input [39:0] x;
169 | begin
170 | x_mul = 0;
171 | if(cx[0]) x_mul = x_mul + {{4{x[39]}}, x[39:4]};
172 | if(cx[1]) x_mul = x_mul + {{3{x[39]}}, x[39:3]};
173 | if(cx[2]) x_mul = x_mul + {{2{x[39]}}, x[39:2]};
174 | if(cx[7]) x_mul = ~x_mul; //cheap NEG
175 | end
176 | endfunction
177 |
178 | (* ramstyle = "logic" *) reg [39:0] intreg[2];
179 | always @(posedge clk, posedge reset) begin
180 | if(reset) {intreg[0],intreg[1]} <= 80'd0;
181 | else if(ce) intreg[ch] <= x_mul(x) - y_mul[60:21] + z;
182 | end
183 |
184 | assign tap = intreg[ch];
185 |
186 | endmodule
187 |
188 | // simplified IIR 1-tap.
189 | module DC_blocker
190 | (
191 | input clk,
192 | input ce, // 48/96 KHz
193 | input mute,
194 |
195 | input sample_rate,
196 | input [15:0] din,
197 | output [15:0] dout
198 | );
199 |
200 | wire [39:0] x = {din[15], din, 23'd0};
201 | wire [39:0] x0 = x - (sample_rate ? {{11{x[39]}}, x[39:11]} : {{10{x[39]}}, x[39:10]});
202 | wire [39:0] y1 = y - (sample_rate ? {{10{y[39]}}, y[39:10]} : {{09{y[39]}}, y[39:09]});
203 | wire [39:0] y0 = x0 - x1 + y1;
204 |
205 | reg [39:0] x1, y;
206 | always @(posedge clk) if(ce) begin
207 | x1 <= x0;
208 | y <= ^y0[39:38] ? {{2{y0[39]}},{38{y0[38]}}} : y0;
209 | end
210 |
211 | assign dout = mute ? 16'd0 : y[38:23];
212 |
213 | endmodule
214 |
--------------------------------------------------------------------------------
/support/chip32.asm:
--------------------------------------------------------------------------------
1 | architecture chip32.vm
2 | output "chip32.bin", create
3 |
4 | // we will put data into here that we're working on. It's the last 1K of the 8K chip32 memory
5 | constant rambuf = 0x1b00
6 |
7 | constant rom_dataslot = 0
8 | constant save_dataslot = 1
9 |
10 | // Host init command
11 | constant host_init = 0x4002
12 |
13 | // Error vector (0x0)
14 | jp error_handler
15 |
16 | // Init vector (0x2)
17 | // Choose core
18 | ld r0,#0
19 | core r0
20 |
21 | ld r1,#rom_dataslot // populate data slot
22 | ld r2,#rambuf // get ram buf position
23 | getext r1,r2
24 | ld r1,#ext_sgx
25 | test r2,r1
26 | jp z,set_sgx // Set sgx
27 |
28 | dont_set_sgx:
29 | ld r3,#0
30 | jp start_load
31 |
32 | set_sgx:
33 | ld r3,#1
34 |
35 | start_load:
36 | ld r1,#8
37 | pmpw r1,r3 // Write is_sgx = 1
38 |
39 | ld r1,#0 // Set address for write
40 | ld r2,#1 // Downloading start
41 | pmpw r1,r2 // Write ioctl_download = 1
42 |
43 | ld r1,#rom_dataslot
44 | ld r14,#load_err_msg
45 | loadf r1 // Load ROM
46 | jp nz,print_error_and_exit
47 |
48 | ld r1,#0 // Set address for write
49 | ld r2,#0 // Downloading end
50 | pmpw r1,r2 // Write ioctl_download = 0
51 |
52 | ld r1,#4 // Set address for write
53 | ld r2,#1 // Downloading start
54 | pmpw r1,r2 // Write save_download = 1
55 |
56 | ld r1,#save_dataslot
57 | loadf r1 // Load save
58 |
59 | ld r1,#4 // Set address for write
60 | ld r2,#0 // Downloading end
61 | pmpw r1,r2 // Write save_download = 0
62 |
63 | // Start core
64 | ld r0,#host_init
65 | host r0,r0
66 |
67 | exit 0
68 |
69 | // Error handling
70 | error_handler:
71 | ld r14,#test_err_msg
72 |
73 | print_error_and_exit:
74 | printf r14
75 | exit 1
76 |
77 | ext_sgx:
78 | db "SGX",0
79 |
80 | test_err_msg:
81 | db "Error",0
82 |
83 | load_err_msg:
84 | db "Could not load ROM",0
--------------------------------------------------------------------------------
/target/pocket/audio.sv:
--------------------------------------------------------------------------------
1 | module pce_audio (
2 | input wire clk_sys_42_95,
3 |
4 | // Settings
5 | input wire cd_audio_boost,
6 | input wire adpcm_audio_boost,
7 | input wire [1:0] master_audio_boost,
8 |
9 | input wire [15:0] cdda_sl,
10 | input wire [15:0] cdda_sr,
11 | input wire [15:0] adpcm_s,
12 | input wire [15:0] psg_sl,
13 | input wire [15:0] psg_sr,
14 |
15 | output wire [15:0] audio_l,
16 | output wire [15:0] audio_r
17 | );
18 | wire PSG_EN = 1;
19 | wire CDDA_EN = 1;
20 | wire ADPCM_EN = 1;
21 |
22 | localparam [3:0] comp_f1 = 4;
23 | localparam [3:0] comp_a1 = 2;
24 | localparam comp_x1 = ((32767 * (comp_f1 - 1)) / ((comp_f1 * comp_a1) - 1)) + 1; // +1 to make sure it won't overflow
25 | localparam comp_b1 = comp_x1 * comp_a1;
26 |
27 | localparam [3:0] comp_f2 = 8;
28 | localparam [3:0] comp_a2 = 4;
29 | localparam comp_x2 = ((32767 * (comp_f2 - 1)) / ((comp_f2 * comp_a2) - 1)) + 1; // +1 to make sure it won't overflow
30 | localparam comp_b2 = comp_x2 * comp_a2;
31 |
32 | function [15:0] compr;
33 | input [15:0] inp;
34 | reg [15:0] v, v1, v2;
35 | begin
36 | v = inp[15] ? (~inp) + 1'd1 : inp;
37 | v1 = (v < comp_x1[15:0]) ? (v * comp_a1) : (((v - comp_x1[15:0]) / comp_f1) + comp_b1[15:0]);
38 | v2 = (v < comp_x2[15:0]) ? (v * comp_a2) : (((v - comp_x2[15:0]) / comp_f2) + comp_b2[15:0]);
39 | v = master_audio_boost[1] ? v2 : v1;
40 | compr = inp[15] ? ~(v - 1'd1) : v;
41 | end
42 | endfunction
43 |
44 | reg [17:0] audio_l_int, audio_r_int;
45 | reg [15:0] cmp_l, cmp_r;
46 |
47 | logic [4:0] div_audio;
48 | logic adpcm_ce, psg_ce;
49 |
50 | logic [15:0] adpcm_filt, psg_l_filt, psg_r_filt;
51 |
52 | always @(posedge clk_sys_42_95) begin
53 | // 2684650 and 1342323
54 | div_audio <= div_audio + 1'd1;
55 |
56 | adpcm_ce <= &div_audio[4:0];
57 | psg_ce <= &div_audio[3:0];
58 | end
59 |
60 | IIR_filter #(
61 | .coeff_x (0.00200339512841342642),
62 | .coeff_x0(2),
63 | .coeff_x1(1),
64 | .coeff_x2(0),
65 | .coeff_y0(-1.95511712863912712201),
66 | .coeff_y1(0.95667938324280066276),
67 | .coeff_y2(0),
68 | .stereo (1)
69 | ) psg_filter (
70 | .clk (clk_sys_42_95),
71 | .ce (psg_ce), // (1342323 * 2)
72 | .sample_ce(1),
73 | .input_l (psg_sl),
74 | .input_r (psg_sr),
75 | .output_l (psg_l_filt),
76 | .output_r (psg_r_filt)
77 | );
78 |
79 | IIR_filter #(
80 | .coeff_x (0.00002488367092441635),
81 | .coeff_x0(3),
82 | .coeff_x1(3),
83 | .coeff_x2(1),
84 | .coeff_y0(-2.94383188882174362533),
85 | .coeff_y1(2.88923013608993572987),
86 | .coeff_y2(-0.94537670406128904155),
87 | .stereo (0)
88 | ) adpcm_filter (
89 | .clk (clk_sys_42_95),
90 | .ce (adpcm_ce), // 1342323
91 | .sample_ce(1),
92 | .input_l (adpcm_s),
93 | .output_l (adpcm_filt)
94 | );
95 |
96 | always @(posedge clk_sys_42_95) begin
97 | reg [17:0] pre_l, pre_r;
98 | reg signed [16:0] adpcm_boost;
99 | adpcm_boost <= $signed(
100 | {adpcm_filt[15], adpcm_filt}
101 | ) + $signed(
102 | (adpcm_audio_boost ? {{3{adpcm_filt[15]}}, adpcm_filt[15:2]} : 17'd0)
103 | );
104 |
105 | pre_l <= ( CDDA_EN ? {{2{cdda_sl[15]}}, cdda_sl} : 18'd0)
106 | + ((CDDA_EN && cd_audio_boost) ? {{2{cdda_sl[15]}}, cdda_sl} : 18'd0)
107 | + ( PSG_EN ? {{2{psg_l_filt[15]}}, psg_l_filt} : 18'd0)
108 | + ( ADPCM_EN ? {adpcm_boost[16], adpcm_boost} : 18'd0);
109 |
110 | pre_r <= ( CDDA_EN ? {{2{cdda_sr[15]}}, cdda_sr} : 18'd0)
111 | + ((CDDA_EN && cd_audio_boost) ? {{2{cdda_sr[15]}}, cdda_sr} : 18'd0)
112 | + ( PSG_EN ? {{2{psg_r_filt[15]}}, psg_r_filt} : 18'd0)
113 | + ( ADPCM_EN ? {adpcm_boost[16], adpcm_boost} : 18'd0);
114 |
115 | if (~cd_audio_boost) begin
116 | // 3/4 + 1/4 to cover the whole range.
117 | audio_l_int <= $signed(pre_l) + ($signed(pre_l) >>> 2);
118 | audio_r_int <= $signed(pre_r) + ($signed(pre_r) >>> 2);
119 | end else begin
120 | audio_l_int <= pre_l;
121 | audio_r_int <= pre_r;
122 | end
123 |
124 | cmp_l <= compr(audio_l_int[17:2]);
125 | cmp_r <= compr(audio_r_int[17:2]);
126 | end
127 |
128 | assign audio_l = master_audio_boost > 0 ? cmp_l : audio_l_int[17:2];
129 | assign audio_r = master_audio_boost > 0 ? cmp_r : audio_r_int[17:2];
130 |
131 | endmodule
132 |
--------------------------------------------------------------------------------
/target/pocket/core.qip:
--------------------------------------------------------------------------------
1 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "audio.sv"]
2 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "core_top.v"]
3 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "core_bridge_cmd.v"]
4 | set_global_assignment -name SDC_FILE [file join $::quartus(qip_path) "core_constraints.sdc"]
5 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "data_loader.sv"]
6 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "data_unloader.sv"]
7 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "linebuffer.v"]
8 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) "mf_pllbase.qip"]
9 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "sound_i2s.sv"]
10 | set_global_assignment -name SYSTEMVERILOG_FILE [file join $::quartus(qip_path) "sync_fifo.sv"]
11 |
--------------------------------------------------------------------------------
/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|general[0].gpll~PLL_OUTPUT_COUNTER|divclk \
12 | ic|mp1|mf_pllbase_inst|altera_pll_i|general[1].gpll~PLL_OUTPUT_COUNTER|divclk \
13 | ic|mp1|mf_pllbase_inst|altera_pll_i|general[2].gpll~PLL_OUTPUT_COUNTER|divclk }
14 |
15 | set_multicycle_path -from {ic|pce|sdram|*} -to [get_clocks {*|mp1|mf_pllbase_inst|altera_pll_i|*[1].*|divclk}] -start -setup 2
16 | set_multicycle_path -from {ic|pce|*} -to [get_clocks {*|mp1|mf_pllbase_inst|altera_pll_i|*[1].*|divclk}] -start -hold 1
17 | set_multicycle_path -from {ic|pce|*} -to [get_clocks {*|mp1|mf_pllbase_inst|altera_pll_i|*[1].*|divclk}] -start -setup 2
18 |
19 | set_multicycle_path -from {ic|pce|pce_audio|psg_filter|*} -setup 3
20 | set_multicycle_path -from {ic|pce|pce_audio|psg_filter|*} -hold 2
21 | set_multicycle_path -from {ic|pce|pce_audio|adpcm_filter|*} -setup 3
22 | set_multicycle_path -from {ic|pce|pce_audio|adpcm_filter|*} -hold 2
23 |
24 | set_multicycle_path -from {ic|pce|color_mix|*} -to {isco|*} -start -hold 1
25 | set_multicycle_path -from {ic|pce|color_mix|*} -to {isco|*} -start -setup 2
26 | set_multicycle_path -from {ic|pce|color_mix|*} -to {iscc|*} -start -hold 1
27 | set_multicycle_path -from {ic|pce|color_mix|*} -to {iscc|*} -start -setup 2
28 |
--------------------------------------------------------------------------------
/target/pocket/data_loader.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 data loader for consuming APF bridge writes and directing them to some storage medium
26 | //
27 | // This takes the 32 bit words from APF, and splits it into four / OUTPUT_WORD_SIZE words (4 separate bytes, or 2 16-bit words).
28 | // You can configure the cycle delay by setting WRITE_MEM_CLOCK_DELAY
29 | module data_loader #(
30 | // Upper 4 bits of address
31 | parameter ADDRESS_MASK_UPPER_4 = 0,
32 | parameter ADDRESS_SIZE = 28,
33 |
34 | // Number of clk_memory cycles to delay each write output
35 | // Min 4. Component will assert this value is within the valid range
36 | // Be aware that APF sends data every ~75 74MHz cycles, so you cannot send data slower than this
37 | parameter WRITE_MEM_CLOCK_DELAY = 4,
38 |
39 | // Number of clk_memory cycles to hold the write_en signal high
40 | // Min 1. Component will assert this value is within the valid range
41 | parameter WRITE_MEM_EN_CYCLE_LENGTH = 1,
42 |
43 | // Word size in number of bytes. Can either be 1 (output 8 bits), or 2 (output 16 bits)
44 | // Component will assert this value is within the valid range
45 | parameter OUTPUT_WORD_SIZE = 1
46 | ) (
47 | input wire clk_74a,
48 | input wire clk_memory,
49 |
50 | input wire bridge_wr,
51 | input wire bridge_endian_little,
52 | input wire [31:0] bridge_addr,
53 | input wire [31:0] bridge_wr_data,
54 |
55 | // These outputs are synced to the memory clock
56 | output reg write_en = 0,
57 | output reg [ADDRESS_SIZE-1:0] write_addr = 0,
58 | output reg [8 * OUTPUT_WORD_SIZE - 1:0] write_data = 0
59 | );
60 |
61 | `define MAX(x, y) ((x > y) ? x : y)
62 |
63 | localparam WORD_SIZE = 8 * OUTPUT_WORD_SIZE;
64 |
65 | // Only use the lower 28 bits of the address
66 | localparam FIFO_SIZE = WORD_SIZE + 28;
67 |
68 | wire mem_empty;
69 |
70 | wire [FIFO_SIZE - 1:0] fifo_out;
71 |
72 | reg read_req = 0;
73 | reg write_req = 0;
74 | reg [31:0] shift_data;
75 | reg [27:0] buff_bridge_addr;
76 |
77 | wire [FIFO_SIZE - 1:0] fifo_in = {shift_data[WORD_SIZE-1:0], buff_bridge_addr[27:0]};
78 |
79 | dcfifo dcfifo_component (
80 | .data(fifo_in),
81 | .rdclk(clk_memory),
82 | .rdreq(read_req),
83 | .wrclk(clk_74a),
84 | .wrreq(write_req),
85 | .q(fifo_out),
86 | .rdempty(mem_empty)
87 | // .wrempty(),
88 | // .aclr(),
89 | // .eccstatus(),
90 | // .rdfull(),
91 | // .rdusedw(),
92 | // .wrfull(),
93 | // .wrusedw()
94 | );
95 | defparam dcfifo_component.clocks_are_synchronized = "FALSE",
96 | dcfifo_component.intended_device_family = "Cyclone V", dcfifo_component.lpm_numwords = 4,
97 | dcfifo_component.lpm_showahead = "OFF", dcfifo_component.lpm_type = "dcfifo",
98 | dcfifo_component.lpm_width = FIFO_SIZE, dcfifo_component.lpm_widthu = 2,
99 | dcfifo_component.overflow_checking = "OFF", dcfifo_component.rdsync_delaypipe = 5,
100 | dcfifo_component.underflow_checking = "OFF", dcfifo_component.use_eab = "OFF",
101 | dcfifo_component.wrsync_delaypipe = 5;
102 |
103 | /// APF to Mem clock
104 |
105 | reg prev_bridge_wr = 0;
106 | reg [2:0] write_count = 0;
107 | reg [2:0] write_state = 0;
108 |
109 | localparam WRITE_START = 1;
110 | localparam WRITE_REQ_SHIFT = 2;
111 |
112 | // Receive APF writes and buffer them into the memory clock domain
113 | always @(posedge clk_74a) begin
114 | prev_bridge_wr <= bridge_wr;
115 |
116 | if (~prev_bridge_wr && bridge_wr && bridge_addr[31:28] == ADDRESS_MASK_UPPER_4) begin
117 | // Beginning APF write to core
118 | write_state <= WRITE_REQ_SHIFT;
119 | write_req <= 1;
120 | write_count <= 0;
121 |
122 | shift_data <= bridge_endian_little ? bridge_wr_data : {
123 | bridge_wr_data[7:0], bridge_wr_data[15:8], bridge_wr_data[23:16], bridge_wr_data[31:24]
124 | };
125 |
126 | buff_bridge_addr <= bridge_addr[27:0];
127 | end
128 |
129 | case (write_state)
130 | WRITE_START: begin
131 | write_req <= 1;
132 |
133 | write_state <= WRITE_REQ_SHIFT;
134 | end
135 | WRITE_REQ_SHIFT: begin
136 | write_req <= 0;
137 |
138 | // We will be writing again in the next cycle
139 | shift_data <= {8'h0, shift_data[31:WORD_SIZE]};
140 | buff_bridge_addr <= buff_bridge_addr + OUTPUT_WORD_SIZE;
141 |
142 | write_count <= write_count + 1;
143 |
144 | if (write_count == (4 / OUTPUT_WORD_SIZE) - 1) begin
145 | // Finished write
146 | write_state <= 0;
147 | end else begin
148 | write_state <= WRITE_START;
149 | end
150 | end
151 | endcase
152 | end
153 |
154 | /// Mem clock to core
155 |
156 | reg [5:0] read_state = 0;
157 |
158 | localparam READ_DELAY = 1;
159 | localparam READ_WRITE = 2;
160 | localparam READ_WRITE_EN_CYCLE_OFF = READ_WRITE + WRITE_MEM_EN_CYCLE_LENGTH;
161 | localparam READ_WRITE_END_DEFAULT = WRITE_MEM_CLOCK_DELAY - 1;
162 | // Must use max to prevent READ_WRITE_END from being the same as READ_WRITE_EN_CYCLE_OFF
163 | localparam READ_WRITE_END =
164 | `MAX(READ_WRITE_END_DEFAULT, READ_WRITE_EN_CYCLE_OFF + 1);
165 | localparam HAS_DELAY = READ_WRITE_END_DEFAULT > READ_WRITE_EN_CYCLE_OFF;
166 |
167 | always @(posedge clk_memory) begin
168 | if (read_state != 0) begin
169 | read_state <= read_state + 1;
170 | end else if (~mem_empty) begin
171 | // Start read
172 | read_state <= READ_DELAY;
173 | read_req <= 1;
174 | end
175 |
176 | case (read_state)
177 | READ_DELAY: begin
178 | read_req <= 0;
179 | write_en <= 0;
180 | end
181 | READ_WRITE: begin
182 | // Read data is available
183 | write_en <= 1;
184 |
185 | // Lowest 28 bits are the address
186 | write_addr <= fifo_out[27:0];
187 |
188 | write_data <= fifo_out[WORD_SIZE+27:28];
189 |
190 | read_req <= 0;
191 | end
192 | READ_WRITE_EN_CYCLE_OFF: begin
193 | write_en <= 0;
194 |
195 | if (!HAS_DELAY) begin
196 | // No extra delay, immediately go back to start
197 | read_state <= 0;
198 | end
199 | end
200 | READ_WRITE_END: begin
201 | read_state <= 0;
202 | end
203 | endcase
204 | end
205 |
206 | initial begin
207 | // Verify parameters
208 | if (WRITE_MEM_CLOCK_DELAY < 4) begin
209 | $error("WRITE_MEM_CLOCK_DELAY has a minimum value of 4. Received %d", WRITE_MEM_CLOCK_DELAY);
210 | end
211 |
212 | if (WRITE_MEM_EN_CYCLE_LENGTH < 1 || WRITE_MEM_EN_CYCLE_LENGTH >= WRITE_MEM_CLOCK_DELAY - 2) begin
213 | $error(
214 | "WRITE_MEM_EN_CYCLE_LENGTH must be between 1 and %d (inclusive, based off of WRITE_MEM_CLOCK_DELAY). Received %d",
215 | WRITE_MEM_CLOCK_DELAY - 2 - 1, WRITE_MEM_EN_CYCLE_LENGTH);
216 | end
217 |
218 | if (OUTPUT_WORD_SIZE < 1 || OUTPUT_WORD_SIZE > 2) begin
219 | $error("OUTPUT_WORD_SIZE must be 1 or 2. Received %d", OUTPUT_WORD_SIZE);
220 | end
221 | end
222 |
223 | endmodule
224 |
--------------------------------------------------------------------------------
/target/pocket/data_unloader.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 data unloader for consuming APF bridge reads, reading from some underlying memory, and supplying that data to APF
26 | //
27 | // This consumes four / OUTPUT_WORD_SIZE words (4 separate bytes, or 2 16-bit words) and sends APF 32 bit words.
28 | // You can configure the cycle delay by setting READ_MEM_CLOCK_DELAY
29 | module data_unloader #(
30 | // Upper 4 bits of address
31 | parameter ADDRESS_MASK_UPPER_4 = 0,
32 | parameter ADDRESS_SIZE = 28,
33 |
34 | // Number of memory clock cycles it takes for a read to complete
35 | parameter READ_MEM_CLOCK_DELAY = 1,
36 |
37 | // Word size in number of bytes. Can either be 1 (input 8 bits), or 2 (input 16 bits)
38 | parameter INPUT_WORD_SIZE = 1
39 | ) (
40 | input wire clk_74a,
41 | input wire clk_memory,
42 |
43 | input wire bridge_rd,
44 | input wire bridge_endian_little,
45 | input wire [31:0] bridge_addr,
46 | output reg [31:0] bridge_rd_data = 0,
47 |
48 | // These outputs are synced to the memory clock
49 | output reg read_en = 0,
50 | output reg [ADDRESS_SIZE-1:0] read_addr = 0,
51 | input wire [8 * INPUT_WORD_SIZE - 1:0] read_data
52 | );
53 |
54 | localparam WORD_SIZE = 8 * INPUT_WORD_SIZE;
55 |
56 | // APF address to memory FIFO
57 | reg [27:0] fifo_address_in = 0;
58 | reg address_read_req = 0;
59 | reg address_write_req = 0;
60 | wire address_empty;
61 |
62 | wire [27:0] fifo_address_out;
63 |
64 | dcfifo fifo_address_req (
65 | .data(fifo_address_in),
66 | .rdclk(clk_memory),
67 | .rdreq(address_read_req),
68 | .wrclk(clk_74a),
69 | .wrreq(address_write_req),
70 | .q(fifo_address_out),
71 | .rdempty(address_empty)
72 | // .wrempty(),
73 | // .aclr(),
74 | // .eccstatus(),
75 | // .rdfull(),
76 | // .rdusedw(),
77 | // .wrfull(),
78 | // .wrusedw()
79 | );
80 | defparam fifo_address_req.clocks_are_synchronized = "FALSE",
81 | fifo_address_req.intended_device_family = "Cyclone V", fifo_address_req.lpm_numwords = 4,
82 | fifo_address_req.lpm_showahead = "OFF", fifo_address_req.lpm_type = "dcfifo",
83 | fifo_address_req.lpm_width = 28, fifo_address_req.lpm_widthu = 2,
84 | fifo_address_req.overflow_checking = "OFF", fifo_address_req.rdsync_delaypipe = 5,
85 | fifo_address_req.underflow_checking = "OFF", fifo_address_req.use_eab = "OFF",
86 | fifo_address_req.wrsync_delaypipe = 5;
87 |
88 | // Memory output to APF FIFO
89 | reg [WORD_SIZE - 1:0] fifo_data_in = 0;
90 | reg data_read_req = 0;
91 | reg data_write_req = 0;
92 | wire data_empty;
93 |
94 | wire [WORD_SIZE - 1:0] fifo_data_out;
95 |
96 | dcfifo fifo_data_response (
97 | .data(fifo_data_in),
98 | .rdclk(clk_74a),
99 | .rdreq(data_read_req),
100 | .wrclk(clk_memory),
101 | .wrreq(data_write_req),
102 | .q(fifo_data_out),
103 | .rdempty(data_empty)
104 | // .wrempty(),
105 | // .aclr(),
106 | // .eccstatus(),
107 | // .rdfull(),
108 | // .rdusedw(),
109 | // .wrfull(),
110 | // .wrusedw()
111 | );
112 | defparam fifo_data_response.clocks_are_synchronized = "FALSE",
113 | fifo_data_response.intended_device_family = "Cyclone V", fifo_data_response.lpm_numwords = 4,
114 | fifo_data_response.lpm_showahead = "OFF", fifo_data_response.lpm_type = "dcfifo",
115 | fifo_data_response.lpm_width = WORD_SIZE, fifo_data_response.lpm_widthu = 2,
116 | fifo_data_response.overflow_checking = "OFF", fifo_data_response.rdsync_delaypipe = 5,
117 | fifo_data_response.underflow_checking = "OFF", fifo_data_response.use_eab = "OFF",
118 | fifo_data_response.wrsync_delaypipe = 5;
119 |
120 | /// APF side
121 |
122 | reg prev_bridge_rd = 0;
123 | reg [2:0] addr_count = 0;
124 | reg [2:0] addr_state = 0;
125 |
126 | localparam ADDR_START = 1;
127 | localparam ADDR_REQ = 2;
128 |
129 | // Receive APF read addresses and buffer them into the memory clock domain
130 | always @(posedge clk_74a) begin
131 | prev_bridge_rd <= bridge_rd;
132 |
133 | if (~prev_bridge_rd && bridge_rd && bridge_addr[31:28] == ADDRESS_MASK_UPPER_4) begin
134 | // Beginning APF read from core
135 | addr_state <= ADDR_REQ;
136 | address_write_req <= 1;
137 | addr_count <= 0;
138 |
139 | fifo_address_in <= bridge_addr[27:0];
140 | end
141 |
142 | case (addr_state)
143 | ADDR_START: begin
144 | address_write_req <= 1;
145 |
146 | addr_state <= ADDR_REQ;
147 | end
148 | ADDR_REQ: begin
149 | address_write_req <= 0;
150 |
151 | fifo_address_in <= fifo_address_in + INPUT_WORD_SIZE;
152 |
153 | addr_count <= addr_count + 1;
154 |
155 | if (addr_count == (4 / INPUT_WORD_SIZE) - 1) begin
156 | // Finished write
157 | addr_count <= 0;
158 | addr_state <= 0;
159 | end else begin
160 | addr_state <= ADDR_START;
161 | end
162 | end
163 | endcase
164 | end
165 |
166 | reg [2:0] data_send_state = 0;
167 | reg [2:0] apf_data_count = 0;
168 | reg [31:0] apf_bridge_write_data = 0;
169 |
170 | wire [31:0] apf_final_data = {fifo_data_out, apf_bridge_write_data[31-WORD_SIZE:0]};
171 |
172 | localparam READ_DATA_DELAY = 1;
173 | localparam READ_DATA_WRITE = 2;
174 |
175 | // Receive data from memory and write to APF bridge
176 | always @(posedge clk_74a) begin
177 | if (data_send_state != 0) begin
178 | data_send_state <= data_send_state + 1;
179 | end else if (~data_empty) begin
180 | // Start data read
181 | data_send_state <= READ_DATA_DELAY;
182 | data_read_req <= 1;
183 |
184 | apf_data_count <= 0;
185 | end
186 |
187 | case (data_send_state)
188 | READ_DATA_DELAY: begin
189 | data_read_req <= 0;
190 |
191 | // Shift current APF data
192 | apf_bridge_write_data <= apf_bridge_write_data >> WORD_SIZE;
193 | end
194 | READ_DATA_WRITE: begin
195 | // Data from memory is available
196 | if (apf_data_count == (4 / INPUT_WORD_SIZE) - 1) begin
197 | // We have all of the data we need, send to APF
198 | bridge_rd_data <= bridge_endian_little ? apf_final_data :
199 | {apf_final_data[7:0], apf_final_data[15:8], apf_final_data[23:16], apf_final_data[31:24]};
200 |
201 | data_send_state <= 0;
202 | end else begin
203 | apf_bridge_write_data <= apf_final_data;
204 |
205 | data_read_req <= 1;
206 | data_send_state <= READ_DATA_DELAY;
207 |
208 | apf_data_count <= apf_data_count + 1;
209 | end
210 | end
211 | endcase
212 | end
213 |
214 | /// Mem side
215 |
216 | reg [5:0] data_read_state = 0;
217 |
218 | localparam READ_ADDRESS_DELAY = 1;
219 | localparam READ_MEM_START = 2;
220 | localparam READ_MEM_COMPLETE = READ_MEM_START + READ_MEM_CLOCK_DELAY;
221 | localparam READ_ADDRESS_END = READ_MEM_COMPLETE + 1;
222 |
223 | always @(posedge clk_memory) begin
224 | if (data_read_state != 0) begin
225 | data_read_state <= data_read_state + 1;
226 | end else if (~address_empty) begin
227 | // Start address read
228 | data_read_state <= READ_ADDRESS_DELAY;
229 | address_read_req <= 1;
230 | end
231 |
232 | case (data_read_state)
233 | READ_ADDRESS_DELAY: begin
234 | address_read_req <= 0;
235 | end
236 | READ_MEM_START: begin
237 | // Address read data is available
238 | read_en <= 1;
239 |
240 | read_addr <= fifo_address_out[ADDRESS_SIZE-1:0];
241 | end
242 | READ_MEM_COMPLETE: begin
243 | // We have data to send to APF
244 | read_en <= 0;
245 |
246 | data_write_req <= 1;
247 | fifo_data_in <= read_data;
248 | end
249 | READ_ADDRESS_END: begin
250 | data_write_req <= 0;
251 |
252 | data_read_state <= 0;
253 | end
254 | endcase
255 | end
256 |
257 | endmodule
258 |
--------------------------------------------------------------------------------
/target/pocket/linebuffer.v:
--------------------------------------------------------------------------------
1 | module linebuffer (
2 | input wire clk_vid,
3 |
4 | input wire vsync_in,
5 | input wire hsync_in,
6 |
7 | input wire ce_pix,
8 | input wire disable_pix,
9 | input wire [23:0] rgb_in,
10 |
11 | output wire vsync_out,
12 | output wire hsync_out,
13 |
14 | output reg de,
15 | output reg [23:0] rgb_out
16 | );
17 |
18 | // If 0, outputting bank 0, writing bank 1
19 | // If 1, outputting bank 1, writing bank 0
20 | reg output_bank_select = 0;
21 |
22 | reg bank_read_ack;
23 | reg bank_write;
24 |
25 | wire [23:0] bank0_q;
26 | wire [23:0] bank1_q;
27 |
28 | wire [9:0] bank0_used;
29 | wire [9:0] bank1_used;
30 |
31 | wire bank0_empty;
32 | wire bank1_empty;
33 |
34 | linebuffer_bank bank0 (
35 | .clk(clk_vid),
36 |
37 | .data(rgb_in),
38 | .read_ack(bank_read_ack && ~output_bank_select),
39 | .write_req(bank_write && output_bank_select),
40 |
41 | .q(bank0_q),
42 | .empty(bank0_empty),
43 | .used(bank0_used)
44 | );
45 |
46 | linebuffer_bank bank1 (
47 | .clk(clk_vid),
48 |
49 | .data(rgb_in),
50 | .read_ack(bank_read_ack && output_bank_select),
51 | .write_req(bank_write && ~output_bank_select),
52 |
53 | .q(bank1_q),
54 | .empty(bank1_empty),
55 | .used(bank1_used)
56 | );
57 |
58 | wire bank_empty = output_bank_select ? bank1_empty : bank0_empty;
59 | wire [23:0] bank_q = output_bank_select ? bank1_q : bank0_q;
60 | wire [9:0] bank_line_width = ~output_bank_select ? bank1_used : bank0_used;
61 |
62 | // Incoming video data
63 | reg prev_hsync_in = 0;
64 | reg prev_vsync_in = 0;
65 | reg prev_disable_pix = 0;
66 |
67 | /// The number of pixels drawn in the last line (latched)
68 | reg [9:0] output_line_width;
69 | /// The number of lines drawn (only content, not empty)
70 | reg [9:0] output_line;
71 |
72 | reg [3:0] enable_delay = 0;
73 | reg [3:0] border_delay = 0;
74 |
75 | reg line_224 = 0;
76 | reg [9:0] expected_line_count = 0;
77 |
78 | always @(posedge clk_vid) begin
79 | prev_hsync_in <= hsync_in;
80 | prev_vsync_in <= vsync_in;
81 | prev_disable_pix <= disable_pix;
82 |
83 | bank_write <= 0;
84 |
85 | if (vsync_in && ~prev_vsync_in) begin
86 | line_224 <= output_line < 231;
87 | expected_line_count <= output_line < 231 ? 224 : 240;
88 | end
89 |
90 | if (hsync_in && ~prev_hsync_in) begin
91 | // Hsync, switch banks
92 | output_bank_select <= ~output_bank_select;
93 |
94 | // Latch width of new output bank
95 | output_line_width <= bank_line_width > 0 ? bank_line_width : output_line_width;
96 | end
97 |
98 | // Handle the weird timing of borders
99 | if (~disable_pix && prev_disable_pix) begin
100 | // Falling edge of border
101 | enable_delay <= 3;
102 | end else if (disable_pix && ~prev_disable_pix) begin
103 | // Rising edge of border
104 | border_delay <= 4;
105 | end else if (ce_pix) begin
106 | if (border_delay > 0) begin
107 | border_delay <= border_delay - 1;
108 | end
109 |
110 | if (~disable_pix || border_delay > 0) begin
111 | if (enable_delay > 0) begin
112 | enable_delay <= enable_delay - 1;
113 | end else begin
114 | // Delay finished, draw pixel
115 | bank_write <= 1;
116 | end
117 | end
118 | end
119 | end
120 |
121 | // Outgoing video data
122 | reg prev_de = 0;
123 |
124 | reg [3:0] hs_delay = 0;
125 | reg [8:0] border_start_offset = 0;
126 | reg [8:0] border_end_offset = 0;
127 | reg line_started = 0;
128 | reg prev_line_started = 0;
129 |
130 | /// Whether or not this line is empty
131 | reg line_empty = 0;
132 | /// The number of "empty" (black) lines drawn
133 | reg [9:0] line_empty_count = 0;
134 |
135 | /// Total lines drawn to the screen (including empty black lines)
136 | reg [9:0] total_rendered_count;
137 |
138 | reg [9:0] expected_line_width;
139 | reg [2:0] slot;
140 |
141 | always @(*) begin
142 | if (output_line_width < 280) begin
143 | expected_line_width <= 10'd256;
144 | slot <= 0;
145 | end else if (output_line_width < 380) begin
146 | expected_line_width <= 10'd360;
147 | slot <= 1;
148 | end else begin
149 | expected_line_width <= 10'd512;
150 | slot <= 2;
151 | end
152 | end
153 |
154 | wire [9:0] width_diff = expected_line_width > output_line_width ? expected_line_width - output_line_width : 0 /* synthesis keep */;
155 | // Divide by 2 and round up
156 | wire [8:0] calculated_border = width_diff[0] ? width_diff[9:1] + 1 : width_diff[9:1] /* synthesis keep */;
157 |
158 | wire [23:0] video_slot_rgb = {7'b0, slot, line_224, 10'b0, 3'b0};
159 |
160 | always @(posedge clk_vid) begin
161 | bank_read_ack <= 0;
162 | de <= 0;
163 | rgb_out <= 0;
164 |
165 | if (hs_delay > 0) begin
166 | hs_delay <= hs_delay - 1;
167 | end
168 |
169 | if (~prev_vsync_in && vsync_in) begin
170 | // Reset line_started
171 | line_started <= 0;
172 |
173 | prev_line_started <= 0;
174 | total_rendered_count <= 0;
175 | output_line <= 0;
176 | end else if (~prev_hsync_in && hsync_in) begin
177 | // HSync went high. Delay by 6 vid cycles to prevent overlapping with VSync
178 | hs_delay <= 15;
179 | line_started <= 0;
180 |
181 | prev_line_started <= line_started;
182 |
183 | border_start_offset <= 0;
184 | border_end_offset <= 0;
185 |
186 | line_empty <= 0;
187 | line_empty_count <= 0;
188 | end
189 |
190 | if (hs_delay == 1 && bank_empty && prev_line_started && total_rendered_count < expected_line_count) begin
191 | // Right before draw, and no pixels, and previous line drew. This line will be empty
192 | line_empty <= 1;
193 | total_rendered_count <= total_rendered_count + 1;
194 | end
195 |
196 | if (line_empty && line_empty_count < expected_line_width) begin
197 | // Empty line, draw pixels up until expected_line_width
198 | de <= 1;
199 | rgb_out <= 0;
200 | line_started <= 1;
201 | // Make sure we don't draw extra border pixels
202 | border_end_offset <= calculated_border;
203 |
204 | line_empty_count <= line_empty_count + 1;
205 | end else if (calculated_border == 0 && hs_delay == 1 && ~bank_empty) begin
206 | // If no border, set read ack high one pixel early
207 | bank_read_ack <= 1;
208 | total_rendered_count <= total_rendered_count + 1;
209 | output_line <= output_line + 1;
210 | end else if (hs_delay == 0 && ~bank_empty) begin
211 | // Write out video data
212 | de <= 1;
213 |
214 | // Track whether we've written pixels
215 | line_started <= 1;
216 |
217 | if (border_start_offset < calculated_border) begin
218 | // Draw black bars to center video
219 | if (border_start_offset == calculated_border - 1) begin
220 | // Set high one pixel early
221 | bank_read_ack <= 1;
222 | total_rendered_count <= total_rendered_count + 1;
223 | output_line <= output_line + 1;
224 | end
225 | border_start_offset <= border_start_offset + 1;
226 |
227 | rgb_out <= 0;
228 | end else begin
229 | bank_read_ack <= 1;
230 |
231 | rgb_out <= bank_q;
232 | end
233 | end else if (line_started && bank_empty && border_end_offset < calculated_border) begin
234 | // We've exhausted the line buffer, write black until we're done
235 | border_end_offset <= border_end_offset + 1;
236 |
237 | de <= 1;
238 | rgb_out <= 0;
239 | end else if (prev_de) begin
240 | // Falling edge of de
241 | rgb_out <= video_slot_rgb;
242 | end
243 |
244 | prev_de <= de;
245 | end
246 |
247 | // Hsync delayed by 6 cycles
248 | assign hsync_out = hs_delay == 15 - 6;
249 | assign vsync_out = vsync_in && ~prev_vsync_in;
250 |
251 | endmodule
252 |
253 | module linebuffer_bank (
254 | input wire clk,
255 |
256 | input wire [23:0] data,
257 | input wire read_ack,
258 | input wire write_req,
259 |
260 | output wire [23:0] q,
261 | output wire empty,
262 | output wire [9:0] used
263 | );
264 | scfifo bank (
265 | .clock(clk),
266 | .data(data),
267 | .rdreq(read_ack),
268 | .wrreq(write_req),
269 | .empty(empty),
270 | // .full(sub_wire1),
271 | .q(q),
272 | .usedw(used)
273 | );
274 | defparam bank.add_ram_output_register = "ON", bank.intended_device_family = "Cyclone V",
275 | bank.lpm_numwords = 1024, bank.lpm_showahead = "ON", bank.lpm_type = "scfifo",
276 | bank.lpm_width = 24, bank.lpm_widthu = 10, bank.overflow_checking = "ON",
277 | bank.underflow_checking = "ON", bank.use_eab = "ON";
278 |
279 | endmodule
280 |
--------------------------------------------------------------------------------
/target/pocket/mf_pllbase.ppf:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/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 'locked'
20 | output wire locked
21 | );
22 |
23 | altera_pll #(
24 | .fractional_vco_multiplier("true"),
25 | .reference_clock_frequency("74.25 MHz"),
26 | .operation_mode("normal"),
27 | .number_of_clocks(3),
28 | .output_clock_frequency0("85.909090 MHz"),
29 | .phase_shift0("0 ps"),
30 | .duty_cycle0(50),
31 | .output_clock_frequency1("42.954545 MHz"),
32 | .phase_shift1("0 ps"),
33 | .duty_cycle1(50),
34 | .output_clock_frequency2("42.954545 MHz"),
35 | .phase_shift2("5820 ps"),
36 | .duty_cycle2(50),
37 | .output_clock_frequency3("0 MHz"),
38 | .phase_shift3("0 ps"),
39 | .duty_cycle3(50),
40 | .output_clock_frequency4("0 MHz"),
41 | .phase_shift4("0 ps"),
42 | .duty_cycle4(50),
43 | .output_clock_frequency5("0 MHz"),
44 | .phase_shift5("0 ps"),
45 | .duty_cycle5(50),
46 | .output_clock_frequency6("0 MHz"),
47 | .phase_shift6("0 ps"),
48 | .duty_cycle6(50),
49 | .output_clock_frequency7("0 MHz"),
50 | .phase_shift7("0 ps"),
51 | .duty_cycle7(50),
52 | .output_clock_frequency8("0 MHz"),
53 | .phase_shift8("0 ps"),
54 | .duty_cycle8(50),
55 | .output_clock_frequency9("0 MHz"),
56 | .phase_shift9("0 ps"),
57 | .duty_cycle9(50),
58 | .output_clock_frequency10("0 MHz"),
59 | .phase_shift10("0 ps"),
60 | .duty_cycle10(50),
61 | .output_clock_frequency11("0 MHz"),
62 | .phase_shift11("0 ps"),
63 | .duty_cycle11(50),
64 | .output_clock_frequency12("0 MHz"),
65 | .phase_shift12("0 ps"),
66 | .duty_cycle12(50),
67 | .output_clock_frequency13("0 MHz"),
68 | .phase_shift13("0 ps"),
69 | .duty_cycle13(50),
70 | .output_clock_frequency14("0 MHz"),
71 | .phase_shift14("0 ps"),
72 | .duty_cycle14(50),
73 | .output_clock_frequency15("0 MHz"),
74 | .phase_shift15("0 ps"),
75 | .duty_cycle15(50),
76 | .output_clock_frequency16("0 MHz"),
77 | .phase_shift16("0 ps"),
78 | .duty_cycle16(50),
79 | .output_clock_frequency17("0 MHz"),
80 | .phase_shift17("0 ps"),
81 | .duty_cycle17(50),
82 | .pll_type("General"),
83 | .pll_subtype("General")
84 | ) altera_pll_i (
85 | .rst (rst),
86 | .outclk ({outclk_2, outclk_1, outclk_0}),
87 | .locked (locked),
88 | .fboutclk ( ),
89 | .fbclk (1'b0),
90 | .refclk (refclk)
91 | );
92 | endmodule
93 |
94 |
--------------------------------------------------------------------------------
/target/pocket/pin_ddio_clk.ppf:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/target/pocket/pin_ddio_clk.qip:
--------------------------------------------------------------------------------
1 | set_global_assignment -name IP_TOOL_NAME "ALTDDIO_OUT"
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) "pin_ddio_clk.v"]
5 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pin_ddio_clk_inst.v"]
6 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pin_ddio_clk.ppf"]
7 |
--------------------------------------------------------------------------------
/target/pocket/pin_ddio_clk.v:
--------------------------------------------------------------------------------
1 | // megafunction wizard: %ALTDDIO_OUT%
2 | // GENERATION: STANDARD
3 | // VERSION: WM1.0
4 | // MODULE: ALTDDIO_OUT
5 |
6 | // ============================================================
7 | // File Name: pin_ddio_clk.v
8 | // Megafunction Name(s):
9 | // ALTDDIO_OUT
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 pin_ddio_clk (
41 | datain_h,
42 | datain_l,
43 | outclock,
44 | dataout);
45 |
46 | input [0:0] datain_h;
47 | input [0:0] datain_l;
48 | input outclock;
49 | output [0:0] dataout;
50 |
51 | wire [0:0] sub_wire0;
52 | wire [0:0] dataout = sub_wire0[0:0];
53 |
54 | altddio_out ALTDDIO_OUT_component (
55 | .datain_h (datain_h),
56 | .datain_l (datain_l),
57 | .outclock (outclock),
58 | .dataout (sub_wire0),
59 | .aclr (1'b0),
60 | .aset (1'b0),
61 | .oe (1'b1),
62 | .oe_out (),
63 | .outclocken (1'b1),
64 | .sclr (1'b0),
65 | .sset (1'b0));
66 | defparam
67 | ALTDDIO_OUT_component.extend_oe_disable = "OFF",
68 | ALTDDIO_OUT_component.intended_device_family = "Cyclone V",
69 | ALTDDIO_OUT_component.invert_output = "OFF",
70 | ALTDDIO_OUT_component.lpm_hint = "UNUSED",
71 | ALTDDIO_OUT_component.lpm_type = "altddio_out",
72 | ALTDDIO_OUT_component.oe_reg = "UNREGISTERED",
73 | ALTDDIO_OUT_component.power_up_high = "OFF",
74 | ALTDDIO_OUT_component.width = 1;
75 |
76 |
77 | endmodule
78 |
79 | // ============================================================
80 | // CNX file retrieval info
81 | // ============================================================
82 | // Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
83 | // Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone V"
84 | // Retrieval info: CONSTANT: EXTEND_OE_DISABLE STRING "OFF"
85 | // Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone V"
86 | // Retrieval info: CONSTANT: INVERT_OUTPUT STRING "OFF"
87 | // Retrieval info: CONSTANT: LPM_HINT STRING "UNUSED"
88 | // Retrieval info: CONSTANT: LPM_TYPE STRING "altddio_out"
89 | // Retrieval info: CONSTANT: OE_REG STRING "UNREGISTERED"
90 | // Retrieval info: CONSTANT: POWER_UP_HIGH STRING "OFF"
91 | // Retrieval info: CONSTANT: WIDTH NUMERIC "1"
92 | // Retrieval info: USED_PORT: datain_h 0 0 1 0 INPUT NODEFVAL "datain_h[0..0]"
93 | // Retrieval info: CONNECT: @datain_h 0 0 1 0 datain_h 0 0 1 0
94 | // Retrieval info: USED_PORT: datain_l 0 0 1 0 INPUT NODEFVAL "datain_l[0..0]"
95 | // Retrieval info: CONNECT: @datain_l 0 0 1 0 datain_l 0 0 1 0
96 | // Retrieval info: USED_PORT: dataout 0 0 1 0 OUTPUT NODEFVAL "dataout[0..0]"
97 | // Retrieval info: CONNECT: dataout 0 0 1 0 @dataout 0 0 1 0
98 | // Retrieval info: USED_PORT: outclock 0 0 0 0 INPUT_CLK_EXT NODEFVAL "outclock"
99 | // Retrieval info: CONNECT: @outclock 0 0 0 0 outclock 0 0 0 0
100 | // Retrieval info: GEN_FILE: TYPE_NORMAL pin_ddio_clk.v TRUE FALSE
101 | // Retrieval info: GEN_FILE: TYPE_NORMAL pin_ddio_clk.qip TRUE FALSE
102 | // Retrieval info: GEN_FILE: TYPE_NORMAL pin_ddio_clk.bsf FALSE TRUE
103 | // Retrieval info: GEN_FILE: TYPE_NORMAL pin_ddio_clk_inst.v TRUE TRUE
104 | // Retrieval info: GEN_FILE: TYPE_NORMAL pin_ddio_clk_bb.v FALSE TRUE
105 | // Retrieval info: GEN_FILE: TYPE_NORMAL pin_ddio_clk.inc FALSE TRUE
106 | // Retrieval info: GEN_FILE: TYPE_NORMAL pin_ddio_clk.cmp FALSE TRUE
107 | // Retrieval info: GEN_FILE: TYPE_NORMAL pin_ddio_clk.ppf TRUE FALSE
108 | // Retrieval info: LIB_FILE: altera_mf
109 |
--------------------------------------------------------------------------------
/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_in (audgen_sampdata),
110 | .data_out(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_in,
35 | output reg [WIDTH - 1:0] data_out = 0
36 | );
37 |
38 | reg read_req = 0;
39 | wire empty;
40 |
41 | wire [WIDTH - 1:0] fifo_out;
42 |
43 | dcfifo dcfifo_component (
44 | .data(data_in),
45 | .rdclk(clk_read),
46 | .rdreq(read_req),
47 | .wrclk(clk_write),
48 | .wrreq(write_en),
49 | .q(fifo_out),
50 | .rdempty(empty),
51 | .aclr(),
52 | .eccstatus(),
53 | .rdfull(),
54 | .rdusedw(),
55 | .wrempty(),
56 | .wrfull(),
57 | .wrusedw()
58 | );
59 | defparam dcfifo_component.intended_device_family = "Cyclone V", dcfifo_component.lpm_numwords = 4,
60 | dcfifo_component.lpm_showahead = "OFF", dcfifo_component.lpm_type = "dcfifo",
61 | dcfifo_component.lpm_width = 32, dcfifo_component.lpm_widthu = 2,
62 | dcfifo_component.overflow_checking = "ON", dcfifo_component.rdsync_delaypipe = 5,
63 | dcfifo_component.underflow_checking = "ON", dcfifo_component.use_eab = "ON",
64 | dcfifo_component.wrsync_delaypipe = 5;
65 |
66 | reg [1:0] read_state = 0;
67 |
68 | localparam READ_DELAY = 1;
69 | localparam READ_WRITE = 2;
70 |
71 | always @(posedge clk_read) begin
72 | read_req <= 0;
73 |
74 | if (~empty) begin
75 | read_state <= READ_DELAY;
76 | read_req <= 1;
77 | end
78 |
79 | case (read_state)
80 | READ_DELAY: begin
81 | read_state <= READ_WRITE;
82 | end
83 | READ_WRITE: begin
84 | read_state <= 0;
85 |
86 | data_out <= fifo_out;
87 | end
88 | endcase
89 | end
90 |
91 | endmodule
92 |
--------------------------------------------------------------------------------