├── .gitignore ├── Makefile ├── README.md ├── assets ├── JoystickAdapterCable_small.png ├── cable.png ├── i2c_expander.png ├── jumpers_small.JPG ├── jumpers_small.png ├── pano_man.png └── pano_man_large.png ├── build.sbt ├── misc ├── create_mif.rb └── romgen │ ├── libgcc_s_dw2-1.dll │ ├── libstdc++-6.dll │ ├── romgen.cpp │ └── romgen.exe ├── pacman_audio_sim └── pacman_audio_sim.xise ├── project ├── build.properties └── plugins.sbt ├── src └── main │ ├── T80 │ ├── T80.vhd │ ├── T80_ALU.vhd │ ├── T80_MCode.vhd │ ├── T80_Pack.vhd │ ├── T80_RegX.vhd │ └── T80sed.vhd │ ├── pacman │ ├── README.md │ ├── build_roms_pacman.bat │ ├── build_roms_pacman.sh │ ├── gfx1.vhd │ ├── pacman.vhd │ ├── pacman_audio.vhd │ ├── pacman_audio_tb.vhd │ ├── pacman_clocks_xilinx.vhd │ ├── pacman_dblscan.vhd │ ├── pacman_debounce.vhd │ ├── pacman_mul4.vhd │ ├── pacman_rams.vhd │ ├── pacman_tb.vhd │ ├── pacman_video.vhd │ ├── pacman_vram_addr.vhd │ ├── pkg_pacman.vhd │ ├── prom1_dst.vhd │ ├── prom4_dst.vhd │ ├── prom7_dst.vhd │ └── rom0.vhd │ ├── pano_rtl │ └── audio.v │ ├── roms.md5 │ ├── pacman.md5 │ ├── puckman.md5 │ └── puckmanb.md5 │ ├── roms │ ├── puckmanb.md5 │ └── put_roms_here │ └── scala │ ├── mr1 │ ├── Decode.scala │ ├── Execute.scala │ ├── Fetch.scala │ ├── MR1.scala │ ├── RegFile.scala │ ├── Riscv.scala │ ├── Writeback.scala │ └── cpu_ram.scala │ └── panoman │ ├── MR1Top.scala │ ├── PacmanClock.scala │ ├── Pano.scala │ ├── PanoAudio.scala │ ├── PanoCore.scala │ ├── PanoIOs.scala │ ├── PanomanTop.scala │ └── PanomonMain.scala ├── sw ├── .gitignore ├── Makefile ├── audio.c ├── audio.h ├── global.h ├── i2c.c ├── i2c.h ├── mcp23017.h ├── progmem.c ├── reg.h ├── sections.lds ├── start.S └── top_defines.h └── xilinx ├── .gitignore ├── Makefile ├── Pano.bit ├── pacman_clk.vhd ├── pacman_clk.xaw ├── pacman_clk1.vhd ├── pacman_clk1.xaw ├── pacman_clk1_arwz.ucf ├── pacman_clk_arwz.ucf ├── pano.cgp ├── panoman.xise ├── progmem.bmm └── top.ucf /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | *.log 3 | *.bak 4 | .*.swp 5 | *.bin 6 | *.vpw 7 | *.vtg 8 | *.vpwhist 9 | 10 | # sbt specific 11 | .cache/ 12 | .history/ 13 | .lib/ 14 | dist/* 15 | target 16 | lib_managed/ 17 | src_managed/ 18 | project/boot/ 19 | project/plugins/project/ 20 | 21 | # Scala-IDE specific 22 | .scala_dependencies 23 | .worksheet 24 | 25 | .idea 26 | out 27 | 28 | # Eclipse 29 | bin/ 30 | .classpath 31 | .project 32 | .settings 33 | .cache-main 34 | 35 | #User 36 | /*.vhd 37 | /*.v 38 | *.cf 39 | *.json 40 | *.vcd 41 | !tester/src/test/resources/*.vhd 42 | cpu0.yaml 43 | simWorkspace/ 44 | tmp/ 45 | skip/ 46 | misc/romgen/romgen 47 | 48 | # Roms 49 | src/main/roms 50 | 51 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CLEAN_LOG=-Dsbt.log.noformat=true 2 | 3 | sim: 4 | sbt $(CLEAN_LOG) "test-only rt.PanoTester" 5 | 6 | syn: 7 | sbt $(CLEAN_LOG) "run-main panoman.PanomanTop" 8 | 9 | waves: 10 | gtkwave -o simWorkspace/PanoCoreDut/test.vcd & 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [![](./assets/pano_man.png)](./assets/pano_man_large.png) 2 | 3 | ## PanoMan 4 | This project simulates the classic Pacman arcade game on a first generation PanoLogic thin client. 5 | 6 | Why? 7 | I absolutely love hacking surplus gear for new purposes, that and I spent way too much time playing Pacman in my youth. I was also interested in learning Verilog and/or VHDL but now that I've played around with SpinalHDL I'm hooked. 8 | 9 | This project is a Frankenstein's monster of code from many different places written in 3 different HDLs: VHDL, Verilog and SpinalHDL. Additionally the project combines a modern RISC-V processor with a archaic Z80. Amazingly enough it was fairly easy to get everything working together largely thanks to SpinalHDL. 10 | 11 | ## Heritage 12 | This project is essentially a small layer of "glue" code that ties together the work of others including: 13 | 14 | * Tom Verbeure's ray tracer [project](https://github.com/tomverbeure/rt) which was used as the basic infrastructure to quickly get code up and running on the Pano. 15 | * [Mike J's](http://www.fpgaarcade.com/author/mikej/) simulation model of the Pacman hardware in VHDL for the Spartan 3E. 16 | * The [Papilio-Arcade](https://github.com/GadgetFactory/Papilio-Arcade.git) project modifications of MikeJ's project for the Papilio platform. 17 | * Daniel Wallner's Z80 CPU [core](https://opencores.org/projects/tv80). 18 | * Tom Verbeure's amazing reverse engineering efforts and Pano logic [bring up](https://github.com/tomverbeure/panologic) code. 19 | * The [SpinalHDL](https://github.com/SpinalHDL) project. 20 | 21 | ## Why a RISC-V ?? 22 | 23 | The sound subsystem in the Pano is based on a codec from Wolfson which must be initialized before it can be used. I had no interest creating hardware to do the initialization so that leaves software. I had even less interest in trying to patch the Pacman Z80 ROMs so ... just drop in a 32 bits processor, since it was easy (*REALLY EASY* since Tom did all the work so it was already there). 24 | 25 | Additionally the RISC-V is used to poll the handle the I2C port expander and it will eventually be used to handle USB as well. 26 | 27 | ## HW Requirements 28 | 29 | * A Pano Logic G1 (the one with a VGA port) 30 | * A suitable 5 volt power supply 31 | * A JTAG programmer to load the bitstream into the FPGA. 32 | 33 | If you want to actually be able to play a game you'll also need: 34 | 35 | * A switch style joystick. 36 | * Soldering skills to connect the joystick to the Pano **-or-** one of Tom's I2C expansion boards. 37 | 38 | ## Software Requirements 39 | 40 | The free Webpack version of Xilinx [ISE 14.7](https://www.xilinx.com/support/download/index.html/content/xilinx/en/downloadNav/vivado-design-tools/archive-ise.html) is needed to program the Pano device. This will also allow you regenerate the .bit file from VHDL and Verilog sources. Do **NOT** download the latest Windows 10 version as it does not support the Spartan 3E family of chips used in the first generation of the Pano device. 41 | 42 | Either Windows or Linux can be used to recreate the .bit file if the ROMs are updated, but Linux is probably necessary to make wider changes to the project. 43 | 44 | If you simply want to run the pong demo on your Pano, then all you need to do is load a pre-made [bitstream](./xilinx/Pano.bit) into the device usings Xilinx's Impact tool. 45 | 46 | ## ROMs 47 | 48 | For legal reasons the Pacman ROM images are **NOT** included in this project, instead David Widel's Pong demo written for the same hardware has been provided. 49 | 50 | In order to run the Pacman you will need to create ROM image files from an actual arcade game or download the images from elsewhere on the Internet. These are the same files needed by the infamous [Mame project](https://www.mamedev.org/) so they should be relatively easy to locate. 51 | 52 | ## Joystick Interface 53 | Video and sound weren't much of a challenge since Tom Verbeur had already done all of the ground work there. 54 | 55 | The joystick, coin detectors, and start buttons on the other hand presented a bit of a challenge. Normally a Pacman game needs 8 or 12 GPIO inputs: 56 | 57 | 1. Two inputs for the two coin slots. 58 | 1. One input for the 1 player game start button. 59 | 1. One input for the 2 player game start button. 60 | 1. Eight inputs for 2 joysticks for the cocktail table version or four inputs for one joystick on the upright version. 61 | 62 | The obvious way to connect a Joystick to the Pano is to use one of the USB ports, but that's a problem because there's no code for the USB port yet and it looks like a major undertaking. 63 | 64 | Another solution would be to use an I2C port expander. This requires building an external interface, but does not require any modifications to the Pano. The benefit of an I2C port expander is that it provides more than enough inputs to implement the cocktail version of Pacman with separate joysticks for 2 players. 65 | 66 | The Pano does have some signals that are relatively easy to access that could be considered GPIOs and there are JUST enough for Pacman if we restrict ourself to a single player in the "Free" play mode. This requires modifications to the Pano to bring out the "GPIO" lines. 67 | 68 | #### "GPIO" Joystick Interface 69 | The Pano has 6 signals that can be considered as "GPIO" ports, three are used to drive the LEDs, one is used to read the"Pano" button, and 2 are connected to the VGA monitors Display Data Channel (DDC) port. 70 | 71 | One surprise was that unlike the green and blue LEDs the red LED is not driven directly by a Xilinx pin so it's can't be used as an input without hardware modifications. This leaves us with 5 GPIOs and one output port that are easily accessible. 72 | 73 | The start button is easy, we'll just use the existing "Pano" button for it. 74 | 75 | For the impatient person who isn't concerned about esthetics or physical robustness flying wires are a quick and easy way to hook up the joystick. 76 | 77 | I choose to use a connector to make things more robust, neat and tidy. Since the case is so small adding a connector isn't really an option, however two of the signals are already on the VGA connector and the VGA connector has just enough spare pins for the other two! 78 | 79 | Even with moderate soldering skills adding two jumper wires from the VGA connector from the LEDS is pretty easy. Here's the result: 80 | 81 | ![](./assets/jumpers_small.png) 82 | 83 | Then we can make a Y cable to combine the joystick and VGA cables. Note: The pinout of the DB9 connector matches the pinout of the Atari 2600 joystick. 84 | 85 | 86 | | Signal | Pano | Monitor | Joystick | 87 | |---------|--------|-----------|------------| 88 | | red | 1 |1 | -| 89 | | green | 2 | 2|-| 90 | |blue|3|3|-| 91 | |blue led/left|4|-|3| 92 | |gnd|5|-|8| 93 | |gnd|6|6|-| 94 | |gnd|7|7|-| 95 | |gnd|8|8|-| 96 | |+5V|9|-|7| 97 | |gnd|10|10|-| 98 | |green led/right|11|-|4| 99 | |VGA SDA/down|12|-|2| 100 | |Hsync|13|13|-| 101 | |Vsync|14|14|-| 102 | |VGA SCL/up|15|-|1| 103 | |B input paddle|-|-|5| 104 | |Trigger input|-|-|6| 105 | |A input paddle|-|-|9| 106 | 107 | 108 | ![](./assets/JoystickAdapterCable_small.png) 109 | ![](./assets/cable.png) 110 | 111 | #### I2C Port expander Joystick Interface 112 | 113 | The RISC-V code supports an MCP23017 I2C port expander chip connected to the to VGA monitor's Display Data Channel (DDC) port. If a chip is detected then it will be used instead of the "GPIO" interface. 114 | 115 | There are many other I2C port expander chips that could be used but they are not compatible the current code. The Microchip MCP23017 was chosen for no particular reason. 116 | 117 | When the port expander is detected the code uses the Pano button for the coin detector and the joystick's fire buttons for the one and two player game start buttons. 118 | 119 | The PB5 GPIO line can be grounded to configure the game for the cocktail table configuation. 120 | 121 | Finally the PB6 GPIO line can be grounded to mute the game audio for late night/early morning games. 122 | 123 | #### Tom's Joystick Interface 124 | Tom Verbeure has created a [PCB](https://tomverbeure.github.io/2019/02/05/VGA-I2C-My-First-PCB.html) for an I2C port expander for the Pano. One huge advantage of Tom's board is that it eliminates the need to build a custom breakout cable. 125 | 126 | ![](https://tomverbeure.github.io/assets/vga_i2c/Joystick.JPG) 127 | 128 | #### Homebrew I2C Joystick Interface 129 | 130 | Another alternative is to use of the MCP23017 "breakout boards" that are available on Amazon or ebay. The MCP23017 is also available in a breadboard friendly DIP package if that's your thing. 131 | 132 | 133 | **Connections** 134 | 135 | | Signal | MCP23017 | Joystick | Pano | Notes | 136 | |-|-|-|-|-| 137 | | P1 right | 21 - PA0 | #1 - 4 |-|| 138 | | P1 left | 22 - PA1 | #1 - 3 |-|| 139 | | P1 down | 23 - PA2 | #1 - 2 |-|| 140 | | P1 trigger | 24 - PA3 | #1 - 6 |-|1 player start| 141 | | P1 up | 25 - PA4 | #1 - 1 |-|| 142 | | (SW1) | 26 - PA5 | - | - | not used | 143 | | (SW2) | 27 - PA6 | - | - | not used | 144 | | (LED1) | 29 - PA7 | - | - | not used | 145 | | P2 right | 1 - PB0 | #2 - 4 |-|| 146 | | P2 left | 2 - PB1 | #2 - 3 |-|| 147 | | P2 down | 3 - PB2 | #2 - 2 |-|| 148 | | P2 trigger | 4 - PB3 | | 6 |-| 2 player start| 149 | | P2 up | 5 - PB4 | #2 - 1 |-|| 150 | | Cabinet | 6 - PB5 | - | -| Ground for cocktail version | 151 | | Mute | 7 - PB6 | - | -| Ground to mute audio | 152 | | (LED1_2) | 8 - PB7 | - | - | not used | 153 | | SCL | 12 | - | 15 || 154 | | SDA | 13 | - | 12|| 155 | | Ground | 10, 15, 16, 17 | both - 8 | 5 || 156 | | +5V | 9, 18 | - | 9 || 157 | 158 | Note: the second joystick is **only** needed for the cocktail version of the game where two players sit on either end of a table and look down on the screen. In this configuration the screen rotates between rounds so that it is right side up for the current player. Two player share the same joystick on the upright version of the game. 159 | 160 | Here's an example of the breakout board version: 161 | 162 | ![](./assets/i2c_expander.png) 163 | 164 | ## Updating ROMs 165 | To update the bitstream with new ROMs: 166 | 167 | 1. Place the ROM images in ~/pano_man/src/main/roms. 168 | 2. Run "./build_roms_pacman.sh" (or build_roms.bat on Windoze) from the ~/pano_man/src/main/pacman subdirectory. 169 | 4. Start ISE. 170 | 5. From the ISE IDE select "Pano" from the Design/Hierarchy window. 171 | 6. Right click on "Generate Programming File" in the Design/Processes windows and then select "Rerun All". 172 | 7. Go get coffee while you wait for the programming file (pano.bit) to be generated. 173 | 8. Select iMpact from the Tools menu, click "Ok", to dismiss the warning dialog. 174 | 175 | 176 | ## Building Everything from Scratch 177 | 178 | **NB:** While it may be possible to use Windows for development I haven't tried it and don't recommend it. 179 | 180 | * Install RISC-V GCC compiler suite 181 | 182 | See the [picorv32](https://github.com/cliffordwolf/picorv32) github project on how to do it. Warning: this make take a long time to complete! 183 | 184 | * Install [SpinalHDL](https://github.com/SpinalHDL/SpinalHDL) 185 | 186 | The actual installation instructions can be found in the [VexRisc]( https://github.com/SpinalHDL/VexRiscv#dependencies) project. 187 | 188 | * Clone this github repository into `~/pano_man` 189 | * Change into the root of the repository `~/pano_man` 190 | 191 | * Build the firmware for the RISC-V processor 192 | 193 | ``` 194 | (cd sw;make) 195 | ``` 196 | This creates a file called `~/pano_man/sw/progmem8k.bin` 197 | 198 | * Build the Verilog for synthesis 199 | 200 | When you run this, not only will you create the `Pano.v` file, but also a bunch of `.bin` files that contain RAM initialization contents, which will be loaded by Xilinx ISE during synthesis. 201 | 202 | ``` 203 | make syn 204 | ``` 205 | 206 | * Fire up Xilinx ISE 207 | ``` 208 | cd xilinx 209 | make ise 210 | ``` 211 | 212 | * Create the bitstream 213 | 214 | * File -> Open Project -> ~/pano_man/xilinx/panoman.xise 215 | * Double click on 'Generate Programming File' 216 | 217 | 218 | * Fire up Xilinx Impact 219 | 220 | ``` 221 | cd ~/pano_man/xilinx 222 | make impact 223 | ``` 224 | 225 | * Load bitstream into the device 226 | 227 | 228 | 229 | ## Possible Future Projects 230 | 231 | 232 | * Port the code to the [second generation](https://github.com/tomverbeure/panologic-g2) Pano 233 | * Add support for USB Joysticks 234 | * Port other games that ran on the same hardware such as Invaders and Galaxian 235 | 236 | ## Notes 237 | 238 | 1. The Pacman ROM for MAME images are typically found in a zip file named *puckmanb.zip*. 239 | 2. This project has been featured on [Hackaday](https://hackaday.com/2019/01/11/pac-man-fever-comes-to-the-pano-logic-fpga) ! 240 | 3. If you build/use/modify this project I'd enjoy hearing about it. You can find my email address in the git log. 241 | -------------------------------------------------------------------------------- /assets/JoystickAdapterCable_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skiphansen/pano_man/e7759f816c179f253180fe34e4dd040a5fa5c0cd/assets/JoystickAdapterCable_small.png -------------------------------------------------------------------------------- /assets/cable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skiphansen/pano_man/e7759f816c179f253180fe34e4dd040a5fa5c0cd/assets/cable.png -------------------------------------------------------------------------------- /assets/i2c_expander.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skiphansen/pano_man/e7759f816c179f253180fe34e4dd040a5fa5c0cd/assets/i2c_expander.png -------------------------------------------------------------------------------- /assets/jumpers_small.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skiphansen/pano_man/e7759f816c179f253180fe34e4dd040a5fa5c0cd/assets/jumpers_small.JPG -------------------------------------------------------------------------------- /assets/jumpers_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skiphansen/pano_man/e7759f816c179f253180fe34e4dd040a5fa5c0cd/assets/jumpers_small.png -------------------------------------------------------------------------------- /assets/pano_man.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skiphansen/pano_man/e7759f816c179f253180fe34e4dd040a5fa5c0cd/assets/pano_man.png -------------------------------------------------------------------------------- /assets/pano_man_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skiphansen/pano_man/e7759f816c179f253180fe34e4dd040a5fa5c0cd/assets/pano_man_large.png -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | 2 | lazy val root = (project in file(".")). 3 | settings( 4 | inThisBuild(List( 5 | organization := "com.github.spinalhdl", 6 | scalaVersion := "2.11.6", 7 | version := "0.1.0-SNAPSHOT" 8 | )), 9 | libraryDependencies ++= Seq( 10 | "com.github.spinalhdl" % "spinalhdl-core_2.11" % "1.2.2", 11 | "com.github.spinalhdl" % "spinalhdl-lib_2.11" % "1.2.2", 12 | "org.scalatest" % "scalatest_2.11" % "2.2.1", 13 | "org.yaml" % "snakeyaml" % "1.8" 14 | ), 15 | name := "panoman" 16 | ) 17 | 18 | addCompilerPlugin("org.scala-lang.plugins" % "scala-continuations-plugin_2.11.6" % "1.0.2") 19 | scalacOptions += "-P:continuations:enable" 20 | fork := true 21 | -------------------------------------------------------------------------------- /misc/create_mif.rb: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env ruby 2 | 3 | require 'optparse' 4 | require 'pp' 5 | 6 | options = {} 7 | OptionParser.new do |opts| 8 | opts.banner = "Usage: create_mif.rb [options]" 9 | opts.on("-v", "--[no-]verbose", "Run verbosely") do |v| 10 | options[:verbose] = v 11 | end 12 | 13 | opts.on("-fFORMAT", "--format=FORMAT", "Specify output format ('mif', 'hex', 'coe', 'mem')") do |f| 14 | options[:format] = f 15 | end 16 | 17 | opts.on("-dDEPTH", "--depth=DEPTH", Integer, "Memory depth") do |d| 18 | options[:depth] = d 19 | end 20 | 21 | opts.on("-wWIDTH", "--width=WIDTH", Integer, "Memory width (bits)") do |w| 22 | options[:width] = w 23 | end 24 | 25 | opts.on("-oOFFSET", "--offset=OFFSET", Integer, "First byte to use of the binary input file (default = 0)") do |o| 26 | options[:offset] = o 27 | end 28 | 29 | opts.on("-iINCREMENT", "--increment=INCREMENT", Integer, "How many bytes to the next byte (default = 1)") do |i| 30 | options[:increment] = i 31 | end 32 | 33 | end.parse! 34 | 35 | start_offset = options[:offset] || 0 36 | increment = options[:increment] || 1 37 | 38 | bin = File.open(ARGV[0], "rb").read 39 | bytes = bin.unpack("C*")[start_offset..-1].each_slice(increment).collect{ |a| a.first } 40 | 41 | depth = options[:depth] || bytes.size 42 | width = options[:width] || 8 43 | format = options[:format] || "mif" 44 | 45 | bytes_per_word = (width+7)>>3 46 | nr_addr_bits = Math.log2(depth).ceil 47 | 48 | if options[:verbose] 49 | STDERR.puts "output format : #{format}" 50 | STDERR.puts "depth : #{depth}" 51 | STDERR.puts "width : #{width}" 52 | STDERR.puts "bytes per word: #{bytes_per_word}" 53 | STDERR.puts "start offset : #{start_offset}" 54 | STDERR.puts "increment : #{increment}" 55 | end 56 | 57 | if format == "mif" 58 | puts %{-- Created by create_mif.rb 59 | DEPTH = #{depth}; 60 | WIDTH = #{width}; 61 | ADDRESS_RADIX = HEX; 62 | DATA_RADIX = HEX; 63 | CONTENT 64 | BEGIN 65 | } 66 | 67 | addr_fmt_string = "%%0%dx" % ((nr_addr_bits+3)>>2) 68 | data_fmt_string = "%%0%dx" % (bytes_per_word * 2) 69 | 70 | fmt_string = "#{addr_fmt_string}: #{data_fmt_string};" 71 | 72 | words = bytes.each_slice(bytes_per_word) 73 | words.each_with_index do |w, addr| 74 | value = 0 75 | w.reverse.collect { |b| value = value * 256 + b } 76 | puts fmt_string % [addr, value] 77 | end 78 | 79 | if words.size < depth 80 | puts "[#{addr_fmt_string}..#{addr_fmt_string}]: #{data_fmt_string};" % [ words.size, depth-1, 0 ] 81 | end 82 | 83 | puts "END;" 84 | puts 85 | 86 | elsif format == "coe" 87 | puts %{; Created by create_mif.rb 88 | ; block memory configuration: 89 | ; DEPTH = #{depth}; 90 | ; WIDTH = #{width}; 91 | memory_initialization_radix=16; 92 | memory_initialization_vector=} 93 | 94 | words = bytes.each_slice(bytes_per_word).collect do |w| 95 | value = 0 96 | w.reverse.collect { |b| value = value * 256 + b } 97 | value 98 | end 99 | 100 | (depth - words.size).times { words << 0 } 101 | data_fmt_string = "%%0%dx" % (bytes_per_word * 2) 102 | str = words.collect{ |w| data_fmt_string % w }.join(",\n") + ";" 103 | 104 | puts str 105 | 106 | elsif format == "hex" 107 | 108 | words = bytes.each_slice(bytes_per_word).collect do |w| 109 | value = 0 110 | w.reverse.collect { |b| value = value * 256 + b } 111 | value 112 | end 113 | 114 | (depth - words.size).times { words << 0 } 115 | 116 | data_fmt_string = "%%0%dx" % (bytes_per_word * 2) 117 | str = words.collect{ |w| data_fmt_string % w }.join("\n") 118 | 119 | puts str 120 | 121 | elsif format == "mem" 122 | 123 | words = bytes.each_slice(bytes_per_word).collect do |w| 124 | value = 0 125 | w.reverse.collect { |b| value = value * 256 + b } 126 | value 127 | end 128 | 129 | (depth - words.size).times { words << 0 } 130 | 131 | data_fmt_string = "%%0%dx" % (bytes_per_word * 2) 132 | str = words.collect{ |w| data_fmt_string % w }.join("\n") 133 | 134 | puts "@00000000" 135 | puts str 136 | 137 | else 138 | Kernel.abort("Unknown format '#{format}'! Aborting...") 139 | end 140 | -------------------------------------------------------------------------------- /misc/romgen/libgcc_s_dw2-1.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skiphansen/pano_man/e7759f816c179f253180fe34e4dd040a5fa5c0cd/misc/romgen/libgcc_s_dw2-1.dll -------------------------------------------------------------------------------- /misc/romgen/libstdc++-6.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skiphansen/pano_man/e7759f816c179f253180fe34e4dd040a5fa5c0cd/misc/romgen/libstdc++-6.dll -------------------------------------------------------------------------------- /misc/romgen/romgen.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skiphansen/pano_man/e7759f816c179f253180fe34e4dd040a5fa5c0cd/misc/romgen/romgen.exe -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.16 -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "5.2.1") 2 | 3 | -------------------------------------------------------------------------------- /src/main/T80/T80_ALU.vhd: -------------------------------------------------------------------------------- 1 | -- **** 2 | -- T80(b) core. In an effort to merge and maintain bug fixes .... 3 | -- 4 | -- 5 | -- Ver 301 parity flag is just parity for 8080, also overflow for Z80, by Sean Riddle 6 | -- Ver 300 started tidyup 7 | -- MikeJ March 2005 8 | -- Latest version from www.fpgaarcade.com (original www.opencores.org) 9 | -- 10 | -- **** 11 | -- 12 | -- Z80 compatible microprocessor core 13 | -- 14 | -- Version : 0247 15 | -- 16 | -- Copyright (c) 2001-2002 Daniel Wallner (jesus@opencores.org) 17 | -- 18 | -- All rights reserved 19 | -- 20 | -- Redistribution and use in source and synthezised forms, with or without 21 | -- modification, are permitted provided that the following conditions are met: 22 | -- 23 | -- Redistributions of source code must retain the above copyright notice, 24 | -- this list of conditions and the following disclaimer. 25 | -- 26 | -- Redistributions in synthesized form must reproduce the above copyright 27 | -- notice, this list of conditions and the following disclaimer in the 28 | -- documentation and/or other materials provided with the distribution. 29 | -- 30 | -- Neither the name of the author nor the names of other contributors may 31 | -- be used to endorse or promote products derived from this software without 32 | -- specific prior written permission. 33 | -- 34 | -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 35 | -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 36 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 37 | -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 38 | -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 39 | -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 40 | -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 41 | -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 42 | -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 43 | -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 44 | -- POSSIBILITY OF SUCH DAMAGE. 45 | -- 46 | -- Please report bugs to the author, but before you do so, please 47 | -- make sure that this is not a derivative work and that 48 | -- you have the latest version of this file. 49 | -- 50 | -- The latest version of this file can be found at: 51 | -- http://www.opencores.org/cvsweb.shtml/t80/ 52 | -- 53 | -- Limitations : 54 | -- 55 | -- File history : 56 | -- 57 | -- 0214 : Fixed mostly flags, only the block instructions now fail the zex regression test 58 | -- 59 | -- 0238 : Fixed zero flag for 16 bit SBC and ADC 60 | -- 61 | -- 0240 : Added GB operations 62 | -- 63 | -- 0242 : Cleanup 64 | -- 65 | -- 0247 : Cleanup 66 | -- 67 | 68 | library IEEE; 69 | use IEEE.std_logic_1164.all; 70 | use IEEE.numeric_std.all; 71 | 72 | entity T80_ALU is 73 | generic( 74 | Mode : integer := 0; 75 | Flag_C : integer := 0; 76 | Flag_N : integer := 1; 77 | Flag_P : integer := 2; 78 | Flag_X : integer := 3; 79 | Flag_H : integer := 4; 80 | Flag_Y : integer := 5; 81 | Flag_Z : integer := 6; 82 | Flag_S : integer := 7 83 | ); 84 | port( 85 | Arith16 : in std_logic; 86 | Z16 : in std_logic; 87 | ALU_Op : in std_logic_vector(3 downto 0); 88 | IR : in std_logic_vector(5 downto 0); 89 | ISet : in std_logic_vector(1 downto 0); 90 | BusA : in std_logic_vector(7 downto 0); 91 | BusB : in std_logic_vector(7 downto 0); 92 | F_In : in std_logic_vector(7 downto 0); 93 | Q : out std_logic_vector(7 downto 0); 94 | F_Out : out std_logic_vector(7 downto 0) 95 | ); 96 | end T80_ALU; 97 | 98 | architecture rtl of T80_ALU is 99 | 100 | procedure AddSub(A : std_logic_vector; 101 | B : std_logic_vector; 102 | Sub : std_logic; 103 | Carry_In : std_logic; 104 | signal Res : out std_logic_vector; 105 | signal Carry : out std_logic) is 106 | 107 | variable B_i : unsigned(A'length - 1 downto 0); 108 | variable Res_i : unsigned(A'length + 1 downto 0); 109 | begin 110 | if Sub = '1' then 111 | B_i := not unsigned(B); 112 | else 113 | B_i := unsigned(B); 114 | end if; 115 | 116 | Res_i := unsigned("0" & A & Carry_In) + unsigned("0" & B_i & "1"); 117 | Carry <= Res_i(A'length + 1); 118 | Res <= std_logic_vector(Res_i(A'length downto 1)); 119 | end; 120 | 121 | -- AddSub variables (temporary signals) 122 | signal UseCarry : std_logic; 123 | signal Carry7_v : std_logic; 124 | signal Overflow_v : std_logic; 125 | signal HalfCarry_v : std_logic; 126 | signal Carry_v : std_logic; 127 | signal Q_v : std_logic_vector(7 downto 0); 128 | 129 | signal BitMask : std_logic_vector(7 downto 0); 130 | 131 | begin 132 | 133 | with IR(5 downto 3) select BitMask <= "00000001" when "000", 134 | "00000010" when "001", 135 | "00000100" when "010", 136 | "00001000" when "011", 137 | "00010000" when "100", 138 | "00100000" when "101", 139 | "01000000" when "110", 140 | "10000000" when others; 141 | 142 | UseCarry <= not ALU_Op(2) and ALU_Op(0); 143 | AddSub(BusA(3 downto 0), BusB(3 downto 0), ALU_Op(1), ALU_Op(1) xor (UseCarry and F_In(Flag_C)), Q_v(3 downto 0), HalfCarry_v); 144 | AddSub(BusA(6 downto 4), BusB(6 downto 4), ALU_Op(1), HalfCarry_v, Q_v(6 downto 4), Carry7_v); 145 | AddSub(BusA(7 downto 7), BusB(7 downto 7), ALU_Op(1), Carry7_v, Q_v(7 downto 7), Carry_v); 146 | 147 | -- bug fix - parity flag is just parity for 8080, also overflow for Z80 148 | process (Carry_v, Carry7_v, Q_v) 149 | begin 150 | if(Mode=2) then 151 | OverFlow_v <= not (Q_v(0) xor Q_v(1) xor Q_v(2) xor Q_v(3) xor 152 | Q_v(4) xor Q_v(5) xor Q_v(6) xor Q_v(7)); else 153 | OverFlow_v <= Carry_v xor Carry7_v; 154 | end if; 155 | end process; 156 | 157 | process (Arith16, ALU_OP, F_In, BusA, BusB, IR, Q_v, Carry_v, HalfCarry_v, OverFlow_v, BitMask, ISet, Z16) 158 | variable Q_t : std_logic_vector(7 downto 0); 159 | variable DAA_Q : unsigned(8 downto 0); 160 | begin 161 | Q_t := "--------"; 162 | F_Out <= F_In; 163 | DAA_Q := "---------"; 164 | case ALU_Op is 165 | when "0000" | "0001" | "0010" | "0011" | "0100" | "0101" | "0110" | "0111" => 166 | F_Out(Flag_N) <= '0'; 167 | F_Out(Flag_C) <= '0'; 168 | case ALU_OP(2 downto 0) is 169 | when "000" | "001" => -- ADD, ADC 170 | Q_t := Q_v; 171 | F_Out(Flag_C) <= Carry_v; 172 | F_Out(Flag_H) <= HalfCarry_v; 173 | F_Out(Flag_P) <= OverFlow_v; 174 | when "010" | "011" | "111" => -- SUB, SBC, CP 175 | Q_t := Q_v; 176 | F_Out(Flag_N) <= '1'; 177 | F_Out(Flag_C) <= not Carry_v; 178 | F_Out(Flag_H) <= not HalfCarry_v; 179 | F_Out(Flag_P) <= OverFlow_v; 180 | when "100" => -- AND 181 | Q_t(7 downto 0) := BusA and BusB; 182 | F_Out(Flag_H) <= '1'; 183 | when "101" => -- XOR 184 | Q_t(7 downto 0) := BusA xor BusB; 185 | F_Out(Flag_H) <= '0'; 186 | when others => -- OR "110" 187 | Q_t(7 downto 0) := BusA or BusB; 188 | F_Out(Flag_H) <= '0'; 189 | end case; 190 | if ALU_Op(2 downto 0) = "111" then -- CP 191 | F_Out(Flag_X) <= BusB(3); 192 | F_Out(Flag_Y) <= BusB(5); 193 | else 194 | F_Out(Flag_X) <= Q_t(3); 195 | F_Out(Flag_Y) <= Q_t(5); 196 | end if; 197 | if Q_t(7 downto 0) = "00000000" then 198 | F_Out(Flag_Z) <= '1'; 199 | if Z16 = '1' then 200 | F_Out(Flag_Z) <= F_In(Flag_Z); -- 16 bit ADC,SBC 201 | end if; 202 | else 203 | F_Out(Flag_Z) <= '0'; 204 | end if; 205 | F_Out(Flag_S) <= Q_t(7); 206 | case ALU_Op(2 downto 0) is 207 | when "000" | "001" | "010" | "011" | "111" => -- ADD, ADC, SUB, SBC, CP 208 | when others => 209 | F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor 210 | Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7)); 211 | end case; 212 | if Arith16 = '1' then 213 | F_Out(Flag_S) <= F_In(Flag_S); 214 | F_Out(Flag_Z) <= F_In(Flag_Z); 215 | F_Out(Flag_P) <= F_In(Flag_P); 216 | end if; 217 | when "1100" => 218 | -- DAA 219 | F_Out(Flag_H) <= F_In(Flag_H); 220 | F_Out(Flag_C) <= F_In(Flag_C); 221 | DAA_Q(7 downto 0) := unsigned(BusA); 222 | DAA_Q(8) := '0'; 223 | if F_In(Flag_N) = '0' then 224 | -- After addition 225 | -- Alow > 9 or H = 1 226 | if DAA_Q(3 downto 0) > 9 or F_In(Flag_H) = '1' then 227 | if (DAA_Q(3 downto 0) > 9) then 228 | F_Out(Flag_H) <= '1'; 229 | else 230 | F_Out(Flag_H) <= '0'; 231 | end if; 232 | DAA_Q := DAA_Q + 6; 233 | end if; 234 | -- new Ahigh > 9 or C = 1 235 | if DAA_Q(8 downto 4) > 9 or F_In(Flag_C) = '1' then 236 | DAA_Q := DAA_Q + 96; -- 0x60 237 | end if; 238 | else 239 | -- After subtraction 240 | if DAA_Q(3 downto 0) > 9 or F_In(Flag_H) = '1' then 241 | if DAA_Q(3 downto 0) > 5 then 242 | F_Out(Flag_H) <= '0'; 243 | end if; 244 | DAA_Q(7 downto 0) := DAA_Q(7 downto 0) - 6; 245 | end if; 246 | if unsigned(BusA) > 153 or F_In(Flag_C) = '1' then 247 | DAA_Q := DAA_Q - 352; -- 0x160 248 | end if; 249 | end if; 250 | F_Out(Flag_X) <= DAA_Q(3); 251 | F_Out(Flag_Y) <= DAA_Q(5); 252 | F_Out(Flag_C) <= F_In(Flag_C) or DAA_Q(8); 253 | Q_t := std_logic_vector(DAA_Q(7 downto 0)); 254 | if DAA_Q(7 downto 0) = "00000000" then 255 | F_Out(Flag_Z) <= '1'; 256 | else 257 | F_Out(Flag_Z) <= '0'; 258 | end if; 259 | F_Out(Flag_S) <= DAA_Q(7); 260 | F_Out(Flag_P) <= not (DAA_Q(0) xor DAA_Q(1) xor DAA_Q(2) xor DAA_Q(3) xor 261 | DAA_Q(4) xor DAA_Q(5) xor DAA_Q(6) xor DAA_Q(7)); 262 | when "1101" | "1110" => 263 | -- RLD, RRD 264 | Q_t(7 downto 4) := BusA(7 downto 4); 265 | if ALU_Op(0) = '1' then 266 | Q_t(3 downto 0) := BusB(7 downto 4); 267 | else 268 | Q_t(3 downto 0) := BusB(3 downto 0); 269 | end if; 270 | F_Out(Flag_H) <= '0'; 271 | F_Out(Flag_N) <= '0'; 272 | F_Out(Flag_X) <= Q_t(3); 273 | F_Out(Flag_Y) <= Q_t(5); 274 | if Q_t(7 downto 0) = "00000000" then 275 | F_Out(Flag_Z) <= '1'; 276 | else 277 | F_Out(Flag_Z) <= '0'; 278 | end if; 279 | F_Out(Flag_S) <= Q_t(7); 280 | F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor 281 | Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7)); 282 | when "1001" => 283 | -- BIT 284 | Q_t(7 downto 0) := BusB and BitMask; 285 | F_Out(Flag_S) <= Q_t(7); 286 | if Q_t(7 downto 0) = "00000000" then 287 | F_Out(Flag_Z) <= '1'; 288 | F_Out(Flag_P) <= '1'; 289 | else 290 | F_Out(Flag_Z) <= '0'; 291 | F_Out(Flag_P) <= '0'; 292 | end if; 293 | F_Out(Flag_H) <= '1'; 294 | F_Out(Flag_N) <= '0'; 295 | F_Out(Flag_X) <= '0'; 296 | F_Out(Flag_Y) <= '0'; 297 | if IR(2 downto 0) /= "110" then 298 | F_Out(Flag_X) <= BusB(3); 299 | F_Out(Flag_Y) <= BusB(5); 300 | end if; 301 | when "1010" => 302 | -- SET 303 | Q_t(7 downto 0) := BusB or BitMask; 304 | when "1011" => 305 | -- RES 306 | Q_t(7 downto 0) := BusB and not BitMask; 307 | when "1000" => 308 | -- ROT 309 | case IR(5 downto 3) is 310 | when "000" => -- RLC 311 | Q_t(7 downto 1) := BusA(6 downto 0); 312 | Q_t(0) := BusA(7); 313 | F_Out(Flag_C) <= BusA(7); 314 | when "010" => -- RL 315 | Q_t(7 downto 1) := BusA(6 downto 0); 316 | Q_t(0) := F_In(Flag_C); 317 | F_Out(Flag_C) <= BusA(7); 318 | when "001" => -- RRC 319 | Q_t(6 downto 0) := BusA(7 downto 1); 320 | Q_t(7) := BusA(0); 321 | F_Out(Flag_C) <= BusA(0); 322 | when "011" => -- RR 323 | Q_t(6 downto 0) := BusA(7 downto 1); 324 | Q_t(7) := F_In(Flag_C); 325 | F_Out(Flag_C) <= BusA(0); 326 | when "100" => -- SLA 327 | Q_t(7 downto 1) := BusA(6 downto 0); 328 | Q_t(0) := '0'; 329 | F_Out(Flag_C) <= BusA(7); 330 | when "110" => -- SLL (Undocumented) / SWAP 331 | if Mode = 3 then 332 | Q_t(7 downto 4) := BusA(3 downto 0); 333 | Q_t(3 downto 0) := BusA(7 downto 4); 334 | F_Out(Flag_C) <= '0'; 335 | else 336 | Q_t(7 downto 1) := BusA(6 downto 0); 337 | Q_t(0) := '1'; 338 | F_Out(Flag_C) <= BusA(7); 339 | end if; 340 | when "101" => -- SRA 341 | Q_t(6 downto 0) := BusA(7 downto 1); 342 | Q_t(7) := BusA(7); 343 | F_Out(Flag_C) <= BusA(0); 344 | when others => -- SRL 345 | Q_t(6 downto 0) := BusA(7 downto 1); 346 | Q_t(7) := '0'; 347 | F_Out(Flag_C) <= BusA(0); 348 | end case; 349 | F_Out(Flag_H) <= '0'; 350 | F_Out(Flag_N) <= '0'; 351 | F_Out(Flag_X) <= Q_t(3); 352 | F_Out(Flag_Y) <= Q_t(5); 353 | F_Out(Flag_S) <= Q_t(7); 354 | if Q_t(7 downto 0) = "00000000" then 355 | F_Out(Flag_Z) <= '1'; 356 | else 357 | F_Out(Flag_Z) <= '0'; 358 | end if; 359 | F_Out(Flag_P) <= not (Q_t(0) xor Q_t(1) xor Q_t(2) xor Q_t(3) xor 360 | Q_t(4) xor Q_t(5) xor Q_t(6) xor Q_t(7)); 361 | if ISet = "00" then 362 | F_Out(Flag_P) <= F_In(Flag_P); 363 | F_Out(Flag_S) <= F_In(Flag_S); 364 | F_Out(Flag_Z) <= F_In(Flag_Z); 365 | end if; 366 | when others => 367 | null; 368 | end case; 369 | Q <= Q_t; 370 | end process; 371 | end; 372 | -------------------------------------------------------------------------------- /src/main/T80/T80_Pack.vhd: -------------------------------------------------------------------------------- 1 | -- **** 2 | -- T80(b) core. In an effort to merge and maintain bug fixes .... 3 | -- 4 | -- 5 | -- Ver 300 started tidyup 6 | -- MikeJ March 2005 7 | -- Latest version from www.fpgaarcade.com (original www.opencores.org) 8 | -- 9 | -- **** 10 | -- 11 | -- Z80 compatible microprocessor core 12 | -- 13 | -- Version : 0242 14 | -- 15 | -- Copyright (c) 2001-2002 Daniel Wallner (jesus@opencores.org) 16 | -- 17 | -- All rights reserved 18 | -- 19 | -- Redistribution and use in source and synthezised forms, with or without 20 | -- modification, are permitted provided that the following conditions are met: 21 | -- 22 | -- Redistributions of source code must retain the above copyright notice, 23 | -- this list of conditions and the following disclaimer. 24 | -- 25 | -- Redistributions in synthesized form must reproduce the above copyright 26 | -- notice, this list of conditions and the following disclaimer in the 27 | -- documentation and/or other materials provided with the distribution. 28 | -- 29 | -- Neither the name of the author nor the names of other contributors may 30 | -- be used to endorse or promote products derived from this software without 31 | -- specific prior written permission. 32 | -- 33 | -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 34 | -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 35 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 36 | -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 37 | -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 38 | -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 39 | -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 40 | -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 41 | -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 42 | -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 43 | -- POSSIBILITY OF SUCH DAMAGE. 44 | -- 45 | -- Please report bugs to the author, but before you do so, please 46 | -- make sure that this is not a derivative work and that 47 | -- you have the latest version of this file. 48 | -- 49 | -- The latest version of this file can be found at: 50 | -- http://www.opencores.org/cvsweb.shtml/t80/ 51 | -- 52 | -- Limitations : 53 | -- 54 | -- File history : 55 | -- 56 | 57 | library IEEE; 58 | use IEEE.std_logic_1164.all; 59 | 60 | package T80_Pack is 61 | 62 | component T80 63 | generic( 64 | Mode : integer := 0; -- 0 => Z80, 1 => Fast Z80, 2 => 8080, 3 => GB 65 | IOWait : integer := 0; -- 1 => Single cycle I/O, 1 => Std I/O cycle 66 | Flag_C : integer := 0; 67 | Flag_N : integer := 1; 68 | Flag_P : integer := 2; 69 | Flag_X : integer := 3; 70 | Flag_H : integer := 4; 71 | Flag_Y : integer := 5; 72 | Flag_Z : integer := 6; 73 | Flag_S : integer := 7 74 | ); 75 | port( 76 | RESET_n : in std_logic; 77 | CLK_n : in std_logic; 78 | CEN : in std_logic; 79 | WAIT_n : in std_logic; 80 | INT_n : in std_logic; 81 | NMI_n : in std_logic; 82 | BUSRQ_n : in std_logic; 83 | M1_n : out std_logic; 84 | IORQ : out std_logic; 85 | NoRead : out std_logic; 86 | Write : out std_logic; 87 | RFSH_n : out std_logic; 88 | HALT_n : out std_logic; 89 | BUSAK_n : out std_logic; 90 | A : out std_logic_vector(15 downto 0); 91 | DInst : in std_logic_vector(7 downto 0); 92 | DI : in std_logic_vector(7 downto 0); 93 | DO : out std_logic_vector(7 downto 0); 94 | MC : out std_logic_vector(2 downto 0); 95 | TS : out std_logic_vector(2 downto 0); 96 | IntCycle_n : out std_logic; 97 | IntE : out std_logic; 98 | Stop : out std_logic 99 | ); 100 | end component; 101 | 102 | component T80_Reg 103 | port( 104 | Clk : in std_logic; 105 | CEN : in std_logic; 106 | WEH : in std_logic; 107 | WEL : in std_logic; 108 | AddrA : in std_logic_vector(2 downto 0); 109 | AddrB : in std_logic_vector(2 downto 0); 110 | AddrC : in std_logic_vector(2 downto 0); 111 | DIH : in std_logic_vector(7 downto 0); 112 | DIL : in std_logic_vector(7 downto 0); 113 | DOAH : out std_logic_vector(7 downto 0); 114 | DOAL : out std_logic_vector(7 downto 0); 115 | DOBH : out std_logic_vector(7 downto 0); 116 | DOBL : out std_logic_vector(7 downto 0); 117 | DOCH : out std_logic_vector(7 downto 0); 118 | DOCL : out std_logic_vector(7 downto 0) 119 | ); 120 | end component; 121 | 122 | component T80_MCode 123 | generic( 124 | Mode : integer := 0; 125 | Flag_C : integer := 0; 126 | Flag_N : integer := 1; 127 | Flag_P : integer := 2; 128 | Flag_X : integer := 3; 129 | Flag_H : integer := 4; 130 | Flag_Y : integer := 5; 131 | Flag_Z : integer := 6; 132 | Flag_S : integer := 7 133 | ); 134 | port( 135 | IR : in std_logic_vector(7 downto 0); 136 | ISet : in std_logic_vector(1 downto 0); 137 | MCycle : in std_logic_vector(2 downto 0); 138 | F : in std_logic_vector(7 downto 0); 139 | NMICycle : in std_logic; 140 | IntCycle : in std_logic; 141 | MCycles : out std_logic_vector(2 downto 0); 142 | TStates : out std_logic_vector(2 downto 0); 143 | Prefix : out std_logic_vector(1 downto 0); -- None,BC,ED,DD/FD 144 | Inc_PC : out std_logic; 145 | Inc_WZ : out std_logic; 146 | IncDec_16 : out std_logic_vector(3 downto 0); -- BC,DE,HL,SP 0 is inc 147 | Read_To_Reg : out std_logic; 148 | Read_To_Acc : out std_logic; 149 | Set_BusA_To : out std_logic_vector(3 downto 0); -- B,C,D,E,H,L,DI/DB,A,SP(L),SP(M),0,F 150 | Set_BusB_To : out std_logic_vector(3 downto 0); -- B,C,D,E,H,L,DI,A,SP(L),SP(M),1,F,PC(L),PC(M),0 151 | ALU_Op : out std_logic_vector(3 downto 0); 152 | -- ADD, ADC, SUB, SBC, AND, XOR, OR, CP, ROT, BIT, SET, RES, DAA, RLD, RRD, None 153 | Save_ALU : out std_logic; 154 | PreserveC : out std_logic; 155 | Arith16 : out std_logic; 156 | Set_Addr_To : out std_logic_vector(2 downto 0); -- aNone,aXY,aIOA,aSP,aBC,aDE,aZI 157 | IORQ : out std_logic; 158 | Jump : out std_logic; 159 | JumpE : out std_logic; 160 | JumpXY : out std_logic; 161 | Call : out std_logic; 162 | RstP : out std_logic; 163 | LDZ : out std_logic; 164 | LDW : out std_logic; 165 | LDSPHL : out std_logic; 166 | Special_LD : out std_logic_vector(2 downto 0); -- A,I;A,R;I,A;R,A;None 167 | ExchangeDH : out std_logic; 168 | ExchangeRp : out std_logic; 169 | ExchangeAF : out std_logic; 170 | ExchangeRS : out std_logic; 171 | I_DJNZ : out std_logic; 172 | I_CPL : out std_logic; 173 | I_CCF : out std_logic; 174 | I_SCF : out std_logic; 175 | I_RETN : out std_logic; 176 | I_BT : out std_logic; 177 | I_BC : out std_logic; 178 | I_BTR : out std_logic; 179 | I_RLD : out std_logic; 180 | I_RRD : out std_logic; 181 | I_INRC : out std_logic; 182 | SetDI : out std_logic; 183 | SetEI : out std_logic; 184 | IMode : out std_logic_vector(1 downto 0); 185 | Halt : out std_logic; 186 | NoRead : out std_logic; 187 | Write : out std_logic 188 | ); 189 | end component; 190 | 191 | component T80_ALU 192 | generic( 193 | Mode : integer := 0; 194 | Flag_C : integer := 0; 195 | Flag_N : integer := 1; 196 | Flag_P : integer := 2; 197 | Flag_X : integer := 3; 198 | Flag_H : integer := 4; 199 | Flag_Y : integer := 5; 200 | Flag_Z : integer := 6; 201 | Flag_S : integer := 7 202 | ); 203 | port( 204 | Arith16 : in std_logic; 205 | Z16 : in std_logic; 206 | ALU_Op : in std_logic_vector(3 downto 0); 207 | IR : in std_logic_vector(5 downto 0); 208 | ISet : in std_logic_vector(1 downto 0); 209 | BusA : in std_logic_vector(7 downto 0); 210 | BusB : in std_logic_vector(7 downto 0); 211 | F_In : in std_logic_vector(7 downto 0); 212 | Q : out std_logic_vector(7 downto 0); 213 | F_Out : out std_logic_vector(7 downto 0) 214 | ); 215 | end component; 216 | 217 | end; 218 | -------------------------------------------------------------------------------- /src/main/T80/T80_RegX.vhd: -------------------------------------------------------------------------------- 1 | -- **** 2 | -- T80(b) core. In an effort to merge and maintain bug fixes .... 3 | -- 4 | -- 5 | -- Ver 300 started tidyup 6 | -- MikeJ March 2005 7 | -- Latest version from www.fpgaarcade.com (original www.opencores.org) 8 | -- 9 | -- **** 10 | -- 11 | -- T80 Registers for Xilinx Select RAM 12 | -- 13 | -- Version : 0244 14 | -- 15 | -- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org) 16 | -- 17 | -- All rights reserved 18 | -- 19 | -- Redistribution and use in source and synthezised forms, with or without 20 | -- modification, are permitted provided that the following conditions are met: 21 | -- 22 | -- Redistributions of source code must retain the above copyright notice, 23 | -- this list of conditions and the following disclaimer. 24 | -- 25 | -- Redistributions in synthesized form must reproduce the above copyright 26 | -- notice, this list of conditions and the following disclaimer in the 27 | -- documentation and/or other materials provided with the distribution. 28 | -- 29 | -- Neither the name of the author nor the names of other contributors may 30 | -- be used to endorse or promote products derived from this software without 31 | -- specific prior written permission. 32 | -- 33 | -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 34 | -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 35 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 36 | -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 37 | -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 38 | -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 39 | -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 40 | -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 41 | -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 42 | -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 43 | -- POSSIBILITY OF SUCH DAMAGE. 44 | -- 45 | -- Please report bugs to the author, but before you do so, please 46 | -- make sure that this is not a derivative work and that 47 | -- you have the latest version of this file. 48 | -- 49 | -- The latest version of this file can be found at: 50 | -- http://www.opencores.org/cvsweb.shtml/t51/ 51 | -- 52 | -- Limitations : 53 | -- 54 | -- File history : 55 | -- 56 | -- 0242 : Initial release 57 | -- 58 | -- 0244 : Removed UNISIM library and added componet declaration 59 | -- 60 | 61 | library IEEE; 62 | use IEEE.std_logic_1164.all; 63 | use IEEE.numeric_std.all; 64 | 65 | entity T80_Reg is 66 | port( 67 | Clk : in std_logic; 68 | CEN : in std_logic; 69 | WEH : in std_logic; 70 | WEL : in std_logic; 71 | AddrA : in std_logic_vector(2 downto 0); 72 | AddrB : in std_logic_vector(2 downto 0); 73 | AddrC : in std_logic_vector(2 downto 0); 74 | DIH : in std_logic_vector(7 downto 0); 75 | DIL : in std_logic_vector(7 downto 0); 76 | DOAH : out std_logic_vector(7 downto 0); 77 | DOAL : out std_logic_vector(7 downto 0); 78 | DOBH : out std_logic_vector(7 downto 0); 79 | DOBL : out std_logic_vector(7 downto 0); 80 | DOCH : out std_logic_vector(7 downto 0); 81 | DOCL : out std_logic_vector(7 downto 0) 82 | ); 83 | end T80_Reg; 84 | 85 | architecture rtl of T80_Reg is 86 | 87 | component RAM16X1D 88 | port( 89 | DPO : out std_ulogic; 90 | SPO : out std_ulogic; 91 | A0 : in std_ulogic; 92 | A1 : in std_ulogic; 93 | A2 : in std_ulogic; 94 | A3 : in std_ulogic; 95 | D : in std_ulogic; 96 | DPRA0 : in std_ulogic; 97 | DPRA1 : in std_ulogic; 98 | DPRA2 : in std_ulogic; 99 | DPRA3 : in std_ulogic; 100 | WCLK : in std_ulogic; 101 | WE : in std_ulogic); 102 | end component; 103 | 104 | signal ENH : std_logic; 105 | signal ENL : std_logic; 106 | 107 | begin 108 | 109 | ENH <= CEN and WEH; 110 | ENL <= CEN and WEL; 111 | 112 | bG1: for I in 0 to 7 generate 113 | begin 114 | Reg1H : RAM16X1D 115 | port map( 116 | DPO => DOBH(i), 117 | SPO => DOAH(i), 118 | A0 => AddrA(0), 119 | A1 => AddrA(1), 120 | A2 => AddrA(2), 121 | A3 => '0', 122 | D => DIH(i), 123 | DPRA0 => AddrB(0), 124 | DPRA1 => AddrB(1), 125 | DPRA2 => AddrB(2), 126 | DPRA3 => '0', 127 | WCLK => Clk, 128 | WE => ENH); 129 | Reg1L : RAM16X1D 130 | port map( 131 | DPO => DOBL(i), 132 | SPO => DOAL(i), 133 | A0 => AddrA(0), 134 | A1 => AddrA(1), 135 | A2 => AddrA(2), 136 | A3 => '0', 137 | D => DIL(i), 138 | DPRA0 => AddrB(0), 139 | DPRA1 => AddrB(1), 140 | DPRA2 => AddrB(2), 141 | DPRA3 => '0', 142 | WCLK => Clk, 143 | WE => ENL); 144 | Reg2H : RAM16X1D 145 | port map( 146 | DPO => DOCH(i), 147 | SPO => open, 148 | A0 => AddrA(0), 149 | A1 => AddrA(1), 150 | A2 => AddrA(2), 151 | A3 => '0', 152 | D => DIH(i), 153 | DPRA0 => AddrC(0), 154 | DPRA1 => AddrC(1), 155 | DPRA2 => AddrC(2), 156 | DPRA3 => '0', 157 | WCLK => Clk, 158 | WE => ENH); 159 | Reg2L : RAM16X1D 160 | port map( 161 | DPO => DOCL(i), 162 | SPO => open, 163 | A0 => AddrA(0), 164 | A1 => AddrA(1), 165 | A2 => AddrA(2), 166 | A3 => '0', 167 | D => DIL(i), 168 | DPRA0 => AddrC(0), 169 | DPRA1 => AddrC(1), 170 | DPRA2 => AddrC(2), 171 | DPRA3 => '0', 172 | WCLK => Clk, 173 | WE => ENL); 174 | end generate; 175 | 176 | end; 177 | -------------------------------------------------------------------------------- /src/main/T80/T80sed.vhd: -------------------------------------------------------------------------------- 1 | -- **** 2 | -- T80(b) core. In an effort to merge and maintain bug fixes .... 3 | -- 4 | -- 5 | -- Ver 300 started tidyup 6 | -- MikeJ March 2005 7 | -- Latest version from www.fpgaarcade.com (original www.opencores.org) 8 | -- 9 | -- **** 10 | -- ** CUSTOM 2 CLOCK MEMORY ACCESS FOR PACMAN, MIKEJ ** 11 | -- 12 | -- Z80 compatible microprocessor core, synchronous top level with clock enable 13 | -- Different timing than the original z80 14 | -- Inputs needs to be synchronous and outputs may glitch 15 | -- 16 | -- Version : 0238 17 | -- 18 | -- Copyright (c) 2001-2002 Daniel Wallner (jesus@opencores.org) 19 | -- 20 | -- All rights reserved 21 | -- 22 | -- Redistribution and use in source and synthezised forms, with or without 23 | -- modification, are permitted provided that the following conditions are met: 24 | -- 25 | -- Redistributions of source code must retain the above copyright notice, 26 | -- this list of conditions and the following disclaimer. 27 | -- 28 | -- Redistributions in synthesized form must reproduce the above copyright 29 | -- notice, this list of conditions and the following disclaimer in the 30 | -- documentation and/or other materials provided with the distribution. 31 | -- 32 | -- Neither the name of the author nor the names of other contributors may 33 | -- be used to endorse or promote products derived from this software without 34 | -- specific prior written permission. 35 | -- 36 | -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 37 | -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 38 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 39 | -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 40 | -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 41 | -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 42 | -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 43 | -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 44 | -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 45 | -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 46 | -- POSSIBILITY OF SUCH DAMAGE. 47 | -- 48 | -- Please report bugs to the author, but before you do so, please 49 | -- make sure that this is not a derivative work and that 50 | -- you have the latest version of this file. 51 | -- 52 | -- The latest version of this file can be found at: 53 | -- http://www.opencores.org/cvsweb.shtml/t80/ 54 | -- 55 | -- Limitations : 56 | -- 57 | -- File history : 58 | -- 59 | -- 0235 : First release 60 | -- 61 | -- 0236 : Added T2Write generic 62 | -- 63 | -- 0237 : Fixed T2Write with wait state 64 | -- 65 | -- 0238 : Updated for T80 interface change 66 | -- 67 | -- 0242 : Updated for T80 interface change 68 | -- 69 | 70 | library IEEE; 71 | use IEEE.std_logic_1164.all; 72 | use IEEE.numeric_std.all; 73 | use work.T80_Pack.all; 74 | 75 | entity T80sed is 76 | port( 77 | RESET_n : in std_logic; 78 | CLK_n : in std_logic; 79 | CLKEN : in std_logic; 80 | WAIT_n : in std_logic; 81 | INT_n : in std_logic; 82 | NMI_n : in std_logic; 83 | BUSRQ_n : in std_logic; 84 | M1_n : out std_logic; 85 | MREQ_n : out std_logic; 86 | IORQ_n : out std_logic; 87 | RD_n : out std_logic; 88 | WR_n : out std_logic; 89 | RFSH_n : out std_logic; 90 | HALT_n : out std_logic; 91 | BUSAK_n : out std_logic; 92 | A : out std_logic_vector(15 downto 0); 93 | DI : in std_logic_vector(7 downto 0); 94 | DO : out std_logic_vector(7 downto 0) 95 | ); 96 | end T80sed; 97 | 98 | architecture rtl of T80sed is 99 | 100 | signal IntCycle_n : std_logic; 101 | signal NoRead : std_logic; 102 | signal Write : std_logic; 103 | signal IORQ : std_logic; 104 | signal DI_Reg : std_logic_vector(7 downto 0); 105 | signal MCycle : std_logic_vector(2 downto 0); 106 | signal TState : std_logic_vector(2 downto 0); 107 | 108 | begin 109 | 110 | u0 : T80 111 | generic map( 112 | Mode => 0, 113 | IOWait => 1) 114 | port map( 115 | CEN => CLKEN, 116 | M1_n => M1_n, 117 | IORQ => IORQ, 118 | NoRead => NoRead, 119 | Write => Write, 120 | RFSH_n => RFSH_n, 121 | HALT_n => HALT_n, 122 | WAIT_n => Wait_n, 123 | INT_n => INT_n, 124 | NMI_n => NMI_n, 125 | RESET_n => RESET_n, 126 | BUSRQ_n => BUSRQ_n, 127 | BUSAK_n => BUSAK_n, 128 | CLK_n => CLK_n, 129 | A => A, 130 | DInst => DI, 131 | DI => DI_Reg, 132 | DO => DO, 133 | MC => MCycle, 134 | TS => TState, 135 | IntCycle_n => IntCycle_n); 136 | 137 | process (RESET_n, CLK_n) 138 | begin 139 | if RESET_n = '0' then 140 | RD_n <= '1'; 141 | WR_n <= '1'; 142 | IORQ_n <= '1'; 143 | MREQ_n <= '1'; 144 | DI_Reg <= "00000000"; 145 | elsif CLK_n'event and CLK_n = '1' then 146 | if CLKEN = '1' then 147 | RD_n <= '1'; 148 | WR_n <= '1'; 149 | IORQ_n <= '1'; 150 | MREQ_n <= '1'; 151 | if MCycle = "001" then 152 | if TState = "001" or (TState = "010" and Wait_n = '0') then 153 | RD_n <= not IntCycle_n; 154 | MREQ_n <= not IntCycle_n; 155 | IORQ_n <= IntCycle_n; 156 | end if; 157 | if TState = "011" then 158 | MREQ_n <= '0'; 159 | end if; 160 | else 161 | if (TState = "001" or TState = "010") and NoRead = '0' and Write = '0' then 162 | RD_n <= '0'; 163 | IORQ_n <= not IORQ; 164 | MREQ_n <= IORQ; 165 | end if; 166 | if ((TState = "001") or (TState = "010")) and Write = '1' then 167 | WR_n <= '0'; 168 | IORQ_n <= not IORQ; 169 | MREQ_n <= IORQ; 170 | end if; 171 | end if; 172 | if TState = "010" and Wait_n = '1' then 173 | DI_Reg <= DI; 174 | end if; 175 | end if; 176 | end if; 177 | end process; 178 | 179 | end; 180 | -------------------------------------------------------------------------------- /src/main/pacman/README.md: -------------------------------------------------------------------------------- 1 | # ![](/home/skip/projects/skip/assets/pano_man.png) 2 | 3 | ## PanoMan 4 | This project simulates the classic Pacman arcade game on a first generation PanoLogic thin client. 5 | 6 | Why? 7 | I absolutely love hacking surplus gear for new purposes, that and I spent way too much time playing Pacman in my youth. I was also interested in learning Verilog and/or VHDL but now that I've played around with SpinalHDL I'm hooked. 8 | 9 | This project is a Frankenstein's monster of code from many different places written in 3 different HDLs: VHDL, Verilog and SpinalHDL. Additionally the project combines a modern RISC-V processor with a archaic Z80. Amazingly enough it was fairly easy to get everything working together largely thanks to SpinalHDL. 10 | 11 | ## Heritage 12 | This project is essentially a small layer of "glue" code that ties together the work of others including: 13 | 14 | * Tom Verbeures ray tracer [project](https://github.com/tomverbeure/rt) which was used as the basic infrastructure to quickly get code up and running on the Pano. 15 | * [Mike Js](http://www.fpgaarcade.com/author/mikej/) simulation model of the Pacman hardware in VHDL for the Spartan 3E. 16 | * The [Papilio-Arcade](https://github.com/GadgetFactory/Papilio-Arcade.git) project modifications of MikeJ's project for the Papilio platform. 17 | * Daniel Wallners Z80 CPU [core](https://opencores.org/projects/tv80). 18 | * Tom Verbeures amazing reverse engineering efforts and Pano logic [bring up](https://github.com/tomverbeure/panologic) code. 19 | * The [SpinalHDL](https://github.com/SpinalHDL) project. 20 | 21 | ## Why a RISC-V ?? 22 | 23 | The sound subsystem in the Pano is based on a codec from Wolfson which must be initialized before it can be used. I had no interest creating hardware to do the initialization so that leaves software. I had even less interest in trying to patch the Pacman Z80 ROMs so ... just drop in a 32 bits processor, since it was easy (*REALLY EASY* since Tom did all the work so it was already there). 24 | 25 | ## HW Requirements 26 | 27 | * A Pano Logic G1 (the one with a VGA port) 28 | * A suitable 5 volt power supply 29 | * A JTAG programmer to load the bitstream into the FPGA. 30 | 31 | If you want to actually be able to play a game you'll also need: 32 | 33 | * A switch style joystick. 34 | * Soldering skills to connect the joystick to the Pano. 35 | 36 | ## Software Requirements 37 | 38 | The free Webpack version of Xilinx [ISE 14.7](https://www.xilinx.com/support/download/index.html/content/xilinx/en/downloadNav/design-tools/v2012_4---14_7.html) is needed to program the Pano device. This will also allow you regenerate the .bit file from VHDL and Verilog sources. Do **NOT** download the latest Windows 10 version as it does not support the Spartan 3E family of chips used in the first generation of the Pano device. 39 | 40 | Either Windows or Linux can be used to recreate the .bit file if the ROMs are updated, but Linux is probably necessary to make wider changes to the project. 41 | 42 | If you simply want to run the pong demo on your Pano, then all you need to do is load a pre-made [bitstream](./xilinx/Pano.bit) into the device usings Xilinx's Impact tool. 43 | 44 | ## ROMs 45 | 46 | For legal reasons the Pacman ROM images are **NOT** included in this project, instead David Widel's Pong demo written for the same hardware has been provided. 47 | 48 | In order to run the Pacman you will need to create ROM image files from an actual arcade game or download the images from elsewhere on the Internet. These are the same files needed by the infamous [Mame project](https://www.mamedev.org/) so they should be relatively easy to locate. 49 | 50 | 51 | ## Joystick Interface 52 | Video and sound weren't much of a challenge since Tom Verbeur had already done all of the ground work there. 53 | 54 | The joystick, coin detector, and start buttons on the other hand presented a bit of a challenge. Normally a Pacman game needs 8 GPIO inputs: 55 | 56 | 1. Two inputs for the two coin slots. 57 | 1. One input for the 1 player game start button. 58 | 1. One input for the 2 player game start button. 59 | 1. Four inputs for the joystick. 60 | 61 | The obvious way to connect a Joystick to the Pano is to use one of the USB ports, but that's a problem because there's no code for the USB port yet and it looks like a major undertaking. 62 | 63 | Another solution would be to use an I2C port expander, but this would require something to be built along with code to poll it and it would not be easy to house it in the tiny Pano case. 64 | 65 | The Pano does have some signals that are relatively easy to access that could be considered GPIOs. Three are used to drive the 3 LEDs, one is used to read the"Pano" button, and 2 are connected to the VGA monitors Display Data Channel (DDC) port. This get us close. 66 | 67 | One surprise was that unlike the green and blue LED ports the red LED port can't be used as an input without hardware modifications. Apparently the red LED is not driven directly by a Xilinx pin. 68 | 69 | It turns out that there is a "DIP" switch setting that configured the Pacman machine for free plays. By selecting this mode we eliminate the need for the coins slot inputs. 70 | 71 | The 2 player start button isn't essential so we can skip it and thus get down to5 inputs for the Joystick and start button. The start is easy, we'll just use the existing "Pano" button for that. 72 | 73 | This leaves us with 4 inputs we need to connect to our joystick. For the impatient person who isn't concerned about esthetics or physical robustness flying wires are a quick and easy way to hook up the joystick. 74 | 75 | I choose to use a connector to make things more robust, neat and tidy. Since the case is so small adding a connector isn't really an option, however two of the signals are already on the VGA connector and the VGA connector has just enough spare pins for the other two! 76 | 77 | Adding two jumper wires from the VGA connector from the LEDS is pretty easy to do with any soldering skills at all. Here's the result: 78 | 79 | ![](./assets/jumpers_small.png) 80 | 81 | Then we can make a Y cable to combine the joystick and VGA cables. Note: The pinout of the DB9 connector matches the pinout of the Atari 2600 joystick. 82 | 83 | 84 | | Signal | Pano | Monitor | Joystick | 85 | |---------|--------|-----------|------------| 86 | | red | 1 |1 | -| 87 | | green | 2 | 2|-| 88 | |blue|3|3|-| 89 | |blue led/left|4|-|3| 90 | |gnd|5|-|8| 91 | |gnd|6|6|-| 92 | |gnd|7|7|-| 93 | |gnd|8|8|-| 94 | |+5V|9|-|7| 95 | |gnd|10|10|-| 96 | |green led/right|11|-|4| 97 | |VGA SDA/down|12|-|2| 98 | |Hsync|13|13|-| 99 | |Vsync|14|14|-| 100 | |VGA SCL/up|15|-|1| 101 | 102 | 103 | ![](./assets/JoystickAdapterCable_small.png) 104 | ![](./assets/cable.png) 105 | 106 | ## Updating ROMs 107 | To update the bitstream with new ROMs: 108 | 109 | 1. Place the ROM images in .../pano_man/src/main/roms. 110 | 2. Run "./build_roms_pacman.sh" (or build_roms.bat on Windoze) from the .../pano_man/src/main/pacman subdirectory. 111 | 4. Start ISE. 112 | 5. From the ISE IDE select "Pano" from the Design/Hierarchy window. 113 | 6. Right click on "Generate Programming File" in the Design/Processes windows and then select "Rerun All". 114 | 7. Go get coffee while you wait for the programming file (pano.bit) to be generated. 115 | 8. Select iMpact from the Tools menu, click "Ok", to dismiss the warning dialog. 116 | 117 | 118 | ## Building Everything from Scratch 119 | 120 | **NB:** While it may be possible to use Windows for development I haven't tried it and don't recommend it. 121 | 122 | * Install RISC-V GCC compiler suite 123 | 124 | See the [picorv32](https://github.com/cliffordwolf/picorv32) github project on how to do it. Warning: this make take a long time to complete! 125 | 126 | * Install [SpinalHDL](https://github.com/SpinalHDL/SpinalHDL) 127 | 128 | The actual installation instructions can be found in the [VexRisc]( https://github.com/SpinalHDL/VexRiscv#dependencies) project. 129 | 130 | * Clone this github repository into `~/pano_man` 131 | * Change into the root of the repository `~/pano_man` 132 | 133 | * Build the firmware for the RISC-V processor 134 | 135 | ``` 136 | (cd sw;make) 137 | ``` 138 | This creates a file called `~/pano_man/sw/progmem8k.bin` 139 | 140 | * Build the Verilog for synthesis 141 | 142 | When you run this, not only will you create the `Pano.v` file, but also a bunch of `.bin` files that contain RAM initialization contents, which will be loaded by Xilinx ISE during synthesis. 143 | 144 | ``` 145 | make syn 146 | ``` 147 | 148 | * Fire up Xilinx ISE 149 | ``` 150 | cd xilinx 151 | make ise 152 | ``` 153 | 154 | * Create the bitstream 155 | 156 | * File -> Open Project -> .../pano_man/xilinx/xilinx.xise 157 | * Double click on 'Generate Programming File' 158 | 159 | 160 | * Fire up Xilinx Impact 161 | 162 | ``` 163 | cd ~/projects/rt/xilinx 164 | make impact 165 | ``` 166 | 167 | * Load bitstream into the device 168 | 169 | 170 | 171 | ## Possible Future Projects 172 | 173 | * Add support for MCP23017 I2C port expander to provide support for 2 player mode and coin slots 174 | 175 | * Add support for saving the high score in SPI flash 176 | * Port code to the [second generation](https://github.com/tomverbeure/panologic-g2) of the Pano 177 | * Once basic USB support is available add support for USB Joysticks 178 | 179 | * Port other games that ran on the same hardware such as Invaders and Galaxian -------------------------------------------------------------------------------- /src/main/pacman/build_roms_pacman.bat: -------------------------------------------------------------------------------- 1 | rem @echo off 2 | 3 | REM SHA1 sums of files required 4 | REM 8d0268dee78e47c712202b0ec4f1f51109b1f2a5 *82s123.7f 5 | REM bbcec0570aeceb582ff8238a4bc8546a23430081 *82s126.1m 6 | REM 0c4d0bee858b97632411c440bea6948a74759746 *82s126.3m 7 | REM 19097b5f60d1030f8b82d9f1d3a241f93e5c75d6 *82s126.4a 8 | REM 87117ba5082cd7a615b4ec7c02dd819003fbd669 *namcopac.6e 9 | REM 326dbbf94c6fa2e96613dedb53702f8832b47d59 *namcopac.6f 10 | REM 7e1945f6eb51f2e51806d0439f975f7a2889b9b8 *namcopac.6h 11 | REM 01b4c38108d9dc4e48da4f8d685248e1e6821377 *namcopac.6j 12 | REM 06ef227747a440831c9a3a613b76693d52a2f0a9 *pacman.5e 13 | REM 4a937ac02216ea8c96477d4a15522070507fb599 *pacman.5f 14 | 15 | set rom_path_src=..\roms 16 | set rom_path=. 17 | set romgen_path=..\..\..\misc\romgen 18 | 19 | REM concatenate consecutive ROM regions 20 | copy /b/y %rom_path_src%\*.5e + %rom_path_src%\*.5f %rom_path%\gfx1.bin > NUL 21 | copy /b/y %rom_path_src%\*.6e + %rom_path_src%\*.6f + %rom_path_src%\*.6h + %rom_path_src%\*.6j %rom_path%\main.bin > NUL 22 | 23 | REM generate RTL code for small PROMS 24 | %romgen_path%\romgen %rom_path_src%\*.1m PROM1_DST 9 l r e > %rom_path%\prom1_dst.vhd 25 | %romgen_path%\romgen %rom_path_src%\*.4a PROM4_DST 8 l r e > %rom_path%\prom4_dst.vhd 26 | %romgen_path%\romgen %rom_path_src%\*.7f PROM7_DST 4 l r e > %rom_path%\prom7_dst.vhd 27 | 28 | REM generate RAMB structures for larger ROMS 29 | %romgen_path%\romgen %rom_path%\gfx1.bin GFX1 13 l r e > %rom_path%\gfx1.vhd 30 | %romgen_path%\romgen %rom_path%\main.bin ROM_PGM_0 14 l r e > %rom_path%\rom0.vhd 31 | 32 | echo done 33 | pause 34 | -------------------------------------------------------------------------------- /src/main/pacman/build_roms_pacman.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #set -x 4 | 5 | rom_path_src=../roms 6 | rom_path=. 7 | rom_md5_path=../roms.md5 8 | romgen_path=../../../misc/romgen 9 | 10 | build_them() { 11 | echo "Supported Pacman arcade ROMS verified (${romset} version)" 12 | rm ${rom_path_src}/main.bin 2> /dev/null 13 | for file in $main ; do 14 | cat ${rom_path_src}/${file} >> ${rom_path_src}/main.bin 15 | done 16 | 17 | rm ${rom_path_src}/gfx1.bin 2> /dev/null 18 | for file in $gfx1 ; do 19 | cat ${rom_path_src}/${file} >> ${rom_path_src}/gfx1.bin 20 | done 21 | 22 | # generate RTL code for small PROMS 23 | ${romgen_path}/romgen ${rom_path_src}/$prom1 PROM1_DST 9 l r e > ${rom_path}/prom1_dst.vhd 2> /dev/null 24 | ${romgen_path}/romgen ${rom_path_src}/$prom4 PROM4_DST 8 l r e > ${rom_path}/prom4_dst.vhd 2> /dev/null 25 | ${romgen_path}/romgen ${rom_path_src}/$prom7 PROM7_DST 4 l r e > ${rom_path}/prom7_dst.vhd 2> /dev/null 26 | 27 | # generate RAMB structures for larger ROMS 28 | ${romgen_path}/romgen ${rom_path_src}/gfx1.bin GFX1 13 l r e > ${rom_path}/gfx1.vhd 2> /dev/null 29 | ${romgen_path}/romgen ${rom_path_src}/main.bin ROM_PGM_0 14 l r e > ${rom_path}/rom0.vhd 2> /dev/null 30 | 31 | echo "Done" 32 | } 33 | 34 | if [ ! -e ${romgen_path}/romgen ]; then 35 | (cd ${romgen_path};make romgen) 36 | fi 37 | 38 | if [ ! -e ${romgen_path}/romgen ]; then 39 | echo "failed to build romgen utility" 40 | exit 1 41 | fi 42 | 43 | (cd ${rom_path_src};md5sum -c ${rom_md5_path}/puckmanb.md5) 2>/dev/null 1> /dev/null 44 | if [ $? -eq 0 ]; then 45 | romset="puckmanb" 46 | main="namcopac.6e namcopac.6f namcopac.6h namcopac.6j" 47 | gfx1="pacman.5e pacman.5f" 48 | prom1="82s126.1m" 49 | prom4="82s126.4a" 50 | prom7="82s123.7f" 51 | build_them 52 | exit 53 | fi 54 | 55 | (cd ${rom_path_src};md5sum -c ${rom_md5_path}/puckman.md5) 2>/dev/null 1> /dev/null 56 | if [ $? -eq 0 ]; then 57 | romset="puckman" 58 | main="pm1_prg1.6e pm1_prg2.6k pm1_prg3.6f pm1_prg4.6m pm1_prg5.6h pm1_prg6.6n pm1_prg7.6j pm1_prg8.6p" 59 | gfx1="pm1_chg1.5e pm1_chg2.5h pm1_chg3.5f pm1_chg4.5j" 60 | prom1="pm1-3.1m" 61 | prom4="pm1-4.4a" 62 | prom7="pm1-1.7f" 63 | build_them 64 | exit 65 | fi 66 | 67 | (cd ${rom_path_src};md5sum -c ${rom_md5_path}/pacman.md5) 2>/dev/null 1> /dev/null 68 | 69 | if [ $? -eq 0 ]; then 70 | romset="pacman" 71 | main="pacman.6e pacman.6f pacman.6h pacman.6j" 72 | gfx1="pacman.5e pacman.5f" 73 | prom1="82s126.1m" 74 | prom4="82s126.4a" 75 | prom7="82s123.7f" 76 | build_them 77 | exit 78 | fi 79 | 80 | echo "No supported Pacman arcade ROMS found" 81 | 82 | -------------------------------------------------------------------------------- /src/main/pacman/pacman_audio_tb.vhd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skiphansen/pano_man/e7759f816c179f253180fe34e4dd040a5fa5c0cd/src/main/pacman/pacman_audio_tb.vhd -------------------------------------------------------------------------------- /src/main/pacman/pacman_clocks_xilinx.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- A simulation model of Pacman hardware 3 | -- Copyright (c) MikeJ - January 2006 4 | -- 5 | -- All rights reserved 6 | -- 7 | -- Redistribution and use in source and synthezised forms, with or without 8 | -- modification, are permitted provided that the following conditions are met: 9 | -- 10 | -- Redistributions of source code must retain the above copyright notice, 11 | -- this list of conditions and the following disclaimer. 12 | -- 13 | -- Redistributions in synthesized form must reproduce the above copyright 14 | -- notice, this list of conditions and the following disclaimer in the 15 | -- documentation and/or other materials provided with the distribution. 16 | -- 17 | -- Neither the name of the author nor the names of other contributors may 18 | -- be used to endorse or promote products derived from this software without 19 | -- specific prior written permission. 20 | -- 21 | -- THIS CODE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 25 | -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | -- POSSIBILITY OF SUCH DAMAGE. 32 | -- 33 | -- You are responsible for any legal issues arising from your use of this code. 34 | -- 35 | -- The latest version of this file can be found at: www.fpgaarcade.com 36 | -- 37 | -- Email pacman@fpgaarcade.com 38 | -- 39 | -- Revision list 40 | -- 41 | -- version 004 spartan3e release 42 | -- version 001 Jan 2006 release - initial release of this module 43 | 44 | library ieee; 45 | use ieee.std_logic_1164.all; 46 | use ieee.std_logic_unsigned.all; 47 | use ieee.numeric_std.all; 48 | 49 | library UNISIM; 50 | use UNISIM.Vcomponents.all; 51 | 52 | entity PACMAN_CLOCKS is 53 | port ( 54 | I_CLK_REF : in std_logic; 55 | I_RESET_L : in std_logic; 56 | -- 57 | O_CLK_REF : out std_logic; 58 | -- 59 | O_ENA_12 : out std_logic; 60 | O_ENA_6 : out std_logic; 61 | O_CLK : out std_logic; 62 | O_RESET : out std_logic 63 | ); 64 | end; 65 | 66 | architecture RTL of PACMAN_CLOCKS is 67 | 68 | signal reset_dcm_h : std_logic; 69 | signal clk_ref_ibuf : std_logic; 70 | signal clk_dcm_op_0 : std_logic; 71 | signal clk_dcm_op_dv : std_logic; 72 | signal clk_dcm_0_bufg : std_logic; 73 | signal clk : std_logic; 74 | signal dcm_locked : std_logic; 75 | signal delay_count : std_logic_vector(7 downto 0) := (others => '0'); 76 | signal div_cnt : std_logic_vector(1 downto 0); 77 | 78 | -- attribute DLL_FREQUENCY_MODE : string; 79 | -- attribute DUTY_CYCLE_CORRECTION : string; 80 | -- attribute CLKOUT_PHASE_SHIFT : string; 81 | -- attribute PHASE_SHIFT : integer; 82 | -- attribute CLKFX_MULTIPLY : integer; 83 | -- attribute CLKFX_DIVIDE : integer; 84 | -- attribute CLKDV_DIVIDE : real; 85 | -- attribute STARTUP_WAIT : string; 86 | -- attribute CLKIN_PERIOD : real; 87 | 88 | -- The original uses a 6.144 MHz clock 89 | -- 90 | -- Here we are taking in 32MHz clock, and using the CLKFX 32*(10/13) to get 24.615MHz 91 | -- We are then clock enabling the whole design at /4 and /2 92 | -- 93 | -- This runs the game at 6.15 MHz which is 0.16% fast. 94 | -- 95 | -- (The scan doubler requires a x2 freq clock) 96 | -- function str2bool (str : string) return boolean is 97 | -- begin 98 | -- if (str = "TRUE") or (str = "true") then 99 | -- return TRUE; 100 | -- else 101 | -- return FALSE; 102 | -- end if; 103 | -- end str2bool; 104 | 105 | -- PanoLogic uses a 100 Mhz clock so to generate 6.144 we'll 106 | 107 | begin 108 | 109 | reset_dcm_h <= not I_RESET_L; 110 | IBUFG0 : IBUFG port map (I=> I_CLK_REF, O => clk_ref_ibuf); 111 | 112 | -- dcma : if true generate 113 | -- attribute DLL_FREQUENCY_MODE of dcm_inst : label is "LOW"; 114 | -- attribute DUTY_CYCLE_CORRECTION of dcm_inst : label is "TRUE"; 115 | -- attribute CLKOUT_PHASE_SHIFT of dcm_inst : label is "NONE"; 116 | -- attribute PHASE_SHIFT of dcm_inst : label is 0; 117 | -- attribute CLKFX_MULTIPLY of dcm_inst : label is 10; 118 | -- attribute CLKFX_DIVIDE of dcm_inst : label is 13; 119 | -- attribute CLKDV_DIVIDE of dcm_inst : label is 2.0; 120 | -- attribute STARTUP_WAIT of dcm_inst : label is "FALSE"; 121 | -- attribute CLKIN_PERIOD of dcm_inst : label is 31.25; 122 | -- -- 123 | -- begin 124 | dcm_inst : DCM_SP 125 | generic map ( 126 | DLL_FREQUENCY_MODE => "LOW", 127 | DUTY_CYCLE_CORRECTION => TRUE, 128 | CLKOUT_PHASE_SHIFT => "NONE", 129 | PHASE_SHIFT => 0, 130 | CLKFX_MULTIPLY => 61, 131 | CLKFX_DIVIDE => 13, 132 | CLKDV_DIVIDE => 2.0, 133 | STARTUP_WAIT => FALSE, 134 | CLKIN_PERIOD => 31.25 135 | ) 136 | port map ( 137 | CLKIN => clk_ref_ibuf, 138 | CLKFB => clk_dcm_0_bufg, 139 | DSSEN => '0', 140 | PSINCDEC => '0', 141 | PSEN => '0', 142 | PSCLK => '0', 143 | RST => reset_dcm_h, 144 | CLK0 => clk_dcm_op_0, 145 | CLK90 => open, 146 | CLK180 => open, 147 | CLK270 => open, 148 | CLK2X => open, 149 | CLK2X180 => open, 150 | CLKDV => open, 151 | CLKFX => clk_dcm_op_dv, 152 | CLKFX180 => open, 153 | LOCKED => dcm_locked, 154 | PSDONE => open 155 | ); 156 | 157 | 158 | BUFG0 : BUFG port map (I=> clk_dcm_op_0, O => clk_dcm_0_bufg); 159 | O_CLK_REF <= clk_dcm_0_bufg; 160 | BUFG1 : BUFG port map (I=> clk_dcm_op_dv, O => clk); 161 | O_CLK <= clk; 162 | 163 | p_delay : process(I_RESET_L, clk) 164 | begin 165 | if (I_RESET_L = '0') then 166 | delay_count <= x"00"; -- longer delay for cpu 167 | O_RESET <= '1'; 168 | elsif rising_edge(clk) then 169 | if (delay_count(7 downto 0) = (x"FF")) then 170 | delay_count <= (x"FF"); 171 | O_RESET <= '0'; 172 | else 173 | delay_count <= delay_count + "1"; 174 | O_RESET <= '1'; 175 | end if; 176 | end if; 177 | end process; 178 | 179 | p_clk_div : process(I_RESET_L, clk) 180 | begin 181 | if (I_RESET_L = '0') then 182 | div_cnt <= (others => '0'); 183 | elsif rising_edge(clk) then 184 | div_cnt <= div_cnt + "1"; 185 | end if; 186 | end process; 187 | 188 | p_assign_ena : process(div_cnt) 189 | begin 190 | O_ENA_12 <= div_cnt(0); 191 | O_ENA_6 <= div_cnt(0) and not div_cnt(1); 192 | end process; 193 | end RTL; 194 | -------------------------------------------------------------------------------- /src/main/pacman/pacman_dblscan.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- VHDL conversion by MikeJ - October 2002 3 | -- 4 | -- FPGA video scan doubler 5 | -- 6 | -- based on a design by Tatsuyuki Satoh 7 | -- 8 | -- 9 | -- All rights reserved 10 | -- 11 | -- Redistribution and use in source and synthezised forms, with or without 12 | -- modification, are permitted provided that the following conditions are met: 13 | -- 14 | -- Redistributions of source code must retain the above copyright notice, 15 | -- this list of conditions and the following disclaimer. 16 | -- 17 | -- Redistributions in synthesized form must reproduce the above copyright 18 | -- notice, this list of conditions and the following disclaimer in the 19 | -- documentation and/or other materials provided with the distribution. 20 | -- 21 | -- Neither the name of the author nor the names of other contributors may 22 | -- be used to endorse or promote products derived from this software without 23 | -- specific prior written permission. 24 | -- 25 | -- THIS CODE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 27 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 | -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 29 | -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | -- POSSIBILITY OF SUCH DAMAGE. 36 | -- 37 | -- You are responsible for any legal issues arising from your use of this code. 38 | -- 39 | -- The latest version of this file can be found at: www.fpgaarcade.com 40 | -- 41 | -- Email support@fpgaarcade.com 42 | -- 43 | -- Revision list 44 | -- 45 | -- version 002 initial release 46 | -- version 003 Jan 2006 release, general tidy up 47 | -- version 004 spartan3e release 48 | -- version 005 simplified logic, uses only one RAMB 49 | library ieee; 50 | use ieee.std_logic_1164.all; 51 | use ieee.std_logic_unsigned.all; 52 | use ieee.numeric_std.all; 53 | 54 | library UNISIM; 55 | use UNISIM.Vcomponents.all; 56 | 57 | entity VGA_SCANDBL is 58 | port ( 59 | I_R : in std_logic_vector( 2 downto 0); 60 | I_G : in std_logic_vector( 2 downto 0); 61 | I_B : in std_logic_vector( 1 downto 0); 62 | I_HSYNC : in std_logic; 63 | I_VSYNC : in std_logic; 64 | -- 65 | O_R : out std_logic_vector( 2 downto 0); 66 | O_G : out std_logic_vector( 2 downto 0); 67 | O_B : out std_logic_vector( 1 downto 0); 68 | O_HSYNC : out std_logic; 69 | O_VSYNC : out std_logic; 70 | -- 71 | CLK : in std_logic; 72 | CLK_X2 : in std_logic 73 | ); 74 | end; 75 | 76 | architecture RTL of VGA_SCANDBL is 77 | signal CLK_DUP : std_logic := '0'; 78 | -- 79 | -- input timing 80 | -- 81 | signal ihs_t1 : std_logic := '0'; 82 | signal ivs_t1 : std_logic := '0'; 83 | signal hpos_i : std_logic_vector(8 downto 0) := (others => '0'); 84 | signal bank_i : std_logic := '0'; 85 | signal rgb_in : std_logic_vector(7 downto 0) := (others => '0'); 86 | signal hsize_i : std_logic_vector(8 downto 0) := (others => '0'); 87 | -- 88 | -- output timing 89 | -- 90 | signal ohs_t1 : std_logic := '0'; 91 | signal ovs_t1 : std_logic := '0'; 92 | signal hpos_o : std_logic_vector(8 downto 0) := (others => '0'); 93 | signal bank_o : std_logic := '0'; 94 | signal rgb_out : std_logic_vector(7 downto 0) := (others => '0'); 95 | signal vs_cnt : std_logic_vector(2 downto 0) := (others => '0'); 96 | begin 97 | rgb_in <= I_B & I_G & I_R; 98 | u_ram : RAMB16_S9_S9 99 | generic map ( 100 | SIM_COLLISION_CHECK => "generate_x_only" 101 | ) 102 | port map ( 103 | -- input 104 | DOA => open, 105 | DIA => rgb_in, 106 | DOPA => open, 107 | DIPA => "0", 108 | ADDRA(10) => '0', 109 | ADDRA(9) => bank_i, 110 | ADDRA(8 downto 0) => hpos_i, 111 | WEA => '1', 112 | ENA => '1', 113 | SSRA => '0', 114 | CLKA => CLK, 115 | 116 | -- output 117 | DOB => rgb_out, 118 | DIB => x"00", 119 | DOPB => open, 120 | DIPB => "0", 121 | ADDRB(10) => '0', 122 | ADDRB(9) => bank_o, 123 | ADDRB(8 downto 0) => hpos_o, 124 | WEB => '0', 125 | ENB => '1', 126 | SSRB => '0', 127 | CLKB => CLK_X2 128 | ); 129 | 130 | CLK_DUP <= CLK; 131 | p_input_timing : process(CLK_DUP) 132 | variable rising_h : boolean; 133 | variable rising_v : boolean; 134 | begin 135 | if rising_edge (CLK_DUP) then 136 | ihs_t1 <= I_HSYNC; 137 | ivs_t1 <= I_VSYNC; 138 | rising_h := (I_HSYNC = '1') and (ihs_t1 = '0'); 139 | rising_v := (I_VSYNC = '1') and (ivs_t1 = '0'); 140 | 141 | if rising_v then 142 | bank_i <= '0'; 143 | elsif rising_h then 144 | bank_i <= not bank_i; 145 | end if; 146 | 147 | if rising_h then 148 | hpos_i <= (others => '0'); 149 | hsize_i <= hpos_i; 150 | else 151 | hpos_i <= hpos_i + "1"; 152 | end if; 153 | end if; 154 | end process; 155 | 156 | p_output_timing : process(CLK_X2) 157 | variable rising_h : boolean; 158 | variable rising_v : boolean; 159 | begin 160 | if rising_edge (CLK_X2) then 161 | ohs_t1 <= I_HSYNC; 162 | ovs_t1 <= I_VSYNC; 163 | rising_h := (I_HSYNC = '1') and (ohs_t1 = '0'); 164 | rising_v := (I_VSYNC = '1') and (ovs_t1 = '0'); 165 | 166 | if rising_h or (hpos_o = hsize_i) then 167 | hpos_o <= (others => '0'); 168 | else 169 | hpos_o <= hpos_o + "1"; 170 | end if; 171 | 172 | if rising_v then 173 | bank_o <= '1'; 174 | vs_cnt <= (others => '0'); 175 | elsif rising_h then 176 | bank_o <= not bank_o; 177 | if (vs_cnt(2) = '0') then 178 | vs_cnt <= vs_cnt + "1"; 179 | end if; 180 | end if; 181 | end if; 182 | end process; 183 | 184 | p_output : process(CLK_X2) 185 | begin 186 | if rising_edge (CLK_X2) then 187 | O_VSYNC <= not vs_cnt(2); 188 | if (hpos_o < 32) then 189 | O_HSYNC <= '1'; 190 | else 191 | O_HSYNC <= '0'; 192 | end if; 193 | 194 | O_B <= rgb_out(7 downto 6); 195 | O_G <= rgb_out(5 downto 3); 196 | O_R <= rgb_out(2 downto 0); 197 | 198 | end if; 199 | end process; 200 | 201 | end architecture RTL; 202 | -------------------------------------------------------------------------------- /src/main/pacman/pacman_debounce.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- A simulation model of Pacman hardware 3 | -- Copyright (c) MikeJ - January 2006 4 | -- 5 | -- All rights reserved 6 | -- 7 | -- Redistribution and use in source and synthezised forms, with or without 8 | -- modification, are permitted provided that the following conditions are met: 9 | -- 10 | -- Redistributions of source code must retain the above copyright notice, 11 | -- this list of conditions and the following disclaimer. 12 | -- 13 | -- Redistributions in synthesized form must reproduce the above copyright 14 | -- notice, this list of conditions and the following disclaimer in the 15 | -- documentation and/or other materials provided with the distribution. 16 | -- 17 | -- Neither the name of the author nor the names of other contributors may 18 | -- be used to endorse or promote products derived from this software without 19 | -- specific prior written permission. 20 | -- 21 | -- THIS CODE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 25 | -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | -- POSSIBILITY OF SUCH DAMAGE. 32 | -- 33 | -- You are responsible for any legal issues arising from your use of this code. 34 | -- 35 | -- The latest version of this file can be found at: www.fpgaarcade.com 36 | -- 37 | -- Email pacman@fpgaarcade.com 38 | -- 39 | -- Revision list 40 | -- 41 | -- version 004 oct 2006 release, active high 42 | -- version 003 Jan 2006 release, initial release of this module 43 | -- 44 | library ieee; 45 | use ieee.std_logic_1164.all; 46 | use ieee.std_logic_unsigned.all; 47 | use ieee.numeric_std.all; 48 | 49 | use work.pkg_pacman.all; 50 | 51 | entity PACMAN_DEBOUNCE is 52 | generic ( 53 | G_WIDTH : in integer 54 | ); 55 | port ( 56 | I_BUTTON : in std_logic_vector(G_WIDTH-1 downto 0); -- active high 57 | O_BUTTON : out std_logic_vector(G_WIDTH-1 downto 0); 58 | CLK : in std_logic 59 | ); 60 | end; 61 | 62 | architecture RTL of PACMAN_DEBOUNCE is 63 | 64 | signal tick_counter : std_logic_vector(12 downto 0); 65 | signal button : std_logic_vector(G_WIDTH-1 downto 0); 66 | begin 67 | 68 | p_debounce : process 69 | variable tick : boolean; 70 | begin 71 | wait until rising_edge(CLK); 72 | tick := (tick_counter(12) = '1'); 73 | -- pragma translate_off 74 | -- synopsys translate_off 75 | tick := true; 76 | -- synopsys translate_on 77 | -- pragma translate_on 78 | if tick then 79 | tick_counter <= '0' & x"FFE"; 80 | else 81 | tick_counter <= tick_counter - "1"; 82 | end if; 83 | -- tick approx 1.5KHz 84 | 85 | for i in 0 to G_WIDTH-1 loop 86 | if (I_BUTTON(i) = '1') then 87 | button(i) <= '1'; 88 | elsif tick then 89 | button(i) <= '0'; 90 | end if; 91 | end loop; 92 | end process; 93 | 94 | O_BUTTON <= button; 95 | 96 | end architecture RTL; 97 | -------------------------------------------------------------------------------- /src/main/pacman/pacman_mul4.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- A simulation model of Pacman hardware 3 | -- Copyright (c) MikeJ - January 2006 4 | -- 5 | -- All rights reserved 6 | -- 7 | -- Redistribution and use in source and synthezised forms, with or without 8 | -- modification, are permitted provided that the following conditions are met: 9 | -- 10 | -- Redistributions of source code must retain the above copyright notice, 11 | -- this list of conditions and the following disclaimer. 12 | -- 13 | -- Redistributions in synthesized form must reproduce the above copyright 14 | -- notice, this list of conditions and the following disclaimer in the 15 | -- documentation and/or other materials provided with the distribution. 16 | -- 17 | -- Neither the name of the author nor the names of other contributors may 18 | -- be used to endorse or promote products derived from this software without 19 | -- specific prior written permission. 20 | -- 21 | -- THIS CODE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 25 | -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | -- POSSIBILITY OF SUCH DAMAGE. 32 | -- 33 | -- You are responsible for any legal issues arising from your use of this code. 34 | -- 35 | -- The latest version of this file can be found at: www.fpgaarcade.com 36 | -- 37 | -- Email pacman@fpgaarcade.com 38 | -- 39 | -- Revision list 40 | -- 41 | -- version 003 Jan 2006 release, general tidy up 42 | -- version 002 initial release 43 | -- 44 | library ieee; 45 | use ieee.std_logic_1164.all; 46 | use ieee.std_logic_unsigned.all; 47 | use ieee.numeric_std.all; 48 | 49 | use work.pkg_pacman.all; 50 | 51 | entity PACMAN_MUL_PARTIAL is 52 | port ( 53 | A : in std_logic_vector(1 downto 0); 54 | B : in std_logic_vector(1 downto 0); 55 | R : out std_logic_vector(3 downto 0) 56 | ); 57 | end; 58 | 59 | architecture RTL of PACMAN_MUL_PARTIAL is 60 | 61 | begin 62 | p_lut_comb : process(A,B) 63 | variable ip : std_logic_vector(3 downto 0); 64 | begin 65 | ip := A & B; 66 | case ip is 67 | when "0000" => r <= x"0"; 68 | when "0001" => r <= x"0"; 69 | when "0010" => r <= x"0"; 70 | when "0011" => r <= x"0"; 71 | when "0100" => r <= x"0"; 72 | when "0101" => r <= x"1"; 73 | when "0110" => r <= x"2"; 74 | when "0111" => r <= x"3"; 75 | when "1000" => r <= x"0"; 76 | when "1001" => r <= x"2"; 77 | when "1010" => r <= x"4"; 78 | when "1011" => r <= x"6"; 79 | when "1100" => r <= x"0"; 80 | when "1101" => r <= x"3"; 81 | when "1110" => r <= x"6"; 82 | when "1111" => r <= x"9"; 83 | when others => null; 84 | end case; 85 | end process; 86 | end architecture RTL; 87 | 88 | library ieee; 89 | use ieee.std_logic_1164.all; 90 | use ieee.std_logic_unsigned.all; 91 | use ieee.numeric_std.all; 92 | 93 | library UNISIM; 94 | use UNISIM.Vcomponents.all; 95 | 96 | use work.pkg_pacman.all; 97 | 98 | entity PACMAN_MUL4 is 99 | port ( 100 | A : in std_logic_vector(3 downto 0); 101 | B : in std_logic_vector(3 downto 0); 102 | R : out std_logic_vector(7 downto 0) 103 | ); 104 | end; 105 | 106 | architecture RTL of PACMAN_MUL4 is 107 | 108 | signal r1 : std_logic_vector(3 downto 0); 109 | signal r2 : std_logic_vector(3 downto 0); 110 | signal r3 : std_logic_vector(3 downto 0); 111 | signal r4 : std_logic_vector(3 downto 0); 112 | 113 | signal add12 : std_logic_vector(7 downto 0); 114 | signal add34 : std_logic_vector(7 downto 0); 115 | 116 | component PACMAN_MUL_PARTIAL 117 | port ( 118 | A : in std_logic_vector(1 downto 0); 119 | B : in std_logic_vector(1 downto 0); 120 | R : out std_logic_vector(3 downto 0) 121 | ); 122 | end component; 123 | 124 | begin 125 | -- simple combinatorial multiplier 126 | 127 | partial_1 : PACMAN_MUL_PARTIAL 128 | port map ( A => A(1 downto 0), B => B(1 downto 0), R => r1); 129 | 130 | partial_2 : PACMAN_MUL_PARTIAL 131 | port map ( A => A(1 downto 0), B => B(3 downto 2), R => r2); 132 | 133 | partial_3 : PACMAN_MUL_PARTIAL 134 | port map ( A => A(3 downto 2), B => B(1 downto 0), R => r3); 135 | 136 | partial_4 : PACMAN_MUL_PARTIAL 137 | port map ( A => A(3 downto 2), B => B(3 downto 2), R => r4); 138 | 139 | -- balanced adder tree 140 | add12 <= ("0000" & r1 ) + ("00" & r2 & "00"); 141 | add34 <= ("00" & r3 & "00") + ( r4 & "0000"); 142 | R <= add12 + add34; 143 | 144 | end architecture RTL; 145 | 146 | -------------------------------------------------------------------------------- /src/main/pacman/pacman_rams.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- A simulation model of Pacman hardware 3 | -- Copyright (c) MikeJ - January 2006 4 | -- 5 | -- All rights reserved 6 | -- 7 | -- Redistribution and use in source and synthezised forms, with or without 8 | -- modification, are permitted provided that the following conditions are met: 9 | -- 10 | -- Redistributions of source code must retain the above copyright notice, 11 | -- this list of conditions and the following disclaimer. 12 | -- 13 | -- Redistributions in synthesized form must reproduce the above copyright 14 | -- notice, this list of conditions and the following disclaimer in the 15 | -- documentation and/or other materials provided with the distribution. 16 | -- 17 | -- Neither the name of the author nor the names of other contributors may 18 | -- be used to endorse or promote products derived from this software without 19 | -- specific prior written permission. 20 | -- 21 | -- THIS CODE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 25 | -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | -- POSSIBILITY OF SUCH DAMAGE. 32 | -- 33 | -- You are responsible for any legal issues arising from your use of this code. 34 | -- 35 | -- The latest version of this file can be found at: www.fpgaarcade.com 36 | -- 37 | -- Email pacman@fpgaarcade.com 38 | -- 39 | -- Revision list 40 | -- 41 | -- version 003 Jan 2006 release, general tidy up 42 | -- version 001 initial release 43 | -- 44 | library ieee; 45 | use ieee.std_logic_1164.all; 46 | use ieee.std_logic_unsigned.all; 47 | use ieee.numeric_std.all; 48 | 49 | library UNISIM; 50 | use UNISIM.Vcomponents.all; 51 | 52 | use work.pkg_pacman.all; 53 | 54 | entity PACMAN_RAMS is 55 | port ( 56 | I_AB : in std_logic_vector(11 downto 0); 57 | I_DATA : in std_logic_vector( 7 downto 0); 58 | O_DATA : out std_logic_vector( 7 downto 0); 59 | I_R_W_L : in std_logic; 60 | I_VRAM_L : in std_logic; 61 | ENA_6 : in std_logic; 62 | CLK : in std_logic 63 | ); 64 | end; 65 | 66 | architecture RTL of PACMAN_RAMS is 67 | 68 | signal ram_addr : std_logic_vector(11 downto 0); 69 | signal dout_ram : std_logic_vector(7 downto 0); 70 | signal we_ram : std_logic; 71 | 72 | begin 73 | -- combined rams, simplified decoding logic 74 | ram_addr <= I_AB(11 downto 0); 75 | we_ram <= not I_R_W_L and not I_VRAM_L; 76 | o_data <= dout_ram; 77 | 78 | -- combined vram, cram and wram 79 | -- vram 1K at I_AB(11 downto 10) = 00 80 | -- cram 1K at I_AB(11 downto 10) = 01 81 | -- spare 1K at I_AB(11 downto 10) = 10 82 | -- wram 1K at I_AB(11 downto 10) = 11 83 | 84 | ramhi : component RAMB16_S4 85 | port map ( 86 | do => dout_ram(7 downto 4), 87 | addr => ram_addr, 88 | clk => CLK, 89 | di => I_DATA(7 downto 4), 90 | en => ENA_6, 91 | ssr => '0', 92 | we => we_ram 93 | ); 94 | 95 | ramlo : component RAMB16_S4 96 | port map ( 97 | do => dout_ram(3 downto 0), 98 | addr => ram_addr, 99 | clk => CLK, 100 | di => I_DATA(3 downto 0), 101 | en => ENA_6, 102 | ssr => '0', 103 | we => we_ram 104 | ); 105 | 106 | end architecture RTL; 107 | -------------------------------------------------------------------------------- /src/main/pacman/pacman_tb.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- A simulation model of Pacman hardware 3 | -- Copyright (c) MikeJ - January 2006 4 | -- 5 | -- All rights reserved 6 | -- 7 | -- Redistribution and use in source and synthezised forms, with or without 8 | -- modification, are permitted provided that the following conditions are met: 9 | -- 10 | -- Redistributions of source code must retain the above copyright notice, 11 | -- this list of conditions and the following disclaimer. 12 | -- 13 | -- Redistributions in synthesized form must reproduce the above copyright 14 | -- notice, this list of conditions and the following disclaimer in the 15 | -- documentation and/or other materials provided with the distribution. 16 | -- 17 | -- Neither the name of the author nor the names of other contributors may 18 | -- be used to endorse or promote products derived from this software without 19 | -- specific prior written permission. 20 | -- 21 | -- THIS CODE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 25 | -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | -- POSSIBILITY OF SUCH DAMAGE. 32 | -- 33 | -- You are responsible for any legal issues arising from your use of this code. 34 | -- 35 | -- The latest version of this file can be found at: www.fpgaarcade.com 36 | -- 37 | -- Email pacman@fpgaarcade.com 38 | -- 39 | -- Revision list 40 | -- 41 | -- version 003 Jan 2006 release, general tidy up 42 | -- version 001 initial release 43 | -- 44 | use std.textio.ALL; 45 | library ieee; 46 | use ieee.std_logic_1164.all; 47 | use ieee.std_logic_unsigned.all; 48 | use ieee.numeric_std.all; 49 | 50 | use work.pkg_pacman.all; 51 | 52 | entity PACMAN_TB is 53 | end; 54 | 55 | architecture Sim of PACMAN_TB is 56 | 57 | signal button : std_logic_vector(3 downto 0); 58 | signal sw : std_logic_vector(3 downto 0); 59 | signal video_r : std_logic_vector(3 downto 0); 60 | signal video_g : std_logic_vector(3 downto 0); 61 | signal video_b : std_logic_vector(3 downto 0); 62 | signal hsync : std_logic; 63 | signal vsync : std_logic; 64 | signal clk_ref : std_logic; 65 | signal reset : std_logic; 66 | 67 | constant CLKPERIOD : time := 31.25 ns; 68 | 69 | begin 70 | 71 | p_clk_ref : process 72 | begin 73 | clk_ref <= '0'; 74 | wait for CLKPERIOD / 2; 75 | clk_ref <= '1'; 76 | wait for CLKPERIOD - (CLKPERIOD / 2); 77 | end process; 78 | 79 | p_rst : process 80 | begin 81 | reset <= '1'; 82 | wait for 100 ns; 83 | reset <= '0'; 84 | wait; 85 | end process; 86 | 87 | button <= (others => 'L'); 88 | sw <= (others => 'L'); 89 | 90 | u0 : entity work.PACMAN 91 | port map( 92 | O_VIDEO_R => video_r, 93 | O_VIDEO_G => video_g, 94 | O_VIDEO_B => video_b, 95 | O_HSYNC => hsync, 96 | O_VSYNC => vsync, 97 | -- 98 | O_AUDIO_L => open, 99 | O_AUDIO_R => open, 100 | -- 101 | I_SW => sw, 102 | I_JOYSTICK => button, 103 | O_LED => open, 104 | -- 105 | I_RESET => reset, 106 | I_CLK_REF => clk_ref 107 | ); 108 | 109 | end Sim; 110 | -------------------------------------------------------------------------------- /src/main/pacman/pacman_vram_addr.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- A simulation model of Pacman hardware 3 | -- Copyright (c) MikeJ & CarlW - January 2006 4 | -- 5 | -- All rights reserved 6 | -- 7 | -- Redistribution and use in source and synthezised forms, with or without 8 | -- modification, are permitted provided that the following conditions are met: 9 | -- 10 | -- Redistributions of source code must retain the above copyright notice, 11 | -- this list of conditions and the following disclaimer. 12 | -- 13 | -- Redistributions in synthesized form must reproduce the above copyright 14 | -- notice, this list of conditions and the following disclaimer in the 15 | -- documentation and/or other materials provided with the distribution. 16 | -- 17 | -- Neither the name of the author nor the names of other contributors may 18 | -- be used to endorse or promote products derived from this software without 19 | -- specific prior written permission. 20 | -- 21 | -- THIS CODE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 25 | -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | -- POSSIBILITY OF SUCH DAMAGE. 32 | -- 33 | -- You are responsible for any legal issues arising from your use of this code. 34 | -- 35 | -- The latest version of this file can be found at: www.fpgaarcade.com 36 | -- 37 | -- Email pacman@fpgaarcade.com 38 | -- 39 | -- Revision list 40 | -- 41 | -- version 003 Jan 2006 release, general tidy up 42 | -- version 001 initial release 43 | -- 44 | library ieee; 45 | use ieee.std_logic_1164.all; 46 | use ieee.std_logic_unsigned.all; 47 | use ieee.numeric_std.all; 48 | 49 | use work.pkg_pacman.all; 50 | 51 | entity X74_157 is 52 | port ( 53 | Y : out std_logic_vector (3 downto 0); 54 | B : in std_logic_vector (3 downto 0); 55 | A : in std_logic_vector (3 downto 0); 56 | G : in std_logic; 57 | S : in std_logic 58 | ); 59 | end; 60 | 61 | architecture RTL of X74_157 is 62 | begin 63 | p_y_comb : process(S,G,A,B) 64 | begin 65 | for i in 0 to 3 loop 66 | -- quad 2 line to 1 line mux (true logic) 67 | if (G = '1') then 68 | Y(i) <= '0'; 69 | else 70 | if (S = '0') then 71 | Y(i) <= A(i); 72 | else 73 | Y(i) <= B(i); 74 | end if; 75 | end if; 76 | end loop; 77 | end process; 78 | end RTL; 79 | 80 | library ieee; 81 | use ieee.std_logic_1164.all; 82 | use ieee.std_logic_arith.all; 83 | use ieee.std_logic_unsigned.all; 84 | 85 | use work.pkg_pacman.all; 86 | 87 | entity X74_257 is 88 | port ( 89 | Y : out std_logic_vector (3 downto 0); 90 | B : in std_logic_vector (3 downto 0); 91 | A : in std_logic_vector (3 downto 0); 92 | S : in std_logic 93 | ); 94 | end; 95 | 96 | architecture RTL of X74_257 is 97 | signal ab : std_logic_vector (3 downto 0); 98 | begin 99 | 100 | Y <= ab; -- no tristate 101 | p_ab : process(S,A,B) 102 | begin 103 | for i in 0 to 3 loop 104 | if (S = '0') then 105 | AB(i) <= A(i); 106 | else 107 | AB(i) <= B(i); 108 | end if; 109 | end loop; 110 | end process; 111 | end RTL; 112 | 113 | library ieee; 114 | use ieee.std_logic_1164.all; 115 | use ieee.std_logic_unsigned.all; 116 | use ieee.numeric_std.all; 117 | 118 | use work.pkg_pacman.all; 119 | 120 | entity PACMAN_VRAM_ADDR is 121 | port ( 122 | AB : out std_logic_vector (11 downto 0); 123 | H256_L : in std_logic; 124 | H128 : in std_logic; 125 | H64 : in std_logic; 126 | H32 : in std_logic; 127 | H16 : in std_logic; 128 | H8 : in std_logic; 129 | H4 : in std_logic; 130 | H2 : in std_logic; 131 | H1 : in std_logic; 132 | V128 : in std_logic; 133 | V64 : in std_logic; 134 | V32 : in std_logic; 135 | V16 : in std_logic; 136 | V8 : in std_logic; 137 | V4 : in std_logic; 138 | V2 : in std_logic; 139 | V1 : in std_logic; 140 | FLIP : in std_logic 141 | ); 142 | end; 143 | 144 | architecture RTL of PACMAN_VRAM_ADDR is 145 | 146 | signal v128p : std_logic; 147 | signal v64p : std_logic; 148 | signal v32p : std_logic; 149 | signal v16p : std_logic; 150 | signal v8p : std_logic; 151 | signal h128p : std_logic; 152 | signal h64p : std_logic; 153 | signal h32p : std_logic; 154 | signal h16p : std_logic; 155 | signal h8p : std_logic; 156 | signal sel : std_logic; 157 | signal y157 : std_logic_vector (11 downto 0); 158 | 159 | component X74_157 160 | port ( 161 | Y : out std_logic_vector (3 downto 0); 162 | B : in std_logic_vector (3 downto 0); 163 | A : in std_logic_vector (3 downto 0); 164 | G : in std_logic; 165 | S : in std_logic 166 | ); 167 | end component; 168 | 169 | component X74_257 170 | port ( 171 | Y : out std_logic_vector (3 downto 0); 172 | B : in std_logic_vector (3 downto 0); 173 | A : in std_logic_vector (3 downto 0); 174 | S : in std_logic 175 | ); 176 | end component; 177 | 178 | begin 179 | p_vp_comb : process(FLIP, V8, V16, V32, V64, V128) 180 | begin 181 | v128p <= FLIP xor V128; 182 | v64p <= FLIP xor V64; 183 | v32p <= FLIP xor V32; 184 | v16p <= FLIP xor V16; 185 | v8p <= FLIP xor V8; 186 | end process; 187 | 188 | p_hp_comb : process(FLIP, H8, H16, H32, H64, H128) 189 | begin 190 | H128P <= FLIP xor H128; 191 | H64P <= FLIP xor H64; 192 | H32P <= FLIP xor H32; 193 | H16P <= FLIP xor H16; 194 | H8P <= FLIP xor H8; 195 | end process; 196 | 197 | p_sel : process(H16, H32, H64) 198 | begin 199 | sel <= not((H32 xor H16) or (H32 xor H64)); 200 | end process; 201 | 202 | --p_oe257 : process(H2) 203 | --begin 204 | -- oe <= not(H2); 205 | --end process; 206 | 207 | U6 : X74_157 208 | port map( 209 | Y => y157(11 downto 8), 210 | B(3) => '0', 211 | B(2) => H4, 212 | B(1) => h64p, 213 | B(0) => h64p, 214 | A => "1111", 215 | G => '0', 216 | S => sel 217 | ); 218 | 219 | U5 : X74_157 220 | port map( 221 | Y => y157(7 downto 4), 222 | B(3) => h64p, 223 | B(2) => h64p, 224 | B(1) => h8p, 225 | B(0) => v128p, 226 | A => "1111", 227 | G => '0', 228 | S => sel 229 | ); 230 | 231 | U4 : X74_157 232 | port map( 233 | Y => y157(3 downto 0), 234 | B(3) => v64p, 235 | B(2) => v32p, 236 | B(1) => v16p, 237 | B(0) => v8p, 238 | A(3) => H64, 239 | A(2) => H32, 240 | A(1) => H16, 241 | A(0) => H4, 242 | G => '0', 243 | S => sel 244 | ); 245 | 246 | U3 : X74_257 247 | port map( 248 | Y => AB(11 downto 8), 249 | B(3) => '0', 250 | B(2) => H4, 251 | B(1) => v128p, 252 | B(0) => v64p, 253 | A => y157(11 downto 8), 254 | S => H256_L 255 | ); 256 | 257 | U2 : X74_257 258 | port map( 259 | Y => AB(7 downto 4), 260 | B(3) => v32p, 261 | B(2) => v16p, 262 | B(1) => v8p, 263 | B(0) => h128p, 264 | A => y157(7 downto 4), 265 | S => H256_L 266 | ); 267 | 268 | U1 : X74_257 269 | port map( 270 | Y => AB(3 downto 0), 271 | B(3) => h64p, 272 | B(2) => h32p, 273 | B(1) => h16p, 274 | B(0) => h8p, 275 | A => y157(3 downto 0), 276 | S => H256_L 277 | ); 278 | 279 | end RTL; 280 | -------------------------------------------------------------------------------- /src/main/pacman/pkg_pacman.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- A simulation model of Pacman hardware 3 | -- Copyright (c) MikeJ - January 2006 4 | -- 5 | -- All rights reserved 6 | -- 7 | -- Redistribution and use in source and synthezised forms, with or without 8 | -- modification, are permitted provided that the following conditions are met: 9 | -- 10 | -- Redistributions of source code must retain the above copyright notice, 11 | -- this list of conditions and the following disclaimer. 12 | -- 13 | -- Redistributions in synthesized form must reproduce the above copyright 14 | -- notice, this list of conditions and the following disclaimer in the 15 | -- documentation and/or other materials provided with the distribution. 16 | -- 17 | -- Neither the name of the author nor the names of other contributors may 18 | -- be used to endorse or promote products derived from this software without 19 | -- specific prior written permission. 20 | -- 21 | -- THIS CODE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 | -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 25 | -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | -- POSSIBILITY OF SUCH DAMAGE. 32 | -- 33 | -- You are responsible for any legal issues arising from your use of this code. 34 | -- 35 | -- The latest version of this file can be found at: www.fpgaarcade.com 36 | -- 37 | -- Email pacman@fpgaarcade.com 38 | -- 39 | -- Revision list 40 | -- 41 | -- version 003 Jan 2006 release, general tidy up 42 | -- version 002 pacman_dblscan added 43 | -- version 001 initial release 44 | -- 45 | library ieee; 46 | use ieee.std_logic_1164.all; 47 | use ieee.std_logic_unsigned.all; 48 | use ieee.numeric_std.all; 49 | 50 | package pkg_pacman is 51 | 52 | end; 53 | 54 | package body pkg_pacman is 55 | 56 | end; 57 | -------------------------------------------------------------------------------- /src/main/pano_rtl/audio.v: -------------------------------------------------------------------------------- 1 | 2 | module audio( 3 | input wire clk12, 4 | input wire reset12_, 5 | 6 | output wire audio_mclk, 7 | output wire audio_bclk, 8 | output reg audio_dacdat, 9 | output reg audio_daclrc, 10 | input wire audio_adcdat, 11 | output reg audio_adclrc, 12 | input wire [15:0] audio_sample 13 | ); 14 | 15 | // Mclk = 12.288 Mhz 16 | // // Normal Mode, mode B, LRP=0, Slave (Figure 23), 16 bits 17 | // { WM8750_AUDIO_INTFC_ADDR, (0<<7) | // BCLKINV: BCLK not inverted 18 | // (1<<6) | // MS : Master mode 19 | // (0<<5) | // LRSWAP : No L/R swap 20 | // (1<<4) | // LRP : DSP mode B: MSB on first clock cycle 21 | // (0<<2) | // WL : 16 bits 22 | // (3<<0) }, // FORMAT : DSP mode 23 | // 24 | 25 | assign audio_mclk = clk12; 26 | 27 | // In USB mode, BCLK = MCLK 28 | assign audio_bclk = clk12; 29 | 30 | reg signed [15:0] sample_left, sample_right; 31 | reg [31:0] sample; 32 | reg [8:0] bit_cntr, bit_cntr_nxt; 33 | reg [15:0] phase_cntr, phase_cntr_nxt; 34 | reg audio_daclrc_nxt, audio_dacdat_nxt; 35 | reg audio_adclrc_nxt; 36 | 37 | //localparam max_bit_cntr = 12288/48; // 48KHz 38 | localparam max_bit_cntr = 255; 39 | 40 | always @* 41 | begin 42 | bit_cntr_nxt = bit_cntr; 43 | phase_cntr_nxt = phase_cntr; 44 | if (bit_cntr_nxt == 0) begin 45 | sample_left = audio_sample; 46 | sample_right = audio_sample; 47 | sample = { sample_left, sample_right }; 48 | end 49 | bit_cntr_nxt = bit_cntr + 1; 50 | 51 | audio_daclrc_nxt = (bit_cntr == 0); 52 | audio_dacdat_nxt = |bit_cntr[8:5] ? 1'b0 : sample[~bit_cntr[4:0]]; 53 | 54 | audio_adclrc_nxt = (bit_cntr == 0); 55 | end 56 | 57 | always @(posedge clk12) 58 | begin 59 | bit_cntr <= bit_cntr_nxt; 60 | phase_cntr <= phase_cntr_nxt; 61 | audio_daclrc <= audio_daclrc_nxt; 62 | audio_dacdat <= audio_dacdat_nxt; 63 | audio_adclrc <= audio_adclrc_nxt; 64 | 65 | if (!reset12_) begin 66 | bit_cntr <= 0; 67 | phase_cntr <= 0; 68 | audio_daclrc <= 1'b0; 69 | audio_dacdat <= 1'b0; 70 | audio_adclrc <= 1'b0; 71 | end 72 | end 73 | 74 | endmodule 75 | 76 | -------------------------------------------------------------------------------- /src/main/roms.md5/pacman.md5: -------------------------------------------------------------------------------- 1 | 80239848ef62294e0e78e33a3f444e9c 82s123.7f 2 | ccfe14e6f085cf7dc8cbeaabe33be586 82s126.1m 3 | 726e495bf2562dee07ac463876bcc9a9 82s126.3m 4 | e46a7be53fc919b1416be6451636ec9d 82s126.4a 5 | 2791455babaf26e0b396c78d2b45f8f6 pacman.5e 6 | 9240f35d1d2beee0ff17195653b5e405 pacman.5f 7 | 290aa5eae9e2f63587b5dd5a7da932da pacman.6e 8 | 19a886fcd8b5e88b0ed1b97f9d8659c0 pacman.6f 9 | d7cce8bffd9563b133ec17ebbb6373d4 pacman.6h 10 | 33c0e197be4c787142af6c3be0d8f6b0 pacman.6j 11 | -------------------------------------------------------------------------------- /src/main/roms.md5/puckman.md5: -------------------------------------------------------------------------------- 1 | 80239848ef62294e0e78e33a3f444e9c pm1-1.7f 2 | 726e495bf2562dee07ac463876bcc9a9 pm1-2.3m 3 | ccfe14e6f085cf7dc8cbeaabe33be586 pm1-3.1m 4 | e46a7be53fc919b1416be6451636ec9d pm1-4.4a 5 | c24e4b2044ace1bbf47e661bec600a6a pm1_chg1.5e 6 | 9e5a185689590b2cb6138094470a93ba pm1_chg2.5h 7 | c01065c6d74030810c2d6889625b08b1 pm1_chg3.5f 8 | a8d78ed9210bbd69352613080ba595d6 pm1_chg4.5j 9 | 76bd59d73904b9a71f0a67e7f00d5fd6 pm1_prg1.6e 10 | 947ebdf9ec34ddaf2e8206b525727b2f pm1_prg2.6k 11 | 8fc5e666736124534f7d33f1987a0631 pm1_prg3.6f 12 | 82f36cc93dcd9e10838f4b3356487076 pm1_prg4.6m 13 | b0099ba911a1d4abddfd0d1b5649394e pm1_prg5.6h 14 | 02cf23196923f9f25ecf7666bd990df2 pm1_prg6.6n 15 | df9371e76d6dd1453ef718c9c4bb4beb pm1_prg7.6j 16 | ef82873cc3878a9c2d2afacec02df624 pm1_prg8.6p 17 | -------------------------------------------------------------------------------- /src/main/roms.md5/puckmanb.md5: -------------------------------------------------------------------------------- 1 | 80239848ef62294e0e78e33a3f444e9c 82s123.7f 2 | ccfe14e6f085cf7dc8cbeaabe33be586 82s126.1m 3 | 726e495bf2562dee07ac463876bcc9a9 82s126.3m 4 | e46a7be53fc919b1416be6451636ec9d 82s126.4a 5 | 3f84d78d59147b9b3c816da72110e55f namcopac.6e 6 | 1177a6a021d53c869756a11eb030f383 namcopac.6f 7 | b53423fc3c8379676370d37fa395d0d6 namcopac.6h 8 | 9affcc23d8addf20c18465dbfa6879da namcopac.6j 9 | 2791455babaf26e0b396c78d2b45f8f6 pacman.5e 10 | 9240f35d1d2beee0ff17195653b5e405 pacman.5f 11 | -------------------------------------------------------------------------------- /src/main/roms/puckmanb.md5: -------------------------------------------------------------------------------- 1 | 80239848ef62294e0e78e33a3f444e9c 82s123.7f 2 | ccfe14e6f085cf7dc8cbeaabe33be586 82s126.1m 3 | 726e495bf2562dee07ac463876bcc9a9 82s126.3m 4 | e46a7be53fc919b1416be6451636ec9d 82s126.4a 5 | 3f84d78d59147b9b3c816da72110e55f namcopac.6e 6 | 1177a6a021d53c869756a11eb030f383 namcopac.6f 7 | b53423fc3c8379676370d37fa395d0d6 namcopac.6h 8 | 9affcc23d8addf20c18465dbfa6879da namcopac.6j 9 | 2791455babaf26e0b396c78d2b45f8f6 pacman.5e 10 | 9240f35d1d2beee0ff17195653b5e405 pacman.5f 11 | -------------------------------------------------------------------------------- /src/main/roms/put_roms_here: -------------------------------------------------------------------------------- 1 | As the filename says rom images go here. 2 | -------------------------------------------------------------------------------- /src/main/scala/mr1/Fetch.scala: -------------------------------------------------------------------------------- 1 | 2 | package mr1 3 | 4 | import spinal.core._ 5 | 6 | 7 | case class Fetch2Decode(config: MR1Config) extends Bundle { 8 | 9 | val valid = Bool 10 | val pc = UInt(config.pcSize bits) 11 | val instr = Bits(32 bits) 12 | 13 | def init() : Fetch2Decode = { 14 | valid init(False) 15 | pc init(0) 16 | instr init(0) 17 | this 18 | } 19 | } 20 | 21 | case class Decode2Fetch(config: MR1Config) extends Bundle { 22 | val stall = Bool 23 | 24 | val pc_jump_valid = Bool 25 | val pc_jump = UInt(config.pcSize bits) 26 | } 27 | 28 | class Fetch(config: MR1Config) extends Component { 29 | 30 | val io = new Bundle { 31 | val instr_req = InstrReqIntfc(config) 32 | val instr_rsp = InstrRspIntfc(config) 33 | 34 | val f2d = out(Reg(Fetch2Decode(config)) init) 35 | val d2f = in(Decode2Fetch(config)) 36 | 37 | val d_rd_update = in(RegRdUpdate(config)) 38 | val e_rd_update = in(RegRdUpdate(config)) 39 | val w_rd_update = in(RegRdUpdate(config)) 40 | 41 | val rd2r = out(Read2RegFile(config)) 42 | val r2rd = in(RegFile2Read(config)) 43 | } 44 | 45 | val fetch_halt = False 46 | 47 | val instr = io.instr_rsp.data 48 | val opcode = instr(6 downto 0) 49 | val down_stall = io.d2f.stall || io.r2rd.stall 50 | val raw_stall = Bool 51 | 52 | val instr_is_jump = (opcode === Opcodes.JAL) || 53 | (opcode === Opcodes.JALR) || 54 | (opcode === Opcodes.B) || 55 | ((opcode === Opcodes.SYS) && False) 56 | val instr_is_jump_r = Bool 57 | 58 | 59 | val pc = new Area { 60 | // Keeps track of real, confirmed PC 61 | val real_pc = Reg(UInt(config.pcSize bits)) init(0) 62 | val real_pc_incr = real_pc + 4 63 | 64 | val send_instr = False 65 | 66 | object PcState extends SpinalEnum(binaryOneHot) { 67 | val Idle = newElement() 68 | val WaitReqReady = newElement() 69 | val WaitRsp = newElement() 70 | val WaitJumpDone = newElement() 71 | val WaitStallDone = newElement() 72 | } 73 | 74 | val cur_state = Reg(PcState()) init(PcState.Idle) 75 | val capture_instr = False 76 | 77 | io.instr_req.valid := False 78 | io.instr_req.addr := real_pc 79 | 80 | switch(cur_state){ 81 | is(PcState.Idle){ 82 | when (!fetch_halt && !down_stall){ 83 | io.instr_req.valid := True 84 | io.instr_req.addr := real_pc 85 | 86 | when(io.instr_req.ready){ 87 | cur_state := PcState.WaitRsp 88 | } 89 | .otherwise{ 90 | cur_state := PcState.WaitReqReady 91 | } 92 | } 93 | } 94 | is(PcState.WaitReqReady){ 95 | io.instr_req.valid := True 96 | io.instr_req.addr := real_pc 97 | 98 | when(io.instr_req.ready){ 99 | cur_state := PcState.WaitRsp 100 | } 101 | } 102 | is(PcState.WaitRsp){ 103 | 104 | when(io.instr_rsp.valid){ 105 | capture_instr := True 106 | real_pc := real_pc_incr 107 | io.instr_req.addr := real_pc_incr 108 | 109 | when(down_stall || raw_stall){ 110 | cur_state := PcState.WaitStallDone 111 | } 112 | .elsewhen(instr_is_jump){ 113 | send_instr := True 114 | cur_state := PcState.WaitJumpDone 115 | } 116 | .otherwise{ 117 | send_instr := True 118 | io.instr_req.valid := True 119 | 120 | when(io.instr_req.ready){ 121 | cur_state := PcState.WaitRsp 122 | } 123 | .otherwise{ 124 | cur_state := PcState.WaitReqReady 125 | } 126 | } 127 | } 128 | } 129 | is(PcState.WaitStallDone){ 130 | when(!(down_stall || raw_stall)){ 131 | send_instr := True 132 | 133 | when(instr_is_jump_r){ 134 | cur_state := PcState.WaitJumpDone 135 | } 136 | .otherwise{ 137 | io.instr_req.valid := True 138 | 139 | when(io.instr_req.ready){ 140 | cur_state := PcState.WaitRsp 141 | } 142 | .otherwise{ 143 | cur_state := PcState.WaitReqReady 144 | } 145 | } 146 | } 147 | } 148 | is(PcState.WaitJumpDone){ 149 | when(io.d2f.pc_jump_valid){ 150 | real_pc := io.d2f.pc_jump 151 | 152 | when(fetch_halt){ 153 | cur_state := PcState.Idle 154 | } 155 | .otherwise{ 156 | io.instr_req.valid := True 157 | io.instr_req.addr := io.d2f.pc_jump 158 | 159 | when(io.instr_req.ready){ 160 | cur_state := PcState.WaitRsp 161 | } 162 | .otherwise{ 163 | cur_state := PcState.WaitReqReady 164 | } 165 | } 166 | } 167 | } 168 | } 169 | } 170 | 171 | val instr_r = RegNextWhen(instr, pc.capture_instr) init(0) 172 | val pc_r = RegNextWhen(pc.real_pc, pc.capture_instr) init(0) 173 | instr_is_jump_r := RegNextWhen(instr_is_jump, pc.capture_instr) init(False) 174 | 175 | val f2d_nxt = Fetch2Decode(config) 176 | 177 | f2d_nxt := io.f2d 178 | 179 | val instr_final = (pc.cur_state === pc.PcState.WaitStallDone) ? instr_r | instr 180 | val pc_final = (pc.cur_state === pc.PcState.WaitStallDone) ? pc_r | pc.real_pc 181 | 182 | when(pc.send_instr){ 183 | f2d_nxt.valid := True 184 | f2d_nxt.pc := pc_final 185 | f2d_nxt.instr := instr_final 186 | } 187 | .elsewhen(!down_stall){ 188 | f2d_nxt.valid := False 189 | if (false){ 190 | // This makes debugging a bit easier, but it costs a few gates and timing 191 | f2d_nxt.pc := 0 192 | f2d_nxt.instr := 0 193 | } 194 | } 195 | 196 | val fetch_active = f2d_nxt.valid && !(down_stall || raw_stall) 197 | 198 | io.f2d := f2d_nxt 199 | 200 | val rf = new Area { 201 | 202 | val rs1_valid = True 203 | val rs2_valid = True 204 | 205 | val rs1_addr = U(instr_final(19 downto 15)) 206 | val rs2_addr = U(instr_final(24 downto 20)) 207 | 208 | val raw_stall = (rs1_valid && ((io.d_rd_update.rd_waddr_valid && (rs1_addr === io.d_rd_update.rd_waddr && io.d_rd_update.rd_waddr =/= 0)) || 209 | (io.e_rd_update.rd_waddr_valid && (rs1_addr === io.e_rd_update.rd_waddr && io.e_rd_update.rd_waddr =/= 0)) || 210 | (io.w_rd_update.rd_waddr_valid && (rs1_addr === io.w_rd_update.rd_waddr && io.w_rd_update.rd_waddr =/= 0)) )) || 211 | (rs2_valid && ((io.d_rd_update.rd_waddr_valid && (rs2_addr === io.d_rd_update.rd_waddr && io.d_rd_update.rd_waddr =/= 0)) || 212 | (io.e_rd_update.rd_waddr_valid && (rs2_addr === io.e_rd_update.rd_waddr && io.e_rd_update.rd_waddr =/= 0)) || 213 | (io.w_rd_update.rd_waddr_valid && (rs2_addr === io.w_rd_update.rd_waddr && io.w_rd_update.rd_waddr =/= 0)) )) 214 | 215 | io.rd2r.rs1_rd := rs1_valid && !(down_stall || raw_stall) 216 | io.rd2r.rs2_rd := rs2_valid && !(down_stall || raw_stall) 217 | io.rd2r.rs1_rd_addr := rs1_valid ? rs1_addr | 0 218 | io.rd2r.rs2_rd_addr := rs2_valid ? rs2_addr | 0 219 | } 220 | 221 | raw_stall := rf.raw_stall 222 | 223 | } 224 | 225 | 226 | -------------------------------------------------------------------------------- /src/main/scala/mr1/MR1.scala: -------------------------------------------------------------------------------- 1 | 2 | package mr1 3 | 4 | import spinal.core._ 5 | 6 | case class MR1Config( 7 | supportMul : Boolean = false, 8 | supportDiv : Boolean = false, 9 | supportCsr : Boolean = false, 10 | supportFormal : Boolean = false, 11 | supportFence : Boolean = false, 12 | supportAsyncReg : Boolean = false, 13 | supportRegInit : Boolean = false, 14 | pcSize : Int = 32, 15 | dataAddrSize : Int = 32, 16 | reflopDataRsp : Boolean = true 17 | ) { 18 | 19 | def hasMul = supportMul 20 | def hasDiv = supportDiv 21 | def hasCsr = supportCsr 22 | def hasFence = supportFence 23 | 24 | def hasAsyncReg = supportAsyncReg 25 | def hasRegInit = supportRegInit 26 | 27 | def hasFormal = supportFormal 28 | } 29 | 30 | case class RegRdUpdate(config: MR1Config) extends Bundle { 31 | 32 | val rd_waddr_valid = Bool 33 | val rd_waddr = UInt(5 bits) 34 | val rd_wdata_valid = Bool 35 | val rd_wdata = Bits(32 bits) 36 | } 37 | 38 | case class RVFI(config: MR1Config) extends Bundle { 39 | 40 | val valid = Bool 41 | val order = UInt(64 bits) 42 | val insn = Bits(32 bits) 43 | val trap = Bool 44 | val halt = Bool 45 | val intr = Bool 46 | val rs1_addr = UInt(5 bits) 47 | val rs2_addr = UInt(5 bits) 48 | val rs1_rdata = Bits(32 bits) 49 | val rs2_rdata = Bits(32 bits) 50 | val rd_addr = UInt(5 bits) 51 | val rd_wdata = Bits(32 bits) 52 | val pc_rdata = UInt(32 bits) 53 | val pc_wdata = UInt(32 bits) 54 | val mem_addr = UInt(32 bits) 55 | val mem_rmask = Bits(4 bits) 56 | val mem_wmask = Bits(4 bits) 57 | val mem_rdata = Bits(32 bits) 58 | val mem_wdata = Bits(32 bits) 59 | 60 | def init() : RVFI = { 61 | valid init(False) addAttribute("keep") 62 | order init(0) addAttribute("keep") 63 | insn init(0) addAttribute("keep") 64 | trap init(False) addAttribute("keep") 65 | halt init(False) addAttribute("keep") 66 | intr init(False) addAttribute("keep") 67 | rs1_addr init(0) addAttribute("keep") 68 | rs2_addr init(0) addAttribute("keep") 69 | rd_addr init(0) addAttribute("keep") 70 | rs1_rdata init(0) addAttribute("keep") 71 | rs2_rdata init(0) addAttribute("keep") 72 | rd_wdata init(0) addAttribute("keep") 73 | pc_rdata init(0) addAttribute("keep") 74 | pc_wdata init(0) addAttribute("keep") 75 | mem_addr init(0) addAttribute("keep") 76 | mem_rmask init(0) addAttribute("keep") 77 | mem_rdata init(0) addAttribute("keep") 78 | mem_wmask init(0) addAttribute("keep") 79 | mem_wdata init(0) addAttribute("keep") 80 | 81 | this 82 | } 83 | } 84 | 85 | object InstrFormat extends SpinalEnum(binaryOneHot) { 86 | val R = newElement() 87 | val I = newElement() 88 | val S = newElement() 89 | val B = newElement() 90 | val U = newElement() 91 | val J = newElement() 92 | val Shamt = newElement() 93 | } 94 | 95 | object InstrType extends SpinalEnum(binaryOneHot) { 96 | val Undef = newElement() 97 | val JAL = newElement() 98 | val JALR = newElement() 99 | val B = newElement() 100 | val L = newElement() 101 | val S = newElement() 102 | val ALU_ADD = newElement() 103 | val ALU = newElement() 104 | val SHIFT = newElement() 105 | val FENCE = newElement() 106 | val E = newElement() 107 | val CSR = newElement() 108 | val MULDIV = newElement() 109 | } 110 | 111 | case class InstrReqIntfc(config: MR1Config) extends Bundle() { 112 | 113 | val valid = out(Bool) 114 | val ready = in(Bool) 115 | val addr = out(UInt(config.pcSize bits)) 116 | } 117 | 118 | case class InstrRspIntfc(config: MR1Config) extends Bundle() { 119 | 120 | val valid = in(Bool) 121 | val data = in(Bits(32 bits)) 122 | } 123 | 124 | case class DataReqIntfc(config: MR1Config) extends Bundle() { 125 | 126 | val valid = out(Bool) 127 | val ready = in(Bool) 128 | val addr = out(UInt(config.dataAddrSize bits)) 129 | val wr = out(Bool) 130 | val size = out(Bits(2 bits)) 131 | val data = out(Bits(32 bits)) 132 | 133 | } 134 | 135 | case class DataRspIntfc(config: MR1Config) extends Bundle() { 136 | 137 | val valid = in(Bool) 138 | val data = in(Bits(32 bits)) 139 | } 140 | 141 | class MR1(config: MR1Config) extends Component { 142 | val io = new Bundle { 143 | val instr_req = InstrReqIntfc(config).setName("instr_req") 144 | val instr_rsp = InstrRspIntfc(config).setName("instr_rsp") 145 | 146 | val data_req = DataReqIntfc(config).setName("data_req") 147 | val data_rsp = DataRspIntfc(config).setName("data_rsp") 148 | 149 | val rvfi = if (config.supportFormal) out(RVFI(config).setName("rvfi")) else null 150 | } 151 | 152 | val fetch = new Fetch(config) 153 | fetch.io.instr_req <> io.instr_req 154 | fetch.io.instr_rsp <> io.instr_rsp 155 | 156 | val decode = new Decode(config) 157 | decode.io.f2d <> fetch.io.f2d 158 | decode.io.d2f <> fetch.io.d2f 159 | decode.io.rd_update <> fetch.io.d_rd_update 160 | 161 | val execute = new Execute(config) 162 | execute.io.d2e <> decode.io.d2e 163 | execute.io.e2d <> decode.io.e2d 164 | execute.io.rd_update <> fetch.io.e_rd_update 165 | execute.io.data_req <> io.data_req 166 | 167 | val reg_file = new RegFile(config) 168 | reg_file.io.rd2r <> fetch.io.rd2r 169 | reg_file.io.r2rd <> fetch.io.r2rd 170 | reg_file.io.r2rr <> decode.io.r2rr 171 | 172 | val wb = new Writeback(config) 173 | wb.io.e2w <> execute.io.e2w 174 | wb.io.w2e <> execute.io.w2e 175 | wb.io.rd_update <> fetch.io.w_rd_update 176 | wb.io.data_rsp <> io.data_rsp 177 | wb.io.w2r <> reg_file.io.w2r 178 | 179 | if (config.hasFormal){ 180 | decode.io.d2e_rvfi <> execute.io.d2e_rvfi 181 | execute.io.e2w_rvfi <> wb.io.e2w_rvfi 182 | wb.io.rvfi <> io.rvfi 183 | } 184 | } 185 | 186 | object MR1Verilog { 187 | def main(args: Array[String]) { 188 | SpinalVerilog(new MR1(config = MR1Config(supportFormal = true, 189 | supportMul = false, 190 | supportDiv = false, 191 | supportCsr = false))) 192 | } 193 | } 194 | 195 | -------------------------------------------------------------------------------- /src/main/scala/mr1/RegFile.scala: -------------------------------------------------------------------------------- 1 | 2 | package mr1 3 | 4 | import spinal.core._ 5 | 6 | case class Read2RegFile(config: MR1Config) extends Bundle { 7 | val rs1_rd = Bool 8 | val rs1_rd_addr = UInt(5 bits) 9 | 10 | val rs2_rd = Bool 11 | val rs2_rd_addr = UInt(5 bits) 12 | } 13 | 14 | case class RegFile2Read(config: MR1Config) extends Bundle { 15 | val stall = Bool 16 | } 17 | 18 | case class RegFile2ReadResult(config: MR1Config) extends Bundle { 19 | val rs1_data = Bits(32 bits) 20 | val rs2_data = Bits(32 bits) 21 | } 22 | 23 | case class Write2RegFile(config: MR1Config) extends Bundle { 24 | val rd_wr = Bool 25 | val rd_wr_addr = UInt(5 bits) 26 | val rd_wr_data = Bits(32 bits) 27 | } 28 | 29 | class RegFile(config: MR1Config) extends Component { 30 | 31 | val io = new Bundle { 32 | val rd2r = in(Read2RegFile(config)) 33 | val r2rd = out(RegFile2Read(config)) 34 | 35 | val r2rr = out(RegFile2ReadResult(config)) 36 | 37 | val w2r = in(Write2RegFile(config)) 38 | 39 | } 40 | 41 | val mem = Mem(Bits(32 bits), 32) 42 | 43 | io.r2rr.rs1_data := mem.readSync(io.rd2r.rs1_rd_addr, io.rd2r.rs1_rd) 44 | io.r2rr.rs2_data := mem.readSync(io.rd2r.rs2_rd_addr, io.rd2r.rs2_rd) 45 | 46 | val reg_init = 47 | if (config.hasRegInit){ 48 | new Area { 49 | val cntr = Reg(UInt(6 bits)) init(0) 50 | cntr := cntr(5) ? cntr | cntr + 1 51 | 52 | val initR = !cntr(5) 53 | io.r2rd.stall := initR 54 | } 55 | } else { 56 | new Area { 57 | val cntr = U"5'D0" 58 | val initR = RegNext(False) init(True) 59 | io.r2rd.stall := initR 60 | } 61 | } 62 | 63 | 64 | val rd_wr = Bool 65 | val rd_wr_addr = UInt(5 bits) 66 | val rd_wr_data = Bits(32 bits) 67 | 68 | // Write 0 to r0 after reset 69 | rd_wr := reg_init.initR ? True | io.w2r.rd_wr 70 | rd_wr_addr := reg_init.initR ? reg_init.cntr(4 downto 0) | io.w2r.rd_wr_addr 71 | rd_wr_data := reg_init.initR ? B"32'd0" | io.w2r.rd_wr_data 72 | 73 | mem.write(rd_wr_addr, rd_wr_data, rd_wr) 74 | 75 | } 76 | 77 | 78 | -------------------------------------------------------------------------------- /src/main/scala/mr1/Riscv.scala: -------------------------------------------------------------------------------- 1 | 2 | package mr1 3 | 4 | import spinal.core._ 5 | 6 | object Opcodes extends SpinalEnum { 7 | def LUI = B"0110111" 8 | def AUIPC = B"0010111" 9 | def JAL = B"1101111" 10 | def JALR = B"1100111" 11 | def B = B"1100011" 12 | def L = B"0000011" 13 | def S = B"0100011" 14 | def ALUI = B"0010011" 15 | def ALU = B"0110011" 16 | def F = B"0001111" 17 | def SYS = B"1110011" 18 | } 19 | -------------------------------------------------------------------------------- /src/main/scala/mr1/Writeback.scala: -------------------------------------------------------------------------------- 1 | 2 | package mr1 3 | 4 | import spinal.core._ 5 | 6 | 7 | class Writeback(config: MR1Config) extends Component { 8 | 9 | val io = new Bundle { 10 | val e2w = in(Execute2Writeback(config)) 11 | val w2e = out(Writeback2Execute(config)) 12 | 13 | val rd_update = out(RegRdUpdate(config)) 14 | 15 | val w2r = out(Write2RegFile(config)) 16 | 17 | val data_rsp = DataRspIntfc(config) 18 | 19 | val e2w_rvfi = in(RVFI(config)) 20 | val rvfi = if (config.hasFormal) out(Reg(RVFI(config)) init) else null 21 | } 22 | 23 | val w2e_stall_d = RegNext(io.w2e.stall, False) 24 | 25 | val wb_start = io.e2w.valid && !w2e_stall_d 26 | val wb_end = io.e2w.valid && !io.w2e.stall 27 | 28 | val ld = new Area { 29 | 30 | val data_rsp_valid = if (config.reflopDataRsp) RegNext(io.data_rsp.valid) else io.data_rsp.valid 31 | val data_rsp_data = if (config.reflopDataRsp) RegNext(io.data_rsp.data) else io.data_rsp.data 32 | 33 | val rsp_data_shift_adj = Bits(32 bits) 34 | rsp_data_shift_adj := data_rsp_data >> (io.e2w.ld_addr_lsb(1 downto 0) * 8) 35 | 36 | val rd_wdata = Bits(32 bits) 37 | rd_wdata := io.e2w.ld_data_size.mux( 38 | B"00" -> (io.e2w.ld_data_signed ? B(S(rsp_data_shift_adj( 7 downto 0)).resize(32)) | 39 | B(U(rsp_data_shift_adj( 7 downto 0)).resize(32)) ), 40 | B"01" -> (io.e2w.ld_data_signed ? B(S(rsp_data_shift_adj(15 downto 0)).resize(32)) | 41 | B(U(rsp_data_shift_adj(15 downto 0)).resize(32)) ), 42 | default -> rsp_data_shift_adj 43 | ) 44 | 45 | val ld_stall = io.e2w.valid && io.e2w.ld_active && !data_rsp_valid 46 | val rd_wr = io.e2w.valid && io.e2w.ld_active && !ld_stall 47 | } 48 | 49 | val rd_wr = io.e2w.valid && (io.e2w.rd_wr | ld.rd_wr) && (io.e2w.rd_waddr =/= 0) 50 | val rd_waddr = rd_wr ? io.e2w.rd_waddr | U"5'd0" 51 | val rd_wdata = B((io.e2w.rd_wdata.range -> io.e2w.rd_wr)) & B(io.e2w.rd_wdata) | 52 | B((ld.rd_wdata.range -> ld.rd_wr )) & B(ld.rd_wdata) 53 | 54 | io.w2e.stall := ld.ld_stall 55 | 56 | // Write to RegFile 57 | io.w2r.rd_wr := rd_wr 58 | io.w2r.rd_wr_addr := rd_waddr 59 | io.w2r.rd_wr_data := rd_wdata 60 | 61 | // Feedback for RAW testing and bypass 62 | io.rd_update.rd_waddr_valid := io.e2w.valid && rd_wr 63 | io.rd_update.rd_waddr := io.e2w.rd_waddr 64 | io.rd_update.rd_wdata_valid := io.e2w.valid && rd_wr 65 | io.rd_update.rd_wdata := rd_wdata 66 | 67 | 68 | val formal = if (config.hasFormal) new Area { 69 | 70 | io.rvfi.valid := wb_end 71 | 72 | when(wb_start){ 73 | io.rvfi.order := io.e2w_rvfi.order 74 | io.rvfi.pc_rdata := io.e2w_rvfi.pc_rdata 75 | io.rvfi.pc_wdata := io.e2w_rvfi.pc_wdata 76 | io.rvfi.insn := io.e2w_rvfi.insn 77 | io.rvfi.trap := io.e2w_rvfi.trap 78 | io.rvfi.halt := io.e2w_rvfi.halt 79 | io.rvfi.intr := io.e2w_rvfi.intr 80 | 81 | io.rvfi.rs1_addr := io.e2w_rvfi.rs1_addr 82 | io.rvfi.rs2_addr := io.e2w_rvfi.rs2_addr 83 | io.rvfi.rd_addr := io.e2w_rvfi.rd_addr 84 | 85 | io.rvfi.rs1_rdata := io.e2w_rvfi.rs1_rdata 86 | io.rvfi.rs2_rdata := io.e2w_rvfi.rs2_rdata 87 | io.rvfi.rd_wdata := 0 88 | 89 | io.rvfi.mem_addr := io.e2w_rvfi.mem_addr 90 | io.rvfi.mem_rmask := io.e2w_rvfi.mem_rmask 91 | io.rvfi.mem_rdata := 0 92 | io.rvfi.mem_wmask := io.e2w_rvfi.mem_wmask 93 | io.rvfi.mem_wdata := io.e2w_rvfi.mem_wdata 94 | } 95 | 96 | when(rd_wr){ 97 | io.rvfi.rd_wdata := rd_wdata 98 | } 99 | 100 | when(io.e2w.ld_active && ld.data_rsp_valid){ 101 | io.rvfi.mem_rdata := ld.data_rsp_data 102 | } 103 | 104 | } else null 105 | 106 | } 107 | 108 | 109 | -------------------------------------------------------------------------------- /src/main/scala/mr1/cpu_ram.scala: -------------------------------------------------------------------------------- 1 | 2 | package mr1 3 | 4 | import spinal.core._ 5 | 6 | 7 | class cpu_ram extends BlackBox { 8 | 9 | val io = new Bundle { 10 | val clock = in(Bool) 11 | val address_a = in(UInt(10 bits)) 12 | val wren_a = in(Bool) 13 | val data_a = in(Bits(32 bits)) 14 | val q_a = out(Bits(32 bits)) 15 | 16 | val address_b = in(UInt(10 bits)) 17 | val wren_b = in(Bool) 18 | val byteena_b = in(Bits(4 bits)) 19 | val data_b = in(Bits(32 bits)) 20 | val q_b = out(Bits(32 bits)) 21 | } 22 | 23 | mapCurrentClockDomain(io.clock) 24 | noIoPrefix() 25 | 26 | // addRTLPath("./quartus/altera_models/cpu_ram/cpu_ram_bb.v") 27 | } 28 | 29 | -------------------------------------------------------------------------------- /src/main/scala/panoman/MR1Top.scala: -------------------------------------------------------------------------------- 1 | 2 | package mr1 3 | 4 | import java.nio.file.{Files, Paths} 5 | import spinal.core._ 6 | import spinal.lib.master 7 | import spinal.lib.io.ReadableOpenDrain 8 | 9 | import panoman._ 10 | 11 | class MR1Top(config: MR1Config ) extends Component { 12 | 13 | val io = new Bundle { 14 | val led1 = out(Bool) 15 | val led2 = out(Bool) 16 | val led3 = out(Bool) 17 | 18 | val switch_ = in(Bool) 19 | 20 | val codec_scl = master(ReadableOpenDrain(Bool)) 21 | val codec_sda = master(ReadableOpenDrain(Bool)) 22 | val vo_scl = master(ReadableOpenDrain(Bool)) 23 | val vo_sda = master(ReadableOpenDrain(Bool)) 24 | val gpio_out = out Bits(18 bits) 25 | } 26 | 27 | val mr1 = new MR1(config) 28 | 29 | val wmask = mr1.io.data_req.size.mux( 30 | 31 | B"00" -> B"0001", 32 | B"01" -> B"0011", 33 | default -> B"1111") |<< mr1.io.data_req.addr(1 downto 0) 34 | 35 | mr1.io.instr_req.ready := True 36 | mr1.io.instr_rsp.valid := RegNext(mr1.io.instr_req.valid) init(False) 37 | 38 | val cpu_ram_rd_data = Bits(32 bits) 39 | val reg_rd_data = Bits(32 bits) 40 | 41 | mr1.io.data_req.ready := True 42 | mr1.io.data_rsp.valid := RegNext(mr1.io.data_req.valid && !mr1.io.data_req.wr) init(False) 43 | mr1.io.data_rsp.data := RegNext(mr1.io.data_req.addr(19)) ? reg_rd_data | cpu_ram_rd_data 44 | 45 | val ramSize = 8192 46 | 47 | val ram = if (true) new Area{ 48 | 49 | val byteArray = Files.readAllBytes(Paths.get("sw/progmem8k.bin")) 50 | val cpuRamContent = for(i <- 0 until ramSize/4) yield { 51 | B( (byteArray(4*i).toLong & 0xff) + ((byteArray(4*i+1).toLong & 0xff)<<8) + ((byteArray(4*i+2).toLong & 0xff)<<16) + ((byteArray(4*i+3).toLong & 0xff)<<24), 32 bits) 52 | } 53 | 54 | val cpu_ram = Mem(Bits(32 bits), initialContent = cpuRamContent) 55 | 56 | mr1.io.instr_rsp.data := cpu_ram.readSync( 57 | enable = mr1.io.instr_req.valid, 58 | address = (mr1.io.instr_req.addr >> 2).resized 59 | ) 60 | 61 | cpu_ram_rd_data := cpu_ram.readWriteSync( 62 | enable = mr1.io.data_req.valid && !mr1.io.data_req.addr(19), 63 | address = (mr1.io.data_req.addr >> 2).resized, 64 | write = mr1.io.data_req.wr, 65 | data = mr1.io.data_req.data, 66 | mask = wmask 67 | ) 68 | } 69 | else new Area{ 70 | val cpu_ram = new cpu_ram() 71 | 72 | cpu_ram.io.address_a := (mr1.io.instr_req.addr >> 2).resized 73 | cpu_ram.io.wren_a := False 74 | cpu_ram.io.data_a := 0 75 | mr1.io.instr_rsp.data := cpu_ram.io.q_a 76 | 77 | 78 | cpu_ram.io.address_b := (mr1.io.data_req.addr >> 2).resized 79 | cpu_ram.io.wren_b := mr1.io.data_req.valid && mr1.io.data_req.wr && !mr1.io.data_req.addr(19) 80 | cpu_ram.io.byteena_b := wmask 81 | cpu_ram.io.data_b := mr1.io.data_req.data 82 | mr1.io.data_rsp.data := cpu_ram.io.q_b 83 | } 84 | 85 | val update_leds = mr1.io.data_req.valid && mr1.io.data_req.wr && (mr1.io.data_req.addr === U"32'h00080000") 86 | 87 | io.led1 := RegNextWhen(mr1.io.data_req.data(0), update_leds) init(False) 88 | io.led2 := RegNextWhen(mr1.io.data_req.data(1), update_leds) init(False) 89 | io.led3 := RegNextWhen(mr1.io.data_req.data(2), update_leds) init(False) 90 | 91 | // I2C interfaces 92 | val codec_scl_addr = (mr1.io.data_req.addr === U"32'h00080010") 93 | val codec_sda_addr = (mr1.io.data_req.addr === U"32'h00080014") 94 | 95 | val write_codec_sda = mr1.io.data_req.valid && mr1.io.data_req.wr && codec_sda_addr 96 | val write_codec_scl = mr1.io.data_req.valid && mr1.io.data_req.wr && codec_scl_addr 97 | 98 | io.codec_sda.write := RegNextWhen(mr1.io.data_req.data(0), write_codec_sda) init(False) 99 | io.codec_scl.write := RegNextWhen(mr1.io.data_req.data(0), write_codec_scl) init(False) 100 | 101 | val vo_scl_addr = (mr1.io.data_req.addr === U"32'h00080018") 102 | val vo_sda_addr = (mr1.io.data_req.addr === U"32'h0008001c") 103 | 104 | 105 | val write_vo_sda = mr1.io.data_req.valid && mr1.io.data_req.wr && vo_sda_addr 106 | val write_vo_scl = mr1.io.data_req.valid && mr1.io.data_req.wr && vo_scl_addr 107 | 108 | io.vo_sda.write := RegNextWhen(mr1.io.data_req.data(0), write_vo_sda) init(False) 109 | io.vo_scl.write := RegNextWhen(mr1.io.data_req.data(0), write_vo_scl) init(False) 110 | 111 | val gpio_addr = (mr1.io.data_req.addr === U"32'h00080020") 112 | val write_gpio = mr1.io.data_req.valid && mr1.io.data_req.wr && gpio_addr 113 | 114 | io.gpio_out := RegNextWhen(mr1.io.data_req.data(0, 18 bits), write_gpio) init(0) 115 | 116 | reg_rd_data := (RegNext(codec_sda_addr) ? (B(0, 31 bits) ## io.codec_sda.read) | 117 | (RegNext(codec_scl_addr) ? (B(0, 31 bits) ## io.codec_scl.read) | 118 | (RegNext(vo_sda_addr) ? (B(0, 31 bits) ## io.vo_sda.read) | 119 | (RegNext(vo_scl_addr) ? (B(0, 31 bits) ## io.vo_scl.read) | 120 | (RegNext(gpio_addr) ? (B(0, 14 bits) ## io.gpio_out) | 121 | B(0, 32 bits)))))) 122 | 123 | } 124 | 125 | -------------------------------------------------------------------------------- /src/main/scala/panoman/PacmanClock.scala: -------------------------------------------------------------------------------- 1 | package panoman 2 | 3 | import spinal.core._ 4 | 5 | class Pacman_clk() extends BlackBox { 6 | val io = new Bundle { 7 | val CLKIN_IN = in Bool 8 | val CLKFX_OUT = out Bool 9 | var CLKIN_IBUFG_OUT = out Bool 10 | var CLK0_OUT = out Bool 11 | } 12 | 13 | // Remove io_ prefix 14 | noIoPrefix() 15 | } 16 | 17 | class Pacman_clk1() extends BlackBox { 18 | val io = new Bundle { 19 | val CLKIN_IN = in Bool 20 | val CLKDV_OUT = out Bool 21 | var CLK0_OUT = out Bool 22 | } 23 | 24 | // Remove io_ prefix 25 | noIoPrefix() 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/main/scala/panoman/Pano.scala: -------------------------------------------------------------------------------- 1 | package panoman 2 | 3 | import spinal.core._ 4 | import spinal.lib.Counter 5 | import spinal.lib.CounterFreeRun 6 | import spinal.lib.GrayCounter 7 | import spinal.lib.master 8 | import spinal.lib.io.ReadableOpenDrain 9 | 10 | 11 | case class Pano() extends Component { 12 | 13 | val io = new Bundle { 14 | val osc_clk = in(Bool) 15 | 16 | val pano_button = in(Bool) 17 | 18 | val vo_clk = out(Bool) 19 | val vo = out(VgaData()) 20 | 21 | val led_green = in(Bool) 22 | val led_blue = in(Bool) 23 | val led_red = out(Bool) 24 | 25 | val vo_scl = master(ReadableOpenDrain(Bool)) 26 | val vo_sda = master(ReadableOpenDrain(Bool)) 27 | 28 | val audio_scl = master(ReadableOpenDrain(Bool)) 29 | val audio_sda = master(ReadableOpenDrain(Bool)) 30 | 31 | var audio_mclk = out(Bool) 32 | var audio_bclk = out(Bool) 33 | var audio_dacdat = out(Bool) 34 | var audio_daclrc = out(Bool) 35 | var audio_adcdat = in(Bool) 36 | var audio_adclrc = out(Bool) 37 | } 38 | noIoPrefix() 39 | 40 | val gpio_out = Bits(18 bits) 41 | 42 | //============================================================ 43 | // Create pacman clock domain 44 | // We need 6.144 Mhz (1x), 12.288 (x2), and 24.576 (x4) 45 | // We'll multiple the 100 Mhz input clock by 8 and divide 46 | // by 5 to generated a 160 Mhz clock which we will feed into a 47 | // second DCM which will divide it by 6.5 to generate 24.615 Mhz. 48 | // We'll divide 24.615 by 2 to generate 12.31 and by 4 to 49 | // generate 6.15 Mhz which is .16 percent faster than ideal. 50 | //============================================================ 51 | 52 | val pacman_clk = new Pacman_clk() 53 | pacman_clk.io.CLKIN_IN <> io.osc_clk 54 | 55 | val pacman_clk1 = new Pacman_clk1() 56 | pacman_clk1.io.CLKIN_IN <> pacman_clk.io.CLKFX_OUT 57 | 58 | 59 | //============================================================ 60 | // Create pacman clock domain 61 | //============================================================ 62 | val pacmanClockDomain = ClockDomain( 63 | clock = pacman_clk1.io.CLKDV_OUT, 64 | frequency = FixedFrequency(24.576 MHz), 65 | config = ClockDomainConfig( 66 | resetKind = BOOT 67 | ) 68 | ) 69 | 70 | val core = new ClockingArea(pacmanClockDomain) { 71 | // Create div2 and div4 clocks 72 | var clk_cntr6 = Reg(UInt(2 bits)) init(0) 73 | clk_cntr6 := clk_cntr6 + 1 74 | var clk12 = RegNext(clk_cntr6(0)) 75 | var clk6 = RegNext(clk_cntr6(0) & ~clk_cntr6(1)) 76 | 77 | val reset_unbuffered_ = True 78 | 79 | val reset_cntr = Reg(UInt(5 bits)) init(0) 80 | when(reset_cntr =/= U(reset_cntr.range -> true)){ 81 | reset_cntr := reset_cntr + 1 82 | reset_unbuffered_ := False 83 | } 84 | 85 | val reset_ = RegNext(reset_unbuffered_) 86 | val u_pano_core = new PanoCore() 87 | io.audio_scl <> u_pano_core.io.codec_scl 88 | io.audio_sda <> u_pano_core.io.codec_sda 89 | io.vo_scl <> u_pano_core.io.vo_scl 90 | io.vo_sda <> u_pano_core.io.vo_sda 91 | io.led_red := u_pano_core.io.led1 92 | gpio_out := u_pano_core.io.gpio_out 93 | } 94 | 95 | var audio = new audio() 96 | audio.io.clk12 <> core.clk12 97 | audio.io.reset12_ := core.reset_ 98 | audio.io.audio_mclk <> io.audio_mclk 99 | audio.io.audio_bclk <> io.audio_bclk 100 | audio.io.audio_dacdat <> io.audio_dacdat 101 | audio.io.audio_adcdat <> io.audio_adcdat 102 | audio.io.audio_daclrc <> io.audio_daclrc 103 | audio.io.audio_adclrc <> io.audio_adclrc 104 | 105 | var pacman = new Pacman() 106 | io.vo_clk <> pacman_clk.io.CLKFX_OUT 107 | pacman.io.clk <> pacman_clk1.io.CLKDV_OUT 108 | pacman.io.ena_12 <> core.clk12 109 | pacman.io.ena_6 <> core.clk6 110 | pacman.io.I_JOYSTICK_B := 31 111 | 112 | when(gpio_out(14)) { 113 | audio.io.audio_sample := S(pacman.io.O_AUDIO << 6) 114 | } 115 | .otherwise{ 116 | audio.io.audio_sample := 0 117 | } 118 | 119 | // pacman.io.I_JOYSTICK_A bits: 120 | // 7 - credit 121 | // 6 - coin2 122 | // 5 - coin1 123 | // 4 - test_l dipswitch (rack advance) 124 | // 3 - p1 down 125 | // 2 - p1 right 126 | // 1 - p1 left 127 | // 0 - p1 up 128 | // 129 | // pacman.io.I_JOYSTICK_B bits: 130 | // 7 - table 0:cocktail 1:upright 131 | // 6 - start2 132 | // 5 - start1 133 | // 4 - test and fire 134 | // 3 - p2 down 135 | // 2 - p2 right 136 | // 1 - p2 left 137 | // 0 - p2 up 138 | // 139 | // pacman.io.I_SW bits: 140 | // 7 - character set ? 141 | // 6 - difficulty ? 142 | // 5,4: 00 - bonus pacman at 10K 143 | // 5,4: 01 - bonus pacman at 15K 144 | // 5,4: 10 - bonus pacman at 20K 145 | // 5,4: 11 - no bonus 146 | // 147 | // 3,2: 00 - 1 pacman 148 | // 3,2: 01 - 2 pacmen 149 | // 3,2: 10 - 3 pacmen 150 | // 3,2: 11 - 5 pacmen 151 | // 152 | // 1,0: 00 - free play 153 | // 1,0: 01 - 1 coin, 1 play 154 | // 1,0: 10 - 1 coin, 2 play 155 | // 1,0: 11 - 2 coin, 1 play 156 | 157 | // gpio_out bits: 158 | // - 17 - Initialization complete 159 | // - 16 - MCP23017 present 160 | // PB7 15 - P2 LED1 161 | // PB6 14 - P2 SW2 - audio mute 162 | // PB5 13 - P2 SW1 - 0 (on): cocktail, 1: upright 163 | // PB4 12 - P2 up 164 | // PB3 11 - P2 trigger - 2 player start 165 | // PB2 10 - P2 down 166 | // PB1 9 - P2 left 167 | // PB0 8 - P2 right 168 | // 169 | // PA7 7 - P1 LED1 170 | // PA6 6 - P1 SW2 171 | // PA5 5 - P1 SW1 172 | // PA4 4 - P1 up 173 | // PA3 3 - P1 trigger - 1 player start 174 | // PA2 2 - P1 down 175 | // PA1 1 - P1 left 176 | // PA0 0 - P1 right 177 | 178 | when(gpio_out(16)) { 179 | // I2C port expander is present, use it 180 | 181 | pacman.io.I_JOYSTICK_A := 182 | (7 -> True, // credit 183 | 6 -> True, // coin2 184 | 5 -> ~io.pano_button, // coin1 185 | 4 -> True, // rack test 186 | 3 -> gpio_out(2), // p1 down 187 | 2 -> gpio_out(0), // p1 right 188 | 1 -> gpio_out(1), // p1 left 189 | 0 -> gpio_out(4)) // p1 up 190 | 191 | pacman.io.I_JOYSTICK_B := 192 | (7 -> gpio_out(13), // upright/cocktail table select 193 | 6 -> gpio_out(11), // start2 194 | 5 -> gpio_out(3), // start1 195 | 4 -> True, // test and fire 196 | 3 -> gpio_out(10), // p2 down 197 | 2 -> gpio_out(8), // p2 right 198 | 1 -> gpio_out(9), // p2 left 199 | 0 -> gpio_out(12)) // p2 up 200 | 201 | pacman.io.I_SW := 202 | (7 -> True, // character set? 203 | 6 -> True, // difficulty 204 | 5 -> False, // 00: bonus pacman at 10k 205 | 4 -> False, 206 | 3 -> True, // 10: pacmen (3) 207 | 2 -> False, 208 | 1 -> False, // 01: cost (1 coin, 1 play) 209 | 0 -> True) 210 | } 211 | .otherwise{ 212 | // Atari 2600 Joystick VGA Pano 213 | // Joystick Signal connector Signal 214 | //--------- ------ ------ -------------------- 215 | // DB9.1 UP J14.15 VGA SCL 216 | // DB9.2 DOWN J14.12 VGA SDA 217 | // DB9.3 LEFT J14.4 Blue LED (via added wire) 218 | // DB9.4 RIGHT J14.11 Green LED (via add wire) 219 | // DB9.5 A Paddle (n/c) 220 | // DB9.6 B Paddle (n/c) 221 | // DB9.7 +5 V J14.9 222 | // DB9.8 Ground J14.5 223 | 224 | pacman.io.I_JOYSTICK_A := 225 | (7 -> True, // credit 226 | 6 -> True, // coin2 227 | 5 -> True, // coin1 228 | 4 -> True, // rack test 229 | 3 -> io.vo_sda.read, // p1 down 230 | 2 -> io.led_green, // p1 right 231 | 1 -> io.led_blue, // p1 left 232 | 0 -> io.vo_scl.read) // p1 up 233 | 234 | pacman.io.I_JOYSTICK_B := 235 | (5 -> ~io.pano_button, // start1 236 | default -> True) 237 | 238 | pacman.io.I_SW := 239 | (7 -> True, // character set? 240 | 6 -> True, // difficulty 241 | 5 -> False, // 00: bonus pacman at 10k 242 | 4 -> False, 243 | 3 -> True, // 10: pacmen (3) 244 | 2 -> False, 245 | 1 -> False, // 00: cost (freeplay) 246 | 0 -> False) 247 | 248 | } 249 | pacman.io.I_RESET := ~gpio_out(17) 250 | 251 | io.vo.vsync := !pacman.io.O_VSYNC 252 | io.vo.hsync := !pacman.io.O_HSYNC 253 | io.vo.blank_ := True 254 | // io.vo.blank_ := !pacman.io.O_BLANK 255 | 256 | 257 | io.vo.r := pacman.io.O_VIDEO_R << 4 258 | io.vo.g := pacman.io.O_VIDEO_G << 4 259 | io.vo.b := pacman.io.O_VIDEO_B << 4 260 | } 261 | 262 | 263 | -------------------------------------------------------------------------------- /src/main/scala/panoman/PanoAudio.scala: -------------------------------------------------------------------------------- 1 | package panoman 2 | 3 | import spinal.core._ 4 | 5 | class audio() extends BlackBox { 6 | val io = new Bundle { 7 | var clk12 = in Bool 8 | var reset12_ = in Bool 9 | 10 | var audio_mclk = out Bool 11 | var audio_bclk = out Bool 12 | var audio_dacdat = out Bool 13 | var audio_daclrc = out Bool 14 | var audio_adcdat = in Bool 15 | var audio_adclrc = out Bool 16 | var audio_sample = in SInt(16 bits) 17 | } 18 | 19 | // Remove io_ prefix 20 | noIoPrefix() 21 | 22 | addRTLPath("./src/main/pano_rtl/audio.v") 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/main/scala/panoman/PanoCore.scala: -------------------------------------------------------------------------------- 1 | package panoman 2 | 3 | import spinal.core._ 4 | import spinal.lib.Counter 5 | import spinal.lib.CounterFreeRun 6 | import spinal.lib.GrayCounter 7 | import spinal.lib.master 8 | import spinal.lib.io.ReadableOpenDrain 9 | 10 | import mr1._ 11 | 12 | class PanoCore extends Component { 13 | 14 | val io = new Bundle { 15 | val led_green = out(Bool) 16 | val led_blue = out(Bool) 17 | val led1 = out(Bool) 18 | 19 | val codec_scl = master(ReadableOpenDrain(Bool)) 20 | val codec_sda = master(ReadableOpenDrain(Bool)) 21 | 22 | val vo_scl = master(ReadableOpenDrain(Bool)) 23 | val vo_sda = master(ReadableOpenDrain(Bool)) 24 | val gpio_out = out Bits(18 bits) 25 | } 26 | 27 | val leds = new Area { 28 | val led_cntr = Reg(UInt(24 bits)) init(0) 29 | 30 | when(led_cntr === U(led_cntr.range -> true)){ 31 | led_cntr := 0 32 | } 33 | .otherwise { 34 | led_cntr := led_cntr +1 35 | } 36 | 37 | io.led_green := led_cntr.msb 38 | } 39 | 40 | val eof_final = Bool 41 | 42 | val mr1Config = MR1Config() 43 | val u_mr1_top = new MR1Top(mr1Config) 44 | u_mr1_top.io.led1 <> io.led_blue 45 | u_mr1_top.io.switch_ <> True 46 | u_mr1_top.io.codec_scl <> io.codec_scl 47 | u_mr1_top.io.codec_sda <> io.codec_sda 48 | u_mr1_top.io.vo_scl <> io.vo_scl 49 | u_mr1_top.io.vo_sda <> io.vo_sda 50 | u_mr1_top.io.led1 <> io.led1 51 | u_mr1_top.io.gpio_out <> io.gpio_out 52 | 53 | } 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/main/scala/panoman/PanoIOs.scala: -------------------------------------------------------------------------------- 1 | package panoman 2 | 3 | import spinal.core._ 4 | 5 | case class VgaData() extends Bundle { 6 | val vsync = Bool 7 | val hsync = Bool 8 | val blank_ = Bool 9 | val r = UInt(8 bits) 10 | val g = UInt(8 bits) 11 | val b = UInt(8 bits) 12 | 13 | def init() : VgaData = { 14 | vsync init(False) 15 | hsync init(False) 16 | blank_ init(False) 17 | r init(0) 18 | g init(0) 19 | b init(0) 20 | this 21 | } 22 | } 23 | 24 | case class Pixel() extends Bundle { 25 | val r = UInt(8 bits) 26 | val g = UInt(8 bits) 27 | val b = UInt(8 bits) 28 | 29 | def setColor(r: Double, g: Double, b: Double) = { 30 | this.r := U( (r * ((1 < $@ 26 | 27 | progmem0.hex: progmem.bin 28 | ../misc/create_mif.rb -f hex -d $(MEM_WORDS) -w 8 -o 0 -i 4 $< > progmem0.hex 29 | ../misc/create_mif.rb -f hex -d $(MEM_WORDS) -w 8 -o 1 -i 4 $< > progmem1.hex 30 | ../misc/create_mif.rb -f hex -d $(MEM_WORDS) -w 8 -o 2 -i 4 $< > progmem2.hex 31 | ../misc/create_mif.rb -f hex -d $(MEM_WORDS) -w 8 -o 3 -i 4 $< > progmem3.hex 32 | 33 | progmem0.coe: progmem.bin 34 | ../misc/create_mif.rb -f coe -d $(MEM_WORDS) -w 8 -o 0 -i 4 $< > progmem0.coe 35 | ../misc/create_mif.rb -f coe -d $(MEM_WORDS) -w 8 -o 1 -i 4 $< > progmem1.coe 36 | ../misc/create_mif.rb -f coe -d $(MEM_WORDS) -w 8 -o 2 -i 4 $< > progmem2.coe 37 | ../misc/create_mif.rb -f coe -d $(MEM_WORDS) -w 8 -o 3 -i 4 $< > progmem3.coe 38 | 39 | progmem0.mif: progmem.bin 40 | ../misc/create_mif.rb -f mif -d $(MEM_WORDS) -w 8 -o 0 -i 4 $< > progmem0.mif 41 | ../misc/create_mif.rb -f mif -d $(MEM_WORDS) -w 8 -o 1 -i 4 $< > progmem1.mif 42 | ../misc/create_mif.rb -f mif -d $(MEM_WORDS) -w 8 -o 2 -i 4 $< > progmem2.mif 43 | ../misc/create_mif.rb -f mif -d $(MEM_WORDS) -w 8 -o 3 -i 4 $< > progmem3.mif 44 | 45 | progmem.mif: progmem.bin 46 | ../misc/create_mif.rb -f mif -d $(MEM_WORDS) -w 32 $< > progmem.mif 47 | 48 | progmem.mem: progmem.bin 49 | ../misc/create_mif.rb -f mem -d $(MEM_WORDS) -w 32 $< > progmem.mem 50 | 51 | progmem.bin: progmem.elf 52 | $(OBJCOPY) -O binary $< $@ 53 | 54 | progmem8k.bin: progmem.elf 55 | $(OBJCOPY) --pad-to=8192 -O binary $< $@ 56 | 57 | progmem.elf: $(OBJ_FILES) top_defines.h start.o sections.lds Makefile 58 | $(LD) $(LDFLAGS) -s -o $@ $(OBJ_FILES) > progmem.map 59 | 60 | progmem_dis.elf: $(OBJ_FILES) top_defines.h sections.lds Makefile 61 | $(LD) $(LDFLAGS) -o $@ $(OBJ_FILES) > progmem.map 62 | 63 | create_sin_table: create_sin_table.c 64 | gcc -o $@ $< -lm 65 | 66 | clean: 67 | \rm -fr *.o *.hex *.elf *.dis *.bin *.coe *.map *.mif *.mem create_sin_table fpxx_sin_table.h 68 | -------------------------------------------------------------------------------- /sw/audio.c: -------------------------------------------------------------------------------- 1 | 2 | #include "audio.h" 3 | 4 | #include "i2c.h" 5 | 6 | short int audio_registers[][2] = { 7 | // For now, use default volume settings for LOUT1/ROUT1 8 | // { WM8750_LOUT1_VOL_ADDR, -1 }, 9 | // { WM8750_ROUT1_VOL_ADDR, -1 }, 10 | 11 | { WM8750_LOUT1_VOL_ADDR, (0<<8) | // LO2VU : Don't update LOUT1 volume yet 12 | (0<<7) | // LO2ZC : Change gain on zero cross only 13 | (0x78<<0) }, // LOUT2VOL : Volume... 14 | 15 | { WM8750_ROUT1_VOL_ADDR, (1<<8) | // RO2VU : Update LOUT1 and ROUT1 volume 16 | (0<<7) | // RO2ZC : Change gain on zero cross only 17 | (0x78<<0) }, // ROUT2VOL : Volume... 18 | 19 | 20 | // Disable digital soft mute, no de-emphasis 21 | { WM8750_ADC_DAC_CTRL_ADDR, (0<<3) | // DACMU: Disable digital soft mute 22 | (3<<1) }, // DEEMP: 48 Khz sampling rate 23 | 24 | // DSP Mode, mode B, LRP=1, Slave (Figure 23), 16 bits 25 | { WM8750_AUDIO_INTFC_ADDR, (0<<7) | // BCLKINV: BCLK not inverted 26 | (0<<6) | // MS : Master mode 27 | (0<<5) | // LRSWAP : No L/R swap 28 | (1<<4) | // LRP : DSP mode B: MSB on first clock cycle 29 | (0<<2) | // WL : 16 bits 30 | (3<<0) }, // FORMAT : DSP mode 31 | 32 | // MCLK 12.288 MHz, 48kHz sample rate 33 | { WM8750_SAMPLE_RATE_ADDR, (0<<7) | // BCM : Bit Clock Mode disabled 34 | (0<<6) | // CLKDIV2: MCLK not divided by 2 35 | (0<<1) | // SR : ADC and DAC 48kHz 36 | (0<<0) }, // USB : 12MHz Normal clock mode 37 | // Set left and right channel volume 38 | { WM8750_LCHAN_VOL_ADDR, (0<<8) | // LDVU : No left DAC volume update 39 | (0xff) }, // LDACVOL: Set to 0 db 40 | { WM8750_RCHAN_VOL_ADDR, (1<<8) | // RDVU : Update left and right DAC volume 41 | (0xff) }, // RDACVOL: Set to 0 db 42 | 43 | // Bass control 44 | { WM8750_BASS_CTRL_ADDR, (0<<7) | // BB : Linear bass control 45 | (1<<6) | // BC : high bass cutoff 46 | (0xf<<0) }, // BASS: bass intensity bypass 47 | 48 | // Treble control 49 | { WM8750_TREBLE_CTRL_ADDR, (0<<6) | // TC : high treble cutoff 50 | (0xf<<0) }, // TRBL: treble intensity bypass 51 | 52 | // Set DAC to mono, enable thermal shutdown 53 | { WM8750_3D_CTRL_ADDR, (0<<0) }, // 3DEN: Disabled 54 | 55 | // Various... 56 | { WM8750_ADDITIONAL_CTRL1_ADDR, (1<<8) | // TSDEN : Thermal shutdown enabled 57 | (3<<6) | // VSEL : Analog bias current optimized for 3.3V 58 | (3<<4) | // DMONOMIX: mono goes to both DACL and DACR 59 | (0<<2) | // DATSEL : left data=left ADC, right data=right ADC 60 | (0<<1) | // DACINV : DAC phase not inverted 61 | (1<<0) }, // TOEN : Time-out enable on ADC zero cross detection on gain change 62 | 63 | 64 | // Invert ROUT for speaker 65 | { WM8750_ADDITIONAL_CTRL2_ADDR, (0<<7) | // OUT3SW : OUT3 outputs VREF 66 | (1<<6) | // HWSWEN : for now, disable head-phone switch 67 | (0<<5) | // HWSWPOL : head-phone switch polarity (irrelevant when HWSEN=0) 68 | (1<<4) | // ROUT2INV: invert ROUT2 when using speaker 69 | (0<<3) | // TRI : Don't set tri-state mode 70 | (0<<2) | // LRCM : Disable ADCLRC and DACLRC when ADC resp. DAC are disabled. 71 | (0<<1) | // ADCOSR : ADC oversample rate x128 72 | (0<<0) }, // DACOSR : DAC oversample rate x128 73 | 74 | { WM8750_PWR_MANAGEMENT1_ADDR, (1<<7) | // VMIDSEL: 50k divider for playback/record 75 | (1<<6) | // VREF : must be on 76 | (0<<5) | // AINL : Analog In PGA Right 77 | (0<<4) | // AINR : Analog In PGA Right 78 | (0<<3) | // ADCL : ADC Left 79 | (0<<2) | // ADCR : ADC Right 80 | (0<<1) | // MICB : MIC Bias 81 | (0<<0) }, // DIGENB : Don't gate MCLK internally 82 | 83 | { WM8750_PWR_MANAGEMENT2_ADDR, (1<<8) | // DACL : DAC Left 84 | (1<<7) | // DACR : DAC Right 85 | // (0<<6) | // LOUT1: Disable for now 86 | // (0<<5) | // ROUT1: Disable for now 87 | (1<<6) | // LOUT1: Disable for now 88 | (1<<5) | // ROUT1: Disable for now 89 | (1<<4) | // LOUT2: Speaker is on 90 | (1<<3) | // ROUT2: Speaker is on 91 | (0<<2) | // MONO : Mono output is not used 92 | (0<<1) }, // OUT3 : Out3 is not used 93 | 94 | { WM8750_ADDITIONAL_CTRL3_ADDR, (0<<7) | // ADCLRM : ADCLRC is ADC word clock input or output 95 | (0<<6) | // VROI : VREF to analog output resistance is 1.5k 96 | (0<<5) }, // HPFLREN: High Pass filter on left and right enabled/disabled together 97 | 98 | // Left and right DAC output goes to left output mixer 99 | { WM8750_LEFT_MIXER_CTRL1_ADDR, (1<<8) | // LD2LO : Enable left DAC to left mixer 100 | (0<<7) | // LI2LO : Disable LMIXSEL signal to left mixer 101 | (0<<4) | // LI2LOVOL: Irrelevant 102 | (0<<0) }, // LMIXSEL : Irrrelevan 103 | 104 | { WM8750_LEFT_MIXER_CTRL2_ADDR, (1<<8) | // RD2LO : Enable right DAC to left mixer 105 | (0<<7) | // RI2LO : Disable RMIXSEL signal to left mixer 106 | (0<<4) }, // RI2LOVOL: Irrelevant 107 | 108 | // Left and right DAC output goes to right output mixer 109 | { WM8750_RIGHT_MIXER_CTRL1_ADDR, (1<<8) | // RD2RO : Enable right DAC to right mixer 110 | (0<<7) | // RI2RO : Disable RMIXSEL signal to right mixer 111 | (0<<4) | // RI2ROVOL: Irrelevant 112 | (0<<0) }, // RMIXSEL : Irrrelevan 113 | 114 | { WM8750_RIGHT_MIXER_CTRL2_ADDR, (1<<8) | // LD2RO : Enable left DAC to right mixer 115 | (0<<7) | // LI2RO : Disable LMIXSEL signal to right mixer 116 | (0<<4) }, // LI2ROVOL: Irrelevant 117 | 118 | 119 | // Mono output isn't used 120 | { WM8750_MONO_MIXER_CTRL1_ADDR, 0 }, 121 | { WM8750_MONO_MIXER_CTRL2_ADDR, 0 }, 122 | 123 | // LOUT2/ROUT2 configuration for mono 124 | { WM8750_LOUT2_VOL_ADDR, (0<<8) | // LO2VU : Don't update LOUT2 volume yet 125 | (0<<7) | // LO2ZC : Change gain on zero cross only 126 | (120<<0) }, // LOUT2VOL : Volume... 127 | 128 | { WM8750_ROUT2_VOL_ADDR, (1<<8) | // RO2VU : Update LOUT2 and ROUT2 volume 129 | (0<<7) | // RO2ZC : Change gain on zero cross only 130 | (120<<0) }, // ROUT2VOL : Volume... 131 | 132 | // Mono output isn't used 133 | { WM8750_MONOOUT_VOL_ADDR, 0 }, 134 | { -1, -1 } 135 | }; 136 | 137 | 138 | void audio_init() 139 | { 140 | i2c_init(CODEC_I2C_ADR); 141 | 142 | int idx = 0; 143 | while(audio_registers[idx][0] != -1){ 144 | int addr = audio_registers[idx][0]; 145 | int value = audio_registers[idx][1]; 146 | 147 | i2c_write_reg(CODEC_I2C_ADR, WM8750L_I2C_ADR, (addr<<1) | (value>>8), (value & 0xff)); 148 | ++idx; 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /sw/audio.h: -------------------------------------------------------------------------------- 1 | #ifndef AUDIO_H 2 | #define AUDIO_H 3 | 4 | #define WM8750_LIN_VOL_ADDR 0x00 5 | #define WM8750_RIN_VOL_ADDR 0x01 6 | #define WM8750_LOUT1_VOL_ADDR 0x02 7 | #define WM8750_ROUT1_VOL_ADDR 0x03 8 | #define WM8750_ADC_DAC_CTRL_ADDR 0x05 9 | #define WM8750_AUDIO_INTFC_ADDR 0x07 10 | #define WM8750_SAMPLE_RATE_ADDR 0x08 11 | #define WM8750_LCHAN_VOL_ADDR 0x0A 12 | #define WM8750_RCHAN_VOL_ADDR 0x0B 13 | #define WM8750_BASS_CTRL_ADDR 0x0C 14 | #define WM8750_TREBLE_CTRL_ADDR 0x0D 15 | #define WM8750_RESET_ADDR 0x0F 16 | #define WM8750_3D_CTRL_ADDR 0x10 17 | #define WM8750_ALC1_ADDR 0x11 18 | #define WM8750_ALC2_ADDR 0x12 19 | #define WM8750_ALC3_ADDR 0x13 20 | #define WM8750_NOISE_GATE_ADDR 0x14 21 | #define WM8750_LADC_VOL 0x15 22 | #define WM8750_RADC_VOL 0x16 23 | #define WM8750_ADDITIONAL_CTRL1_ADDR 0x17 24 | #define WM8750_ADDITIONAL_CTRL2_ADDR 0x18 25 | #define WM8750_PWR_MANAGEMENT1_ADDR 0x19 26 | #define WM8750_PWR_MANAGEMENT2_ADDR 0x1a 27 | #define WM8750_ADDITIONAL_CTRL3_ADDR 0x1b 28 | #define WM8750_ADC_IN_MODE_ADDR 0x1f 29 | #define WM8750_ADCL_SIGNAL_PATH_ADDR 0x20 30 | #define WM8750_ADCR_SIGNAL_PATH_ADDR 0x21 31 | #define WM8750_LEFT_MIXER_CTRL1_ADDR 0x22 32 | #define WM8750_LEFT_MIXER_CTRL2_ADDR 0x23 33 | #define WM8750_RIGHT_MIXER_CTRL1_ADDR 0x24 34 | #define WM8750_RIGHT_MIXER_CTRL2_ADDR 0x25 35 | #define WM8750_MONO_MIXER_CTRL1_ADDR 0x26 36 | #define WM8750_MONO_MIXER_CTRL2_ADDR 0x27 37 | #define WM8750_LOUT2_VOL_ADDR 0x28 38 | #define WM8750_ROUT2_VOL_ADDR 0x29 39 | #define WM8750_MONOOUT_VOL_ADDR 0x2A 40 | 41 | void audio_init(); 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /sw/global.h: -------------------------------------------------------------------------------- 1 | #ifndef GLOBAL_H 2 | #define GLOBAL_H 3 | 4 | #include 5 | #include "top_defines.h" 6 | 7 | typedef unsigned char byte; 8 | 9 | #define GPIO_CONFIG *((volatile uint32_t *)(0xf0000000 | GPIO_CONFIG_ADDR )) 10 | #define GPIO_DOUT *((volatile uint32_t *)(0xf0000000 | GPIO_DOUT_ADDR )) 11 | #define GPIO_DIN *((volatile uint32_t *)(0xf0000000 | GPIO_DIN_ADDR )) 12 | #define GPIO_DOUT_SET *((volatile int32_t *)(0xf0000000 | GPIO_DOUT_SET_ADDR)) 13 | #define GPIO_DOUT_CLR *((volatile uint32_t *)(0xf0000000 | GPIO_DOUT_CLR_ADDR)) 14 | 15 | 16 | #define SBUF ((volatile uint32_t *)(0xf0100000)) 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /sw/i2c.c: -------------------------------------------------------------------------------- 1 | #include "global.h" 2 | #include "i2c.h" 3 | #include "reg.h" 4 | 5 | #define UNUSED(x) (void)(x) 6 | static void i2c_set_scl(int Port, int bit) 7 | { 8 | REG_WR(Port + SCL_OFFSET,bit); 9 | } 10 | 11 | static void i2c_set_sda(int Port, int bit) 12 | { 13 | REG_WR(Port + SDA_OFFSET,bit); 14 | } 15 | 16 | 17 | static int i2c_get_scl(int Port) 18 | { 19 | return REG_RD(Port + SCL_OFFSET); 20 | } 21 | 22 | static int i2c_get_sda(int Port) 23 | { 24 | return REG_RD(Port + SDA_OFFSET); 25 | } 26 | 27 | void i2c_init(int Port) 28 | { 29 | i2c_set_sda(Port, 1); 30 | i2c_set_scl(Port, 1); 31 | } 32 | 33 | 34 | void i2c_dly(int Port) 35 | { 36 | int i; 37 | int x; 38 | 39 | UNUSED(Port); 40 | 41 | for(i=0; i < 20; ++i) { 42 | x = REG_RD(GPIO_ADR); 43 | } 44 | } 45 | 46 | void i2c_start(int Port) 47 | { 48 | i2c_set_sda(Port, 1); // i2c start bit sequence 49 | i2c_dly(Port); 50 | i2c_set_scl(Port, 1); 51 | i2c_dly(Port); 52 | i2c_set_sda(Port, 0); 53 | i2c_dly(Port); 54 | i2c_set_scl(Port, 0); 55 | i2c_dly(Port); 56 | } 57 | 58 | void i2c_stop(int Port) 59 | { 60 | i2c_set_sda(Port, 0); // i2c stop bit sequence 61 | i2c_dly(Port); 62 | i2c_set_scl(Port, 1); 63 | i2c_dly(Port); 64 | i2c_set_sda(Port, 1); 65 | i2c_dly(Port); 66 | } 67 | 68 | unsigned char i2c_rx(int Port, char ack) 69 | { 70 | char x, d=0; 71 | 72 | REG_WR(LED_CONFIG_ADR,1); 73 | i2c_set_sda(Port, 1); 74 | 75 | for(x=0; x<8; x++) { 76 | d <<= 1; 77 | 78 | i2c_set_scl(Port, 1); 79 | i2c_dly(Port); 80 | 81 | // wait for any i2c_set_scl clock stretching 82 | while(i2c_get_scl(Port) == 0); 83 | 84 | d |= i2c_get_sda(Port); 85 | i2c_set_scl(Port, 0); 86 | i2c_dly(Port); 87 | } 88 | 89 | if(ack) { 90 | i2c_set_sda(Port, 0); 91 | } 92 | else { 93 | i2c_set_sda(Port, 1); 94 | } 95 | 96 | i2c_set_scl(Port, 1); 97 | i2c_dly(Port); // send (N)ACK bit 98 | 99 | i2c_set_scl(Port, 0); 100 | i2c_dly(Port); // send (N)ACK bit 101 | 102 | i2c_set_sda(Port, 1); 103 | return d; 104 | } 105 | 106 | // return 1: ACK, 0: NACK 107 | int i2c_tx(int Port, unsigned char d) 108 | { 109 | char x; 110 | int bit; 111 | 112 | for(x=8; x; x--) { 113 | i2c_set_sda(Port, (d & 0x80)>>7); 114 | d <<= 1; 115 | i2c_dly(Port); 116 | i2c_set_scl(Port, 1); 117 | i2c_dly(Port); 118 | i2c_set_scl(Port, 0); 119 | } 120 | i2c_set_sda(Port, 1); 121 | i2c_dly(Port); 122 | i2c_dly(Port); 123 | bit = i2c_get_sda(Port); // possible ACK bit 124 | i2c_set_scl(Port, 1); 125 | i2c_dly(Port); 126 | 127 | i2c_set_scl(Port, 0); 128 | i2c_dly(Port); 129 | 130 | return !bit; 131 | } 132 | 133 | // return 1: ACK, 0: NACK 134 | int i2c_write_buf(int Port, byte ADR, byte* data, int len) 135 | { 136 | int ack; 137 | 138 | i2c_start(Port); 139 | ack = i2c_tx(Port, ADR); 140 | if(!ack) { 141 | i2c_stop(Port); 142 | return 0; 143 | } 144 | 145 | 146 | int i; 147 | for(i=0;i 2 | #include 3 | 4 | #include "reg.h" 5 | #include "top_defines.h" 6 | #include "audio.h" 7 | #include "mcp23017.h" 8 | #include "i2c.h" 9 | #include "global.h" 10 | 11 | int mcp23017_init(void); 12 | 13 | static byte mcp23017_registers[][2] = { 14 | {REG_IODIRA, 0x7f}, // LED is output 15 | {REG_IODIRB, 0x7f}, // LED is output 16 | {REG_GPPUA, 0x7f}, // Enable pull resistors on port A for everything except LED 17 | {REG_GPPUB, 0x7f}, // Enable pull resistors on port B for everything except LED 18 | {REG_OLATA, 0x80}, // Enable LED A 19 | {REG_OLATB, 0x80}, // Enable LED B 20 | {0xff} 21 | }; 22 | 23 | int mcp23017_init() 24 | { 25 | int idx = 0; 26 | int Ret = 0; 27 | 28 | while(mcp23017_registers[idx][0] != 0xff) { 29 | byte addr = mcp23017_registers[idx][0]; 30 | byte value = mcp23017_registers[idx++][1]; 31 | 32 | Ret = i2c_write_reg(VGA_I2C_ADR, MCP23017_I2C_ADR, addr,value); 33 | if(Ret != 1) { 34 | // i2c_write_reg failed, bail 35 | break; 36 | } 37 | } 38 | 39 | return Ret; 40 | } 41 | 42 | int main() 43 | { 44 | int cntr = 0; 45 | int Bits = I2C_INIT_COMPLETE | I2C_AUDIO_ENABLE; 46 | 47 | REG_WR(LED_CONFIG_ADR,1); 48 | audio_init(); 49 | i2c_init(VGA_I2C_ADR); 50 | mcp23017_init(); 51 | 52 | do { 53 | // Try to initialize the MCP23017. 54 | if(!mcp23017_init()) { 55 | // Init failed, no MCP23017 is present 56 | break; 57 | } 58 | 59 | // If we get this far then we have a MCP23017, use it 60 | Bits |= I2C_EXPANDER; 61 | while(1) { 62 | int toggle_bit = (cntr>>8) & 1; 63 | 64 | i2c_write_reg(VGA_I2C_ADR,MCP23017_I2C_ADR,REG_OLATA,toggle_bit <<7); 65 | i2c_write_reg(VGA_I2C_ADR,MCP23017_I2C_ADR,REG_OLATB,(~toggle_bit)<<7); 66 | 67 | i2c_read_regs(VGA_I2C_ADR,MCP23017_I2C_ADR,REG_GPIOA,(byte *)&Bits,2); 68 | REG_WR(GPIO_ADR,Bits); 69 | ++cntr; 70 | } 71 | } while(0); 72 | 73 | REG_WR(GPIO_ADR,Bits); 74 | while(1); 75 | } 76 | 77 | -------------------------------------------------------------------------------- /sw/reg.h: -------------------------------------------------------------------------------- 1 | #ifndef REG_H 2 | #define REG_H 3 | 4 | #define REG_WR(reg_name, wr_data) (*((volatile uint32_t *)(0x00080000 | (reg_name))) = (wr_data)) 5 | #define REG_RD(reg_name) (*((volatile uint32_t *)(0x00080000 | (reg_name)))) 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /sw/sections.lds: -------------------------------------------------------------------------------- 1 | /* 2 | This is free and unencumbered software released into the public domain. 3 | 4 | Anyone is free to copy, modify, publish, use, compile, sell, or 5 | distribute this software, either in source code form or as a compiled 6 | binary, for any purpose, commercial or non-commercial, and by any 7 | means. 8 | */ 9 | 10 | SECTIONS { 11 | .memory : { 12 | . = 0x00000; 13 | start*(.text); 14 | *(.text); 15 | *(*); 16 | end = .; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /sw/start.S: -------------------------------------------------------------------------------- 1 | .section .text 2 | .global start 3 | .global main 4 | 5 | start: 6 | /* set stack pointer */ 7 | lui sp,(8*1024)>>12 8 | 9 | /* jump to main C code */ 10 | jal ra,main 11 | 12 | /* trap */ 13 | ebreak 14 | 15 | -------------------------------------------------------------------------------- /sw/top_defines.h: -------------------------------------------------------------------------------- 1 | #define SCL_OFFSET 0 2 | #define SDA_OFFSET 0x4 3 | 4 | #define LED_CONFIG_ADR 0x00000000 5 | #define CODEC_I2C_ADR 0x00000010 6 | #define VGA_I2C_ADR 0x00000018 7 | #define GPIO_ADR 0x00000020 8 | 9 | // Bits in GPIO register: 10 | #define I2C_AUDIO_ENABLE 0x04000 // bit 14 -> audio enable 11 | #define I2C_EXPANDER 0x10000 // bit 16 -> Port expander present 12 | #define I2C_INIT_COMPLETE 0x20000 // bit 17 -> Initialization complete 13 | 14 | #define TXT_BUF_ADR 0x00008000 15 | 16 | -------------------------------------------------------------------------------- /xilinx/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !Makefile 3 | !*.vhd 4 | !*.bit 5 | !*.cgp 6 | !*.ucf 7 | !*.xise 8 | !*.ipf 9 | !*.bmm 10 | !*.xaw 11 | 12 | -------------------------------------------------------------------------------- /xilinx/Makefile: -------------------------------------------------------------------------------- 1 | 2 | XILINX_DIR = /opt/Xilinx/14.7/ISE_DS/ 3 | XILINX_BIN = $(XILINX_DIR)/ISE/bin/lin64 4 | 5 | BITSTREAM_NAME = Pano 6 | 7 | #ise: progmem.hex c64_font.hex vga8x12_font.hex screen_buffer.hex 8 | ise: 9 | $(XILINX_BIN)/ise 10 | 11 | impact: 12 | sudo LD_PRELOAD=$(XILINX_DIR)/usb-driver/libusb-driver.so $(XILINX_BIN)/impact 13 | 14 | update_ram: progmem.mem 15 | $(XILINX_BIN)/data2mem -bm progmem.bmm -bt $(BITSTREAM_NAME).bit -bd progmem.mem -o b $(BITSTREAM_NAME).new.bit 16 | $(XILINX_BIN)/data2mem -bm progmem.bmm -bt $(BITSTREAM_NAME).new.bit -d > $(BITSTREAM_NAME).new.bit.dump 17 | mv $(BITSTREAM_NAME).bit $(BITSTREAM_NAME).bit.orig 18 | mv $(BITSTREAM_NAME).new.bit $(BITSTREAM_NAME).bit 19 | 20 | dump: 21 | $(XILINX_BIN)/data2mem -bm progmem.bmm -bt $(BITSTREAM_NAME).bit -d > $(BITSTREAM_NAME).bit.dump 22 | 23 | .PHONY: progmem.mem 24 | progmem.mem: 25 | cd ../sw/ && make 26 | cp ../sw/progmem.mem . 27 | 28 | .PHONY: progmem.hex 29 | progmem.hex: 30 | cd ../sw/ && make 31 | cp ../sw/progmem*.hex . 32 | 33 | c64_font.hex: 34 | cd ../misc/ && make 35 | cp ../misc/$@ $@ 36 | 37 | vga8x12_font.hex: 38 | cd ../misc/ && make 39 | cp ../misc/$@ $@ 40 | 41 | screen_buffer.hex: 42 | cd ../misc/ && make 43 | cp ../misc/$@ $@ 44 | -------------------------------------------------------------------------------- /xilinx/Pano.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/skiphansen/pano_man/e7759f816c179f253180fe34e4dd040a5fa5c0cd/xilinx/Pano.bit -------------------------------------------------------------------------------- /xilinx/pacman_clk.vhd: -------------------------------------------------------------------------------- 1 | -- Module pacman_clk 2 | -- Generated by Xilinx Architecture Wizard 3 | -- Written for synthesis tool: XST 4 | -- Period Jitter (unit interval) for block DCM_SP_INST = 0.12 UI 5 | -- Period Jitter (Peak-to-Peak) for block DCM_SP_INST = 0.74 ns 6 | 7 | library ieee; 8 | use ieee.std_logic_1164.ALL; 9 | use ieee.numeric_std.ALL; 10 | library UNISIM; 11 | use UNISIM.Vcomponents.ALL; 12 | 13 | entity pacman_clk is 14 | port ( CLKIN_IN : in std_logic; 15 | CLKFX_OUT : out std_logic; 16 | CLKIN_IBUFG_OUT : out std_logic; 17 | CLK0_OUT : out std_logic); 18 | end pacman_clk; 19 | 20 | architecture BEHAVIORAL of pacman_clk is 21 | signal CLKFB_IN : std_logic; 22 | signal CLKFX_BUF : std_logic; 23 | signal CLKIN_IBUFG : std_logic; 24 | signal CLK0_BUF : std_logic; 25 | signal GND_BIT : std_logic; 26 | begin 27 | GND_BIT <= '0'; 28 | CLKIN_IBUFG_OUT <= CLKIN_IBUFG; 29 | CLK0_OUT <= CLKFB_IN; 30 | CLKFX_BUFG_INST : BUFG 31 | port map (I=>CLKFX_BUF, 32 | O=>CLKFX_OUT); 33 | 34 | CLKIN_IBUFG_INST : IBUFG 35 | port map (I=>CLKIN_IN, 36 | O=>CLKIN_IBUFG); 37 | 38 | CLK0_BUFG_INST : BUFG 39 | port map (I=>CLK0_BUF, 40 | O=>CLKFB_IN); 41 | 42 | DCM_SP_INST : DCM_SP 43 | generic map( CLK_FEEDBACK => "1X", 44 | CLKDV_DIVIDE => 2.0, 45 | CLKFX_DIVIDE => 5, 46 | CLKFX_MULTIPLY => 8, 47 | CLKIN_DIVIDE_BY_2 => FALSE, 48 | CLKIN_PERIOD => 10.000, 49 | CLKOUT_PHASE_SHIFT => "NONE", 50 | DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS", 51 | DFS_FREQUENCY_MODE => "LOW", 52 | DLL_FREQUENCY_MODE => "LOW", 53 | DUTY_CYCLE_CORRECTION => TRUE, 54 | FACTORY_JF => x"C080", 55 | PHASE_SHIFT => 0, 56 | STARTUP_WAIT => FALSE) 57 | port map (CLKFB=>CLKFB_IN, 58 | CLKIN=>CLKIN_IBUFG, 59 | DSSEN=>GND_BIT, 60 | PSCLK=>GND_BIT, 61 | PSEN=>GND_BIT, 62 | PSINCDEC=>GND_BIT, 63 | RST=>GND_BIT, 64 | CLKDV=>open, 65 | CLKFX=>CLKFX_BUF, 66 | CLKFX180=>open, 67 | CLK0=>CLK0_BUF, 68 | CLK2X=>open, 69 | CLK2X180=>open, 70 | CLK90=>open, 71 | CLK180=>open, 72 | CLK270=>open, 73 | LOCKED=>open, 74 | PSDONE=>open, 75 | STATUS=>open); 76 | 77 | end BEHAVIORAL; 78 | 79 | 80 | -------------------------------------------------------------------------------- /xilinx/pacman_clk.xaw: -------------------------------------------------------------------------------- 1 | XILINX-XDB 0.1 STUB 0.1 ASCII 2 | XILINX-XDM V1.6e 3 | $9;x75=(`fgn#~efp.rqkocd|z%xgd~ xhnjj}))'ykhal`Pcmi-|dq639>0<#?=4:2-317<9?1:<#>?0292452<9=$<46?9'iA3<55<9?:97;33804=2922<7L\LHVKY52=FZ^PTCCBV_BCPGDBNFNUH@F?7;@PT^ZIIDPUH@FGA_DZWAWHFD8?0M_YU_NLO]ZEKC@DTZLBZE0`8EWQ]WFDGURJLM^QTMQEOAGMTOAE>0:CQS_YHFESTHI\PC133?DTPRVEE@TQKDS]@5475:CQS_YHFEST^H]JT^NLCLE602KY[WQ@NM[\RDJNLVNM_RC@DDc8EVUHKV]BXEh4AVX\GIME]O^R\H?>6:CT^ZEKCK_MXT^J1^LLAAOS9:1J[WQLLJ]LQQVR\V^R\Hm4AVX\BIIP\PZN46OXZ^RBVQb:>7NBD2Y:8GIM5P82;96MCK826?FJLL_i0OAEKV^FJRLBB=2IGGKL7;BNHBGYNF<1H@FHW8:AOOC^60930OAEIX^@VBc=DDBLSSO[IG^KMWQeEKCORTAXB[IQNZ=>EKCORTCXZ:;BNHMK763JF@ECQKIWKGAZD^W;h0OAEFN^KAQCA682IGGD@PICWECZOI[]l0OAEFN^KAQCAXG\^37NBDIO]JJf=DDBCES]K]INFf?FJLAGUX^NQ[YQG26>EKCF__S]FNSD]PLL@Sk2IGGRHJEE@BGN?2:FOHZ@UMX_NBNWPMNFF1>BT[LD:96JZTX]@]FJBWJEY^HM[INL4?AYQIE_N46KWTDPMEIg@BMMHJOFQMUG;8BLHX]GC__55IOTV\WQTf3OE^XR[AIUQb?CIR\V\J@XK>;H78MGSAO11BBYK]N@N25>LN\]OYSD@_UU]W]UCd3CC_XH\PPJ0SOf=MA]^N^RXNLTG5?IIFLLN=7AALKDF0?IIP;2GCV:5B_WCOQ@1VTLFDN86^\EO:8TVOIKMOH?6\\Tc9PMBC_\LXEMA84SHLDH@e<[]KYXX^PW@KW2>USI]_X=?5\YRVFIZU^FJBYCCAZS29WKU2<\[_N46[\E^@VBB?<]ZOTNXHHS49UM@Q6j2RJ[RXJRRKLJ4bj-4dd776zHIz?56NOx18E>40=9rY?976;:949565a8l<1?:<72zl;4?76]:e;:7>=0=9:9mU3<32?6585121e4`0=;19h86]:e;:7>=0=9:9mU3<32?6585121e4`>=:on>m6]:e;:7>=0=9:9mU3<32?6585121e4`>=;88<46]:e;:7>=0=9:9mU3<32?6585121e4`>=;89856]:e;:7>=0=9:9m14;4>32d3ag<6=8i0_8k5858;2?74;o:nn7=8899P0161a>2Y>i76;:949565a8lh1?i<6;R67>=2=0?0:?>h?ec80`27<[5\458;0?>12898j=km:2fgb>U2m32?6585121e4`d==;9;7^:;:969<3<6;:l;io4:22g8W0c=0=03:7?<3g2ff?4a>=0=9:9mpS?k0;6<4>:9yP006150;1i;:4?:187>=}#n32>7)<>:958 74=011/>>48e:&4g?152g9'54<0;2.:?7<9;%37>70<,8?1>l5+17812>"6?3<=7)?7:618 4?=<2.:m78;;%3a>07<,8i1>95+428b?!572k1/?:4k;%1;>`=#;k0>=6*;0;78 17=n695+48854>"3j3<;7):k:6:8 06=02.>>7;n;%77>37<,<<1:<5+568:?!3e2>19<5+7884e>"6:3<0(?>54`9'1a<53-?h6>5f3`83>!0f2180(;m57998m67=83.=m76=;%4`>2><3`=:6=4+6`8;6>"113=376g9f;29 3g=0;1/:4488:9j35<72-2>207d:l:18'2d"6m38>7)?i:418?j4b290/:l472:9l6d<72-5<#>h03>65`2g83>!0f21807bi4?:%4b>=4<3f986=4+6`8;6>"1k3=37)?j:378?j53290/:l472:9l30<72-i1m3:1(;o58398yg4?29096=4?{%4a>73207b8::18'2do203:1(;o5839'2f<0021d:84?:%4b>=4<,?i1;554}c1g>5<5290;w)8m:4;8m0>=83.=m76=;%4`>2><3f<>6=4+6`8;6>"1k3=376s|3b83>7}:<>08m63:4?:3y>02<5>27947;7;|q01?6=:r7?;7=<;<15>0>{<15>33<,>81:85rs2d94?7|5:n1955+7386<>{t:00;6=u+73851>{t;l0;6=u+73851>{zf:31<7?t}o1b>5<6std8n7>51zm7f<728qvb>j50;3xyk5b290:wp`CLKDV_BUF, 27 | O=>CLKDV_OUT); 28 | 29 | CLK0_BUFG_INST : BUFG 30 | port map (I=>CLK0_BUF, 31 | O=>CLKFB_IN); 32 | 33 | DCM_SP_INST : DCM_SP 34 | generic map( CLK_FEEDBACK => "1X", 35 | CLKDV_DIVIDE => 6.5, 36 | CLKFX_DIVIDE => 1, 37 | CLKFX_MULTIPLY => 4, 38 | CLKIN_DIVIDE_BY_2 => FALSE, 39 | CLKIN_PERIOD => 6.250, 40 | CLKOUT_PHASE_SHIFT => "NONE", 41 | DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS", 42 | DFS_FREQUENCY_MODE => "LOW", 43 | DLL_FREQUENCY_MODE => "LOW", 44 | DUTY_CYCLE_CORRECTION => TRUE, 45 | FACTORY_JF => x"C080", 46 | PHASE_SHIFT => 0, 47 | STARTUP_WAIT => FALSE) 48 | port map (CLKFB=>CLKFB_IN, 49 | CLKIN=>CLKIN_IN, 50 | DSSEN=>GND_BIT, 51 | PSCLK=>GND_BIT, 52 | PSEN=>GND_BIT, 53 | PSINCDEC=>GND_BIT, 54 | RST=>GND_BIT, 55 | CLKDV=>CLKDV_BUF, 56 | CLKFX=>open, 57 | CLKFX180=>open, 58 | CLK0=>CLK0_BUF, 59 | CLK2X=>open, 60 | CLK2X180=>open, 61 | CLK90=>open, 62 | CLK180=>open, 63 | CLK270=>open, 64 | LOCKED=>open, 65 | PSDONE=>open, 66 | STATUS=>open); 67 | 68 | end BEHAVIORAL; 69 | 70 | 71 | -------------------------------------------------------------------------------- /xilinx/pacman_clk1.xaw: -------------------------------------------------------------------------------- 1 | XILINX-XDB 0.1 STUB 0.1 ASCII 2 | XILINX-XDM V1.6e 3 | $6gx4>563&bdah!|khr,twimmj~x#~efp.zjhlh''%{mncnn^aoo4(i~;0<<5>4:37*2><9?-cO=6?3:3547=6P81?968!2420?3(2?2KYOEYFZ058EWQ]WFDGURMNSBCGMKAXKEA:46O]W[]LJI_XKEABBRKWTDPMEI723HX\VRAALX]@HNOIW_KGYH?m;@PT^ZIIDPUOO@Q\WHV@LLH@WJF@==5NRVX\KKJ^WMNYSN>>0:CQS_YHFESTHI\PC032?DTPRVEE@TQKDS]@HN713HX\VRAALX]G@WYAD@ZM@B^>5:CQS_YHFESTJOQJXUGQJDJ6:2KY[WQ@NM[\MKUSWG_Fi6O]W[]LJI_XXDIO=85NRVX\KKJ^W[OXIYQCOFK@5==FZ^PTCCBV_WCOMAYCNZUFCIKn;@QPKFYPA]Bm7LYU_BNHFP@SQYO:=;5NW[]@HNDRN]S[IEKC9UIYKk4CMI3[GSAOVCE_Y64CMI3[JSS>2IGG<6?6:AOO717=2IGG?V7;BNH6]7?8<1H@F7?5:AOOAP>3JF@H[QMUGd8GIMC^VH^JJQFNRV`?FJLL_UOE[GKE89@HNBQWF__96MCKG@;?FJLNKUBB85LLJD[<>EKCOR:4=m4CMIE\ZBN^@NNi6MCKGZ\IPJSAYFR96MCKHL25>EKC@DTHDXFDD]A]Z4?3JF@ECQFNb9@HNOIWYOYEBJj;BNHMKYTZJU_U]K>2:AOOJSSWYBJ_HQ\HHDWg>EKCVLNIILNCJ;8GJKJA]^NH:5LRDCWAA0@EWZE^^NKl;GGF@GGDCVH^J45IIO]VJLRT02LDYYQ\TSc8BJSSW\DBX^o4FNWW[SGK]L;0E55FNUGQJDJ692@BXYK]_HLSQQYSQYO=7AANDDF5?IIDCLN87AAX3:OK^2=JW_KGYH94NDVTKWM33GEEI<5@8:ME@ATDXLh0\EO\E^QKMCR>3YCEDL]MURc8TLHN[NDOII64PHLTMARO02ZYE@ZVPD33?UTHXVZBBD]NCUKUA0=W[JF@:6^\DNLF0>VTMG20\^GACEG@7>TT\k1XEJKWTDPMEI0<[@DL@Hm4SUCQPPVX_HC_:6][AUWP57=TQZ^NAR]VNBJQKKIR[:1_C]:4TSWF<>STMVH^JJ74URG\FP@@[<1]EHY>b:ZBSZPBZZCDB5WSU48\adXAm;;7Ujb_LcikwPbzzcdb<>4Xeo\Ilhhz_oydaa5:Y3>5[23R:1;P:4asuy7>bdek1}i}foo"2*52<~ang==5wc2q2256b%r@Ar06>FGp80M6;4>{R1f>2?=?k0:?>h?ec80```|f>?1=6`86;48 22=?;1v_>j57884f?74;o:nn7:j889P16<013=i6<=0d7k2Y8h796:6`9565a8lh19o?8;R70>2?=?k0:?>h?ec81b3d?3Z9o6:757c8276`7mk09j;j<;e5:>5<628qX?h489;5a>454n9oi6>jjf:tW35<7280:6;u\3d84=?1e2898j=km:2ffb>d1k3:1<7=56z&a>2g<,8n1;n5+1d84`>"6n3=87)9>:59a05<72891<7>t$7297c=#k38i7)j5699'b?453-;;6?<4$03963=#9;09>6*>3;7a?!732?20(<;53:&22?3>3-;<6974$0:965=#;j0<7)655+3687=>"41330(>o5509'7g<212.?=78m;%64>6=#<;0>96*;4;76?!212?n0(9655:&7e?363->h6884$5g913=#o7<4$7;90<=#>l0=j6*j:79'5f<3;2c8:7>5$4d932=#>80=h65f3183>!3a2>=0(;?56e98m30=83.>j798;%7f>3b<3`"2m31/9h49d:9j27<72-?m6:94$4g92a=77<,8h18o54o3c94?"2n3=<76a=6;29 0`=?>10c?950;&6b?1032e9n7>5$4d932=#>80=h6*>a;02?>i503:1(8h57698k7?=83.>j798;:m06?6=,5<#=o0<;65rb3694?4=83:p(;>5209j15<72-?m6:94$7392a=;h73>5<#=o0<;6*91;4g?>i2i3:1(8h5769'24<1l21v>650;3x916=;?1/::4:0:p74<72;q68=4<0:?10?3f3-;26?;4}r00>5<5s4>;6?<4=36915=z{;i1<7<6s|2g83>4}::m0>m6*97;7b?xu5=3:1{|l1=?6=9rwe>l4?:0y~j7d=83;pqpsr@AAx77 two wire mode: I2C 49 | # csb is pulled down to GND -> I2C addr 0x34 50 | NET "audio_mclk" LOC = U9 |IOSTANDARD = LVCMOS33; 51 | NET "audio_bclk" LOC = P10 |IOSTANDARD = LVCMOS33; 52 | NET "audio_dacdat" LOC = U15 |IOSTANDARD = LVCMOS33; 53 | NET "audio_daclrc" LOC = N12 |IOSTANDARD = LVCMOS33; 54 | NET "audio_adcdat" LOC = V3 |IOSTANDARD = LVCMOS33; 55 | NET "audio_adclrc" LOC = V15 |IOSTANDARD = LVCMOS33; 56 | NET "audio_sda" LOC = T3 |IOSTANDARD = LVCMOS33; 57 | NET "audio_scl" LOC = R10 |IOSTANDARD = LVCMOS33; 58 | #============================================================ 59 | # DDR2 DRAM 60 | #============================================================ 61 | #NET "sdram_a[0]" LOC = F11 |IOSTANDARD = LVCMOS18; 62 | #NET "sdram_a[1]" LOC = D13 |IOSTANDARD = LVCMOS18; 63 | #NET "sdram_a[2]" LOC = E13 |IOSTANDARD = LVCMOS18; 64 | #NET "sdram_a[3]" LOC = E11 |IOSTANDARD = LVCMOS18; 65 | #NET "sdram_a[4]" LOC = B16 |IOSTANDARD = LVCMOS18; 66 | #NET "sdram_a[5]" LOC = A16 |IOSTANDARD = LVCMOS18; 67 | #NET "sdram_a[6]" LOC = A12 |IOSTANDARD = LVCMOS18; 68 | #NET "sdram_a[7]" LOC = A11 |IOSTANDARD = LVCMOS18; 69 | #NET "sdram_a[8]" LOC = D14 |IOSTANDARD = LVCMOS18; 70 | #NET "sdram_a[9]" LOC = A14 |IOSTANDARD = LVCMOS18; 71 | #NET "sdram_a[10]" LOC = B14 |IOSTANDARD = LVCMOS18; 72 | #NET "sdram_a[11]" LOC = A13 |IOSTANDARD = LVCMOS18; 73 | #NET "sdram_ck" LOC = J17 |IOSTANDARD = LVCMOS18; 74 | #NET "sdram_ck_" LOC = J16 |IOSTANDARD = LVCMOS18; 75 | #NET "sdram_cke" LOC = E15 |IOSTANDARD = LVCMOS18; 76 | #NET "sdram_cs_" LOC = | IOSTANDARD = LVCMOS18; 77 | #NET "sdram_we_" LOC = P16 |IOSTANDARD = LVCMOS18; 78 | #NET "sdram_cas_" LOC = M14 |IOSTANDARD = LVCMOS18; 79 | #NET "sdram_ras_" LOC = H14 |IOSTANDARD = LVCMOS18; 80 | #NET "sdram_dm[0]" LOC = K12 |IOSTANDARD = LVCMOS18; 81 | #NET "sdram_dm[1]" LOC = K13 |IOSTANDARD = LVCMOS18; 82 | #NET "sdram_dm[2]" LOC = J14 |IOSTANDARD = LVCMOS18; 83 | #NET "sdram_dm[3]" LOC = H15 |IOSTANDARD = LVCMOS18; 84 | #NET "sdram_ba[0]" LOC = F12 |IOSTANDARD = LVCMOS18; 85 | #NET "sdram_ba[1]" LOC = E12 |IOSTANDARD = LVCMOS18; 86 | #NET "sdram_dq[31]" LOC = C18 |IOSTANDARD = LVCMOS18; 87 | #NET "sdram_dq[30]" LOC = C17 |IOSTANDARD = LVCMOS18; 88 | #NET "sdram_dq[29]" LOC = D17 |IOSTANDARD = LVCMOS18; 89 | #NET "sdram_dq[28]" LOC = D16 |IOSTANDARD = LVCMOS18; 90 | #NET "sdram_dq[27]" LOC = F15 |IOSTANDARD = LVCMOS18; 91 | #NET "sdram_dq[26]" LOC = F14 |IOSTANDARD = LVCMOS18; 92 | #NET "sdram_dq[25]" LOC = F18 |IOSTANDARD = LVCMOS18; 93 | #NET "sdram_dq[24]" LOC = F17 |IOSTANDARD = LVCMOS18; 94 | #NET "sdram_dq[23]" LOC = G14 |IOSTANDARD = LVCMOS18; 95 | #NET "sdram_dq[22]" LOC = G13 |IOSTANDARD = LVCMOS18; 96 | #NET "sdram_dq[21]" LOC = G15 |IOSTANDARD = LVCMOS18; 97 | #NET "sdram_dq[20]" LOC = G16 |IOSTANDARD = LVCMOS18; 98 | #NET "sdram_dq[19]" LOC = H16 |IOSTANDARD = LVCMOS18; 99 | #NET "sdram_dq[18]" LOC = H17 |IOSTANDARD = LVCMOS18; 100 | #NET "sdram_dq[17]" LOC = J12 |IOSTANDARD = LVCMOS18; 101 | #NET "sdram_dq[16]" LOC = J13 |IOSTANDARD = LVCMOS18; 102 | #NET "sdram_dq[15]" LOC = K15 |IOSTANDARD = LVCMOS18; 103 | #NET "sdram_dq[14]" LOC = K14 |IOSTANDARD = LVCMOS18; 104 | #NET "sdram_dq[13]" LOC = L16 |IOSTANDARD = LVCMOS18; 105 | #NET "sdram_dq[12]" LOC = L15 |IOSTANDARD = LVCMOS18; 106 | #NET "sdram_dq[11]" LOC = N18 |IOSTANDARD = LVCMOS18; 107 | #NET "sdram_dq[10]" LOC = M18 |IOSTANDARD = LVCMOS18; 108 | #NET "sdram_dq[9]" LOC = M15 |IOSTANDARD = LVCMOS18; 109 | #NET "sdram_dq[8]" LOC = M16 |IOSTANDARD = LVCMOS18; 110 | #NET "sdram_dq[7]" LOC = P17 |IOSTANDARD = LVCMOS18; 111 | #NET "sdram_dq[6]" LOC = P18 |IOSTANDARD = LVCMOS18; 112 | #NET "sdram_dq[5]" LOC = N15 |IOSTANDARD = LVCMOS18; 113 | #NET "sdram_dq[4]" LOC = N14 |IOSTANDARD = LVCMOS18; 114 | #NET "sdram_dq[3]" LOC = R18 |IOSTANDARD = LVCMOS18; 115 | #NET "sdram_dq[2]" LOC = T18 |IOSTANDARD = LVCMOS18; 116 | #NET "sdram_dq[1]" LOC = U18 |IOSTANDARD = LVCMOS18; 117 | #NET "sdram_dq[0]" LOC = T17 |IOSTANDARD = LVCMOS18; 118 | #NET "sdram_dqs[3]" LOC = E16 |IOSTANDARD = LVCMOS18; 119 | #NET "sdram_dqs[2]" LOC = J15 |IOSTANDARD = LVCMOS18; 120 | #NET "sdram_dqs[1]" LOC = L18 |IOSTANDARD = LVCMOS18; 121 | #NET "sdram_dqs[0]" LOC = R15 |IOSTANDARD = LVCMOS18; 122 | #============================================================ 123 | # VGA Out - TI THS8135 124 | #============================================================ 125 | NET "vo_clk" LOC = E10 |IOSTANDARD = LVCMOS18; # CLK 126 | 127 | NET "vo_vsync" LOC = D1 |IOSTANDARD = LVCMOS33; # B2B A[9] 128 | NET "vo_hsync" LOC = C2 |IOSTANDARD = LVCMOS33; # B2B A[11] 129 | NET "vo_blank_" LOC = A8 |IOSTANDARD = LVCMOS18; # BLANK_ 130 | # SYNC_ = 10k pullup to VDD 131 | # SYNC_T = 10k R to ? 132 | # M1 = 10 pulldown to GND 133 | # M2 = 10 pulldown to GND 134 | NET "vo_scl" LOC = D4 |IOSTANDARD = LVCMOS33 | PULLUP; 135 | NET "vo_sda" LOC = G3 |IOSTANDARD = LVCMOS33 | PULLUP ; 136 | 137 | NET "vo_r[7]" LOC = D9 |IOSTANDARD = LVCMOS18; # R9 138 | NET "vo_r[6]" LOC = E9 |IOSTANDARD = LVCMOS18; # R8 139 | NET "vo_r[5]" LOC = C9 |IOSTANDARD = LVCMOS18; # R7 140 | NET "vo_r[4]" LOC = F9 |IOSTANDARD = LVCMOS18; # R6 141 | NET "vo_r[3]" LOC = F8 |IOSTANDARD = LVCMOS18; # R5 142 | NET "vo_r[2]" LOC = C7 |IOSTANDARD = LVCMOS18; # R4 143 | NET "vo_r[1]" LOC = E8 |IOSTANDARD = LVCMOS18; # R3 144 | NET "vo_r[0]" LOC = F7 |IOSTANDARD = LVCMOS18; # R2 145 | # R1 = GND 146 | # R0 = GND 147 | NET "vo_g[7]" LOC = G9 |IOSTANDARD = LVCMOS18; # G9 148 | NET "vo_g[6]" LOC = D11 |IOSTANDARD = LVCMOS18; # G8 149 | NET "vo_g[5]" LOC = C4 |IOSTANDARD = LVCMOS18; # G7 150 | NET "vo_g[4]" LOC = A7 |IOSTANDARD = LVCMOS18; # G6 151 | NET "vo_g[3]" LOC = A10 |IOSTANDARD = LVCMOS18; # G5 152 | NET "vo_g[2]" LOC = D10 |IOSTANDARD = LVCMOS18; # G4 153 | NET "vo_g[1]" LOC = C11 |IOSTANDARD = LVCMOS18; # G3 154 | NET "vo_g[0]" LOC = B10 |IOSTANDARD = LVCMOS18; # G2 155 | # G1 = GND 156 | # G0 = GND 157 | NET "vo_b[7]" LOC = A4 |IOSTANDARD = LVCMOS18; # B9 158 | NET "vo_b[6]" LOC = D6 |IOSTANDARD = LVCMOS18; # B8 159 | NET "vo_b[5]" LOC = C3 |IOSTANDARD = LVCMOS18; # B7 160 | NET "vo_b[4]" LOC = E6 |IOSTANDARD = LVCMOS18; # B6 161 | NET "vo_b[3]" LOC = B4 |IOSTANDARD = LVCMOS18; # B5 162 | NET "vo_b[2]" LOC = C5 |IOSTANDARD = LVCMOS18; # B4 163 | NET "vo_b[1]" LOC = B6 |IOSTANDARD = LVCMOS18; # B3 164 | NET "vo_b[0]" LOC = A6 |IOSTANDARD = LVCMOS18; # B2 165 | # B1 = GND 166 | # B0 = GND 167 | #============================================================ 168 | # USB Host - ISP1760BE 169 | #============================================================ 170 | # 171 | #NET "usb_cs_" LOC = R12 |IOSTANDARD = LVCMOS33; # Pin 106 172 | #NET "usb_rd_" LOC = T12 |IOSTANDARD = LVCMOS33; # Pin 107 173 | #NET "usb_wr_" LOC = P12 |IOSTANDARD = LVCMOS33; # Pin 108 174 | #NET "usb_bat_on_n" LOC = xx |IOSTANDARD = LVCMOS33; # Pin 110. Not connected? 175 | #NET "usb_irq" LOC = U14 |IOSTANDARD = LVCMOS33; # Pin 112 176 | #NET "usb_dreq" LOC = xx |IOSTANDARD = LVCMOS33; # Pin 114. Not connected. 177 | #NET "usb_dack" LOC = xx |IOSTANDARD = LVCMOS33; # Pin 116. Not connected. Pulled up to VCC. 178 | #NET "usb_suspend" LOC = xx |IOSTANDARD = LVCMOS33; # Pin 119. Not connected? 179 | #NET "usb_reset_n" LOC = P11 |IOSTANDARD = LVCMOS33; # Pin 122 180 | #NET "usb_a[17]" LOC = P9 |IOSTANDARD = LVCMOS33; # Pin 105 181 | #NET "usb_a[16]" LOC = R11 |IOSTANDARD = LVCMOS33; # Pin 103 182 | #NET "usb_a[15]" LOC = U6 |IOSTANDARD = LVCMOS33; # Pin 102 183 | #NET "usb_a[14]" LOC = U13 |IOSTANDARD = LVCMOS33; # Pin 101 184 | #NET "usb_a[13]" LOC = T5 |IOSTANDARD = LVCMOS33; # Pin 100 185 | #NET "usb_a[12]" LOC = R5 |IOSTANDARD = LVCMOS33; # Pin 98 186 | #NET "usb_a[11]" LOC = P6 |IOSTANDARD = LVCMOS33; # Pin 97 187 | #NET "usb_a[10]" LOC = R6 |IOSTANDARD = LVCMOS33; # Pin 96 188 | #NET "usb_a[9]" LOC = V5 |IOSTANDARD = LVCMOS33; # Pin 95 189 | #NET "usb_a[8]" LOC = V7 |IOSTANDARD = LVCMOS33; # Pin 93 190 | #NET "usb_a[7]" LOC = P7 |IOSTANDARD = LVCMOS33; # Pin 92 191 | #NET "usb_a[6]" LOC = N7 |IOSTANDARD = LVCMOS33; # Pin 91 192 | #NET "usb_a[5]" LOC = N8 |IOSTANDARD = LVCMOS33; # Pin 89 193 | #NET "usb_a[4]" LOC = P8 |IOSTANDARD = LVCMOS33; # Pin 87 194 | #NET "usb_a[3]" LOC = T8 |IOSTANDARD = LVCMOS33; # Pin 86 195 | #NET "usb_a[2]" LOC = R8 |IOSTANDARD = LVCMOS33; # Pin 84 196 | #NET "usb_a[1]" LOC = N11 |IOSTANDARD = LVCMOS33; # Pin 82 197 | # usb_d[31:16] not connected. 198 | #NET "usb_d[15]" LOC = V13 |IOSTANDARD = LVCMOS33; # Pin 58 199 | #NET "usb_d[14]" LOC = R9 |IOSTANDARD = LVCMOS33; # Pin 57 200 | #NET "usb_d[13]" LOC = V11 |IOSTANDARD = LVCMOS33; # Pin 56 201 | #NET "usb_d[12]" LOC = U4 |IOSTANDARD = LVCMOS33; # Pin 54 202 | #NET "usb_d[11]" LOC = M10 |IOSTANDARD = LVCMOS33; # Pin 52 203 | #NET "usb_d[10]" LOC = R13 |IOSTANDARD = LVCMOS33; # Pin 51 204 | #NET "usb_d[9]" LOC = P13 |IOSTANDARD = LVCMOS33; # Pin 49 205 | #NET "usb_d[8]" LOC = R14 |IOSTANDARD = LVCMOS33; # Pin 47 206 | #NET "usb_d[7]" LOC = T14 |IOSTANDARD = LVCMOS33; # Pin 46 207 | #NET "usb_d[6]" LOC = T16 |IOSTANDARD = LVCMOS33; # Pin 45 208 | #NET "usb_d[5]" LOC = M9 |IOSTANDARD = LVCMOS33; # Pin 43 209 | #NET "usb_d[4]" LOC = N9 |IOSTANDARD = LVCMOS33; # Pin 42 210 | #NET "usb_d[3]" LOC = V12 |IOSTANDARD = LVCMOS33; # Pin 41 211 | #NET "usb_d[2]" LOC = T15 |IOSTANDARD = LVCMOS33; # Pin 39 212 | #NET "usb_d[1]" LOC = U5 |IOSTANDARD = LVCMOS33; # Pin 38 213 | #NET "usb_d[0]" LOC = V6 |IOSTANDARD = LVCMOS33; # Pin 37 214 | #NET "usb_clkin" LOC = K6 |IOSTANDARD = LVCMOS33; # Pin 13 215 | #============================================================ 216 | # Board to Board Connector 217 | #============================================================ 218 | #NET "b2b_a[18]" LOC = E5 | IOSTANDARD = LVCMOS33; # B2B A[18] 219 | NET "pano_button" LOC = R7 | IOSTANDARD = LVCMOS33; # B2B A'[8] 220 | #NET "b2b_aa[16]" LOC = B7 | IOSTANDARD = LVCMOS33; # B2B A'[16] 221 | 222 | --------------------------------------------------------------------------------