├── LICENSE ├── README.md ├── bin └── bin2rom.py ├── data ├── boot.bin ├── hexascii.hex └── jump.hex ├── doc ├── fpgaboy.pdf └── static │ └── tetris.png └── src ├── gb ├── gameboy.v ├── interrupt.v ├── joypad.v ├── mmu.v ├── ppu.v ├── timer.v └── video_converter.v ├── io ├── debug │ ├── cls_spi.v │ ├── cls_spi_tb.v │ ├── oled_spi.v │ └── oled_spi_tb.v ├── input │ ├── joypad_snes_adapter.v │ └── joypad_snes_adapter_tb.v └── video │ └── vga_controller.v ├── top ├── s6atlys.ucf └── s6atlys.v ├── tv80 ├── env │ ├── env_io.v │ ├── env_tasks.v │ ├── op_decode.v │ ├── tb.vf │ └── tb_top.v └── rtl │ └── core │ ├── tv80_alu.v │ ├── tv80_core.v │ ├── tv80_mcode.v │ ├── tv80_reg.v │ ├── tv80n.v │ └── tv80s.v └── util ├── async_mem.v ├── async_mem2.v ├── debounce.v └── divider.v /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Trevor Rundell, Oleg Kozhushnyan 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # About 2 | 3 | FPGABoy is an implementation of Nintendo's classic handheld Game Boy system. It was originally created in 2009 by Trevor Rundell and Oleg Kozhushnyan as our final project for MIT's 6.111 course (Introductory Digital Systems Laboratory). The project has been been modified substantially since then, mostly to work with the smaller FPGA's I have available to me now. 4 | 5 | **FPGABoy IS CURRENTLY NON FUNCTIONAL!** I play around with it occasionally in my spare time, but I'm not actively doing development. I welcome contributions from anyone and everyone. This was a really fun project and I would love to see it working again on a wider range of hardware. 6 | 7 | ![Tetris running on FPGABoy](https://raw.github.com/trun/fpgaboy/master/doc/static/tetris.png) 8 | 9 | # Development 10 | 11 | ## Hardware 12 | 13 | FPGABoy was originally designed to run on a [6.111 Labkit](http://www-mtl.mit.edu/Courses/6.111/labkit/) which contains a fairly powerful Virtex-2 FPGA. I no longer have access to that hardware, so the project has been modified to run on a [Digilent Atlys](http://digilentinc.com/Products/Detail.cfm?NavPath=2,400,836&Prod=ATLYS) board which contains a smaller Spartan-6 FPGA. 14 | 15 | ## Software 16 | 17 | Development is being done using [Xilinx ISE WebPACK 13.4](http://www.xilinx.com/products/design-tools/ise-design-suite/ise-webpack.htm). 18 | 19 | ## Peripherals 20 | 21 | FPGABoy requires a number of external components for input and output. Support for the following exists, in various states of compatibility. 22 | 23 | ### Input (Joypad) 24 | 25 | - On board buttons (in development) 26 | - NES controller (supported in original, currently untested) 27 | - SNES controller (working!) 28 | 29 | ### Output (Video) 30 | 31 | - VGA (supported in original, currently untested) 32 | - HDMI (in development) 33 | 34 | # Documentation 35 | 36 | - [fpgaboy.pdf](https://raw.github.com/trun/fpgaboy/master/doc/fpgaboy.pdf) - Our original paper on the design and implementation of FPGABoy. 37 | 38 | ## Additional Resources 39 | 40 | - [Pan Docs](http://nocash.emubase.de/pandocs.htm) / [Alternate Link](http://bgb.bircd.org/pandocs.txt) - "Everything You Always Wanted To Know About Gameboy" 41 | 42 | - [GameBoy Dev'rs](http://www.devrs.com/gb/hardware.php#hardgb) - Schematics and specifications for various elements of the GameBoy hardware. 43 | -------------------------------------------------------------------------------- /bin/bin2rom.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | 5 | f = open(sys.argv[1], 'rb') 6 | while True: 7 | d = f.read(100) 8 | if len(d) == 0: 9 | break 10 | for b in d: 11 | sys.stdout.write('%02x\n' % ord(b)) 12 | -------------------------------------------------------------------------------- /data/boot.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trun/fpgaboy/1f50adf1b698741af8af3716b2adc089a9672210/data/boot.bin -------------------------------------------------------------------------------- /data/hexascii.hex: -------------------------------------------------------------------------------- 1 | 30 31 32 33 2 | 34 35 36 37 3 | 38 39 41 42 4 | 43 44 45 46 -------------------------------------------------------------------------------- /data/jump.hex: -------------------------------------------------------------------------------- 1 | 40 00 2 | 48 00 3 | 50 00 4 | 58 00 5 | 60 00 -------------------------------------------------------------------------------- /doc/fpgaboy.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trun/fpgaboy/1f50adf1b698741af8af3716b2adc089a9672210/doc/fpgaboy.pdf -------------------------------------------------------------------------------- /doc/static/tetris.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trun/fpgaboy/1f50adf1b698741af8af3716b2adc089a9672210/doc/static/tetris.png -------------------------------------------------------------------------------- /src/gb/gameboy.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | `timescale 1ns / 1ps 3 | 4 | module gameboy ( 5 | input wire clock, 6 | input wire cpu_clock, 7 | input wire reset, 8 | input wire reset_init, 9 | 10 | // Main RAM + Cartridge 11 | output wire [15:0] A, 12 | input wire [7:0] Di, 13 | output wire [7:0] Do, 14 | output wire wr_n, 15 | output wire rd_n, 16 | output wire cs_n, 17 | 18 | // Video RAM 19 | output wire [15:0] A_vram, 20 | input wire [7:0] Di_vram, 21 | output wire [7:0] Do_vram, 22 | output wire wr_vram_n, 23 | output wire rd_vram_n, 24 | output wire cs_vram_n, 25 | 26 | // Video Display 27 | output wire [1:0] pixel_data, 28 | output wire pixel_clock, 29 | output wire pixel_latch, 30 | output wire hsync, 31 | output wire vsync, 32 | 33 | // Controller 34 | input wire [3:0] joypad_data, 35 | output wire [1:0] joypad_sel, 36 | 37 | // Audio 38 | output wire audio_left, 39 | output wire audio_right, 40 | 41 | // Debug - CPU Pins 42 | output wire [7:0] dbg_led, 43 | output wire [15:0] PC, 44 | output wire [15:0] SP, 45 | output wire [15:0] AF, 46 | output wire [15:0] BC, 47 | output wire [15:0] DE, 48 | output wire [15:0] HL, 49 | output wire [15:0] A_cpu, 50 | output wire [7:0] Di_cpu, 51 | output wire [7:0] Do_cpu 52 | ); 53 | 54 | //assign pixel_data = 2'b0; 55 | assign pixel_clock = 1'b0; 56 | //assign pixel_latch = 1'b0; 57 | //assign hsync = 1'b0; 58 | //assign vsync = 1'b0; 59 | 60 | assign audio_left = 1'b0; 61 | assign audio_right = 1'b0; 62 | 63 | // 64 | // CPU I/O Pins 65 | // 66 | 67 | wire reset_n, wait_n, int_n, nmi_n, busrq_n; // cpu inputs 68 | wire m1_n, mreq_n, iorq_n, rd_cpu_n, wr_cpu_n, rfsh_n, halt_n, busak_n; // cpu outputs 69 | 70 | // 71 | // Debug - CPU I/O Pins 72 | // 73 | 74 | assign dbg_led = { 75 | m1_n, 76 | mreq_n, 77 | iorq_n, 78 | int_n, 79 | halt_n, 80 | reset_n, 81 | rd_n, 82 | wr_n 83 | }; 84 | 85 | // 86 | // CPU internal registers 87 | // 88 | 89 | wire IntE_FF1; 90 | wire IntE_FF2; 91 | wire INT_s; 92 | 93 | // 94 | // TV80 CPU 95 | // 96 | 97 | tv80s tv80_core( 98 | .reset_n(reset_n), 99 | .clk(cpu_clock), 100 | .wait_n(wait_n), 101 | .int_n(int_n), 102 | .nmi_n(nmi_n), 103 | .busrq_n(busrq_n), 104 | .m1_n(m1_n), 105 | .mreq_n(mreq_n), 106 | .iorq_n(iorq_n), 107 | .rd_n(rd_cpu_n), 108 | .wr_n(wr_cpu_n), 109 | .rfsh_n(rfsh_n), 110 | .halt_n(halt_n), 111 | .busak_n(busak_n), 112 | .A(A_cpu), 113 | .di(Di_cpu), 114 | .do(Do_cpu), 115 | .ACC(AF[15:8]), 116 | .F(AF[7:0]), 117 | .BC(BC), 118 | .DE(DE), 119 | .HL(HL), 120 | .PC(PC), 121 | .SP(SP), 122 | .IntE_FF1(IntE_FF1), 123 | .IntE_FF2(IntE_FF2), 124 | .INT_s(INT_s) 125 | ); 126 | 127 | assign reset_n = !reset; 128 | assign wait_n = 1'b1; 129 | assign nmi_n = 1'b1; 130 | assign busrq_n = 1'b1; 131 | 132 | // 133 | // MMU 134 | // 135 | 136 | wire cs_interrupt; 137 | wire cs_timer; 138 | wire cs_sound; 139 | wire cs_joypad; 140 | 141 | wire [7:0] Do_mmu; 142 | wire [7:0] Do_interrupt; 143 | wire [7:0] Do_timer; 144 | wire [7:0] Do_sound; 145 | wire [7:0] Do_joypad; 146 | 147 | wire [15:0] A_ppu; 148 | wire [7:0] Do_ppu; 149 | wire [7:0] Di_ppu; 150 | wire cs_ppu; 151 | 152 | mmu memory ( 153 | .clock(clock), 154 | .reset(reset), 155 | 156 | // CPU <-> MMU 157 | .A_cpu(A_cpu), 158 | .Di_cpu(Do_cpu), 159 | .Do_cpu(Do_mmu), 160 | .rd_cpu_n(rd_cpu_n), 161 | .wr_cpu_n(wr_cpu_n), 162 | 163 | // MMU <-> I/O Registers + External RAMs 164 | .A(A), 165 | .Do(Do), 166 | .Di(Di), 167 | .wr_n(wr_n), 168 | .rd_n(rd_n), 169 | .cs_n(cs_n), 170 | 171 | // MMU <-> PPU 172 | .A_ppu(A_ppu), 173 | .Do_ppu(Do_ppu), 174 | .Di_ppu(Di_ppu), 175 | .cs_ppu(cs_ppu), 176 | 177 | // Data lines (I/O Registers) -> MMU 178 | .Do_interrupt(Do_interrupt), 179 | .Do_timer(Do_timer), 180 | .Do_sound(Do_sound), 181 | .Do_joypad(Do_joypad), 182 | 183 | // MMU -> Modules (I/O Registers) 184 | .cs_interrupt(cs_interrupt), 185 | .cs_timer(cs_timer), 186 | .cs_sound(cs_sound), 187 | .cs_joypad(cs_joypad) 188 | ); 189 | 190 | // 191 | // Interrupt Controller 192 | // 193 | 194 | wire[4:0] int_req; 195 | wire[4:0] int_ack; 196 | wire[7:0] jump_addr; 197 | 198 | interrupt_controller interrupt( 199 | .reset(reset), 200 | .clock(clock), 201 | .cs(cs_interrupt), 202 | .rd_n(rd_n), 203 | .wr_n(wr_n), 204 | .m1_n(m1_n), 205 | .int_n(int_n), 206 | .iorq_n(iorq_n), 207 | .int_ack(int_ack), 208 | .int_req(int_req), 209 | .jump_addr(jump_addr), 210 | .A(A), 211 | .Di(Do_cpu), 212 | .Do(Do_interrupt) 213 | ); 214 | 215 | // During an interrupts the CPU reads the jump address 216 | // from a table in memory. It gets the address of this 217 | // table from the interrupt module which is why this 218 | // mux exists. 219 | assign Di_cpu = (!iorq_n && !m1_n) ? jump_addr : Do_mmu; 220 | 221 | // 222 | // Timer Controller 223 | // 224 | 225 | timer_controller timer ( 226 | .reset(reset), 227 | .clock(cpu_clock), 228 | .cs(cs_timer), 229 | .rd_n(rd_n), 230 | .wr_n(wr_n), 231 | .int_ack(int_ack[2]), 232 | .int_req(int_req[2]), 233 | .A(A), 234 | .Di(Do_cpu), 235 | .Do(Do_timer) 236 | ); 237 | 238 | // 239 | // Video Controller 240 | // 241 | 242 | video_controller video ( 243 | .reset(reset), 244 | .clock(clock), 245 | 246 | // Interrupts 247 | .int_vblank_ack(int_ack[0]), 248 | .int_vblank_req(int_req[0]), 249 | .int_lcdc_ack(int_ack[1]), 250 | .int_lcdc_req(int_req[1]), 251 | 252 | // PPU <-> MMU 253 | .A(A_ppu), 254 | .Di(Do_ppu), 255 | .Do(Di_ppu), 256 | .rd_n(rd_n), 257 | .wr_n(wr_n), 258 | .cs(cs_ppu), 259 | 260 | // PPU <-> VRAM 261 | .A_vram(A_vram), 262 | .Di_vram(Do_vram), 263 | .Do_vram(Di_vram), 264 | .rd_vram_n(rd_vram_n), 265 | .wr_vram_n(wr_vram_n), 266 | .cs_vram_n(cs_vram_n), 267 | 268 | // LCD Output 269 | .hsync(hsync), 270 | .vsync(vsync), 271 | .pixel_data(pixel_data), 272 | .pixel_latch(pixel_latch) 273 | //.pixel_clock(clock) // TODO ?? 274 | ); 275 | 276 | // 277 | // Input Controller 278 | // 279 | 280 | joypad_controller joypad_controller ( 281 | .reset(reset), 282 | .clock(clock), 283 | .int_ack(int_ack[4]), 284 | .int_req(int_req[4]), 285 | .A(A), 286 | .Di(Do_cpu), 287 | .Do(Do_joypad), 288 | .cs(cs_timer), 289 | .rd_n(rd_n), 290 | .wr_n(wr_n), 291 | .button_sel(joypad_sel), 292 | .button_data(joypad_data) 293 | ); 294 | 295 | endmodule 296 | -------------------------------------------------------------------------------- /src/gb/interrupt.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | `timescale 1ns / 1ps 3 | 4 | module interrupt_controller ( 5 | input wire clock, 6 | input wire reset, 7 | input wire m1_n, 8 | input wire iorq_n, 9 | output wire int_n, 10 | input wire [4:0] int_req, 11 | output reg [4:0] int_ack, 12 | output wire [7:0] jump_addr, 13 | input wire [15:0] A, 14 | input wire [7:0] Di, 15 | output wire [7:0] Do, 16 | input wire wr_n, 17 | input wire rd_n, 18 | input wire cs 19 | ); 20 | 21 | ////////////////////////////////////// 22 | // Interrupt Registers 23 | // 24 | // IF - Interrupt Flag (FF0F) 25 | // Bit 4: New Value on Selected Joypad Keyline(s) (rst 60) 26 | // Bit 3: Serial I/O transfer end (rst 58) 27 | // Bit 2: Timer Overflow (rst 50) 28 | // Bit 1: LCD (see STAT) (rst 48) 29 | // Bit 0: V-Blank (rst 40) 30 | // 31 | // IE - Interrupt Enable (FFFF) 32 | // Bit 4: New Value on Selected Joypad Keyline(s) 33 | // Bit 3: Serial I/O transfer end 34 | // Bit 2: Timer Overflow 35 | // Bit 1: LCDC (see STAT) 36 | // Bit 0: V-Blank 37 | // 38 | // 0 <= disable 39 | // 1 <= enable 40 | ////////////////////////////////////// 41 | 42 | wire[7:0] IF; 43 | reg[7:0] IE; 44 | 45 | parameter POLL_STATE = 0; 46 | parameter WAIT_STATE = 1; 47 | parameter ACK_STATE = 2; 48 | parameter CLEAR_STATE = 3; 49 | 50 | parameter VBLANK_INT = 0; 51 | parameter LCDC_INT = 1; 52 | parameter TIMER_INT = 2; 53 | parameter SERIAL_INT = 3; 54 | parameter INPUT_INT = 4; 55 | 56 | parameter VBLANK_JUMP = 8'hA0; // 8'h40; 57 | parameter LCDC_JUMP = 8'hA2; // 8'h48; 58 | parameter TIMER_JUMP = 8'hA4; // 8'h50; 59 | parameter SERIAL_JUMP = 8'hA6; // 8'h58; 60 | parameter INPUT_JUMP = 8'hA8; // 8'h60; 61 | 62 | reg[1:0] state; 63 | reg[2:0] interrupt; 64 | reg[7:0] reg_out; 65 | 66 | always @(posedge clock) 67 | begin 68 | 69 | if (reset) 70 | begin 71 | IE <= 8'h0; 72 | state <= POLL_STATE; 73 | end 74 | else 75 | begin 76 | 77 | // Read / Write for registers 78 | if (cs) 79 | begin 80 | if (!wr_n) 81 | begin 82 | case (A) 83 | 16'hFFFF: IE <= Di; 84 | endcase 85 | end 86 | else if (!rd_n) 87 | begin 88 | case (A) 89 | 16'hFF0F: reg_out <= IF; 90 | 16'hFFFF: reg_out <= IE; 91 | endcase 92 | end 93 | end 94 | 95 | case (state) 96 | POLL_STATE: 97 | begin 98 | if (IF[VBLANK_INT] && IE[VBLANK_INT]) 99 | begin 100 | interrupt <= VBLANK_INT; 101 | state <= WAIT_STATE; 102 | end 103 | else if (IF[LCDC_INT] && IE[LCDC_INT]) 104 | begin 105 | interrupt <= LCDC_INT; 106 | state <= WAIT_STATE; 107 | end 108 | else if (IF[TIMER_INT] && IE[TIMER_INT]) 109 | begin 110 | interrupt <= TIMER_INT; 111 | state <= WAIT_STATE; 112 | end 113 | else if (IF[SERIAL_INT] && IE[SERIAL_INT]) 114 | begin 115 | interrupt <= SERIAL_INT; 116 | state <= WAIT_STATE; 117 | end 118 | else if (IF[INPUT_INT] && IE[INPUT_INT]) 119 | begin 120 | interrupt <= INPUT_INT; 121 | state <= WAIT_STATE; 122 | end 123 | end 124 | WAIT_STATE: 125 | begin 126 | if (!m1_n && !iorq_n) 127 | state <= ACK_STATE; 128 | end 129 | ACK_STATE: 130 | begin 131 | int_ack[interrupt] <= 1'b1; 132 | state <= CLEAR_STATE; 133 | end 134 | CLEAR_STATE: 135 | begin 136 | int_ack[interrupt] <= 1'b0; 137 | if (m1_n || iorq_n) 138 | state <= POLL_STATE; 139 | end 140 | endcase 141 | 142 | end 143 | end 144 | 145 | assign IF = int_req; // this makes the value read only 146 | 147 | assign Do = (cs) ? reg_out : 8'hFF; 148 | assign int_n = (state == WAIT_STATE) ? 1'b0 : 1'b1; // active low 149 | assign jump_addr = 150 | (interrupt == VBLANK_INT) ? VBLANK_JUMP : 151 | (interrupt == LCDC_INT) ? LCDC_JUMP : 152 | (interrupt == TIMER_INT) ? TIMER_JUMP : 153 | (interrupt == SERIAL_INT) ? SERIAL_JUMP : 154 | (interrupt == INPUT_INT) ? INPUT_JUMP : 8'hZZ; 155 | 156 | endmodule 157 | -------------------------------------------------------------------------------- /src/gb/joypad.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | `timescale 1ns / 1ps 3 | 4 | module joypad_controller( 5 | input wire clock, 6 | input wire reset, 7 | input wire int_ack, 8 | output reg int_req, 9 | input wire [15:0] A, 10 | input wire [7:0] Di, 11 | output wire [7:0] Do, 12 | input wire rd_n, 13 | input wire wr_n, 14 | input wire cs, 15 | output reg [1:0] button_sel, 16 | input wire [3:0] button_data 17 | ); 18 | 19 | //////////////////////////////////////////////// 20 | // Joypad Registers 21 | // 22 | // JOYP - Joypad (FF00) 23 | // Bit 5: 0 <= select button keys (R/W) 24 | // Bit 4: 0 <= select direction keys (R/W) 25 | // Bit 3: 0 <= Down or Start 26 | // Bit 2: 0 <= Up or Select 27 | // Bit 1: 0 <= Left or B 28 | // Bit 0: 0 <= Right or A 29 | //////////////////////////////////////////////// 30 | 31 | always @(posedge clock) begin 32 | if (reset) 33 | int_req <= 0; 34 | else begin 35 | if (!wr_n) begin 36 | if (A == 16'hFF00) 37 | button_sel <= Di[5:4]; 38 | end 39 | end 40 | end 41 | 42 | assign Do = (cs) ? { 2'b11, button_sel[1:0], button_data[3:0] } : 8'hFF; 43 | 44 | endmodule 45 | -------------------------------------------------------------------------------- /src/gb/mmu.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | `timescale 1ns / 1ps 3 | 4 | module mmu( 5 | input wire clock, 6 | input wire reset, 7 | 8 | // CPU 9 | input wire [15:0] A_cpu, 10 | input wire [7:0] Di_cpu, // should be Do from cpu 11 | output wire [7:0] Do_cpu, // should be mux'd to cpu's Di 12 | input wire rd_cpu_n, 13 | input wire wr_cpu_n, 14 | 15 | // Main RAM (Cartridge + WRAM) 16 | output wire [15:0] A, 17 | output wire [7:0] Do, 18 | input wire [7:0] Di, 19 | output wire wr_n, 20 | output wire rd_n, 21 | output wire cs_n, 22 | 23 | // PPU (VRAM + OAM + Registers) 24 | output wire [15:0] A_ppu, 25 | output wire [7:0] Do_ppu, 26 | input wire [7:0] Di_ppu, 27 | output wire rd_ppu_n, 28 | output wire wr_ppu_n, 29 | output wire cs_ppu, 30 | 31 | // I/O Registers (except for PPU) 32 | input wire [7:0] Do_interrupt, 33 | input wire [7:0] Do_timer, 34 | input wire [7:0] Do_sound, 35 | input wire [7:0] Do_joypad, 36 | output wire cs_interrupt, 37 | output wire cs_timer, 38 | output wire cs_sound, 39 | output wire cs_joypad 40 | ); 41 | 42 | // internal data out pins 43 | wire [7:0] Do_high_ram; 44 | 45 | // internal r/w enables 46 | wire cs_boot_rom; 47 | wire cs_jump_rom; 48 | wire cs_high_ram; 49 | 50 | // remapped addresses 51 | wire [6:0] A_jump_rom; 52 | wire [6:0] A_high_ram; 53 | 54 | // when 8'h01 gets written into FF50h the ROM is disabled 55 | reg boot_rom_enable; 56 | 57 | // Internal ROMs 58 | reg [7:0] boot_rom [0:255]; 59 | reg [7:0] jump_rom [0:9]; 60 | 61 | initial begin 62 | $readmemh("data/boot.hex", boot_rom, 0, 255); 63 | $readmemh("data/jump.hex", jump_rom, 0, 9); 64 | end 65 | 66 | // High RAM 67 | async_mem #(.asz(8), .depth(127)) high_ram ( 68 | .rd_data(Do_high_ram), 69 | .wr_clk(clock), 70 | .wr_data(Di_cpu), 71 | .wr_cs(cs_high_ram && !wr_n), 72 | .addr(A_high_ram), 73 | .rd_cs(cs_high_ram) 74 | ); 75 | 76 | always @ (posedge clock) 77 | begin 78 | if (reset) 79 | begin 80 | boot_rom_enable <= 1; 81 | end 82 | else 83 | begin 84 | if (!wr_n) 85 | begin 86 | case(A) 87 | 16'hFF46: 88 | begin 89 | // TODO: DMA 90 | end 91 | 16'hFF50: if (Di == 8'h01) boot_rom_enable <= 1'b0; 92 | endcase 93 | end 94 | end 95 | end 96 | 97 | // selector flags 98 | assign cs_n = (A < 16'hFE00) ? 1'b0 : 1'b1; // echo of internal ram 99 | 100 | assign cs_ppu = 101 | (A >= 16'h8000 && A < 16'hA000) || // VRAM 102 | (A >= 16'hFE00 && A < 16'hFEA0) || // OAM 103 | (A >= 16'hFF40 && A <= 16'hFF4B && A != 16'hFF46); // registers (except for DMA) 104 | 105 | assign cs_boot_rom = boot_rom_enable && A < 16'h0100; 106 | assign cs_jump_rom = A >= 16'hFEA0 && A < 16'hFF00; 107 | assign cs_high_ram = A >= 16'hFF80 && A < 16'hFFFF; 108 | 109 | assign cs_interrupt = A == 16'hFF0F || A == 16'hFFFF; 110 | assign cs_sound = A >= 16'hFF10 && A <= 16'hFF3F; // there are some gaps here 111 | assign cs_timer = A >= 16'hFF04 && A <= 16'hFF07; 112 | assign cs_joypad = A == 16'hFF00; 113 | 114 | // remap internal addresses 115 | assign A_jump_rom = A - 16'hFEA0; 116 | assign A_high_ram = A - 16'hFF80; 117 | 118 | // Main RAM + Cartridge 119 | assign A = A_cpu; 120 | assign Do = Di_cpu; 121 | assign wr_n = wr_cpu_n; 122 | assign rd_n = rd_cpu_n; 123 | 124 | // PPU 125 | assign A_ppu = A_cpu; 126 | assign Do_ppu = Di_cpu; 127 | assign wr_ppu_n = wr_cpu_n; 128 | assign rd_ppu_n = rd_cpu_n; 129 | 130 | assign Do_cpu = 131 | (cs_boot_rom) ? boot_rom[A_cpu] : 132 | (cs_high_ram) ? Do_high_ram : 133 | (cs_jump_rom) ? jump_rom[A_jump_rom] : 134 | (cs_interrupt) ? Do_interrupt : 135 | (cs_timer) ? Do_timer : 136 | (cs_sound) ? Do_sound : 137 | (cs_joypad) ? Do_joypad : 138 | (cs_ppu) ? Do_ppu : 139 | (!cs_n) ? Di : 8'hFF; 140 | 141 | endmodule 142 | -------------------------------------------------------------------------------- /src/gb/ppu.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | `timescale 1ns / 1ps 3 | 4 | module video_controller ( 5 | input wire reset, 6 | input wire clock, 7 | 8 | // Interrupts 9 | input wire int_vblank_ack, 10 | output reg int_vblank_req, 11 | input wire int_lcdc_ack, 12 | output reg int_lcdc_req, 13 | 14 | // VRAM + OAM + Registers (PPU <-> MMU) 15 | input wire [15:0] A, 16 | input wire [7:0] Di, // in from MMU 17 | output wire [7:0] Do, // out to MMU 18 | input wire rd_n, 19 | input wire wr_n, 20 | input wire cs, 21 | 22 | // VRAM (PPU <-> VRAM) 23 | output wire [15:0] A_vram, 24 | output wire [7:0] Do_vram, // out to VRAM 25 | input wire [7:0] Di_vram, // in from VRAM 26 | output wire rd_vram_n, 27 | output wire wr_vram_n, 28 | output wire cs_vram_n, 29 | 30 | // LCD Output -- TODO pixel clock? 31 | output wire hsync, 32 | output wire vsync, 33 | output reg [7:0] line_count, 34 | output reg [8:0] pixel_count, 35 | output reg [7:0] pixel_data_count, 36 | output reg [1:0] pixel_data, 37 | output reg pixel_latch 38 | ); 39 | 40 | /////////////////////////////////// 41 | // 42 | // Video Registers 43 | // 44 | // LCDC - LCD Control (FF40) R/W 45 | // 46 | // Bit 7 - LCD Control Operation 47 | // 0: Stop completeLY (no picture on screen) 48 | // 1: operation 49 | // Bit 6 - Window Screen Display Data Select 50 | // 0: $9800-$9BFF 51 | // 1: $9C00-$9FFF 52 | // Bit 5 - Window Display 53 | // 0: off 54 | // 1: on 55 | // Bit 4 - BG Character Data Select 56 | // 0: $8800-$97FF 57 | // 1: $8000-$8FFF <- Same area as OBJ 58 | // Bit 3 - BG Screen Display Data Select 59 | // 0: $9800-$9BFF 60 | // 1: $9C00-$9FFF 61 | // Bit 2 - OBJ Construction 62 | // 0: 8*8 63 | // 1: 8*16 64 | // Bit 1 - Window priority bit 65 | // 0: window overlaps all sprites 66 | // 1: window onLY overlaps sprites whose 67 | // priority bit is set to 1 68 | // Bit 0 - BG Display 69 | // 0: off 70 | // 1: on 71 | // 72 | // STAT - LCDC Status (FF41) R/W 73 | // 74 | // Bits 6-3 - Interrupt Selection By LCDC Status 75 | // Bit 6 - LYC=LY Coincidence (1=Select) 76 | // Bit 5 - Mode 2: OAM-Search (1=Enabled) 77 | // Bit 4 - Mode 1: V-Blank (1=Enabled) 78 | // Bit 3 - Mode 0: H-Blank (1=Enabled) 79 | // Bit 2 - Coincidence Flag 80 | // 0: LYC not equal to LCDC LY 81 | // 1: LYC = LCDC LY 82 | // Bit 1-0 - Mode Flag (Current STATus of the LCD controller) 83 | // 0: During H-Blank. Entire Display Ram can be accessed. 84 | // 1: During V-Blank. Entire Display Ram can be accessed. 85 | // 2: During Searching OAM-RAM. OAM cannot be accessed. 86 | // 3: During Transfering Data to LCD Driver. CPU cannot 87 | // access OAM and display RAM during this period. 88 | // 89 | // The following are typical when the display is enabled: 90 | // 91 | // Mode 0 000___000___000___000___000___000___000________________ H-Blank 92 | // Mode 1 _______________________________________11111111111111__ V-Blank 93 | // Mode 2 ___2_____2_____2_____2_____2_____2___________________2_ OAM 94 | // Mode 3 ____33____33____33____33____33____33__________________3 Transfer 95 | // 96 | // 97 | // The Mode Flag goes through the values 00, 02, 98 | // and 03 at a cycle of about 109uS. 00 is present 99 | // about 49uS, 02 about 20uS, and 03 about 40uS. This 100 | // is interrupted every 16.6ms by the VBlank (01). 101 | // The mode flag stays set at 01 for 1.1 ms. 102 | // 103 | // Mode 0 is present between 201-207 clks, 2 about 77-83 clks, 104 | // and 3 about 169-175 clks. A complete cycle through these 105 | // states takes 456 clks. VBlank lasts 4560 clks. A complete 106 | // screen refresh occurs every 70224 clks.) 107 | // 108 | // SCY - Scroll Y (FF42) R/W 109 | // Vertical scroll of background 110 | // 111 | // SCX - Scroll X (FF43) R/W 112 | // Horizontal scroll of background 113 | // 114 | // LY - LCDC Y-Coordinate (FF44) R 115 | // The LY indicates the vertical line to which 116 | // the present data is transferred to the LCD 117 | // Driver. The LY can take on any value between 118 | // 0 through 153. The values between 144 and 153 119 | // indicate the V-Blank period. Writing will 120 | // reset the counter. 121 | // 122 | // This is just a RASTER register. The current 123 | // line is thrown into here. But since there are 124 | // no RASTERS on an LCD display it's called the 125 | // LCDC Y-Coordinate. 126 | // 127 | // LYC - LY Compare (FF45) R/W 128 | // The LYC compares itself with the LY. If the 129 | // values are the same it causes the STAT to set 130 | // the coincident flag. 131 | // 132 | // DMA (FF46) 133 | // Implemented in the MMU 134 | // 135 | // BGP - BG Palette Data (FF47) W 136 | // 137 | // Bit 7-6 - Data for Dot Data 11 138 | // Bit 5-4 - Data for Dot Data 10 139 | // Bit 3-2 - Data for Dot Data 01 140 | // Bit 1-0 - Data for Dot Data 00 141 | // 142 | // This selects the shade of gray you what for 143 | // your BG pixel. Since each pixel uses 2 bits, 144 | // the corresponding shade will be selected 145 | // from here. The Background Color (00) lies at 146 | // Bits 1-0, just put a value from 0-$3 to 147 | // change the color. 148 | // 149 | // OBP0 - Object Palette 0 Data (FF48) W 150 | // This selects the colors for sprite palette 0. 151 | // It works exactLY as BGP ($FF47). 152 | // See BGP for details. 153 | // 154 | // OBP1 - Object Palette 1 Data (FF49) W 155 | // This selects the colors for sprite palette 1. 156 | // It works exactLY as BGP ($FF47). 157 | // See BGP for details. 158 | // 159 | // WY - Window Y Position (FF4A) R/W 160 | // 0 <= WY <= 143 161 | // 162 | // WX - Window X Position + 7 (FF4B) R/W 163 | // 7 <= WX <= 166 164 | // 165 | /////////////////////////////////// 166 | 167 | reg[7:0] LCDC; 168 | wire[7:0] STAT; 169 | reg[7:0] SCY; 170 | reg[7:0] SCX; 171 | reg[7:0] LYC; 172 | reg[7:0] BGP; 173 | reg[7:0] OBP0; 174 | reg[7:0] OBP1; 175 | reg[7:0] WY; 176 | reg[7:0] WX; 177 | 178 | // temp registers for r/rw mixtures 179 | reg[4:0] STAT_w; 180 | 181 | // timing params -- see STAT register 182 | parameter PIXELS = 456; 183 | parameter LINES = 154; 184 | parameter HACTIVE_VIDEO = 160; 185 | parameter HBLANK_PERIOD = 41; 186 | parameter OAM_ACTIVE = 80; 187 | parameter RAM_ACTIVE = 172; 188 | parameter VACTIVE_VIDEO = 144; 189 | parameter VBLANK_PERIOD = 10; 190 | 191 | reg[1:0] mode; 192 | parameter HBLANK_MODE = 0; 193 | parameter VBLANK_MODE = 1; 194 | parameter OAM_LOCK_MODE = 2; 195 | parameter RAM_LOCK_MODE = 3; 196 | 197 | reg[3:0] state; 198 | parameter IDLE_STATE = 0; 199 | 200 | parameter BG_ADDR_STATE = 1; 201 | parameter BG_ADDR_WAIT_STATE = 2; 202 | parameter BG_DATA_STATE = 3; 203 | parameter BG_DATA_WAIT_STATE = 4; 204 | parameter BG_PIXEL_COMPUTE_STATE = 8; 205 | parameter BG_PIXEL_READ_STATE = 9; 206 | parameter BG_PIXEL_WAIT_STATE = 10; 207 | parameter BG_PIXEL_WRITE_STATE = 11; 208 | parameter BG_PIXEL_HOLD_STATE = 12; 209 | 210 | parameter SPRITE_POS_STATE = 13; 211 | parameter SPRITE_POS_WAIT_STATE = 14; 212 | parameter SPRITE_ATTR_STATE = 15; 213 | parameter SPRITE_ATTR_WAIT_STATE = 16; 214 | parameter SPRITE_DATA_STATE = 17; 215 | parameter SPRITE_DATA_WAIT_STATE = 18; 216 | parameter SPRITE_PIXEL_COMPUTE_STATE = 19; 217 | parameter SPRITE_PIXEL_READ_STATE = 20; 218 | parameter SPRITE_PIXEL_WAIT_STATE = 21; 219 | parameter SPRITE_PIXEL_DRAW_STATE = 22; 220 | parameter SPRITE_PIXEL_DATA_STATE = 23; 221 | parameter SPRITE_WRITE_STATE = 24; 222 | parameter SPRITE_HOLD_STATE = 25; 223 | 224 | parameter PIXEL_WAIT_STATE = 26; 225 | parameter PIXEL_READ_STATE = 27; 226 | parameter PIXEL_READ_WAIT_STATE = 28; 227 | parameter PIXEL_OUT_STATE = 29; 228 | parameter PIXEL_OUT_HOLD_STATE = 30; 229 | parameter PIXEL_INCREMENT_STATE = 31; 230 | 231 | wire [7:0] next_line_count; 232 | wire [8:0] next_pixel_count; 233 | 234 | reg [7:0] tile_x_pos; 235 | reg [7:0] tile_y_pos; 236 | reg [4:0] tile_byte_pos1; 237 | reg [4:0] tile_byte_pos2; 238 | reg [3:0] tile_byte_offset1; 239 | reg [3:0] tile_byte_offset2; 240 | reg [7:0] tile_data1; 241 | reg [7:0] tile_data2; 242 | reg render_background; 243 | 244 | reg [7:0] sprite_x_pos; 245 | reg [7:0] sprite_y_pos; 246 | reg [7:0] sprite_data1; 247 | reg [7:0] sprite_data2; 248 | reg [7:0] sprite_location; 249 | reg [7:0] sprite_attributes; 250 | reg [1:0] sprite_pixel; 251 | reg [1:0] bg_pixel; 252 | reg [2:0] sprite_pixel_num; 253 | reg [7:0] sprite_palette; 254 | reg [4:0] sprite_y_size; 255 | 256 | reg [4:0] tile_col_num; // increments from 0 -> 31 257 | reg [6:0] sprite_num; // increments from 0 -> 39 258 | 259 | // OAM 260 | 261 | reg [7:0] oam_addrA, oam_addrB; 262 | wire [7:0] oam_outA, oam_outB; 263 | wire wr_oam; 264 | wire cs_oam; 265 | 266 | async_mem2 #(.asz(8), .depth(160)) oam ( 267 | .clkA(clock), 268 | .clkB(clock), 269 | .addrA(oam_addrA), 270 | .addrB(oam_addrB), 271 | .rd_dataA(oam_outA), 272 | .rd_dataB(oam_outB), 273 | .wr_dataA(Di), 274 | .wr_csA(wr_oam) 275 | ); 276 | 277 | // VRAM 278 | 279 | reg [12:0] vram_addrA, vram_addrB; 280 | wire [7:0] vram_outA, vram_outB; 281 | wire wr_vram; 282 | wire cs_vram; 283 | 284 | async_mem2 #(.asz(13), .depth(8192)) vram ( 285 | .clkA(clock), 286 | .clkB(clock), 287 | .addrA(vram_addrA), 288 | .addrB(vram_addrB), 289 | .rd_dataA(vram_outA), 290 | .rd_dataB(vram_outB), 291 | .wr_dataA(Di), 292 | .wr_csA(wr_vram) 293 | ); 294 | 295 | // Scanlines 296 | 297 | reg [4:0] scanline1_addrA, scanline1_addrB; 298 | reg [7:0] scanline1_inA, scanline1_inB; 299 | wire [7:0] scanline1_outA, scanline1_outB; 300 | reg wr_scanline1; 301 | 302 | async_mem2 #(.asz(5), .depth(20)) scanline1 ( 303 | .clkA(clock), 304 | .clkB(clock), 305 | .addrA(scanline1_addrA), 306 | .addrB(scanline1_addrB), 307 | .rd_dataA(scanline1_outA), 308 | .rd_dataB(scanline1_outB), 309 | .wr_dataA(scanline1_inA), 310 | .wr_dataB(scanline1_inB), 311 | .wr_csA(wr_scanline1), 312 | .wr_csB(wr_scanline1) 313 | ); 314 | 315 | reg [4:0] scanline2_addrA, scanline2_addrB; 316 | reg [7:0] scanline2_inA, scanline2_inB; 317 | wire [7:0] scanline2_outA, scanline2_outB; 318 | reg wr_scanline2; 319 | 320 | async_mem2 #(.asz(5), .depth(20)) scanline2 ( 321 | .clkA(clock), 322 | .clkB(clock), 323 | .addrA(scanline2_addrA), 324 | .addrB(scanline2_addrB), 325 | .rd_dataA(scanline2_outA), 326 | .rd_dataB(scanline2_outB), 327 | .wr_dataA(scanline2_inA), 328 | .wr_dataB(scanline2_inB), 329 | .wr_csA(wr_scanline2), 330 | .wr_csB(wr_scanline2) 331 | ); 332 | 333 | // Registers 334 | 335 | reg [7:0] Do_reg; 336 | wire cs_reg; 337 | 338 | // Clock -> CPU Clock Divider 339 | 340 | wire clock_enable; 341 | divider #(8) clock_divider(reset, clock, clock_enable); 342 | 343 | always @(posedge clock) 344 | begin 345 | if (reset) 346 | begin 347 | // initialize registers 348 | LCDC <= 8'h00; //91 349 | SCY <= 8'h00; //4f 350 | SCX <= 8'h00; 351 | LYC <= 8'h00; 352 | BGP <= 8'hFC; //fc 353 | OBP0 <= 8'h00; 354 | OBP1 <= 8'h00; 355 | WY <= 8'h00; 356 | WX <= 8'h00; 357 | 358 | // reset internal registers 359 | int_vblank_req <= 0; 360 | int_lcdc_req <= 0; 361 | mode <= 0; 362 | state <= 0; 363 | STAT_w <= 0; 364 | 365 | pixel_count <= 0; 366 | line_count <= 0; 367 | end 368 | else 369 | begin 370 | 371 | // memory r/w 372 | if (cs) 373 | begin 374 | if (!rd_n) 375 | begin 376 | case (A) 377 | 16'hFF40: Do_reg <= LCDC; 378 | 16'hFF41: Do_reg <= STAT; 379 | 16'hFF42: Do_reg <= SCY; 380 | 16'hFF43: Do_reg <= SCX; 381 | 16'hFF44: Do_reg <= line_count; 382 | 16'hFF45: Do_reg <= LYC; 383 | 16'hFF47: Do_reg <= BGP; 384 | 16'hFF48: Do_reg <= OBP0; 385 | 16'hFF49: Do_reg <= OBP1; 386 | 16'hFF4A: Do_reg <= WX; 387 | 16'hFF4B: Do_reg <= WY; 388 | endcase 389 | end 390 | else if (!wr_n) 391 | begin 392 | case (A) 393 | 16'hFF40: LCDC <= Di; 394 | 16'hFF41: STAT_w[4:0] <= Di[7:3]; 395 | 16'hFF42: SCY <= Di; 396 | 16'hFF43: SCX <= Di; 397 | //16'hFF44: line_count <= 0; // TODO: reset counter 398 | 16'hFF45: LYC <= Di; 399 | 16'hFF47: BGP <= Di; 400 | 16'hFF48: OBP0 <= Di; 401 | 16'hFF49: OBP1 <= Di; 402 | 16'hFF4A: WX <= Di; 403 | 16'hFF4B: WY <= Di; 404 | endcase 405 | end 406 | end 407 | 408 | // clear interrupts 409 | if (int_vblank_ack) 410 | int_vblank_req <= 0; 411 | if (int_lcdc_ack) 412 | int_lcdc_req <= 0; 413 | 414 | if (LCDC[7]) // grapics enabled 415 | begin 416 | 417 | ////////////////////////////// 418 | // STAT INTERRUPTS AND MODE // 419 | ////////////////////////////// 420 | 421 | // vblank -- mode 1 422 | if (line_count >= VACTIVE_VIDEO) 423 | begin 424 | if (mode != VBLANK_MODE) 425 | begin 426 | int_vblank_req <= 1; 427 | if (STAT[4]) 428 | int_lcdc_req <= 1; 429 | end 430 | mode <= VBLANK_MODE; 431 | end 432 | // oam lock -- mode 2 433 | else if (pixel_count < OAM_ACTIVE) 434 | begin 435 | if (STAT[5] && mode != OAM_LOCK_MODE) 436 | int_lcdc_req <= 1; 437 | mode <= OAM_LOCK_MODE; 438 | end 439 | // ram + oam lock -- mode 3 440 | else if (pixel_count < OAM_ACTIVE + RAM_ACTIVE) 441 | begin 442 | mode <= RAM_LOCK_MODE; 443 | // does not generate an interrupt 444 | end 445 | // hblank -- mode 0 446 | else 447 | begin 448 | if (STAT[3] && mode != HBLANK_MODE) 449 | int_lcdc_req <= 1; 450 | mode <= HBLANK_MODE; 451 | end 452 | 453 | // lyc interrupt 454 | if (pixel_count == 0 && line_count == LYC) 455 | begin 456 | // stat bit set automatically 457 | if (STAT[6]) 458 | int_lcdc_req <= 1; 459 | end 460 | 461 | ///////////////////// 462 | // RENDER GRAPHICS // 463 | ///////////////////// 464 | 465 | case (state) 466 | IDLE_STATE: begin 467 | if (mode == RAM_LOCK_MODE) begin 468 | tile_col_num <= 0; 469 | sprite_num <= 0; 470 | pixel_data_count <= 0; 471 | state <= BG_ADDR_STATE; 472 | end 473 | end 474 | 475 | // BACKGROUND 476 | 477 | BG_ADDR_STATE: begin 478 | // disable writes 479 | wr_scanline1 <= 0; 480 | wr_scanline2 <= 0; 481 | 482 | // enable window 483 | if (LCDC[5] && WY < line_count) begin 484 | tile_x_pos <= { tile_col_num, 3'b0 } + (WX - 7); 485 | tile_y_pos <= line_count - WY; 486 | vram_addrA <= { (line_count - WY) >> 3, 5'b0 } + 487 | (({tile_col_num, 3'b0} + (WX - 7)) >> 3) + 488 | ((LCDC[6]) ? 16'h1C00 : 16'h1800); 489 | render_background <= 1; 490 | state <= BG_ADDR_WAIT_STATE; 491 | end 492 | 493 | // enable background 494 | else if (LCDC[0]) begin 495 | tile_x_pos <= { tile_col_num, 3'b0 } + SCX; 496 | tile_y_pos <= SCY + line_count; 497 | vram_addrA <= { (SCY + line_count) >> 3, 5'b0 } + 498 | (({tile_col_num, 3'b0} + (SCX)) >> 3) + 499 | ((LCDC[3]) ? 16'h1C00 : 16'h1800); 500 | render_background <= 1; 501 | state <= BG_ADDR_WAIT_STATE; 502 | end 503 | 504 | else begin 505 | tile_x_pos <= { tile_col_num, 3'b0 }; 506 | tile_y_pos <= line_count; 507 | render_background <= 0; 508 | state <= BG_PIXEL_COMPUTE_STATE; 509 | end 510 | end 511 | 512 | BG_ADDR_WAIT_STATE: begin 513 | state <= BG_DATA_STATE; 514 | end 515 | 516 | BG_DATA_STATE: begin 517 | vram_addrA <= 518 | LCDC[4] ? 16'h0000 + { vram_outA, 4'b0 } + { tile_y_pos[2:0], 1'b0 } : 519 | { vram_outA, 4'b0 } + { tile_y_pos[2:0], 1'b0 } < 128 ? 520 | 16'h1000 + { vram_outA, 4'b0 } + { tile_y_pos[2:0], 1'b0 } : 521 | 16'h1000 - (~({ vram_outA, 4'b0 } + { tile_y_pos[2:0], 1'b0 }) + 1); 522 | vram_addrB <= 523 | LCDC[4] ? 16'h0000 + { vram_outA, 4'b0 } + { tile_y_pos[2:0], 1'b0 } + 1 : 524 | { vram_outA, 4'b0 } + { tile_y_pos[2:0], 1'b0 } + 1 < 128 ? 525 | 16'h1000 + { vram_outA, 4'b0 } + { tile_y_pos[2:0], 1'b0 } + 1 : 526 | 16'h1000 - (~({ vram_outA, 4'b0 } + { tile_y_pos[2:0], 1'b0 } + 1) + 1); 527 | state <= BG_DATA_WAIT_STATE; 528 | end 529 | 530 | BG_DATA_WAIT_STATE: begin 531 | state <= BG_PIXEL_COMPUTE_STATE; 532 | end 533 | 534 | BG_PIXEL_COMPUTE_STATE: begin 535 | tile_data1 <= vram_outA; 536 | tile_data2 <= vram_outB; 537 | tile_byte_pos1 <= tile_x_pos >> 3; 538 | tile_byte_pos2 <= ((tile_x_pos + 8) & 8'hFF) >> 3; 539 | tile_byte_offset1 <= tile_x_pos[2:0]; 540 | tile_byte_offset2 <= 8 - tile_x_pos[2:0]; 541 | state <= BG_PIXEL_READ_STATE; 542 | end 543 | 544 | BG_PIXEL_READ_STATE: begin 545 | scanline1_addrA <= tile_byte_pos1; 546 | scanline1_addrB <= tile_byte_pos2; 547 | scanline2_addrA <= tile_byte_pos1; 548 | scanline2_addrB <= tile_byte_pos2; 549 | state <= BG_PIXEL_WAIT_STATE; 550 | end 551 | 552 | BG_PIXEL_WAIT_STATE: begin 553 | state <= BG_PIXEL_WRITE_STATE; 554 | end 555 | 556 | BG_PIXEL_WRITE_STATE: begin 557 | // first byte 558 | scanline1_inA <= 559 | render_background ? scanline1_outA & (8'hFF << tile_byte_offset2) | 560 | (tile_data1 >> tile_byte_offset1) : 0; 561 | scanline2_inA <= 562 | render_background ? scanline2_outA & (8'hFF << tile_byte_offset2) | 563 | (tile_data2 >> tile_byte_offset1) : 0; 564 | 565 | // second byte 566 | scanline1_inB <= 567 | render_background ? scanline1_outB & ~(8'hFF << tile_byte_offset2) | 568 | (tile_data1 << tile_byte_offset2) : 0; 569 | scanline2_inB <= 570 | render_background ? scanline2_outB & ~(8'hFF << tile_byte_offset2) | 571 | (tile_data2 << tile_byte_offset2) : 0; 572 | 573 | // enable writes 574 | wr_scanline1 <= tile_byte_pos1 < 20 ? 1 : 0; 575 | wr_scanline2 <= tile_byte_pos2 < 20 ? 1 : 0; 576 | 577 | state <= BG_PIXEL_HOLD_STATE; 578 | end 579 | 580 | BG_PIXEL_HOLD_STATE: begin 581 | // increment col 582 | if (tile_col_num == 31) 583 | state <= SPRITE_POS_STATE; 584 | else begin 585 | tile_col_num <= tile_col_num + 1; 586 | state <= BG_ADDR_STATE; 587 | end 588 | end 589 | 590 | endcase 591 | 592 | end else begin 593 | mode <= HBLANK_MODE; 594 | end 595 | 596 | // failsafe -- if we somehow exceed the allotted cycles for rendering 597 | //if (mode != RAM_LOCK_MODE && state < PIXEL_WAIT_STATE && state > IDLE_STATE) 598 | // state <= PIXEL_WAIT_STATE; 599 | 600 | if (mode < RAM_LOCK_MODE) 601 | vram_addrA <= A - 16'h8000; 602 | if (mode < OAM_LOCK_MODE) 603 | oam_addrA <= A - 16'hFE00; 604 | 605 | if (clock_enable) begin 606 | pixel_count <= next_pixel_count; 607 | line_count <= next_line_count; 608 | end 609 | end 610 | end 611 | 612 | assign next_pixel_count = 613 | LCDC[7] ? (pixel_count == PIXELS - 1 ? 0 : pixel_count + 1) : 0; 614 | 615 | assign next_line_count = 616 | LCDC[7] ? (pixel_count == PIXELS - 1 ? 617 | (line_count == LINES - 1 ? 0 : line_count + 1) : line_count) : 0; 618 | 619 | assign hsync = (pixel_count > OAM_ACTIVE + RAM_ACTIVE + HACTIVE_VIDEO) ? 1'b1 : 1'b0; 620 | assign vsync = (line_count > VACTIVE_VIDEO) ? 1'b1 : 1'b0; 621 | 622 | assign cs_vram = cs && A >= 16'h8000 && A < 16'hA000; 623 | assign cs_oam = cs && A >= 16'hFE00 && A < 16'hFEA0; 624 | assign cs_reg = cs && cs_vram_n && !cs_oam; 625 | 626 | assign wr_vram = cs_oam && !wr_n && mode != RAM_LOCK_MODE; 627 | assign wr_oam = cs_oam && !wr_n && mode != RAM_LOCK_MODE && mode != OAM_LOCK_MODE; 628 | 629 | assign STAT[7:3] = STAT_w[4:0]; // r/w 630 | assign STAT[2] = (line_count == LYC) ? 1 : 0; // LYC Coincidence flag 631 | assign STAT[1:0] = mode; // read only -- set internally 632 | 633 | assign Do = 634 | (cs_vram) ? vram_outA : 635 | (cs_oam) ? oam_outA : 636 | (cs_reg) ? Do_reg : 8'hFF; 637 | 638 | endmodule 639 | -------------------------------------------------------------------------------- /src/gb/timer.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | `timescale 1ns / 1ps 3 | 4 | module timer_controller ( 5 | input wire clock, 6 | input wire reset, 7 | input wire int_ack, 8 | output reg int_req, 9 | input wire [15:0] A, 10 | input wire [7:0] Di, 11 | output wire [7:0] Do, 12 | input wire wr_n, 13 | input wire rd_n, 14 | input wire cs 15 | ); 16 | 17 | //////////////////////////////////////////////// 18 | // Timer Registers 19 | // 20 | // DIV - Divider Register (FF04) 21 | // Increments 16384 times a second 22 | // 23 | // TIMA - Timer Counter (FF05) 24 | // Increments at frequency specified by TAC 25 | // 26 | // TMA - Timer Modulo (FF06) 27 | // Value to load into TIMA on overflow 28 | // 29 | // TAC - Timer Control (FF07) 30 | // Bit 2: 0 <= stop, 1 <= start 31 | // Bit 1-0: 00 <= 4.096 KHz 32 | // 01 <= 262.144 KHz 33 | // 10 <= 65.536 KHz 34 | // 11 <= 16.384 KHz 35 | //////////////////////////////////////////////// 36 | 37 | reg[7:0] DIV; 38 | reg[7:0] TIMA; 39 | reg[7:0] TMA; 40 | reg[7:0] TAC; 41 | 42 | reg[7:0] reg_out; 43 | 44 | parameter MAX_TIMER = 8'hFF; 45 | 46 | wire enable; 47 | wire e0, e1, e2, e3; 48 | 49 | divider #(1024) d0(reset, clock, e0); 50 | divider #(16) d1(reset, clock, e1); 51 | divider #(64) d2(reset, clock, e2); 52 | divider #(256) d3(reset, clock, e3); 53 | 54 | always @(posedge clock) 55 | begin 56 | if (reset) 57 | begin 58 | DIV <= 8'h0; 59 | TIMA <= 8'h0; 60 | TMA <= 8'h0; 61 | TAC <= 8'h0; 62 | int_req <= 1'b0; 63 | reg_out <= 8'h0; 64 | end 65 | else 66 | begin 67 | 68 | // Read / Write for registers 69 | if (cs) 70 | begin 71 | if (!wr_n) 72 | begin 73 | case (A) 74 | 16'hFF04: DIV <= 8'h0; 75 | 16'hFF05: TIMA <= Di; 76 | 16'hFF06: TMA <= Di; 77 | 16'hFF07: TAC <= Di; 78 | endcase 79 | end 80 | else if (!rd_n) 81 | begin 82 | case (A) 83 | 16'hFF04: reg_out <= DIV; 84 | 16'hFF05: reg_out <= TIMA; 85 | 16'hFF06: reg_out <= TMA; 86 | 16'hFF07: reg_out <= TAC; 87 | endcase 88 | end 89 | end 90 | 91 | // Clear overflow interrupt 92 | if (int_ack) 93 | int_req <= 1'b0; 94 | 95 | // Increment timers 96 | if (enable) 97 | begin 98 | if (TIMA == MAX_TIMER) 99 | int_req <= 1'b1; 100 | TIMA <= (TIMA == MAX_TIMER) ? TMA : TIMA + 1'b1; 101 | end 102 | 103 | if (e3) 104 | begin 105 | DIV <= DIV + 1'b1; 106 | end 107 | 108 | end 109 | end 110 | 111 | assign Do = (cs) ? reg_out : 8'hZZ; 112 | assign enable = 113 | (TAC[2] == 0) ? 1'b0 : 114 | (TAC[1:0] == 0) ? e0 : 115 | (TAC[1:0] == 1) ? e1 : 116 | (TAC[1:0] == 2) ? e2 : 117 | (TAC[1:0] == 3) ? e3 : 1'b0; 118 | 119 | endmodule 120 | -------------------------------------------------------------------------------- /src/gb/video_converter.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | `timescale 1ns / 1ps 3 | 4 | module video_converter ( 5 | input wire reset, 6 | input wire clock, 7 | // gameboy signals 8 | input wire [1:0] pixel_data, 9 | input wire hsync, // active high 10 | input wire vsync, // active high 11 | input wire data_latch, 12 | // vga signals 13 | input wire pixel_clock, 14 | output wire [23:0] vga_rgb, 15 | output wire vga_hsync, 16 | output wire vga_vsync 17 | ); 18 | 19 | // game boy screen size 20 | parameter GB_SCREEN_WIDTH = 10'd160; 21 | parameter GB_SCREEN_HEIGHT = 10'd144; 22 | 23 | // toggle for which is the front buffer 24 | // 0 -> buffer1 is front buffer 25 | // 1 -> buffer2 is front buffer 26 | reg front_buffer; 27 | 28 | wire[14:0] write_addr; 29 | wire[1:0] read_data; 30 | 31 | wire[14:0] b1_addr; 32 | wire b1_clk; 33 | wire[1:0] b1_din; 34 | wire[1:0] b1_dout; 35 | wire b1_we; // active high 36 | 37 | wire[14:0] b2_addr; 38 | wire b2_clk; 39 | wire[1:0] b2_din; 40 | wire[1:0] b2_dout; 41 | wire b2_we; // active high 42 | 43 | reg[1:0] last_pixel_data; 44 | reg[14:0] last_write_addr; 45 | 46 | assign b1_we = front_buffer ? (data_latch) : 0; 47 | assign b2_we = front_buffer ? 0 : (data_latch); 48 | 49 | assign read_data = (front_buffer) ? b2_dout : b1_dout; 50 | assign b1_din = (front_buffer) ? pixel_data : 0; 51 | assign b2_din = (front_buffer) ? 0 : pixel_data; 52 | 53 | BUFGMUX clock_mux_b1(.S(front_buffer), .O(b1_clk), 54 | .I0(pixel_clock), .I1(clock)); 55 | BUFGMUX clock_mux_b2(.S(front_buffer), .O(b2_clk), 56 | .I0(clock), .I1(pixel_clock)); 57 | 58 | // internal buffer ram 59 | frame_buffer buffer1( 60 | b1_addr, 61 | b1_clk, 62 | b1_din, 63 | b1_dout, 64 | b1_we 65 | ); 66 | 67 | frame_buffer buffer2( 68 | b2_addr, 69 | b2_clk, 70 | b2_din, 71 | b2_dout, 72 | b2_we 73 | ); 74 | 75 | reg gb_last_vsync; 76 | reg gb_last_hsync; 77 | reg gb_last_latch; 78 | reg [7:0] gb_line_count; 79 | reg [7:0] gb_pixel_count; 80 | 81 | // handle writing into the back_buffer 82 | always @ (posedge clock) 83 | begin 84 | if(reset) 85 | begin 86 | front_buffer <= 1'b0; 87 | gb_last_vsync <= 1'b0; 88 | gb_last_hsync <= 1'b0; 89 | gb_last_latch <= 1'b0; 90 | end 91 | else 92 | begin 93 | gb_last_vsync <= vsync; 94 | gb_last_hsync <= hsync; 95 | gb_last_latch <= data_latch; 96 | end 97 | 98 | // negedge hsync 99 | if (gb_last_hsync && !hsync) 100 | begin 101 | gb_line_count <= gb_line_count + 1; 102 | end 103 | 104 | // negedge data_latch 105 | if (gb_last_latch && !data_latch) 106 | begin 107 | gb_pixel_count <= gb_pixel_count + 1; 108 | end 109 | 110 | // posedge vsync 111 | if(!gb_last_vsync && vsync) 112 | begin 113 | front_buffer <= !front_buffer; 114 | gb_line_count <= 0; 115 | gb_pixel_count <= 0; 116 | end 117 | end 118 | 119 | // handle output to the vga module 120 | wire [9:0] pixel_count, line_count; 121 | vga_controller vgac(pixel_clock, reset, vga_hsync, vga_vsync, pixel_count, line_count); 122 | 123 | // write to our current counter 124 | assign write_addr = gb_line_count * 160 + gb_pixel_count; 125 | 126 | parameter X_OFFSET = 160; 127 | parameter Y_OFFSET = 76; 128 | 129 | // read from where the vga wants to read 130 | wire[14:0] buffer_pos = ((line_count - Y_OFFSET) >> 1) * 160 + ((pixel_count - X_OFFSET) >> 1); 131 | 132 | assign b1_addr = (front_buffer) ? write_addr : buffer_pos; 133 | assign b2_addr = (front_buffer) ? buffer_pos : write_addr; 134 | 135 | // generate a gameboy color 136 | // 00 -> white 137 | // 01 -> light gray 138 | // 10 -> dark gray 139 | // 11 -> black 140 | 141 | wire [7:0] my_color = (pixel_count >= X_OFFSET && line_count >= Y_OFFSET && pixel_count < X_OFFSET + 320 && line_count < Y_OFFSET + 288) ? 142 | (read_data == 2'b00) ? 8'b11111111 : 143 | ((read_data == 2'b01) ? 8'b10101010 : 144 | ((read_data == 2'b10) ? 8'b01010101 : 8'b00000000)) : 8'b00000000; 145 | 146 | assign vga_rgb = { my_color, my_color, my_color }; 147 | 148 | endmodule 149 | -------------------------------------------------------------------------------- /src/io/debug/cls_spi.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | `timescale 1ns / 1ps 3 | 4 | module cls_spi( 5 | input wire clock, 6 | input wire reset, 7 | 8 | input wire [15:0] A, 9 | input wire [7:0] Di, 10 | input wire [7:0] Do, 11 | input wire [15:0] PC, 12 | input wire [15:0] SP, 13 | input wire [15:0] AF, 14 | input wire [15:0] BC, 15 | input wire [15:0] DE, 16 | input wire [15:0] HL, 17 | input wire [15:0] joypad_state, 18 | input wire [1:0] mode, 19 | 20 | output wire ss, 21 | output reg mosi, 22 | input wire miso, 23 | output wire sclk 24 | ); 25 | 26 | parameter WAIT = 1; 27 | parameter SEND = 2; 28 | parameter SEND_2 = 3; 29 | parameter SEND_3 = 4; 30 | parameter SEND_4 = 5; 31 | parameter SEND_5 = 6; 32 | parameter SENDHEX = 7; 33 | parameter SENDJOYPAD = 8; 34 | 35 | parameter STARTUP_1 = 10; 36 | parameter STARTUP_2 = 11; 37 | parameter STARTUP_3 = 12; 38 | parameter STARTUP_4 = 13; 39 | 40 | parameter LOOP_1 = 20; 41 | parameter LOOP_2 = 21; 42 | parameter LOOP_3 = 22; 43 | parameter LOOP_4 = 23; 44 | parameter LOOP_5 = 24; 45 | parameter LOOP_6 = 25; 46 | parameter LOOP_7 = 26; 47 | parameter LOOP_8 = 27; 48 | parameter LOOP_9 = 28; 49 | parameter LOOP_10 = 29; 50 | parameter LOOP_11 = 30; 51 | parameter LOOP_7b = 31; 52 | parameter LOOP_8b = 32; 53 | 54 | reg [63:0] send_buf; // send buffer (8 bytes) 55 | reg [2:0] send_idx; // current bit (0h-7h) 56 | reg [2:0] send_ctr; // current byte (0h-7h) 57 | reg [2:0] send_max; // total bytes (0h-7h) 58 | 59 | reg [31:0] wait_ctr; // current cycle 60 | reg [31:0] wait_max; // total cycles 61 | 62 | reg [2:0] hex_idx; // current word 63 | reg [3:0] btn_idx; // current joypad button 64 | reg [1:0] mode_latch; // 0-PCSP, 1-AFBC, 2-DEHL 65 | 66 | // TODO probably don't need 7 bits for state 67 | reg [7:0] state; 68 | reg [7:0] next_state; 69 | reg [7:0] next_state_hex; 70 | reg [7:0] next_state_btn; 71 | 72 | reg ss_enable; 73 | reg sclk_enable; 74 | 75 | reg [7:0] glyph_rom [15:0]; 76 | reg [31:0] data; 77 | reg [1:0] data_idx; 78 | 79 | initial begin 80 | $readmemh("data/hexascii.hex", glyph_rom, 0, 15); 81 | end 82 | 83 | always @(posedge clock) begin 84 | // RESET 85 | if (reset) begin 86 | send_buf <= 64'b0; 87 | send_idx <= 3'b0; 88 | send_ctr <= 3'b0; 89 | send_max <= 3'b0; 90 | wait_ctr <= 32'b0; 91 | wait_max <= 32'b0; 92 | state <= STARTUP_1; 93 | next_state <= 8'b0; 94 | next_state_hex <= 8'b0; 95 | next_state_btn <= 8'b0; 96 | mode_latch <= 2'b0; 97 | 98 | hex_idx <= 3'b0; 99 | btn_idx <= 4'b0; 100 | data <= 32'b0; 101 | data_idx <= 2'b0; 102 | 103 | ss_enable <= 0; 104 | sclk_enable <= 0; 105 | 106 | mosi <= 1'b0; 107 | end 108 | 109 | // STATES 110 | else begin 111 | // SEND - send up to eight serial bytes 112 | if (state == SEND) begin 113 | ss_enable <= 1; 114 | state <= SEND_2; 115 | end 116 | 117 | else if (state == SEND_2) begin 118 | state <= SEND_3; 119 | end 120 | 121 | else if (state == SEND_3) begin 122 | mosi <= send_buf[(7 - send_idx) + (8 * send_ctr)]; 123 | if (send_idx == 7) begin 124 | send_idx <= 0; 125 | state <= SEND_4; 126 | end else begin 127 | sclk_enable <= 1; 128 | send_idx <= send_idx + 1; 129 | end 130 | end 131 | 132 | else if (state == SEND_4) begin 133 | mosi <= 0; 134 | state <= SEND_5; 135 | end 136 | 137 | else if (state == SEND_5) begin 138 | sclk_enable <= 0; 139 | ss_enable <= 0; 140 | if (send_ctr == send_max) begin 141 | send_ctr <= 0; 142 | send_max <= 0; 143 | state <= next_state; 144 | end else begin 145 | send_ctr <= send_ctr + 1; 146 | state <= SEND; 147 | end 148 | end 149 | 150 | // SENDHEX - send a glyph corresponding to a hex value 151 | else if (state == SENDHEX) begin 152 | send_buf <= glyph_rom[(data >> ({hex_idx, 2'b00})) & 4'hF]; 153 | send_max <= 0; 154 | if (hex_idx == 0) begin 155 | next_state <= next_state_hex; 156 | end else begin 157 | next_state <= SENDHEX; 158 | hex_idx <= hex_idx - 1; 159 | end 160 | state <= SEND; 161 | end 162 | 163 | // SENDJOYPAD - send a glyph corresponding to a joypad button 164 | else if (state == SENDJOYPAD) begin 165 | case (btn_idx) 166 | 0: send_buf <= joypad_state[btn_idx] ? 8'h20 : 8'h42; // B 167 | 1: send_buf <= joypad_state[btn_idx] ? 8'h20 : 8'h59; // Y 168 | 2: send_buf <= joypad_state[btn_idx] ? 8'h20 : 8'h73; // Select 169 | 3: send_buf <= joypad_state[btn_idx] ? 8'h20 : 8'h53; // Start 170 | 4: send_buf <= joypad_state[btn_idx] ? 8'h20 : 8'h5E; // Up 171 | 5: send_buf <= joypad_state[btn_idx] ? 8'h20 : 8'h64; // Down 172 | 6: send_buf <= joypad_state[btn_idx] ? 8'h20 : 8'h3C; // Left 173 | 7: send_buf <= joypad_state[btn_idx] ? 8'h20 : 8'h3E; // Right 174 | 8: send_buf <= joypad_state[btn_idx] ? 8'h20 : 8'h41; // A 175 | 9: send_buf <= joypad_state[btn_idx] ? 8'h20 : 8'h58; // X 176 | 10: send_buf <= joypad_state[btn_idx] ? 8'h20 : 8'h4C; // L 177 | 11: send_buf <= joypad_state[btn_idx] ? 8'h20 : 8'h52; // R 178 | default: send_buf <= 8'h20; 179 | endcase 180 | send_max <= 0; 181 | if (btn_idx == 15) begin 182 | btn_idx <= 4'b0; 183 | next_state <= next_state_btn; 184 | end else begin 185 | next_state <= SENDJOYPAD; 186 | btn_idx <= btn_idx + 1; 187 | end 188 | state <= SEND; 189 | end 190 | 191 | // WAIT - wait for # of cycles 192 | else if (state == WAIT) begin 193 | if (wait_ctr == wait_max) begin 194 | wait_ctr <= 0; 195 | state <= next_state; 196 | end else begin 197 | wait_ctr <= wait_ctr + 1; 198 | end 199 | end 200 | 201 | // STARTUP_1 -- send display on, backlight on cmd 202 | else if (state == STARTUP_1) begin 203 | send_buf <= 32'h65335B1B; // ESC BRACKET '3' 'e' 204 | send_max <= 3; 205 | state <= SEND; 206 | next_state <= STARTUP_2; 207 | end 208 | 209 | // STARTUP_2 -- clear the display 210 | else if (state == STARTUP_2) begin 211 | send_buf <= 32'h6A305B1B; // ESC BRACKET '0' 'j' 212 | send_max <= 3; 213 | state <= SEND; 214 | next_state <= STARTUP_3; 215 | end 216 | 217 | // STARTUP_3 -- set the cursor mode 218 | else if (state == STARTUP_3) begin 219 | send_buf <= 32'h63305B1B; // ESC BRACKET '0' 'c' 220 | send_max <= 3; 221 | state <= SEND; 222 | next_state <= STARTUP_4; 223 | end 224 | 225 | // STARTUP_4 -- set the display mode 226 | else if (state == STARTUP_4) begin 227 | send_buf <= 32'h68305B1B; // ESC BRACKET '0' 'h' 228 | send_max <= 3; 229 | state <= SEND; 230 | next_state <= LOOP_1; 231 | end 232 | 233 | // LOOP_1 -- set cursor to 0,0 234 | else if (state == LOOP_1) begin 235 | send_buf <= 48'h48303B305B1B; // ESC BRACKET '0' ';' '0' 'H' 236 | send_max <= 5; 237 | state <= SEND; 238 | next_state <= LOOP_2; 239 | mode_latch <= mode; 240 | end 241 | 242 | else if (state == LOOP_2) begin 243 | send_buf <= 24'h3A4120; // A: 244 | send_max <= 2; 245 | state <= SEND; 246 | next_state <= LOOP_3; 247 | end 248 | 249 | else if (state == LOOP_3) begin 250 | data <= A; 251 | hex_idx <= 3; 252 | state <= SENDHEX; 253 | next_state_hex <= LOOP_4; 254 | end 255 | 256 | else if (state == LOOP_4) begin 257 | send_buf <= 32'h3A4f4920; // IO: 258 | send_max <= 3; 259 | state <= SEND; 260 | next_state <= LOOP_5; 261 | end 262 | 263 | else if (state == LOOP_5) begin 264 | data <= { Di, Do }; 265 | hex_idx <= 3; 266 | state <= SENDHEX; 267 | next_state_hex <= LOOP_6; 268 | end 269 | 270 | else if (state == LOOP_6) begin 271 | send_buf <= 48'h48303B315B1B; // ESC BRACKET '1' ';' '0' 'H' 272 | send_max <= 5; 273 | state <= SEND; 274 | next_state <= mode_latch == 2'b11 ? LOOP_7b : LOOP_7; 275 | end 276 | 277 | else if (state == LOOP_7) begin 278 | case (mode_latch) 279 | 2'b00: send_buf <= 24'h3A4350; // PC: 280 | 2'b01: send_buf <= 24'h3A4641; // AF: 281 | 2'b10: send_buf <= 24'h3A4544; // DE: 282 | endcase 283 | send_max <= 2; 284 | state <= SEND; 285 | next_state <= LOOP_8; 286 | end 287 | 288 | else if (state == LOOP_8) begin 289 | case (mode_latch) 290 | 2'b00: data <= PC; 291 | 2'b01: data <= AF; 292 | 2'b10: data <= DE; 293 | endcase 294 | hex_idx <= 3; 295 | state <= SENDHEX; 296 | next_state_hex <= LOOP_9; 297 | end 298 | 299 | else if (state == LOOP_9) begin 300 | case (mode_latch) 301 | 2'b00: send_buf <= 32'h3A505320; // SP: 302 | 2'b01: send_buf <= 32'h3A434220; // BC: 303 | 2'b10: send_buf <= 32'h3A4C4820; // HL: 304 | endcase 305 | send_max <= 3; 306 | state <= SEND; 307 | next_state <= LOOP_10; 308 | end 309 | 310 | else if (state == LOOP_10) begin 311 | case (mode_latch) 312 | 2'b00: data <= SP; 313 | 2'b01: data <= BC; 314 | 2'b10: data <= HL; 315 | endcase 316 | hex_idx <= 3; 317 | state <= SENDHEX; 318 | next_state_hex <= LOOP_11; 319 | end 320 | 321 | else if (state == LOOP_7b) begin 322 | send_buf <= 16'h2020; 323 | send_max <= 1; 324 | state <= SEND; 325 | next_state <= LOOP_8b; 326 | end 327 | 328 | else if (state == LOOP_8b) begin 329 | state <= SENDJOYPAD; 330 | next_state_btn <= LOOP_11; 331 | end 332 | 333 | else if (state == LOOP_11) begin 334 | wait_max <= 10; 335 | state <= WAIT; 336 | next_state <= LOOP_1; 337 | end 338 | end 339 | end 340 | 341 | assign ss = (ss_enable) ? 1'b0 : 1'b1; 342 | assign sclk = (sclk_enable) ? !clock : 1'b1; 343 | 344 | endmodule 345 | -------------------------------------------------------------------------------- /src/io/debug/cls_spi_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | //////////////////////////////////////////////////////////////////////////////// 4 | // Company: 5 | // Engineer: 6 | // 7 | // Create Date: 17:25:47 05/08/2012 8 | // Design Name: cls_spi 9 | // Module Name: G:/Projects/s6atlystest/cls_spi_tb.v 10 | // Project Name: s6atlystest 11 | // Target Device: 12 | // Tool versions: 13 | // Description: 14 | // 15 | // Verilog Test Fixture created by ISE for module: cls_spi 16 | // 17 | // Dependencies: 18 | // 19 | // Revision: 20 | // Revision 0.01 - File Created 21 | // Additional Comments: 22 | // 23 | //////////////////////////////////////////////////////////////////////////////// 24 | 25 | module cls_spi_tb; 26 | 27 | // Inputs 28 | reg clock; 29 | reg reset; 30 | reg [31:0] data; 31 | reg miso; 32 | 33 | // Outputs 34 | wire ss; 35 | wire mosi; 36 | wire sclk; 37 | 38 | // Instantiate the Unit Under Test (UUT) 39 | cls_spi uut ( 40 | .clock(clock), 41 | .reset(reset), 42 | .data(data), 43 | .ss(ss), 44 | .mosi(mosi), 45 | .miso(miso), 46 | .sclk(sclk) 47 | ); 48 | 49 | initial begin 50 | // Initialize Inputs 51 | clock = 0; 52 | reset = 1; 53 | data = 32'h89ABCDEF; 54 | miso = 0; 55 | 56 | // Wait 100 ns for global reset to finish 57 | #100 reset = 0; 58 | end 59 | 60 | always begin 61 | #10 clock = !clock; 62 | end 63 | 64 | endmodule 65 | 66 | -------------------------------------------------------------------------------- /src/io/debug/oled_spi.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | `timescale 1ns / 1ps 3 | 4 | module oled_spi( 5 | input wire clock, 6 | input wire reset, 7 | input wire shutdown, 8 | 9 | output wire cs, 10 | output reg sdin, 11 | output wire sclk, 12 | output reg dc, 13 | output reg res, 14 | output reg vbatc, 15 | output reg vddc 16 | ); 17 | 18 | parameter WAIT = 1; 19 | parameter SEND = 2; // send 1 byte 20 | parameter SEND2 = 3; // send 2 bytes 21 | parameter SEND3 = 4; // send 3 bytes 22 | parameter SEND4 = 5; // send 4 bytes 23 | 24 | parameter STARTUP_1 = 10; 25 | parameter STARTUP_2 = 11; 26 | parameter STARTUP_3 = 12; 27 | parameter STARTUP_4 = 13; 28 | parameter STARTUP_5 = 14; 29 | parameter STARTUP_6 = 15; 30 | parameter STARTUP_7 = 16; 31 | parameter STARTUP_8 = 17; 32 | parameter STARTUP_9 = 18; 33 | 34 | parameter SHUTDOWN_1 = 6; 35 | parameter SHUTDOWN_2 = 7; 36 | parameter SHUTDOWN_3 = 8; 37 | 38 | reg [31:0] send_buf; 39 | reg [4:0] send_idx; 40 | reg [1:0] send_ctr; 41 | reg [1:0] send_max; 42 | 43 | reg [31:0] wait_ctr; 44 | reg [31:0] wait_max; 45 | 46 | // TODO probably don't need 7 bits for state 47 | reg [7:0] state; 48 | reg [7:0] next_state; 49 | 50 | always @(posedge clock) begin 51 | // RESET 52 | if (reset) begin 53 | send_buf <= 32'b0; 54 | send_idx <= 5'b0; 55 | send_ctr <= 2'b0; 56 | send_max <= 2'b0; 57 | wait_ctr <= 32'b0; 58 | wait_max <= 32'b0; 59 | state <= STARTUP_1; 60 | next_state <= 1'b0; 61 | 62 | sdin <= 1'b0; 63 | dc <= 1'b0; 64 | res <= 1'b1; 65 | vddc <= 1'b1; 66 | vbatc <= 1'b1; 67 | end 68 | 69 | // SHUTDOWN 70 | else if (shutdown) begin 71 | if (state > 0 && state < 10) begin 72 | next_state <= SHUTDOWN_1; 73 | end else begin 74 | state <= SHUTDOWN_1; 75 | end 76 | end 77 | 78 | // STATES 79 | else begin 80 | // SEND - send up to four serial bytes 81 | if (state == SEND) begin 82 | sdin <= send_buf[(7 - send_idx) + (8 * send_ctr)]; 83 | if (send_idx == 7 && send_ctr == send_max) begin 84 | send_idx <= 0; 85 | send_ctr <= 0; 86 | send_max <= 0; 87 | state <= next_state; 88 | end else if (send_idx == 7) begin 89 | send_idx <= 0; 90 | send_ctr <= send_ctr + 1; 91 | end else begin 92 | send_idx <= send_idx + 1; 93 | end 94 | end 95 | 96 | // SEND2 - send two bytes 97 | if (state == SEND2) begin 98 | send_max = 1; 99 | state <= SEND; 100 | end 101 | 102 | // SEND3 - send three bytes 103 | else if (state == SEND3) begin 104 | send_max = 2; 105 | state <= SEND; 106 | end 107 | 108 | // SEND4 - send four bytes 109 | else if (state == SEND4) begin 110 | send_max = 3; 111 | state <= SEND; 112 | end 113 | 114 | // WAIT - wait for # of cycles 115 | else if (state == WAIT) begin 116 | if (wait_ctr == wait_max) begin 117 | wait_ctr <= 0; 118 | state <= next_state; 119 | end else begin 120 | wait_ctr <= wait_ctr + 1; 121 | end 122 | end 123 | 124 | // STARTUP_1 -- apply power to VDD 125 | else if (state == STARTUP_1) begin 126 | dc <= 0; 127 | vddc <= 0; 128 | wait_max <= 5000; // 1ms 129 | state <= WAIT; 130 | next_state <= STARTUP_2; 131 | end 132 | 133 | // STARTUP_2 -- send display off cmd 134 | else if (state == STARTUP_2) begin 135 | send_buf <= 8'hAE; 136 | state <= SEND; 137 | next_state <= STARTUP_3; 138 | end 139 | 140 | // STARTUP_3 -- clear screen 141 | else if (state == STARTUP_3) begin 142 | res <= 0; 143 | wait_max <= 5000; // 1ms 144 | state <= WAIT; 145 | next_state <= STARTUP_4; 146 | end 147 | 148 | // STARTUP_4 -- set charge pump 149 | else if (state == STARTUP_4) begin 150 | res <= 1; 151 | send_buf <= 16'h148D; 152 | state <= SEND2; 153 | next_state <= STARTUP_5; 154 | end 155 | 156 | // STARTUP_5 -- set pre-charge period 157 | else if (state == STARTUP_5) begin 158 | send_buf <= 16'hF1D9; 159 | state <= SEND2; 160 | next_state <= STARTUP_6; 161 | end 162 | 163 | // STARTUP_6 -- apply power to VBAT 164 | else if (state == STARTUP_6) begin 165 | vbatc <= 0; 166 | wait_max <= 500000; // 100ms 167 | state <= WAIT; 168 | next_state <= STARTUP_7; 169 | end 170 | 171 | // STARTUP_7 -- invert the display 172 | else if (state == STARTUP_7) begin 173 | send_buf <= 16'hC8A1; 174 | state <= SEND2; 175 | next_state <= STARTUP_8; 176 | end 177 | 178 | // STARTUP_8 -- select squential COM configuration 179 | else if (state == STARTUP_8) begin 180 | send_buf <= 16'h20DA; 181 | state <= SEND2; 182 | next_state <= STARTUP_9; 183 | end 184 | 185 | // STARTUP_9 -- send display on cmd 186 | else if (state == STARTUP_9) begin 187 | send_buf <= 8'hAF; 188 | state <= SEND; 189 | next_state <= 0; // TODO 190 | end 191 | 192 | // SHUTDOWN_1 -- send display off cmd 193 | else if (state == SHUTDOWN_1) begin 194 | send_buf <= 8'hAE; 195 | state <= SEND; 196 | next_state <= SHUTDOWN_2; 197 | end 198 | 199 | // SHUTDOWN_2 -- turn off VBAT 200 | else if (state == SHUTDOWN_2) begin 201 | vbatc <= 1; 202 | wait_max <= 500000; // 100ms 203 | state <= WAIT; 204 | next_state <= SHUTDOWN_3; 205 | end 206 | 207 | // SHUTDOWN_4 -- turn off VDD 208 | else if (state == SHUTDOWN_3) begin 209 | vddc <= 1; 210 | state <= 0; // TODO 211 | end 212 | end 213 | end 214 | 215 | assign cs = 0; 216 | assign sclk = !clock; 217 | 218 | endmodule 219 | -------------------------------------------------------------------------------- /src/io/debug/oled_spi_tb.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | `timescale 1ns / 1ps 3 | 4 | module oled_spi_tb; 5 | 6 | // Inputs 7 | reg clock; 8 | reg reset; 9 | reg shutdown; 10 | 11 | // Outputs 12 | wire cs; 13 | wire sdin; 14 | wire sclk; 15 | wire dc; 16 | wire res; 17 | wire vbatc; 18 | wire vddc; 19 | 20 | // Instantiate the Unit Under Test (UUT) 21 | oled_spi uut ( 22 | .clock(clock), 23 | .reset(reset), 24 | .shutdown(shutdown), 25 | .cs(cs), 26 | .sdin(sdin), 27 | .sclk(sclk), 28 | .dc(dc), 29 | .res(res), 30 | .vbatc(vbatc), 31 | .vddc(vddc) 32 | ); 33 | 34 | initial begin 35 | // Initialize Inputs 36 | clock = 0; 37 | reset = 1; 38 | shutdown = 0; 39 | 40 | // Wait 100 ns for global reset to finish 41 | #100 reset = 0; 42 | end 43 | 44 | always begin 45 | #10 clock = !clock; 46 | end 47 | 48 | endmodule 49 | 50 | -------------------------------------------------------------------------------- /src/io/input/joypad_snes_adapter.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | `timescale 1ns / 1ps 3 | 4 | module joypad_snes_adapter( 5 | input wire clock, 6 | input wire reset, 7 | // to gameboy 8 | input wire [1:0] button_sel, 9 | output wire [3:0] button_data, 10 | output reg [15:0] button_state, 11 | // to controller 12 | input wire controller_data, 13 | output wire controller_latch, 14 | output wire controller_clock 15 | ); 16 | 17 | //////////////////////////////////////////////////////// 18 | // http://www.gamefaqs.com/snes/916396-snes/faqs/5395 19 | // 20 | // Note: This implementation does *not* match the 21 | // timings specified in the documentation above. 22 | // Instead, it uses a much simpler and slower 1KHz 23 | // clock which provides pretty good responsiveness 24 | // to button presses. Also note that the Atlys board 25 | // only provides a 3.3V Vcc instead of the spec'd 5V. 26 | // 27 | // Note: Color of wires on my controller ext. cable 28 | // Vcc (+5V) - Green 29 | // Clock - Blue 30 | // Latch - Yellow 31 | // Data - Red 32 | // Ground - Brown 33 | //////////////////////////////////////////////////////// 34 | 35 | parameter WAIT_STATE = 0; 36 | parameter LATCH_STATE = 1; 37 | parameter READ_STATE = 2; 38 | 39 | reg [1:0] state; 40 | reg [3:0] button_index; 41 | //reg [15:0] button_state; 42 | 43 | /** 44 | * State transitions occur on the clock's positive edge. 45 | */ 46 | always @(posedge clock) begin 47 | if (reset) 48 | state <= WAIT_STATE; 49 | else begin 50 | if (state == WAIT_STATE) 51 | state <= LATCH_STATE; 52 | else if (state == LATCH_STATE) 53 | state <= READ_STATE; 54 | else if (state == READ_STATE) begin 55 | if (button_index == 15) 56 | state <= WAIT_STATE; 57 | end 58 | end 59 | end 60 | 61 | /** 62 | * Button reading occurs on the negative edge to give 63 | * values from the controller time to settle. 64 | */ 65 | always @(negedge clock) begin 66 | if (reset) begin 67 | button_index <= 4'b0; 68 | button_state <= 16'hFFFF; 69 | end else begin 70 | if (state == WAIT_STATE) 71 | button_index <= 4'b0; 72 | else if (state == READ_STATE) begin 73 | button_state[button_index] <= controller_data; 74 | button_index <= button_index + 1; 75 | end 76 | end 77 | end 78 | 79 | assign controller_latch = (state == LATCH_STATE) ? 1'b1 : 1'b0; 80 | assign controller_clock = (state == READ_STATE) ? clock : 1'b1; 81 | 82 | // button order is 83 | // B Y SELECT START UP DOWN LEFT RIGHT A X L R - - - - 84 | assign button_data = 85 | button_sel[0] == 1'b0 ? { button_state[7], button_state[6], button_state[4], button_state[5] } : 86 | button_sel[1] == 1'b0 ? { button_state[8], button_state[0], button_state[2], button_state[3] } : 4'b1111; 87 | 88 | endmodule 89 | -------------------------------------------------------------------------------- /src/io/input/joypad_snes_adapter_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | //////////////////////////////////////////////////////////////////////////////// 4 | // Company: 5 | // Engineer: 6 | // 7 | // Create Date: 12:37:09 04/26/2012 8 | // Design Name: joypad_snes_adapter 9 | // Module Name: G:/Projects/s6atlystest/joypad_snes_adapter_tb.v 10 | // Project Name: s6atlystest 11 | // Target Device: 12 | // Tool versions: 13 | // Description: 14 | // 15 | // Verilog Test Fixture created by ISE for module: joypad_snes_adapter 16 | // 17 | // Dependencies: 18 | // 19 | // Revision: 20 | // Revision 0.01 - File Created 21 | // Additional Comments: 22 | // 23 | //////////////////////////////////////////////////////////////////////////////// 24 | 25 | module joypad_snes_adapter_tb; 26 | 27 | // Inputs 28 | reg clock; 29 | reg reset; 30 | 31 | wire [1:0] button_sel; 32 | wire controller_data; 33 | 34 | // Outputs 35 | wire [3:0] button_data; 36 | wire controller_latch; 37 | wire controller_clock; 38 | 39 | // Instantiate the Unit Under Test (UUT) 40 | joypad_snes_adapter uut ( 41 | .clock(clock), 42 | .reset(reset), 43 | .button_sel(button_sel), 44 | .button_data(button_data), 45 | .controller_data(controller_data), 46 | .controller_latch(controller_latch), 47 | .controller_clock(controller_clock) 48 | ); 49 | 50 | assign button_sel = 2'b0; 51 | assign controller_data = 1'b0; 52 | 53 | initial begin 54 | // Initialize Inputs 55 | clock = 0; 56 | reset = 1; 57 | 58 | // Wait 100 ns for module reset to finish 59 | #100 reset = 0; 60 | end 61 | 62 | always begin 63 | #10 clock = !clock; 64 | end 65 | 66 | endmodule 67 | 68 | -------------------------------------------------------------------------------- /src/io/video/vga_controller.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | // vga controller module that generates signals to drive a monitor 4 | // pixel and line counts are the current position on the display that should be output 5 | module vga_controller(pixel_clock, reset, hsync, vsync, pixel_count, line_count); 6 | input pixel_clock; 7 | input reset; 8 | output hsync; 9 | output vsync; 10 | output [9:0] pixel_count; 11 | output [9:0] line_count; 12 | 13 | // output registers 14 | reg hsync, vsync; 15 | reg [9:0] pixel_count, line_count; 16 | wire [9:0] next_pixel, next_line; 17 | 18 | // parameters 19 | // 800x525 pixels for 640x480 display 20 | parameter NUM_LINES = 525; 21 | parameter NUM_PIXELS = 800; 22 | 23 | // visible parameters 24 | parameter WIDTH = 640; 25 | parameter HEIGHT = 480; 26 | 27 | // horizontal parameters (pixels) 28 | parameter H_FRONT_PORCH = 16; 29 | parameter H_SYNC = 96; 30 | parameter H_BACK_PORCH = 48; 31 | 32 | // vertical parameters (lines) 33 | parameter V_FRONT_PORCH = 11; 34 | parameter V_SYNC = 2; 35 | parameter V_BACK_PORCH = 32; 36 | 37 | always @(posedge pixel_clock) begin 38 | if(reset) begin 39 | pixel_count <= 10'b0; 40 | line_count <= 10'b0; 41 | hsync <= 1; 42 | vsync <= 1; 43 | end else begin 44 | pixel_count <= next_pixel; 45 | line_count <= next_line; 46 | 47 | // output synchronization signals 48 | hsync <= ~((next_pixel >= WIDTH + H_FRONT_PORCH) & 49 | (next_pixel < WIDTH + H_FRONT_PORCH + H_SYNC)); 50 | vsync <= ~((next_line >= HEIGHT + V_FRONT_PORCH) & 51 | (next_line < HEIGHT + V_FRONT_PORCH + V_SYNC)); 52 | end 53 | end 54 | 55 | // next pixel and line 56 | assign next_pixel = (pixel_count >= NUM_PIXELS - 1) ? 1'b0 : pixel_count + 1'b1; 57 | assign next_line = (pixel_count >= NUM_PIXELS - 1) ? 58 | ((line_count >= NUM_LINES - 1) ? 1'b0 : line_count + 1'b1) : line_count; 59 | 60 | 61 | 62 | endmodule 63 | -------------------------------------------------------------------------------- /src/top/s6atlys.ucf: -------------------------------------------------------------------------------- 1 | # This file is a general .ucf for Atlys rev C board 2 | # To use it in a project: 3 | # - remove or comment the lines corresponding to unused pins 4 | # - rename the used signals according to the project 5 | 6 | 7 | # clock pin for Atlys rev C board 8 | NET "CLK_100M" LOC = "L15"; # Bank = 1, Pin name = IO_L42P_GCLK7_M1UDM, Type = GCLK, Sch name = GCLK 9 | 10 | # onBoard USB controller 11 | # NET "EppAstb" LOC = "B9"; # Bank = 0, Pin name = IO_L35P_GCLK17, Sch name = U1-FLAGA 12 | # NET "EppDstb" LOC = "A9"; # Bank = 0, Pin name = IO_L35N_GCLK16, Sch name = U1-FLAGB 13 | # NET "UsbFlag" LOC = "C15"; # Bank = 0, Pin name = IO_L64P_SCP5, Sch name = U1-FLAGC 14 | # NET "EppWait" LOC = "F13"; # Bank = 0, Pin name = IO_L63P_SCP7, Sch name = U1-SLRD 15 | # NET "EppDB<0>" LOC = "A2"; # Bank = 0, Pin name = IO_L2N, Sch name = U1-FD0 16 | # NET "EppDB<1>" LOC = "D6"; # Bank = 0, Pin name = IO_L3P, Sch name = U1-FD1 17 | # NET "EppDB<2>" LOC = "C6"; # Bank = 0, Pin name = IO_L3N, Sch name = U1-FD2 18 | # NET "EppDB<3>" LOC = "B3"; # Bank = 0, Pin name = IO_L4P, Sch name = U1-FD3 19 | # NET "EppDB<4>" LOC = "A3"; # Bank = 0, Pin name = IO_L4N, Sch name = U1-FD4 20 | # NET "EppDB<5>" LOC = "B4"; # Bank = 0, Pin name = IO_L5P, Sch name = U1-FD5 21 | # NET "EppDB<6>" LOC = "A4"; # Bank = 0, Pin name = IO_L5N, Sch name = U1-FD6 22 | # NET "EppDB<7>" LOC = "C5"; # Bank = 0, Pin name = IO_L6P, Sch name = U1-FD7 23 | 24 | # NET "UsbClk" LOC = "C10"; # Bank = 0, Pin name = IO_L37P_GCLK13, Sch name = U1-IFCLK 25 | # NET "UsbOE" LOC = "A15"; # Bank = 0, Pin name = IO_L64N_SCP4, Sch name = U1-SLOE 26 | # NET "UsbWR" LOC = "E13"; # Bank = 0, Pin name = IO_L63N_SCP6, Sch name = U1-SLWR 27 | # NET "UsbPktEnd" LOC = "C4"; # Bank = 0, Pin name = IO_L1N_VREF, Sch name = U1-PKTEND 28 | # NET "UsbDir" LOC = "B2"; # Bank = 0, Pin name = IO_L2P, Sch name = U1-SLCS 29 | # NET "UsbMode" LOC = "A5"; # Bank = 0, Pin name = IO_L6N, Sch name = U1-INT0# 30 | 31 | # NET "UsbAdr<0>" LOC = "A14"; # Bank = 0, Pin name = IO_L62N_VREF, Sch name = U1-FIFOAD0 32 | # NET "UsbAdr<1>" LOC = "B14"; # Bank = 0, Pin name = IO_L62P, Sch name = U1-FIFOAD1 33 | 34 | # onBoard Quad-SPI Flash 35 | # NET "FlashCLK" LOC = "R15"; # Bank = 2, Pin name = IO_L1P_CCLK_2, Sch name = SCK 36 | # NET "FlashCS" LOC = "V3"; # Bank = 2, Pin name = IO_L65N_CSO_B_2, Sch name = CS 37 | # NET "FlashMemDq<0>" LOC = "T13"; # Bank = 2, Pin name = IO_L3N_MOSI_CSI_B_MISO0_2, Sch name = SDI 38 | # NET "FlashMemDq<1>" LOC = "R13"; # Bank = 2, Pin name = IO_L3P_D0_DIN_MISO_MISO1_2, Sch name = DQ1 39 | # NET "FlashMemDq<2>" LOC = "T14"; # Bank = 2, Pin name = IO_L12P_D1_MISO2_2, Sch name = DQ2 40 | # NET "FlashMemDq<3>" LOC = "V14"; # Bank = 2, Pin name = IO_L12N_D2_MISO3_2, Sch name = DQ3 41 | 42 | # onBoard Leds 43 | NET "LED<0>" LOC = "U18"; # Bank = 1, Pin name = IO_L52N_M1DQ15, Sch name = LD0 44 | NET "LED<1>" LOC = "M14"; # Bank = 1, Pin name = IO_L53P, Sch name = LD1 45 | NET "LED<2>" LOC = "N14"; # Bank = 1, Pin name = IO_L53N_VREF, Sch name = LD2 46 | NET "LED<3>" LOC = "L14"; # Bank = 1, Pin name = IO_L61P, Sch name = LD3 47 | NET "LED<4>" LOC = "M13"; # Bank = 1, Pin name = IO_L61N, Sch name = LD4 48 | NET "LED<5>" LOC = "D4"; # Bank = 0, Pin name = IO_L1P_HSWAPEN_0, Sch name = HSWAP/LD5 49 | NET "LED<6>" LOC = "P16"; # Bank = 1, Pin name = IO_L74N_DOUT_BUSY_1, Sch name = LD6 50 | NET "LED<7>" LOC = "N12"; # Bank = 2, Pin name = IO_L13P_M1_2, Sch name = M1/LD7 51 | 52 | # onBoard PUSH BUTTONS 53 | NET "BTN<0>" LOC = "T15"; # Bank = 2, Pin name = IO_L1N_M0_CMPMISO_2, Sch name = M0/RESET 54 | NET "BTN<1>" LOC = "N4"; # Bank = 3, Pin name = IO_L1P, Sch name = BTNU 55 | NET "BTN<2>" LOC = "P4"; # Bank = 3, Pin name = IO_L2P, Sch name = BTNL 56 | NET "BTN<3>" LOC = "P3"; # Bank = 3, Pin name = IO_L2N, Sch name = BTND 57 | NET "BTN<4>" LOC = "F6"; # Bank = 3, Pin name = IO_L55P_M3A13, Sch name = BTNR 58 | NET "BTN<5>" LOC = "F5"; # Bank = 3, Pin name = IO_L55N_M3A14, Sch name = BTNC 59 | 60 | # onBoard SWITCHES 61 | NET "SW<0>" LOC = "A10"; # Bank = 0, Pin name = IO_L37N_GCLK12, Sch name = SW0 62 | NET "SW<1>" LOC = "D14"; # Bank = 0, Pin name = IO_L65P_SCP3, Sch name = SW1 63 | NET "SW<2>" LOC = "C14"; # Bank = 0, Pin name = IO_L65N_SCP2, Sch name = SW2 64 | NET "SW<3>" LOC = "P15"; # Bank = 1, Pin name = IO_L74P_AWAKE_1, Sch name = SW3 65 | NET "SW<4>" LOC = "P12"; # Bank = 2, Pin name = IO_L13N_D10, Sch name = SW4 66 | NET "SW<5>" LOC = "R5"; # Bank = 2, Pin name = IO_L48P_D7, Sch name = SW5 67 | NET "SW<6>" LOC = "T5"; # Bank = 2, Pin name = IO_L48N_RDWR_B_VREF_2, Sch name = SW6 68 | NET "SW<7>" LOC = "E4"; # Bank = 3, Pin name = IO_L54P_M3RESET, Sch name = SW7 69 | 70 | # TEMAC Ethernet MAC 71 | # NET "phyrst" LOC = "G13"; # Bank = 1, Pin name = IO_L32N_A16_M1A9, Sch name = E-RESET 72 | # NET "phytxclk" LOC = "K16"; # Bank = 1, Pin name = IO_L41N_GCLK8_M1CASN, Sch name = E-TXCLK 73 | 74 | # NET "phyTXD<0>" LOC = "H16"; # Bank = 1, Pin name = IO_L37N_A6_M1A1, Sch name = E-TXD0 75 | # NET "phyTXD<1>" LOC = "H13"; # Bank = 1, Pin name = IO_L36P_A9_M1BA0, Sch name = E-TXD1 76 | # NET "phyTXD<2>" LOC = "K14"; # Bank = 1, Pin name = IO_L39N_M1ODT, Sch name = E-TXD2 77 | # NET "phyTXD<3>" LOC = "K13"; # Bank = 1, Pin name = IO_L34N_A12_M1BA2, Sch name = E-TXD3 78 | # NET "phyTXD<4>" LOC = "J13"; # Bank = 1, Pin name = IO_L39P_M1A3, Sch name = E-TXD4 79 | # NET "phyTXD<5>" LOC = "G14"; # Bank = 1, Pin name = IO_L30N_A20_M1A11, Sch name = E-TXD5 80 | # NET "phyTXD<6>" LOC = "H12"; # Bank = 1, Pin name = IO_L32P_A17_M1A8, Sch name = E-TXD6 81 | # NET "phyTXD<7>" LOC = "K12"; # Bank = 1, Pin name = IO_L34P_A13_M1WE, Sch name = E-TXD7 82 | 83 | # NET "phytxen" LOC = "H15"; # Bank = 1, Pin name = IO_L37P_A7_M1A0, Sch name = E-TXEN 84 | # NET "phytxer" LOC = "G18"; # Bank = 1, Pin name = IO_L38N_A4_M1CLKN, Sch name = E-TXER 85 | # NET "phygtxclk" LOC = "L12"; # Bank = 1, Pin name = IO_L40P_GCLK11_M1A5, Sch name = E-GTXCLK 86 | 87 | # NET "phyRXD<0>" LOC = "G16"; # Bank = 1, Pin name = IO_L38P_A5_M1CLK, Sch name = E-RXD0 88 | # NET "phyRXD<1>" LOC = "H14"; # Bank = 1, Pin name = IO_L36N_A8_M1BA1, Sch name = E-RXD1 89 | # NET "phyRXD<2>" LOC = "E16"; # Bank = 1, Pin name = IO_L33P_A15_M1A10, Sch name = E-RXD2 90 | # NET "phyRXD<3>" LOC = "F15"; # Bank = 1, Pin name = IO_L1P_A25, Sch name = E-RXD3 91 | # NET "phyRXD<4>" LOC = "F14"; # Bank = 1, Pin name = IO_L30P_A21_M1RESET, Sch name = E-RXD4 92 | # NET "phyRXD<5>" LOC = "E18"; # Bank = 1, Pin name = IO_L33N_A14_M1A4, Sch name = E-RXD5 93 | # NET "phyRXD<6>" LOC = "D18"; # Bank = 1, Pin name = IO_L31N_A18_M1A12, Sch name = E-RXD6 94 | # NET "phyRXD<7>" LOC = "D17"; # Bank = 1, Pin name = IO_L31P_A19_M1CKE, Sch name = E-RXD7 95 | 96 | # NET "phyrxdv" LOC = "F17"; # Bank = 1, Pin name = IO_L35P_A11_M1A7, Sch name = E-RXDV 97 | # NET "phyrxer" LOC = "F18"; # Bank = 1, Pin name = IO_L35N_A10_M1A2, Sch name = E-RXER 98 | # NET "phyrxclk" LOC = "K15"; # Bank = 1, Pin name = IO_L41P_GCLK9_IRDY1_M1RASN, Sch name = E-RXCLK 99 | # NET "phymdc" LOC = "F16"; # Bank = 1, Pin name = IO_L1N_A24_VREF, Sch name = E-MDC 100 | # NET "phymdi" LOC = "N17"; # Bank = 1, Pin name = IO_L48P_HDC_M1DQ8, Sch name = E-MDIO 101 | # NET "phyint" LOC = "L16"; # Bank = 1, Pin name = IO_L42N_GCLK6_TRDY1_M1LDM, Sch name = E-INT 102 | 103 | # DDR2 104 | # NET "DDR2CLK0" LOC = "G3"; # Bank = 3, Pin name = IO_L46P_M3CLK, Sch name = DDR-CK_P 105 | # NET "DDR2CLK1" LOC = "G1"; # Bank = 3, Pin name = IO_L46N_M3CLKN, Sch name = DDR-CK_N 106 | # NET "DDR2CKE" LOC = "H7"; # Bank = 3, Pin name = IO_L53P_M3CKE, Sch name = DDR-CKE 107 | # NET "DDR2RASN" LOC = "L5"; # Bank = 3, Pin name = IO_L43P_GCLK23_M3RASN, Sch name = DDR-RAS 108 | # NET "DDR2CASN" LOC = "K5"; # Bank = 3, Pin name = IO_L43N_GCLK22_IRDY2_M3CASN, Sch name = DDR-CAS 109 | # NET "DDR2WEN" LOC = "E3"; # Bank = 3, Pin name = IO_L50P_M3WE, Sch name = DDR-WE 110 | # NET "DDR2RZQ" LOC = "L6"; # Bank = 3, Pin name = IO_L31P, Sch name = RZQ 111 | # NET "DDR2ZIO" LOC = "C2"; # Bank = 3, Pin name = IO_L83P, Sch name = ZIO 112 | 113 | # NET "DDR2BA0" LOC = "F2"; # Bank = 3, Pin name = IO_L48P_M3BA0, Sch name = DDR-BA0 114 | # NET "DDR2BA1" LOC = "F1"; # Bank = 3, Pin name = IO_L48N_M3BA1, Sch name = DDR-BA1 115 | # NET "DDR2BA2" LOC = "E1"; # Bank = 3, Pin name = IO_L50N_M3BA2, Sch name = DDR-BA2 116 | 117 | # NET "DDR2A0" LOC = "J7"; # Bank = 3, Pin name = IO_L47P_M3A0, Sch name = DDR-A0 118 | # NET "DDR2A1" LOC = "J6"; # Bank = 3, Pin name = IO_L47N_M3A1, Sch name = DDR-A1 119 | # NET "DDR2A2" LOC = "H5"; # Bank = 3, Pin name = IO_L49N_M3A2, Sch name = DDR-A2 120 | # NET "DDR2A3" LOC = "L7"; # Bank = 3, Pin name = IO_L45P_M3A3, Sch name = DDR-A3 121 | # NET "DDR2A4" LOC = "F3"; # Bank = 3, Pin name = IO_L51N_M3A4, Sch name = DDR-A4 122 | # NET "DDR2A5" LOC = "H4"; # Bank = 3, Pin name = IO_L44P_GCLK21_M3A5, Sch name = DDR-A5 123 | # NET "DDR2A6" LOC = "H3"; # Bank = 3, Pin name = IO_L44N_GCLK20_M3A6, Sch name = DDR-A6 124 | # NET "DDR2A7" LOC = "H6"; # Bank = 3, Pin name = IO_L49P_M3A7, Sch name = DDR-A7 125 | # NET "DDR2A8" LOC = "D2"; # Bank = 3, Pin name = IO_L52P_M3A8, Sch name = DDR-A8 126 | # NET "DDR2A9" LOC = "D1"; # Bank = 3, Pin name = IO_L52N_M3A9, Sch name = DDR-A9 127 | # NET "DDR2A10" LOC = "F4"; # Bank = 3, Pin name = IO_L51P_M3A10, Sch name = DDR-A10 128 | # NET "DDR2A11" LOC = "D3"; # Bank = 3, Pin name = IO_L54N_M3A11, Sch name = DDR-A11 129 | # NET "DDR2A12" LOC = "G6"; # Bank = 3, Pin name = IO_L53N_M3A12, Sch name = DDR-A12 130 | 131 | # NET "DDR2DQ0" LOC = "L2"; # Bank = 3, Pin name = IO_L37P_M3DQ0, Sch name = DDR-DQ0 132 | # NET "DDR2DQ1" LOC = "L1"; # Bank = 3, Pin name = IO_L37N_M3DQ1, Sch name = DDR-DQ1 133 | # NET "DDR2DQ2" LOC = "K2"; # Bank = 3, Pin name = IO_L38P_M3DQ2, Sch name = DDR-DQ2 134 | # NET "DDR2DQ3" LOC = "K1"; # Bank = 3, Pin name = IO_L38N_M3DQ3, Sch name = DDR-DQ3 135 | # NET "DDR2DQ4" LOC = "H2"; # Bank = 3, Pin name = IO_L41P_GCLK27_M3DQ4, Sch name = DDR-DQ4 136 | # NET "DDR2DQ5" LOC = "H1"; # Bank = 3, Pin name = IO_L41N_GCLK26_M3DQ5, Sch name = DDR-DQ5 137 | # NET "DDR2DQ6" LOC = "J3"; # Bank = 3, Pin name = IO_L40P_M3DQ6, Sch name = DDR-DQ6 138 | # NET "DDR2DQ7" LOC = "J1"; # Bank = 3, Pin name = IO_L40N_M3DQ7, Sch name = DDR-DQ7 139 | # NET "DDR2DQ8" LOC = "M3"; # Bank = 3, Pin name = IO_L36P_M3DQ8, Sch name = DDR-DQ8 140 | # NET "DDR2DQ9" LOC = "M1"; # Bank = 3, Pin name = IO_L36N_M3DQ9, Sch name = DDR-DQ9 141 | # NET "DDR2DQ10" LOC = "N2"; # Bank = 3, Pin name = IO_L35P_M3DQ10, Sch name = DDR-DQ10 142 | # NET "DDR2DQ11" LOC = "N1"; # Bank = 3, Pin name = IO_L35N_M3DQ11, Sch name = DDR-DQ11 143 | # NET "DDR2DQ12" LOC = "T2"; # Bank = 3, Pin name = IO_L33P_M3DQ12, Sch name = DDR-DQ12 144 | # NET "DDR2DQ13" LOC = "T1"; # Bank = 3, Pin name = IO_L33N_M3DQ13, Sch name = DDR-DQ13 145 | # NET "DDR2DQ14" LOC = "U2"; # Bank = 3, Pin name = IO_L32P_M3DQ14, Sch name = DDR-DQ14 146 | # NET "DDR2DQ15" LOC = "U1"; # Bank = 3, Pin name = IO_L32N_M3DQ15, Sch name = DDR-DQ15 147 | 148 | # NET "DDR2UDQS" LOC="P2"; # Bank = 3, Pin name = IO_L34P_M3UDQS, Sch name = DDR-UDQS_P 149 | # NET "DDR2UDQSN" LOC="P1"; # Bank = 3, Pin name = IO_L34N_M3UDQSN, Sch name = DDR-UDQS_N 150 | # NET "DDR2LDQS" LOC="L4"; # Bank = 3, Pin name = IO_L39P_M3LDQS, Sch name = DDR-LDQS_P 151 | # NET "DDR2LDQSN" LOC="L3"; # Bank = 3, Pin name = IO_L39N_M3LDQSN, Sch name = DDR-LDQS_N 152 | # NET "DDR2LDM" LOC="K3"; # Bank = 3, Pin name = IO_L42N_GCLK24_M3LDM, Sch name = DDR-LDM 153 | # NET "DDR2UDM" LOC="K4"; # Bank = 3, Pin name = IO_L42P_GCLK25_TRDY2_M3UDM, Sch name = DDR-UDM 154 | # NET "DDR2ODT" LOC="K6"; # Bank = 3, Pin name = IO_L45N_M3ODT, Sch name = DDR-ODT 155 | 156 | # NET "DDR2ZIO" LOC="C2"; # Bank = 3, Pin name = IO_L83P, Sch name = DDR-ODT 157 | # NET "DDR2RZM" LOC="L6"; # Bank = 3, Pin name = IO_L31P, Sch name = DDR-ODT 158 | 159 | # onboard HDMI OUT 160 | # NET "HDMIOUTCLKP" LOC = "B6"; # Bank = 0, Pin name = IO_L8P, Sch name = TMDS-TX-CLK_P 161 | # NET "HDMIOUTCLKN" LOC = "A6"; # Bank = 0, Pin name = IO_L8N_VREF, Sch name = TMDS-TX-CLK_N 162 | # NET "HDMIOUTD0P" LOC = "D8"; # Bank = 0, Pin name = IO_L11P, Sch name = TMDS-TX-0_P 163 | # NET "HDMIOUTD0N" LOC = "C8"; # Bank = 0, Pin name = IO_L11N, Sch name = TMDS-TX-0_N 164 | # NET "HDMIOUTD1P" LOC = "C7"; # Bank = 0, Pin name = IO_L10P, Sch name = TMDS-TX-1_P 165 | # NET "HDMIOUTD1N" LOC = "A7"; # Bank = 0, Pin name = IO_L10N, Sch name = TMDS-TX-1_N 166 | # NET "HDMIOUTD2P" LOC = "B8"; # Bank = 0, Pin name = IO_L33P, Sch name = TMDS-TX-2_P 167 | # NET "HDMIOUTD2N" LOC = "A8"; # Bank = 0, Pin name = IO_L33N, Sch name = TMDS-TX-2_N 168 | # NET "HDMIOUTSCL" LOC = "D9"; # Bank = 0, Pin name = IO_L34P_GCLK19, Sch name = TMDS-TX-SCL 169 | # NET "HDMIOUTSDA" LOC = "C9"; # Bank = 0, Pin name = IO_L34N_GCLK18, Sch name = TMDS-TX-SDA 170 | 171 | # onboard HDMI IN1 (PMODA) 172 | # NET "HDMIIN1CLKP" LOC = "D11"; # Bank = 0, Pin name = IO_L36P_GCLK15, Sch name = TMDS-RXB-CLK_P 173 | # NET "HDMIIN1CLKN" LOC = "C11"; # Bank = 0, Pin name = IO_L36N_GCLK14, Sch name = TMDS-RXB-CLK_N 174 | # NET "HDMIIN1D0P" LOC = "G9"; # Bank = 0, Pin name = IO_L38P, Sch name = TMDS-RXB-0_P 175 | # NET "HDMIIN1D0N" LOC = "F9"; # Bank = 0, Pin name = IO_L38N_VREF, Sch name = TMDS-RXB-0_N 176 | # NET "HDMIIN1D1P" LOC = "B11"; # Bank = 0, Pin name = IO_L39P, Sch name = TMDS-RXB-1_P 177 | # NET "HDMIIN1D1N" LOC = "A11"; # Bank = 0, Pin name = O_L39N, Sch name = TMDS-RXB-1_N 178 | # NET "HDMIIN1D2P" LOC = "B12"; # Bank = 0, Pin name = IO_L41P, Sch name = TMDS-RXB-2_P 179 | # NET "HDMIIN1D2N" LOC = "A12"; # Bank = 0, Pin name = IO_L41N, Sch name = TMDS-RXB-2_N 180 | # NET "HDMIIN1SCL" LOC = "C13"; # Bank = 0, Pin name = IO_L50P, Sch name = PMOD-SCL 181 | # NET "HDMIIN1SDA" LOC = "A13"; # Bank = 0, Pin name = IO_L50N, Sch name = PMOD-SDA 182 | 183 | # onboard HDMI IN2 184 | # NET "HDMIIN2CLKP" LOC = "H17"; # Bank = 1, Pin name = IO_L43P_GCLK5_M1DQ4, Sch name = TMDS-RX-CLK_P 185 | # NET "HDMIIN2CLKN" LOC = "H18"; # Bank = 1, Pin name = IO_L43N_GCLK4_M1DQ5, Sch name = TMDS-RX-CLK_N 186 | # NET "HDMIIN2D0P" LOC = "K17"; # Bank = 1, Pin name = IO_L45P_A1_M1LDQS, Sch name = TMDS-RX-0_P 187 | # NET "HDMIIN2D0N" LOC = "K18"; # Bank = 1, Pin name = IO_L45N_A0_M1LDQSN, Sch name = TMDS-RX-0_N 188 | # NET "HDMIIN2D1P" LOC = "L17"; # Bank = 1, Pin name = IO_L46P_FCS_B_M1DQ2, Sch name = TMDS-RX-1_P 189 | # NET "HDMIIN2D1N" LOC = "L18"; # Bank = 1, Pin name = IO_L46N_FOE_B_M1DQ3, Sch name = TMDS-RX-1_N 190 | # NET "HDMIIN2D2P" LOC = "J16"; # Bank = 1, Pin name = IO_L44P_A3_M1DQ6, Sch name = TMDS-RX-2_P 191 | # NET "HDMIIN2D2N" LOC = "J18"; # Bank = 1, Pin name = IO_L44N_A2_M1DQ7, Sch name = TMDS-RX-2_N 192 | # NET "HDMIIN2SCL" LOC = "M16"; # Bank = 1, Pin name = IO_L47P_FWE_B_M1DQ0, Sch name = TMDS-RX-SCL 193 | # NET "HDMIIN2SDA" LOC = "M18"; # Bank = 1, Pin name = IO_L47N_LDC_M1DQ1, Sch name = TMDS-RX-SDA 194 | 195 | # onboard USB Host Controller 196 | # NET "USBCLK" LOC = "P17"; # Bank = 1, Pin name = IO_L49P_M1DQ10, Sch name = PIC32-SCK1 197 | # NET "USBSS" LOC = "P18"; # Bank = 1, Pin name = IO_L49N_M1DQ11, Sch name = PIC32-SS1 198 | # NET "USBSDI" LOC = "N15"; # Bank = 1, Pin name = IO_L50P_M1UDQS, Sch name = PIC32-SDI1 199 | # NET "USBSDO" LOC = "N18"; # Bank = 1, Pin name = IO_L48N_M1DQ9, Sch name = PIC32-SDO1 200 | 201 | # Audio 202 | # NET "BITCLK" LOC = "L13"; # Bank = 1, Pin name = IO_L40N_GCLK10_M1A6, Sch name = AUD-BIT-CLK 203 | # NET "AUDSDI" LOC = "T18"; # Bank = 1, Pin name = IO_L51N_M1DQ13, Sch name = AUD-SDI 204 | # NET "AUDSDO" LOC = "N16"; # Bank = 1, Pin name = IO_L50N_M1UDQSN, Sch name = AUD-SDO 205 | # NET "AUDSYNC" LOC = "U17"; # Bank = 1, Pin name = IO_L52P_M1DQ14, Sch name = AUD-SYNC 206 | # NET "AUDRST" LOC = "T17"; # Bank = 1, Pin name = IO_L51P_M1DQ12, Sch name = AUD-RESET 207 | 208 | # PMOD Connector 209 | NET "JB<0>" LOC = "T3"; # Bank = 2, Pin name = IO_L62N_D6, Sch name = JA-D0_N 210 | NET "JB<1>" LOC = "R3"; # Bank = 2, Pin name = IO_L62P_D5, Sch name = JA-D0_P 211 | NET "JB<2>" LOC = "P6"; # Bank = 2, Pin name = IO_L64N_D9, Sch name = JA-D2_N 212 | NET "JB<3>" LOC = "N5"; # Bank = 2, Pin name = IO_L64P_D8, Sch name = JA-D2_P 213 | NET "JB<4>" LOC = "V9"; # Bank = 2, Pin name = IO_L32N_GCLK28, Sch name = JA-CLK_N 214 | NET "JB<5>" LOC = "T9"; # Bank = 2, Pin name = IO_L32P_GCLK29, Sch name = JA-CLK_P 215 | NET "JB<6>" LOC = "V4"; # Bank = 2, Pin name = IO_L63N, Sch name = JA-D1_N 216 | NET "JB<7>" LOC = "T4"; # Bank = 2, Pin name = IO_L63P, Sch name = JA-D1_P 217 | 218 | # onboard VHDCI 219 | # Channnel 1 connects to P signals, Channel 2 to N signals 220 | # NET "VHDCIIO1<0>" LOC = "U16"; # Bank = 2, Pin name = IO_L2P_CMPCLK, Sch name = EXP-IO1_P 221 | # NET "VHDCIIO1<1>" LOC = "U15"; # Bank = 2, Pin name = *IO_L5P, Sch name = EXP-IO2_P 222 | # NET "VHDCIIO1<2>" LOC = "U13"; # Bank = 2, Pin name = IO_L14P_D11, Sch name = EXP-IO3_P 223 | # NET "VHDCIIO1<3>" LOC = "M11"; # Bank = 2, Pin name = *IO_L15P, Sch name = EXP-IO4_P 224 | # NET "VHDCIIO1<4>" LOC = "R11"; # Bank = 2, Pin name = IO_L16P, Sch name = EXP-IO5_P 225 | # NET "VHDCIIO1<5>" LOC = "T12"; # Bank = 2, Pin name = *IO_L19P, Sch name = EXP-IO6_P 226 | # NET "VHDCIIO1<6>" LOC = "N10"; # Bank = 2, Pin name = *IO_L20P, Sch name = EXP-IO7_P 227 | # NET "VHDCIIO1<7>" LOC = "M10"; # Bank = 2, Pin name = *IO_L22P, Sch name = EXP-IO8_P 228 | # NET "VHDCIIO1<8>" LOC = "U11"; # Bank = 2, Pin name = IO_L23P, Sch name = EXP-IO9_P 229 | # NET "VHDCIIO1<9>" LOC = "R10"; # Bank = 2, Pin name = IO_L29P_GCLK3, Sch name = EXP-IO10_P 230 | # NET "VHDCIIO1<10>" LOC = "U10"; # Bank = 2, Pin name = IO_L30P_GCLK1_D13, Sch name = EXP-IO11_P 231 | # NET "VHDCIIO1<11>" LOC = "R8"; # Bank = 2, Pin name = IO_L31P_GCLK31_D14, Sch name = EXP-IO12_P 232 | # NET "VHDCIIO1<12>" LOC = "M8"; # Bank = 2, Pin name = *IO_L40P, Sch name = EXP-IO13_P 233 | # NET "VHDCIIO1<13>" LOC = "U8"; # Bank = 2, Pin name = IO_L41P, Sch name = EXP-IO14_P 234 | # NET "VHDCIIO1<14>" LOC = "U7"; # Bank = 2, Pin name = IO_L43P, Sch name = EXP-IO15_P 235 | # NET "VHDCIIO1<15>" LOC = "N7"; # Bank = 2, Pin name = *IO_L44P, Sch name = EXP-IO16_P 236 | # NET "VHDCIIO1<16>" LOC = "T6"; # Bank = 2, Pin name = IO_L45P, Sch name = EXP-IO17_P 237 | # NET "VHDCIIO1<17>" LOC = "R7"; # Bank = 2, Pin name = IO_L46P, Sch name = EXP-IO18_P 238 | # NET "VHDCIIO1<18>" LOC = "N6"; # Bank = 2, Pin name = *IO_L47P, Sch name = EXP-IO19_P 239 | # NET "VHDCIIO1<19>" LOC = "U5"; # Bank = 2, Pin name = IO_49P_D3, Sch name = EXP-IO20_P 240 | 241 | # NET "VHDCIIO2<0>" LOC = "V16"; # Bank = 2, Pin name = IO_L2N_CMPMOSI, Sch name = EXP-IO1_N 242 | # NET "VHDCIIO2<1>" LOC = "V15"; # Bank = 2, Pin name = *IO_L5N, Sch name = EXP-IO2_N 243 | # NET "VHDCIIO2<2>" LOC = "V13"; # Bank = 2, Pin name = IO_L14N_D12, Sch name = EXP-IO3_N 244 | # NET "VHDCIIO2<3>" LOC = "N11"; # Bank = 2, Pin name = *IO_L15N, Sch name = EXP-IO4_N 245 | # NET "VHDCIIO2<4>" LOC = "T11"; # Bank = 2, Pin name = IO_L16N_VREF, Sch name = EXP-IO5_N 246 | # NET "VHDCIIO2<5>" LOC = "V12"; # Bank = 2, Pin name = *IO_L19N, Sch name = EXP-IO6_N 247 | # NET "VHDCIIO2<6>" LOC = "P11"; # Bank = 2, Pin name = *IO_L20N, Sch name = EXP-IO7_N 248 | # NET "VHDCIIO2<7>" LOC = "N9"; # Bank = 2, Pin name = *IO_L22N, Sch name = EXP-IO8_N 249 | # NET "VHDCIIO2<8>" LOC = "V11"; # Bank = 2, Pin name = IO_L23N, Sch name = EXP-IO9_N 250 | # NET "VHDCIIO2<9>" LOC = "T10"; # Bank = 2, Pin name = IO_L29N_GCLK2, Sch name = EXP-IO10_N 251 | # NET "VHDCIIO2<10>" LOC = "V10"; # Bank = 2, Pin name = IO_L30N_GCLK0_USERCCLK, Sch name = EXP-IO11_N 252 | # NET "VHDCIIO2<11>" LOC = "T8"; # Bank = 2, Pin name = IO_L31N_GCLK30_D15, Sch name = EXP-IO12_N 253 | # NET "VHDCIIO2<12>" LOC = "N8"; # Bank = 2, Pin name = *IO_L40N, Sch name = EXP-IO13_N 254 | # NET "VHDCIIO2<13>" LOC = "V8"; # Bank = 2, Pin name = IO_L41N_VREF, Sch name = EXP-IO14_N 255 | # NET "VHDCIIO2<14>" LOC = "V7"; # Bank = 2, Pin name = IO_L43N, Sch name = EXP-IO15_N 256 | # NET "VHDCIIO2<15>" LOC = "P8"; # Bank = 2, Pin name = *IO_L44N, Sch name = EXP-IO16_N 257 | # NET "VHDCIIO2<16>" LOC = "V6"; # Bank = 2, Pin name = IO_L45N, Sch name = EXP-IO17_N 258 | # NET "VHDCIIO2<17>" LOC = "T7"; # Bank = 2, Pin name = IO_L46N, Sch name = EXP-IO18_N 259 | # NET "VHDCIIO2<18>" LOC = "P7"; # Bank = 2, Pin name = *IO_L47N, Sch name = EXP-IO19_N 260 | # NET "VHDCIIO2<19>" LOC = "V5"; # Bank = 2, Pin name = IO_49N_D4, Sch name = EXP-IO20_N 261 | 262 | # onboard VHDCI - VmodMIB PMOD Connectors 263 | # NET "VHDCIJA<0>" LOC = "T11"; # Bank = 2, Pin name = IO_L16N_VREF, Sch name = JA-D0_N 264 | # NET "VHDCIJA<1>" LOC = "R11"; # Bank = 2, Pin name = IO_L16P, Sch name = JA-D0_P 265 | # NET "VHDCIJA<2>" LOC = "P11"; # Bank = 2, Pin name = *IO_L20N, Sch name = JA-D2_N 266 | # NET "VHDCIJA<3>" LOC = "N10"; # Bank = 2, Pin name = *IO_L20P, Sch name = JA-D2_P 267 | # NET "VHDCIJA<4>" LOC = "T10"; # Bank = 2, Pin name = IO_L29N_GCLK2, Sch name = JA-CLK_N 268 | # NET "VHDCIJA<5>" LOC = "R10"; # Bank = 2, Pin name = IO_L29P_GCLK3, Sch name = JA-CLK_P 269 | # NET "VHDCIJA<6>" LOC = "V12"; # Bank = 2, Pin name = *IO_L19N, Sch name = JA-D1_N 270 | # NET "VHDCIJA<7>" LOC = "T12"; # Bank = 2, Pin name = *IO_L19P, Sch name = JA-D1_P 271 | 272 | # NET "VHDCIJB<0>" LOC = "N9"; # Bank = 2, Pin name = *IO_L22N, Sch name = JB-D0_N 273 | # NET "VHDCIJB<1>" LOC = "M10"; # Bank = 2, Pin name = *IO_L22P, Sch name = JB-D0_P 274 | # NET "VHDCIJB<2>" LOC = "T8"; # Bank = 2, Pin name = IO_L31N_GCLK30_D15, Sch name = JB-D2_N 275 | # NET "VHDCIJB<3>" LOC = "R8"; # Bank = 2, Pin name = IO_L31P_GCLK31_D14, Sch name = JB-D2_P 276 | # NET "VHDCIJB<4>" LOC = "V10"; # Bank = 2, Pin name = IO_L30N_GCLK0_USERCCLK, Sch name = JB-CLK_N 277 | # NET "VHDCIJB<5>" LOC = "U10"; # Bank = 2, Pin name = IO_L30P_GCLK1_D13, Sch name = JB-CLK_P 278 | # NET "VHDCIJB<6>" LOC = "V11"; # Bank = 2, Pin name = IO_L23N, Sch name = JB-D1_N 279 | # NET "VHDCIJB<7>" LOC = "U11"; # Bank = 2, Pin name = IO_L23P, Sch name = JB-D1_P 280 | 281 | # NET "VHDCIJC<0>" LOC = "V15"; # Bank = 2, Pin name = *IO_L5N, Sch name = JC-D0_N 282 | # NET "VHDCIJC<1>" LOC = "U15"; # Bank = 2, Pin name = *IO_L5P, Sch name = JC-D0_P 283 | # NET "VHDCIJC<2>" LOC = "N11"; # Bank = 2, Pin name = *IO_L15N, Sch name = JC-D2_N 284 | # NET "VHDCIJC<3>" LOC = "M11"; # Bank = 2, Pin name = *IO_L15P, Sch name = JC-D2_P 285 | # NET "VHDCIJC<4>" LOC = "V16"; # Bank = 2, Pin name = IO_L2N_CMPMOSI, Sch name = JC-CLK_N 286 | # NET "VHDCIJC<5>" LOC = "U16"; # Bank = 2, Pin name = IO_L2P_CMPCLK, Sch name = JC-CLK_P 287 | # NET "VHDCIJC<6>" LOC = "V13"; # Bank = 2, Pin name = IO_L14N_D12, Sch name = JC-D1_N 288 | # NET "VHDCIJC<7>" LOC = "U13"; # Bank = 2, Pin name = IO_L14P_D11, Sch name = JC-D1_P 289 | 290 | # NET "VHDCIJD<0>" LOC = "T7"; # Bank = 2, Pin name = IO_L46N, Sch name = JD-D0_N 291 | # NET "VHDCIJD<1>" LOC = "R7"; # Bank = 2, Pin name = IO_L46P, Sch name = JD-D0_P 292 | # NET "VHDCIJD<2>" LOC = "V5"; # Bank = 2, Pin name = IO_49N_D4, Sch name = JD-D2_N 293 | # NET "VHDCIJD<3>" LOC = "U5"; # Bank = 2, Pin name = IO_49P_D3, Sch name = JD-D2_P 294 | # NET "VHDCIJD<4>" LOC = "V6"; # Bank = 2, Pin name = IO_L45N, Sch name = JD-CLK_N 295 | # NET "VHDCIJD<5>" LOC = "T6"; # Bank = 2, Pin name = IO_L45P, Sch name = JD-CLK_P 296 | # NET "VHDCIJD<6>" LOC = "P7"; # Bank = 2, Pin name = *IO_L47N, Sch name = JD-D1_N 297 | # NET "VHDCIJD<7>" LOC = "N6"; # Bank = 2, Pin name = *IO_L47P, Sch name = JD-D1_P 298 | 299 | # NET "VHDCIJE<13>" LOC = "V8"; # Bank = 2, Pin name = IO_L41N_VREF, Sch name = JE1/SDA 300 | # NET "VHDCIJE<13>" LOC = "U8"; # Bank = 2, Pin name = IO_L41P, Sch name = JE2/SCL 301 | # NET "VHDCIJE<15>" LOC = "P8"; # Bank = 2, Pin name = *IO_L44N, Sch name = JE3 302 | # NET "VHDCIJE<15>" LOC = "N7"; # Bank = 2, Pin name = *IO_L44P, Sch name = JE4 303 | # NET "VHDCIJE<12>" LOC = "N8"; # Bank = 2, Pin name = *IO_L40N, Sch name = JE7 304 | # NET "VHDCIJE<12>" LOC = "M8"; # Bank = 2, Pin name = *IO_L40P, Sch name = JE8 305 | # NET "VHDCIJE<14>" LOC = "V7"; # Bank = 2, Pin name = IO_L43N, Sch name = JE9 306 | # NET "VHDCIJE<14>" LOC = "U7"; # Bank = 2, Pin name = IO_L43P, Sch name = JE10 307 | 308 | # USB UART Connector 309 | # NET "UartRx" LOC = "A16"; # Bank = 0, Pin name = IO_L66N_SCP0, Sch name = USBB-RXD 310 | # NET "UartTx" LOC = "B16"; # Bank = 0, Pin name = IO_L66P_SCP1, Sch name = USBB-TXD 311 | -------------------------------------------------------------------------------- /src/top/s6atlys.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | `timescale 1ns / 1ps 3 | 4 | // Main board module. 5 | module s6atlys( 6 | // Global clock 7 | input wire CLK_100M, 8 | 9 | // onboard HDMI OUT 10 | //output wire HDMIOUTCLKP, 11 | //output wire HDMIOUTCLKN, 12 | //output wire HDMIOUTD0P, 13 | //output wire HDMIOUTD0N, 14 | //output wire HDMIOUTD1P, 15 | //output wire HDMIOUTD1N, 16 | //output wire HDMIOUTD2P, 17 | //output wire HDMIOUTD2N, 18 | //output wire HDMIOUTSCL, 19 | //output wire HDMIOUTSDA, 20 | 21 | // LEDs 22 | output wire [7:0] LED, 23 | 24 | // Switches 25 | input wire [7:0] SW, 26 | 27 | // Buttons 28 | input wire [5:0] BTN, 29 | 30 | // PMOD Connector 31 | inout wire [7:0] JB 32 | ); 33 | 34 | // 35 | // Initialize outputs -- remove these when they're actually used 36 | // 37 | 38 | // Audio output 39 | //assign AUD_L = 0; 40 | //assign AUD_R = 0; 41 | 42 | // VGA output 43 | //assign VGA_R = 0; 44 | //assign VGA_G = 0; 45 | //assign VGA_B = 0; 46 | //assign VGA_HSYNC = 0; 47 | //assign VGA_VSYNC = 0; 48 | 49 | // 50 | // Clocks (GameBoy clock runs at ~4.194304 MHz) 51 | // 52 | // FPGABoy runs at 33.33 MHz, mostly to simplify the video controller. 53 | // Certain cycle sensitive modules, such as the CPU and Timer are 54 | // internally clocked down to the GameBoy's normal speed. 55 | // 56 | 57 | // Core Clock: 33.33 MHz 58 | wire coreclk, core_clock; 59 | DCM_SP core_clock_dcm (.CLKIN(CLK_100M), .CLKFX(coreclk), .RST(1'b0)); 60 | defparam core_clock_dcm.CLKFX_DIVIDE = 6; 61 | defparam core_clock_dcm.CLKFX_MULTIPLY = 2; 62 | defparam core_clock_dcm.CLKDV_DIVIDE = 3.0; 63 | defparam core_clock_dcm.CLKIN_PERIOD = 10.000; 64 | BUFG core_clock_buf (.I(coreclk), .O(core_clock)); 65 | 66 | // Initial Reset 67 | wire reset_init, reset; 68 | SRL16 reset_sr(.D(1'b0), .CLK(core_clock), .Q(reset_init), 69 | .A0(1'b1), .A1(1'b1), .A2(1'b1), .A3(1'b1)); 70 | 71 | // HDMI Clocks 72 | // TODO: No idea what these look like yet. 73 | 74 | // Joypad Clock: 1 KHz 75 | wire pulse_1khz; 76 | reg clock_1khz; 77 | divider#(.DELAY(33333)) div_1ms ( 78 | .reset(reset_init), 79 | .clock(core_clock), 80 | .enable(pulse_1khz) 81 | ); 82 | 83 | // CLS Clock: 200 Khz 84 | wire pulse_200khz; 85 | reg clock_200khz; 86 | divider#(.DELAY(166)) div_5us ( 87 | .reset(reset_init), 88 | .clock(core_clock), 89 | .enable(pulse_200khz) 90 | ); 91 | 92 | // 93 | // CPU clock - overflows every 8 cycles 94 | // 95 | 96 | reg [2:0] clock_divider; 97 | 98 | wire cpu_clock; 99 | BUFG cpu_clock_buf(.I(clock_divider[2]), .O(cpu_clock)); 100 | 101 | // 102 | // Switches 103 | // 104 | // SW0-SW4 - Breakpoints Switches (Not Implemented) 105 | // SW5 - Step Clock 106 | // SW6 - Step Enable 107 | // SW7 - Power (Reset) 108 | // 109 | 110 | wire reset_sync, step_sync, step_enable; 111 | debounce debounce_step_sync(reset_init, core_clock, SW[5], step_sync); 112 | debounce debounce_step_enable(reset_init, core_clock, SW[6], step_enable); 113 | debounce debounce_reset_sync(reset_init, core_clock, !SW[7], reset_sync); 114 | 115 | assign reset = (reset_init || reset_sync); 116 | 117 | // Game Clock 118 | wire clock; 119 | BUFGMUX clock_mux(.S(step_enable), .O(clock), 120 | .I0(core_clock), .I1(step_sync)); 121 | 122 | // 123 | // Buttons 124 | // 125 | // BTN0 - Not Implemented 126 | // BTN1 - Joypad 127 | // BTN2 - PC SP 128 | // BTN3 - AF BC 129 | // BTN4 - DE HL 130 | // 131 | 132 | reg [1:0] mode; 133 | wire mode0_sync, mode1_sync, mode2_sync, mode3_sync; 134 | debounce debounce_mode0_sync(reset_init, core_clock, BTN[2], mode0_sync); 135 | debounce debounce_mode1_sync(reset_init, core_clock, BTN[3], mode1_sync); 136 | debounce debounce_mode2_sync(reset_init, core_clock, BTN[4], mode2_sync); 137 | debounce debounce_mode3_sync(reset_init, core_clock, BTN[1], mode3_sync); 138 | 139 | // 140 | // GameBoy 141 | // 142 | 143 | // GB <-> Cartridge + WRAM 144 | wire [15:0] A; 145 | wire [7:0] Di; 146 | wire [7:0] Do; 147 | wire wr_n, rd_n, cs_n; 148 | 149 | // GB <-> VRAM 150 | wire [15:0] A_vram; 151 | wire [7:0] Di_vram; 152 | wire [7:0] Do_vram; 153 | wire wr_vram_n, rd_vram_n, cs_vram_n; 154 | 155 | // GB <-> Display Adapter 156 | wire [1:0] pixel_data; 157 | wire pixel_clock; 158 | wire pixel_latch; 159 | wire hsync, vsync; 160 | 161 | // GB <-> Joypad Adapter 162 | wire [3:0] joypad_data; 163 | wire [1:0] joypad_sel; 164 | 165 | // GB <-> Audio Adapter 166 | wire audio_left, audio_right; 167 | 168 | // GB <-> CLS SPI 169 | wire [15:0] PC; 170 | wire [15:0] SP; 171 | wire [15:0] AF; 172 | wire [15:0] BC; 173 | wire [15:0] DE; 174 | wire [15:0] HL; 175 | wire [15:0] A_cpu; 176 | wire [7:0] Di_cpu; 177 | wire [7:0] Do_cpu; 178 | 179 | gameboy gameboy ( 180 | .clock(clock), 181 | .cpu_clock(cpu_clock), 182 | .reset(reset), 183 | .reset_init(reset_init), 184 | .A(A), 185 | .Di(Di), 186 | .Do(Do), 187 | .wr_n(wr_n), 188 | .rd_n(rd_n), 189 | .cs_n(cs_n), 190 | .A_vram(A_vram), 191 | .Di_vram(Di_vram), 192 | .Do_vram(Do_vram), 193 | .wr_vram_n(wr_vram_n), 194 | .rd_vram_n(rd_vram_n), 195 | .cs_vram_n(cs_vram_n), 196 | .pixel_data(pixel_data), 197 | .pixel_clock(pixel_clock), 198 | .pixel_latch(pixel_latch), 199 | .hsync(hsync), 200 | .vsync(vsync), 201 | .joypad_data(joypad_data), 202 | .joypad_sel(joypad_sel), 203 | .audio_left(audio_left), 204 | .audio_right(audio_right), 205 | // debug output 206 | .dbg_led(LED), 207 | .PC(PC), 208 | .SP(SP), 209 | .AF(AF), 210 | .BC(BC), 211 | .DE(DE), 212 | .HL(HL), 213 | .A_cpu(A_cpu), 214 | .Di_cpu(Di_cpu), 215 | .Do_cpu(Do_cpu) 216 | ); 217 | 218 | // Internal ROMs and RAMs 219 | reg [7:0] tetris_rom [0:32767]; 220 | 221 | initial begin 222 | $readmemh("data/tetris.hex", tetris_rom, 0, 32767); 223 | end 224 | 225 | wire [7:0] Di_wram; 226 | 227 | // WRAM 228 | async_mem #(.asz(8), .depth(8192)) wram ( 229 | .rd_data(Di_wram), 230 | .wr_clk(clock), 231 | .wr_data(Do), 232 | .wr_cs(!cs_n && !wr_n), 233 | .addr(A), 234 | .rd_cs(!cs_n && !rd_n) 235 | ); 236 | 237 | // VRAM 238 | async_mem #(.asz(8), .depth(8192)) vram ( 239 | .rd_data(Di_vram), 240 | .wr_clk(clock), 241 | .wr_data(Do_vram), 242 | .wr_cs(!cs_vram_n && !wr_vram_n), 243 | .addr(A_vram), 244 | .rd_cs(!cs_vram_n && !rd_vram_n) 245 | ); 246 | 247 | assign Di = A[14] ? Di_wram : tetris_rom[A]; 248 | 249 | // Joypad Adapter 250 | wire [15:0] joypad_state; 251 | joypad_snes_adapter joypad_adapter( 252 | .clock(clock_1khz), 253 | .reset(reset), 254 | .button_sel(joypad_sel), 255 | .button_data(joypad_data), 256 | .button_state(joypad_state), 257 | .controller_data(JB[4]), 258 | .controller_clock(JB[5]), 259 | .controller_latch(JB[6]) 260 | ); 261 | 262 | cls_spi cls_spi( 263 | .clock(clock_200khz), 264 | .reset(reset), 265 | .mode(mode), 266 | .ss(JB[0]), 267 | .mosi(JB[1]), 268 | .miso(JB[2]), 269 | .sclk(JB[3]), 270 | .A(A_cpu), 271 | .Di(Di_cpu), 272 | .Do(Do_cpu), 273 | .PC(PC), 274 | .SP(SP), 275 | .AF(AF), 276 | .BC(BC), 277 | .DE(DE), 278 | .HL(HL), 279 | .joypad_state(joypad_state) 280 | ); 281 | 282 | // driver for divider clocks and debug elements 283 | always @(posedge core_clock) begin 284 | if (reset_init) begin 285 | clock_1khz <= 1'b0; 286 | clock_200khz <= 1'b0; 287 | mode <= 2'b0; 288 | end else begin 289 | if (pulse_1khz) 290 | clock_1khz <= !clock_1khz; 291 | if (pulse_200khz) 292 | clock_200khz <= !clock_200khz; 293 | 294 | if (mode0_sync) 295 | mode <= 2'b00; 296 | else if (mode1_sync) 297 | mode <= 2'b01; 298 | else if (mode2_sync) 299 | mode <= 2'b10; 300 | else if (mode3_sync) 301 | mode <= 2'b11; 302 | end 303 | end 304 | 305 | always @(posedge clock) begin 306 | if (reset_init) begin 307 | clock_divider <= 1'b0; 308 | end else begin 309 | if (step_enable) 310 | clock_divider <= clock_divider + 4; 311 | else 312 | clock_divider <= clock_divider + 1; 313 | end 314 | end 315 | 316 | endmodule 317 | -------------------------------------------------------------------------------- /src/tv80/env/env_io.v: -------------------------------------------------------------------------------- 1 | 2 | module env_io (/*AUTOARG*/ 3 | // Outputs 4 | DI, 5 | // Inputs 6 | clk, iorq_n, rd_n, wr_n, addr, DO 7 | ); 8 | 9 | input clk; 10 | input iorq_n; 11 | input rd_n; 12 | input wr_n; 13 | input [7:0] addr; 14 | input [7:0] DO; 15 | inout [7:0] DI; 16 | 17 | reg [7:0] io_data; 18 | 19 | reg [7:0] str_buf [0:255]; 20 | reg io_cs; 21 | integer buf_ptr, i; 22 | 23 | reg [7:0] timeout_ctl; 24 | reg [15:0] cur_timeout; 25 | reg [15:0] max_timeout; 26 | 27 | reg [7:0] int_countdown; 28 | reg [7:0] checksum; 29 | reg [7:0] ior_value; // increment-on-read value 30 | 31 | assign DI = (!iorq_n & !rd_n & io_cs) ? io_data : {8{1'bz}}; 32 | 33 | initial 34 | begin 35 | io_cs = 0; 36 | buf_ptr = 0; 37 | cur_timeout = 0; 38 | max_timeout = 10000; 39 | timeout_ctl = 1; 40 | int_countdown = 0; 41 | end 42 | 43 | always @* 44 | begin 45 | if (!iorq_n & !rd_n) 46 | begin 47 | io_cs = (addr[7:5] == 3'b100); 48 | 49 | case (addr) 50 | 8'h82 : io_data = timeout_ctl; 51 | 8'h83 : io_data = max_timeout[7:0]; 52 | 8'h84 : io_data = max_timeout[15:8]; 53 | 54 | 8'h90 : io_data = int_countdown; 55 | 8'h91 : io_data = checksum; 56 | 8'h93 : io_data = ior_value; 57 | 8'h94 : io_data = {$random}; 58 | default : io_data = 8'hzz; 59 | endcase // case(addr) 60 | end // if (!iorq_n & !rd_n) 61 | end // always @ * 62 | 63 | wire wr_stb; 64 | reg last_iowrite; 65 | 66 | assign wr_stb = (!iorq_n & !wr_n); 67 | 68 | always @(posedge clk) 69 | begin 70 | last_iowrite <= #1 wr_stb; 71 | if (!wr_stb & last_iowrite) 72 | case (addr) 73 | 8'h80 : 74 | begin 75 | case (DO) 76 | 1 : tb_top.test_pass; 77 | 78 | 2 : tb_top.test_fail; 79 | 80 | 3 : tb_top.dumpon; 81 | 82 | 4 : tb_top.dumpoff; 83 | 84 | default : 85 | begin 86 | $display ("%t: ERROR : Unknown I/O command %x", $time, DO); 87 | end 88 | endcase // case(DO) 89 | end // case: :... 90 | 91 | 8'h81 : 92 | begin 93 | str_buf[buf_ptr] = DO; 94 | buf_ptr = buf_ptr + 1; 95 | 96 | //$display ("%t: DEBUG : Detected write of character %x", $time, DO); 97 | if (DO == 8'h0A) 98 | begin 99 | $write ("%t: PROGRAM : ", $time); 100 | 101 | for (i=0; i= max_timeout) 131 | begin 132 | $display ("%t: ERROR : Reached timeout %d cycles", $time, max_timeout); 133 | tb_top.test_fail; 134 | end 135 | end // always @ (posedge clk) 136 | 137 | always @(posedge clk) 138 | begin 139 | if (int_countdown == 1) 140 | begin 141 | tb_top.int_n <= #1 1'b0; 142 | int_countdown = 0; 143 | end 144 | else if (int_countdown > 1) 145 | begin 146 | int_countdown = int_countdown - 1; 147 | tb_top.int_n <= #1 1'b1; 148 | end 149 | end 150 | 151 | endmodule // env_io 152 | -------------------------------------------------------------------------------- /src/tv80/env/env_tasks.v: -------------------------------------------------------------------------------- 1 | reg dumping; 2 | 3 | initial 4 | dumping = 0; 5 | 6 | task test_pass; 7 | begin 8 | $display ("%t: --- TEST PASSED ---", $time); 9 | #100; 10 | $finish; 11 | end 12 | endtask // test_pass 13 | 14 | task test_fail; 15 | begin 16 | $display ("%t: !!! TEST FAILED !!!", $time); 17 | #100; 18 | $finish; 19 | end 20 | endtask // test_fail 21 | 22 | task dumpon; 23 | begin 24 | if (!dumping) 25 | begin 26 | $dumpfile (`DUMPFILE_NAME); 27 | $dumpvars; 28 | dumping = 1; 29 | end 30 | end 31 | endtask // dumpon 32 | 33 | task dumpoff; 34 | begin 35 | // ??? 36 | end 37 | endtask // dumpoff 38 | 39 | task clear_ram; 40 | integer i; 41 | begin 42 | for (i=0; i<32768; i=i+1) 43 | tb_top.ram.mem[i] = 0; 44 | end 45 | endtask 46 | 47 | -------------------------------------------------------------------------------- /src/tv80/env/tb.vf: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2003-2004 by Cisco Systems Inc. 3 | * $Id: tb.vf,v 1.5 2005-03-10 23:07:19 ghutchis Exp $ 4 | * All rights reserved. 5 | * 6 | * Author: Guy Hutchison 7 | * 8 | */ 9 | 10 | rtl/core/tv80_alu.v 11 | rtl/core/tv80_mcode.v 12 | rtl/core/tv80_reg.v 13 | rtl/core/tv80_core.v 14 | rtl/core/tv80s.v 15 | rtl/simple_gmii/simple_gmii_top.v 16 | rtl/simple_gmii/simple_gmii_core.v 17 | rtl/simple_gmii/simple_gmii_regs.v 18 | rtl/simple_gmii/sync2.v 19 | rtl/simple_gmii/ram_1r_1w.v 20 | rtl/uart/T16450.v 21 | env/tb_top.v 22 | env/env_io.v 23 | env/op_decode.v 24 | env/async_mem.v 25 | 26 | -------------------------------------------------------------------------------- /src/tv80/env/tb_top.v: -------------------------------------------------------------------------------- 1 | `define TV80_CORE_PATH tb_top.tv80s_inst.i_tv80_core 2 | 3 | module tb_top; 4 | 5 | reg clk; 6 | reg reset_n; 7 | reg wait_n; 8 | reg int_n; 9 | reg nmi_n; 10 | reg busrq_n; 11 | wire m1_n; 12 | wire mreq_n; 13 | wire iorq_n; 14 | wire rd_n; 15 | wire wr_n; 16 | wire rfsh_n; 17 | wire halt_n; 18 | wire busak_n; 19 | wire [15:0] A; 20 | wire [7:0] di; 21 | wire [7:0] do; 22 | wire ram_rd_cs, ram_wr_cs, rom_rd_cs; 23 | reg tx_clk; 24 | 25 | always 26 | begin 27 | clk = 1; 28 | #5; 29 | clk = 0; 30 | #5; 31 | end 32 | 33 | always 34 | begin 35 | tx_clk = 0; 36 | #8; 37 | tx_clk = 1; 38 | #8; 39 | end 40 | 41 | assign rom_rd_cs = !mreq_n & !rd_n & !A[15]; 42 | assign ram_rd_cs = !mreq_n & !rd_n & A[15]; 43 | assign ram_wr_cs = !mreq_n & !wr_n & A[15]; 44 | 45 | tv80s tv80s_inst 46 | ( 47 | // Outputs 48 | .m1_n (m1_n), 49 | .mreq_n (mreq_n), 50 | .iorq_n (iorq_n), 51 | .rd_n (rd_n), 52 | .wr_n (wr_n), 53 | .rfsh_n (rfsh_n), 54 | .halt_n (halt_n), 55 | .busak_n (busak_n), 56 | .A (A[15:0]), 57 | .do (do[7:0]), 58 | // Inputs 59 | .reset_n (reset_n), 60 | .clk (clk), 61 | .wait_n (wait_n), 62 | .int_n (int_n), 63 | .nmi_n (nmi_n), 64 | .busrq_n (busrq_n), 65 | .di (di[7:0])); 66 | 67 | async_mem ram 68 | ( 69 | // Outputs 70 | .rd_data (di), 71 | // Inputs 72 | .wr_clk (clk), 73 | .wr_data (do), 74 | .wr_cs (ram_wr_cs), 75 | .addr (A[14:0]), 76 | .rd_cs (ram_rd_cs)); 77 | 78 | async_mem rom 79 | ( 80 | // Outputs 81 | .rd_data (di), 82 | // Inputs 83 | .wr_clk (), 84 | .wr_data (), 85 | .wr_cs (1'b0), 86 | .addr (A[14:0]), 87 | .rd_cs (rom_rd_cs)); 88 | 89 | env_io env_io_inst 90 | ( 91 | // Outputs 92 | .DI (di[7:0]), 93 | // Inputs 94 | .clk (clk), 95 | .iorq_n (iorq_n), 96 | .rd_n (rd_n), 97 | .wr_n (wr_n), 98 | .addr (A[7:0]), 99 | .DO (do[7:0])); 100 | 101 | //---------------------------------------------------------------------- 102 | // UART 103 | //---------------------------------------------------------------------- 104 | 105 | wire uart_cs_n; 106 | wire [7:0] uart_rd_data; 107 | 108 | wire sin; 109 | wire cts_n; 110 | wire dsr_n; 111 | wire ri_n; 112 | wire dcd_n; 113 | 114 | wire sout; 115 | wire rts_n; 116 | wire dtr_n; 117 | wire out1_n; 118 | wire out2_n; 119 | wire baudout; 120 | wire intr; 121 | 122 | // base address of 0x18 (24dec) 123 | 124 | assign uart_cs_n = ~(!iorq_n & (A[7:3] == 5'h3)); 125 | assign di = (!uart_cs_n & !rd_n) ? uart_rd_data : 8'bz; 126 | assign sin = sout; 127 | 128 | T16450 uart0 129 | (.reset_n (reset_n), 130 | .clk (clk), 131 | .rclk (baudout), 132 | .cs_n (uart_cs_n), 133 | .rd_n (rd_n), 134 | .wr_n (wr_n), 135 | .addr (A[2:0]), 136 | .wr_data (do), 137 | .rd_data (uart_rd_data), 138 | .sin (sin), 139 | .cts_n (cts_n), 140 | .dsr_n (dsr_n), 141 | .ri_n (ri_n), 142 | .dcd_n (dcd_n), 143 | .sout (sout), 144 | .rts_n (rts_n), 145 | .dtr_n (dtr_n), 146 | .out1_n (out1_n), 147 | .out2_n (out2_n), 148 | .baudout (baudout), 149 | .intr (intr)); 150 | 151 | //---------------------------------------------------------------------- 152 | // Network Interface 153 | //---------------------------------------------------------------------- 154 | 155 | //wire nwintf_sel = !iorq_n & (A[7:3] == 5'b00001); 156 | wire [7:0] rx_data, tx_data; 157 | wire rx_clk, rx_dv, rx_er; 158 | wire tx_dv, tx_er; 159 | wire [7:0] nw_data_out; 160 | wire nwintf_oe; 161 | 162 | // loopback config 163 | assign rx_data = tx_data; 164 | assign rx_dv = tx_dv; 165 | assign rx_er = tx_er; 166 | assign rx_clk = tx_clk; 167 | 168 | assign di = (nwintf_oe) ? nw_data_out : 8'bz; 169 | 170 | simple_gmii_top nwintf 171 | ( 172 | // unused outputs 173 | .int_n (), 174 | // Outputs 175 | .tx_dv (tx_dv), 176 | .tx_er (tx_er), 177 | .tx_data (tx_data), 178 | .tx_clk (tx_clk), 179 | .rd_data (nw_data_out), 180 | .doe (nwintf_oe), 181 | // Inputs 182 | .clk (clk), 183 | .reset (!reset_n), 184 | .rx_data (rx_data), 185 | .rx_clk (rx_clk), 186 | .rx_dv (rx_dv), 187 | .rx_er (rx_er), 188 | //.io_select (nwintf_sel), 189 | .iorq_n (iorq_n), 190 | .rd_n (rd_n), 191 | .wr_n (wr_n), 192 | .addr (A[15:0]), 193 | .wr_data (do)); 194 | 195 | //---------------------------------------------------------------------- 196 | // Global Initialization 197 | //---------------------------------------------------------------------- 198 | 199 | initial 200 | begin 201 | clear_ram; 202 | reset_n = 0; 203 | wait_n = 1; 204 | int_n = 1; 205 | nmi_n = 1; 206 | busrq_n = 1; 207 | $readmemh (`PROGRAM_FILE, tb_top.rom.mem); 208 | repeat (20) @(negedge clk); 209 | reset_n = 1; 210 | end // initial begin 211 | 212 | `ifdef DUMP_START 213 | always 214 | begin 215 | if ($time > `DUMP_START) 216 | dumpon; 217 | #100; 218 | end 219 | `endif 220 | 221 | 222 | /* 223 | always 224 | begin 225 | while (mreq_n) @(posedge clk); 226 | wait_n <= #1 0; 227 | @(posedge clk); 228 | wait_n <= #1 1; 229 | while (!mreq_n) @(posedge clk); 230 | end 231 | */ 232 | 233 | `ifdef TV80_INSTRUCTION_DECODE 234 | reg [7:0] state; 235 | initial 236 | state = 0; 237 | 238 | always @(posedge clk) 239 | begin : inst_decode 240 | if ((`TV80_CORE_PATH.mcycle[6:0] == 1) && 241 | (`TV80_CORE_PATH.tstate[6:0] == 8)) 242 | begin 243 | op_decode.decode (`TV80_CORE_PATH.IR[7:0], state); 244 | end 245 | else if (`TV80_CORE_PATH.mcycle[6:0] != 1) 246 | state = 0; 247 | end 248 | `endif 249 | 250 | `include "env_tasks.v" 251 | 252 | endmodule // tb_top 253 | -------------------------------------------------------------------------------- /src/tv80/rtl/core/tv80_alu.v: -------------------------------------------------------------------------------- 1 | // 2 | // TV80 8-Bit Microprocessor Core 3 | // Based on the VHDL T80 core by Daniel Wallner (jesus@opencores.org) 4 | // 5 | // Copyright (c) 2004 Guy Hutchison (ghutchis@opencores.org) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a 8 | // copy of this software and associated documentation files (the "Software"), 9 | // to deal in the Software without restriction, including without limitation 10 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | // and/or sell copies of the Software, and to permit persons to whom the 12 | // Software is furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included 15 | // in all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | module tv80_alu (/*AUTOARG*/ 26 | // Outputs 27 | Q, F_Out, 28 | // Inputs 29 | Arith16, Z16, ALU_Op, IR, ISet, BusA, BusB, F_In 30 | ); 31 | 32 | parameter Mode = 3; 33 | parameter Flag_C = 0; 34 | parameter Flag_N = 1; 35 | parameter Flag_P = 2; 36 | parameter Flag_X = 3; 37 | parameter Flag_H = 4; 38 | parameter Flag_Y = 5; 39 | parameter Flag_Z = 6; 40 | parameter Flag_S = 7; 41 | 42 | input Arith16; 43 | input Z16; 44 | input [3:0] ALU_Op ; 45 | input [5:0] IR; 46 | input [1:0] ISet; 47 | input [7:0] BusA; 48 | input [7:0] BusB; 49 | input [7:0] F_In; 50 | output [7:0] Q; 51 | output [7:0] F_Out; 52 | reg [7:0] Q; 53 | reg [7:0] F_Out; 54 | 55 | function [4:0] AddSub4; 56 | input [3:0] A; 57 | input [3:0] B; 58 | input Sub; 59 | input Carry_In; 60 | begin 61 | AddSub4 = { 1'b0, A } + { 1'b0, (Sub)?~B:B } + Carry_In; 62 | end 63 | endfunction // AddSub4 64 | 65 | function [3:0] AddSub3; 66 | input [2:0] A; 67 | input [2:0] B; 68 | input Sub; 69 | input Carry_In; 70 | begin 71 | AddSub3 = { 1'b0, A } + { 1'b0, (Sub)?~B:B } + Carry_In; 72 | end 73 | endfunction // AddSub4 74 | 75 | function [1:0] AddSub1; 76 | input A; 77 | input B; 78 | input Sub; 79 | input Carry_In; 80 | begin 81 | AddSub1 = { 1'b0, A } + { 1'b0, (Sub)?~B:B } + Carry_In; 82 | end 83 | endfunction // AddSub4 84 | 85 | // AddSub variables (temporary signals) 86 | reg UseCarry; 87 | reg Carry7_v; 88 | reg OverFlow_v; 89 | reg HalfCarry_v; 90 | reg Carry_v; 91 | reg [7:0] Q_v; 92 | 93 | reg [7:0] BitMask; 94 | 95 | 96 | always @(/*AUTOSENSE*/ALU_Op or BusA or BusB or F_In or IR) 97 | begin 98 | case (IR[5:3]) 99 | 3'b000 : BitMask = 8'b00000001; 100 | 3'b001 : BitMask = 8'b00000010; 101 | 3'b010 : BitMask = 8'b00000100; 102 | 3'b011 : BitMask = 8'b00001000; 103 | 3'b100 : BitMask = 8'b00010000; 104 | 3'b101 : BitMask = 8'b00100000; 105 | 3'b110 : BitMask = 8'b01000000; 106 | default: BitMask = 8'b10000000; 107 | endcase // case(IR[5:3]) 108 | 109 | UseCarry = ~ ALU_Op[2] && ALU_Op[0]; 110 | { HalfCarry_v, Q_v[3:0] } = AddSub4(BusA[3:0], BusB[3:0], ALU_Op[1], ALU_Op[1] ^ (UseCarry && F_In[Flag_C]) ); 111 | { Carry7_v, Q_v[6:4] } = AddSub3(BusA[6:4], BusB[6:4], ALU_Op[1], HalfCarry_v); 112 | { Carry_v, Q_v[7] } = AddSub1(BusA[7], BusB[7], ALU_Op[1], Carry7_v); 113 | OverFlow_v = Carry_v ^ Carry7_v; 114 | end // always @ * 115 | 116 | reg [7:0] Q_t; 117 | reg [8:0] DAA_Q; 118 | 119 | always @ (/*AUTOSENSE*/ALU_Op or Arith16 or BitMask or BusA or BusB 120 | or Carry_v or F_In or HalfCarry_v or IR or ISet 121 | or OverFlow_v or Q_v or Z16) 122 | begin 123 | Q_t = 8'hxx; 124 | DAA_Q = {9{1'bx}}; 125 | 126 | F_Out = F_In; 127 | case (ALU_Op) 128 | 4'b0000, 4'b0001, 4'b0010, 4'b0011, 4'b0100, 4'b0101, 4'b0110, 4'b0111 : 129 | begin 130 | F_Out[Flag_N] = 1'b0; 131 | F_Out[Flag_C] = 1'b0; 132 | 133 | case (ALU_Op[2:0]) 134 | 135 | 3'b000, 3'b001 : // ADD, ADC 136 | begin 137 | Q_t = Q_v; 138 | F_Out[Flag_C] = Carry_v; 139 | F_Out[Flag_H] = HalfCarry_v; 140 | F_Out[Flag_P] = OverFlow_v; 141 | end 142 | 143 | 3'b010, 3'b011, 3'b111 : // SUB, SBC, CP 144 | begin 145 | Q_t = Q_v; 146 | F_Out[Flag_N] = 1'b1; 147 | F_Out[Flag_C] = ~ Carry_v; 148 | F_Out[Flag_H] = ~ HalfCarry_v; 149 | F_Out[Flag_P] = OverFlow_v; 150 | end 151 | 152 | 3'b100 : // AND 153 | begin 154 | Q_t[7:0] = BusA & BusB; 155 | F_Out[Flag_H] = 1'b1; 156 | end 157 | 158 | 3'b101 : // XOR 159 | begin 160 | Q_t[7:0] = BusA ^ BusB; 161 | F_Out[Flag_H] = 1'b0; 162 | end 163 | 164 | default : // OR 3'b110 165 | begin 166 | Q_t[7:0] = BusA | BusB; 167 | F_Out[Flag_H] = 1'b0; 168 | end 169 | 170 | endcase // case(ALU_OP[2:0]) 171 | 172 | if (ALU_Op[2:0] == 3'b111 ) 173 | begin // CP 174 | F_Out[Flag_X] = BusB[3]; 175 | F_Out[Flag_Y] = BusB[5]; 176 | end 177 | else 178 | begin 179 | F_Out[Flag_X] = Q_t[3]; 180 | F_Out[Flag_Y] = Q_t[5]; 181 | end 182 | 183 | if (Q_t[7:0] == 8'b00000000 ) 184 | begin 185 | F_Out[Flag_Z] = 1'b1; 186 | if (Z16 == 1'b1 ) 187 | begin 188 | F_Out[Flag_Z] = F_In[Flag_Z]; // 16 bit ADC,SBC 189 | end 190 | end 191 | else 192 | begin 193 | F_Out[Flag_Z] = 1'b0; 194 | end // else: !if(Q_t[7:0] == 8'b00000000 ) 195 | 196 | F_Out[Flag_S] = Q_t[7]; 197 | case (ALU_Op[2:0]) 198 | 3'b000, 3'b001, 3'b010, 3'b011, 3'b111 : // ADD, ADC, SUB, SBC, CP 199 | ; 200 | 201 | default : 202 | F_Out[Flag_P] = ~(^Q_t); 203 | endcase // case(ALU_Op[2:0]) 204 | 205 | if (Arith16 == 1'b1 ) 206 | begin 207 | F_Out[Flag_S] = F_In[Flag_S]; 208 | F_Out[Flag_Z] = F_In[Flag_Z]; 209 | F_Out[Flag_P] = F_In[Flag_P]; 210 | end 211 | end // case: 4'b0000, 4'b0001, 4'b0010, 4'b0011, 4'b0100, 4'b0101, 4'b0110, 4'b0111 212 | 213 | 4'b1100 : 214 | begin 215 | // DAA 216 | F_Out[Flag_H] = F_In[Flag_H]; 217 | F_Out[Flag_C] = F_In[Flag_C]; 218 | DAA_Q[7:0] = BusA; 219 | DAA_Q[8] = 1'b0; 220 | if (F_In[Flag_N] == 1'b0 ) 221 | begin 222 | // After addition 223 | // Alow > 9 || H == 1 224 | if (DAA_Q[3:0] > 9 || F_In[Flag_H] == 1'b1 ) 225 | begin 226 | if ((DAA_Q[3:0] > 9) ) 227 | begin 228 | F_Out[Flag_H] = 1'b1; 229 | end 230 | else 231 | begin 232 | F_Out[Flag_H] = 1'b0; 233 | end 234 | DAA_Q = DAA_Q + 6; 235 | end // if (DAA_Q[3:0] > 9 || F_In[Flag_H] == 1'b1 ) 236 | 237 | // new Ahigh > 9 || C == 1 238 | if (DAA_Q[8:4] > 9 || F_In[Flag_C] == 1'b1 ) 239 | begin 240 | DAA_Q = DAA_Q + 96; // 0x60 241 | end 242 | end 243 | else 244 | begin 245 | // After subtraction 246 | if (DAA_Q[3:0] > 9 || F_In[Flag_H] == 1'b1 ) 247 | begin 248 | if (DAA_Q[3:0] > 5 ) 249 | begin 250 | F_Out[Flag_H] = 1'b0; 251 | end 252 | DAA_Q[7:0] = DAA_Q[7:0] - 6; 253 | end 254 | if (BusA > 153 || F_In[Flag_C] == 1'b1 ) 255 | begin 256 | DAA_Q = DAA_Q - 352; // 0x160 257 | end 258 | end // else: !if(F_In[Flag_N] == 1'b0 ) 259 | 260 | F_Out[Flag_X] = DAA_Q[3]; 261 | F_Out[Flag_Y] = DAA_Q[5]; 262 | F_Out[Flag_C] = F_In[Flag_C] || DAA_Q[8]; 263 | Q_t = DAA_Q[7:0]; 264 | 265 | if (DAA_Q[7:0] == 8'b00000000 ) 266 | begin 267 | F_Out[Flag_Z] = 1'b1; 268 | end 269 | else 270 | begin 271 | F_Out[Flag_Z] = 1'b0; 272 | end 273 | 274 | F_Out[Flag_S] = DAA_Q[7]; 275 | F_Out[Flag_P] = ~ (^DAA_Q); 276 | end // case: 4'b1100 277 | 278 | 4'b1101, 4'b1110 : 279 | begin 280 | // RLD, RRD 281 | Q_t[7:4] = BusA[7:4]; 282 | if (ALU_Op[0] == 1'b1 ) 283 | begin 284 | Q_t[3:0] = BusB[7:4]; 285 | end 286 | else 287 | begin 288 | Q_t[3:0] = BusB[3:0]; 289 | end 290 | F_Out[Flag_H] = 1'b0; 291 | F_Out[Flag_N] = 1'b0; 292 | F_Out[Flag_X] = Q_t[3]; 293 | F_Out[Flag_Y] = Q_t[5]; 294 | if (Q_t[7:0] == 8'b00000000 ) 295 | begin 296 | F_Out[Flag_Z] = 1'b1; 297 | end 298 | else 299 | begin 300 | F_Out[Flag_Z] = 1'b0; 301 | end 302 | F_Out[Flag_S] = Q_t[7]; 303 | F_Out[Flag_P] = ~(^Q_t); 304 | end // case: when 4'b1101, 4'b1110 305 | 306 | 4'b1001 : 307 | begin 308 | // BIT 309 | Q_t[7:0] = BusB & BitMask; 310 | F_Out[Flag_S] = Q_t[7]; 311 | if (Q_t[7:0] == 8'b00000000 ) 312 | begin 313 | F_Out[Flag_Z] = 1'b1; 314 | F_Out[Flag_P] = 1'b1; 315 | end 316 | else 317 | begin 318 | F_Out[Flag_Z] = 1'b0; 319 | F_Out[Flag_P] = 1'b0; 320 | end 321 | F_Out[Flag_H] = 1'b1; 322 | F_Out[Flag_N] = 1'b0; 323 | F_Out[Flag_X] = 1'b0; 324 | F_Out[Flag_Y] = 1'b0; 325 | if (IR[2:0] != 3'b110 ) 326 | begin 327 | F_Out[Flag_X] = BusB[3]; 328 | F_Out[Flag_Y] = BusB[5]; 329 | end 330 | end // case: when 4'b1001 331 | 332 | 4'b1010 : 333 | // SET 334 | Q_t[7:0] = BusB | BitMask; 335 | 336 | 4'b1011 : 337 | // RES 338 | Q_t[7:0] = BusB & ~ BitMask; 339 | 340 | 4'b1000 : 341 | begin 342 | // ROT 343 | case (IR[5:3]) 344 | 3'b000 : // RLC 345 | begin 346 | Q_t[7:1] = BusA[6:0]; 347 | Q_t[0] = BusA[7]; 348 | F_Out[Flag_C] = BusA[7]; 349 | end 350 | 351 | 3'b010 : // RL 352 | begin 353 | Q_t[7:1] = BusA[6:0]; 354 | Q_t[0] = F_In[Flag_C]; 355 | F_Out[Flag_C] = BusA[7]; 356 | end 357 | 358 | 3'b001 : // RRC 359 | begin 360 | Q_t[6:0] = BusA[7:1]; 361 | Q_t[7] = BusA[0]; 362 | F_Out[Flag_C] = BusA[0]; 363 | end 364 | 365 | 3'b011 : // RR 366 | begin 367 | Q_t[6:0] = BusA[7:1]; 368 | Q_t[7] = F_In[Flag_C]; 369 | F_Out[Flag_C] = BusA[0]; 370 | end 371 | 372 | 3'b100 : // SLA 373 | begin 374 | Q_t[7:1] = BusA[6:0]; 375 | Q_t[0] = 1'b0; 376 | F_Out[Flag_C] = BusA[7]; 377 | end 378 | 379 | 3'b110 : // SLL (Undocumented) / SWAP 380 | begin 381 | if (Mode == 3 ) 382 | begin 383 | Q_t[7:4] = BusA[3:0]; 384 | Q_t[3:0] = BusA[7:4]; 385 | F_Out[Flag_C] = 1'b0; 386 | end 387 | else 388 | begin 389 | Q_t[7:1] = BusA[6:0]; 390 | Q_t[0] = 1'b1; 391 | F_Out[Flag_C] = BusA[7]; 392 | end // else: !if(Mode == 3 ) 393 | end // case: 3'b110 394 | 395 | 3'b101 : // SRA 396 | begin 397 | Q_t[6:0] = BusA[7:1]; 398 | Q_t[7] = BusA[7]; 399 | F_Out[Flag_C] = BusA[0]; 400 | end 401 | 402 | default : // SRL 403 | begin 404 | Q_t[6:0] = BusA[7:1]; 405 | Q_t[7] = 1'b0; 406 | F_Out[Flag_C] = BusA[0]; 407 | end 408 | endcase // case(IR[5:3]) 409 | 410 | F_Out[Flag_H] = 1'b0; 411 | F_Out[Flag_N] = 1'b0; 412 | F_Out[Flag_X] = Q_t[3]; 413 | F_Out[Flag_Y] = Q_t[5]; 414 | F_Out[Flag_S] = Q_t[7]; 415 | if (Q_t[7:0] == 8'b00000000 ) 416 | begin 417 | F_Out[Flag_Z] = 1'b1; 418 | end 419 | else 420 | begin 421 | F_Out[Flag_Z] = 1'b0; 422 | end 423 | F_Out[Flag_P] = ~(^Q_t); 424 | 425 | if (ISet == 2'b00 ) 426 | begin 427 | F_Out[Flag_P] = F_In[Flag_P]; 428 | F_Out[Flag_S] = F_In[Flag_S]; 429 | F_Out[Flag_Z] = F_In[Flag_Z]; 430 | end 431 | end // case: 4'b1000 432 | 433 | 434 | default : 435 | ; 436 | 437 | endcase // case(ALU_Op) 438 | 439 | Q = Q_t; 440 | end // always @ (Arith16, ALU_OP, F_In, BusA, BusB, IR, Q_v, Carry_v, HalfCarry_v, OverFlow_v, BitMask, ISet, Z16) 441 | 442 | endmodule // T80_ALU 443 | -------------------------------------------------------------------------------- /src/tv80/rtl/core/tv80_core.v: -------------------------------------------------------------------------------- 1 | // 2 | // TV80 8-Bit Microprocessor Core 3 | // Based on the VHDL T80 core by Daniel Wallner (jesus@opencores.org) 4 | // 5 | // Copyright (c) 2004 Guy Hutchison (ghutchis@opencores.org) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a 8 | // copy of this software and associated documentation files (the "Software"), 9 | // to deal in the Software without restriction, including without limitation 10 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | // and/or sell copies of the Software, and to permit persons to whom the 12 | // Software is furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included 15 | // in all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | module tv80_core (/*AUTOARG*/ 26 | // Outputs 27 | m1_n, iorq, no_read, write, rfsh_n, halt_n, busak_n, A, do, mc, ts, 28 | intcycle_n, IntE, stop, BC, DE, HL, F, ACC, PC, SP, IntE_FF1, IntE_FF2, INT_s, 29 | // Inputs 30 | reset_n, clk, cen, wait_n, int_n, nmi_n, busrq_n, dinst, di 31 | ); 32 | // Beginning of automatic inputs (from unused autoinst inputs) 33 | // End of automatics 34 | 35 | parameter Mode = 3; // 0 => Z80, 1 => Fast Z80, 2 => 8080, 3 => GB 36 | parameter IOWait = 1; // 0 => Single cycle I/O, 1 => Std I/O cycle 37 | /* 38 | parameter Flag_C = 0; 39 | parameter Flag_N = 1; 40 | parameter Flag_P = 2; 41 | parameter Flag_X = 3; 42 | parameter Flag_H = 4; 43 | parameter Flag_Y = 5; 44 | parameter Flag_Z = 6; 45 | parameter Flag_S = 7; 46 | */ 47 | parameter Flag_C = 4; 48 | parameter Flag_N = 0; 49 | parameter Flag_P = 1; 50 | parameter Flag_X = 2; 51 | parameter Flag_H = 5; 52 | parameter Flag_Y = 6; 53 | parameter Flag_Z = 7; 54 | parameter Flag_S = 3; 55 | 56 | 57 | input reset_n; 58 | input clk; 59 | input cen; 60 | input wait_n; 61 | input int_n; 62 | input nmi_n; 63 | input busrq_n; 64 | output m1_n; 65 | output iorq; 66 | output no_read; 67 | output write; 68 | output rfsh_n; 69 | output halt_n; 70 | output busak_n; 71 | output [15:0] A; 72 | input [7:0] dinst; 73 | input [7:0] di; 74 | output [7:0] do; 75 | output [6:0] mc; 76 | output [6:0] ts; 77 | output intcycle_n; 78 | output IntE; 79 | output stop; 80 | output [15:0] BC; 81 | output [15:0] DE; 82 | output [15:0] HL; 83 | output [7:0] F; 84 | output [7:0] ACC; 85 | output [15:0] PC; 86 | output [15:0] SP; 87 | output IntE_FF1; 88 | output IntE_FF2; 89 | output INT_s; 90 | 91 | reg m1_n; 92 | reg iorq; 93 | reg rfsh_n; 94 | reg halt_n; 95 | reg busak_n; 96 | reg [15:0] A; 97 | reg [7:0] do; 98 | reg [6:0] mc; 99 | reg [6:0] ts; 100 | reg intcycle_n; 101 | reg IntE; 102 | reg stop; 103 | 104 | parameter aNone = 3'b111; 105 | parameter aBC = 3'b000; 106 | parameter aDE = 3'b001; 107 | parameter aXY = 3'b010; 108 | parameter aIOA = 3'b100; 109 | parameter aSP = 3'b101; 110 | parameter aZI = 3'b110; 111 | 112 | // Registers 113 | reg [7:0] ACC, F; 114 | reg [7:0] Ap, Fp; 115 | reg [7:0] I; 116 | reg [7:0] R; 117 | reg [15:0] SP, PC; 118 | reg [7:0] RegDIH; 119 | reg [7:0] RegDIL; 120 | wire [15:0] RegBusA; 121 | wire [15:0] RegBusB; 122 | wire [15:0] RegBusC; 123 | reg [2:0] RegAddrA_r; 124 | reg [2:0] RegAddrA; 125 | reg [2:0] RegAddrB_r; 126 | reg [2:0] RegAddrB; 127 | reg [2:0] RegAddrC; 128 | reg RegWEH; 129 | reg RegWEL; 130 | reg Alternate; 131 | 132 | // Help Registers 133 | reg [15:0] TmpAddr; // Temporary address register 134 | reg [7:0] IR; // Instruction register 135 | reg [1:0] ISet; // Instruction set selector 136 | reg [15:0] RegBusA_r; 137 | 138 | reg [15:0] ID16; 139 | reg [7:0] Save_Mux; 140 | 141 | reg [6:0] tstate; 142 | reg [6:0] mcycle; 143 | reg last_mcycle, last_tstate; 144 | reg IntE_FF1; 145 | reg IntE_FF2; 146 | reg Halt_FF; 147 | reg BusReq_s; 148 | reg BusAck; 149 | reg ClkEn; 150 | reg NMI_s; 151 | reg INT_s; 152 | reg [1:0] IStatus; 153 | 154 | reg [7:0] DI_Reg; 155 | reg T_Res; 156 | reg [1:0] XY_State; 157 | reg [2:0] Pre_XY_F_M; 158 | reg NextIs_XY_Fetch; 159 | reg XY_Ind; 160 | reg No_BTR; 161 | reg BTR_r; 162 | reg Auto_Wait; 163 | reg Auto_Wait_t1; 164 | reg Auto_Wait_t2; 165 | reg IncDecZ; 166 | 167 | // ALU signals 168 | reg [7:0] BusB; 169 | reg [7:0] BusA; 170 | wire [7:0] ALU_Q; 171 | wire [7:0] F_Out; 172 | 173 | // Registered micro code outputs 174 | reg [4:0] Read_To_Reg_r; 175 | reg Arith16_r; 176 | reg Z16_r; 177 | reg [3:0] ALU_Op_r; 178 | reg Save_ALU_r; 179 | reg PreserveC_r; 180 | reg [2:0] mcycles; 181 | 182 | // Micro code outputs 183 | wire [2:0] mcycles_d; 184 | wire [2:0] tstates; 185 | reg IntCycle; 186 | reg NMICycle; 187 | wire Inc_PC; 188 | wire Inc_WZ; 189 | wire [3:0] IncDec_16; 190 | wire [1:0] Prefix; 191 | wire Read_To_Acc; 192 | wire Read_To_Reg; 193 | wire [3:0] Set_BusB_To; 194 | wire [3:0] Set_BusA_To; 195 | wire [3:0] ALU_Op; 196 | wire Save_ALU; 197 | wire PreserveC; 198 | wire Arith16; 199 | wire [2:0] Set_Addr_To; 200 | wire Jump; 201 | wire JumpE; 202 | wire JumpXY; 203 | wire Call; 204 | wire RstP; 205 | wire LDZ; 206 | wire LDW; 207 | wire LDSPHL; 208 | wire iorq_i; 209 | wire [2:0] Special_LD; 210 | wire ExchangeDH; 211 | wire ExchangeRp; 212 | wire ExchangeAF; 213 | wire ExchangeRS; 214 | wire I_DJNZ; 215 | wire I_CPL; 216 | wire I_CCF; 217 | wire I_SCF; 218 | wire I_RETN; 219 | wire I_BT; 220 | wire I_BC; 221 | wire I_BTR; 222 | wire I_RLD; 223 | wire I_RRD; 224 | wire I_INRC; 225 | wire SetDI; 226 | wire SetEI; 227 | wire [1:0] IMode; 228 | wire Halt; 229 | 230 | reg [15:0] PC16; 231 | reg [15:0] PC16_B; 232 | reg [15:0] SP16, SP16_A, SP16_B; 233 | reg [15:0] ID16_B; 234 | reg Oldnmi_n; 235 | 236 | tv80_mcode #(Mode, Flag_C, Flag_N, Flag_P, Flag_X, Flag_H, Flag_Y, Flag_Z, Flag_S) i_mcode 237 | ( 238 | .IR (IR), 239 | .ISet (ISet), 240 | .MCycle (mcycle), 241 | .F (F), 242 | .NMICycle (NMICycle), 243 | .IntCycle (IntCycle), 244 | .MCycles (mcycles_d), 245 | .TStates (tstates), 246 | .Prefix (Prefix), 247 | .Inc_PC (Inc_PC), 248 | .Inc_WZ (Inc_WZ), 249 | .IncDec_16 (IncDec_16), 250 | .Read_To_Acc (Read_To_Acc), 251 | .Read_To_Reg (Read_To_Reg), 252 | .Set_BusB_To (Set_BusB_To), 253 | .Set_BusA_To (Set_BusA_To), 254 | .ALU_Op (ALU_Op), 255 | .Save_ALU (Save_ALU), 256 | .PreserveC (PreserveC), 257 | .Arith16 (Arith16), 258 | .Set_Addr_To (Set_Addr_To), 259 | .IORQ (iorq_i), 260 | .Jump (Jump), 261 | .JumpE (JumpE), 262 | .JumpXY (JumpXY), 263 | .Call (Call), 264 | .RstP (RstP), 265 | .LDZ (LDZ), 266 | .LDW (LDW), 267 | .LDSPHL (LDSPHL), 268 | .Special_LD (Special_LD), 269 | .ExchangeDH (ExchangeDH), 270 | .ExchangeRp (ExchangeRp), 271 | .ExchangeAF (ExchangeAF), 272 | .ExchangeRS (ExchangeRS), 273 | .I_DJNZ (I_DJNZ), 274 | .I_CPL (I_CPL), 275 | .I_CCF (I_CCF), 276 | .I_SCF (I_SCF), 277 | .I_RETN (I_RETN), 278 | .I_BT (I_BT), 279 | .I_BC (I_BC), 280 | .I_BTR (I_BTR), 281 | .I_RLD (I_RLD), 282 | .I_RRD (I_RRD), 283 | .I_INRC (I_INRC), 284 | .SetDI (SetDI), 285 | .SetEI (SetEI), 286 | .IMode (IMode), 287 | .Halt (Halt), 288 | .NoRead (no_read), 289 | .Write (write) 290 | ); 291 | 292 | tv80_alu #(Mode, Flag_C, Flag_N, Flag_P, Flag_X, Flag_H, Flag_Y, Flag_Z, Flag_S) i_alu 293 | ( 294 | .Arith16 (Arith16_r), 295 | .Z16 (Z16_r), 296 | .ALU_Op (ALU_Op_r), 297 | .IR (IR[5:0]), 298 | .ISet (ISet), 299 | .BusA (BusA), 300 | .BusB (BusB), 301 | .F_In (F), 302 | .Q (ALU_Q), 303 | .F_Out (F_Out) 304 | ); 305 | 306 | function [6:0] number_to_bitvec; 307 | input [2:0] num; 308 | begin 309 | case (num) 310 | 1 : number_to_bitvec = 7'b0000001; 311 | 2 : number_to_bitvec = 7'b0000010; 312 | 3 : number_to_bitvec = 7'b0000100; 313 | 4 : number_to_bitvec = 7'b0001000; 314 | 5 : number_to_bitvec = 7'b0010000; 315 | 6 : number_to_bitvec = 7'b0100000; 316 | 7 : number_to_bitvec = 7'b1000000; 317 | default : number_to_bitvec = 7'bx; 318 | endcase // case(num) 319 | end 320 | endfunction // number_to_bitvec 321 | 322 | always @(/*AUTOSENSE*/mcycle or mcycles or tstate or tstates) 323 | begin 324 | case (mcycles) 325 | 1 : last_mcycle = mcycle[0]; 326 | 2 : last_mcycle = mcycle[1]; 327 | 3 : last_mcycle = mcycle[2]; 328 | 4 : last_mcycle = mcycle[3]; 329 | 5 : last_mcycle = mcycle[4]; 330 | 6 : last_mcycle = mcycle[5]; 331 | 7 : last_mcycle = mcycle[6]; 332 | default : last_mcycle = 1'bx; 333 | endcase // case(mcycles) 334 | 335 | case (tstates) 336 | 0 : last_tstate = tstate[0]; 337 | 1 : last_tstate = tstate[1]; 338 | 2 : last_tstate = tstate[2]; 339 | 3 : last_tstate = tstate[3]; 340 | 4 : last_tstate = tstate[4]; 341 | 5 : last_tstate = tstate[5]; 342 | 6 : last_tstate = tstate[6]; 343 | default : last_tstate = 1'bx; 344 | endcase 345 | end // always @ (... 346 | 347 | 348 | always @(/*AUTOSENSE*/ALU_Q or BusAck or BusB or DI_Reg 349 | or ExchangeRp or IR or Save_ALU_r or Set_Addr_To or XY_Ind 350 | or XY_State or cen or last_tstate or mcycle) 351 | begin 352 | ClkEn = cen && ~ BusAck; 353 | 354 | if (last_tstate) 355 | T_Res = 1'b1; 356 | else T_Res = 1'b0; 357 | 358 | if (XY_State != 2'b00 && XY_Ind == 1'b0 && 359 | ((Set_Addr_To == aXY) || 360 | (mcycle[0] && IR == 8'b11001011) || 361 | (mcycle[0] && IR == 8'b00110110))) 362 | NextIs_XY_Fetch = 1'b1; 363 | else 364 | NextIs_XY_Fetch = 1'b0; 365 | 366 | if (ExchangeRp) 367 | Save_Mux = BusB; 368 | else if (!Save_ALU_r) 369 | Save_Mux = DI_Reg; 370 | else 371 | Save_Mux = ALU_Q; 372 | end // always @ * 373 | 374 | always @ (posedge clk) 375 | begin 376 | if (reset_n == 1'b0 ) 377 | begin 378 | PC <= #1 0; // Program Counter 379 | A <= #1 0; 380 | TmpAddr <= #1 0; 381 | IR <= #1 8'b00000000; 382 | ISet <= #1 2'b00; 383 | XY_State <= #1 2'b00; 384 | IStatus <= #1 2'b00; 385 | mcycles <= #1 3'b000; 386 | do <= #1 8'b00000000; 387 | 388 | ACC <= #1 8'hFF; 389 | F <= #1 8'hFF; 390 | Ap <= #1 8'hFF; 391 | Fp <= #1 8'hFF; 392 | I <= #1 8'hFE; // 0 393 | `ifdef TV80_REFRESH 394 | R <= #1 0; 395 | `endif 396 | SP <= #1 16'hFFFF; 397 | Alternate <= #1 1'b0; 398 | 399 | Read_To_Reg_r <= #1 5'b00000; 400 | Arith16_r <= #1 1'b0; 401 | BTR_r <= #1 1'b0; 402 | Z16_r <= #1 1'b0; 403 | ALU_Op_r <= #1 4'b0000; 404 | Save_ALU_r <= #1 1'b0; 405 | PreserveC_r <= #1 1'b0; 406 | XY_Ind <= #1 1'b0; 407 | end 408 | else 409 | begin 410 | 411 | if (ClkEn == 1'b1 ) 412 | begin 413 | 414 | ALU_Op_r <= #1 4'b0000; 415 | Save_ALU_r <= #1 1'b0; 416 | Read_To_Reg_r <= #1 5'b00000; 417 | 418 | mcycles <= #1 mcycles_d; 419 | 420 | if (IMode != 2'b11 ) 421 | begin 422 | IStatus <= #1 IMode; 423 | end 424 | 425 | Arith16_r <= #1 Arith16; 426 | PreserveC_r <= #1 PreserveC; 427 | if (ISet == 2'b10 && ALU_Op[2] == 1'b0 && ALU_Op[0] == 1'b1 && mcycle[2] ) 428 | begin 429 | Z16_r <= #1 1'b1; 430 | end 431 | else 432 | begin 433 | Z16_r <= #1 1'b0; 434 | end 435 | 436 | if (mcycle[0] && (tstate[1] | tstate[2] | tstate[3] )) 437 | begin 438 | // mcycle == 1 && tstate == 1, 2, || 3 439 | if (tstate[2] && wait_n == 1'b1 ) 440 | begin 441 | `ifdef TV80_REFRESH 442 | if (Mode < 2 ) 443 | begin 444 | A[7:0] <= #1 R; 445 | A[15:8] <= #1 I; 446 | R[6:0] <= #1 R[6:0] + 1; 447 | end 448 | `endif 449 | if (Jump == 1'b0 && Call == 1'b0 && NMICycle == 1'b0 && IntCycle == 1'b0 && ~ (Halt_FF == 1'b1 || Halt == 1'b1) ) 450 | begin 451 | PC <= #1 PC16; 452 | end 453 | 454 | if (IntCycle == 1'b1 && IStatus == 2'b01 ) 455 | begin 456 | IR <= #1 8'b11111111; 457 | end 458 | else if (Halt_FF == 1'b1 || (IntCycle == 1'b1 && IStatus == 2'b10) || NMICycle == 1'b1 ) 459 | begin 460 | IR <= #1 8'b00000000; 461 | end 462 | else 463 | begin 464 | IR <= #1 dinst; 465 | end 466 | 467 | ISet <= #1 2'b00; 468 | if (Prefix != 2'b00 ) 469 | begin 470 | if (Prefix == 2'b11 ) 471 | begin 472 | if (IR[5] == 1'b1 ) 473 | begin 474 | XY_State <= #1 2'b10; 475 | end 476 | else 477 | begin 478 | XY_State <= #1 2'b01; 479 | end 480 | end 481 | else 482 | begin 483 | if (Prefix == 2'b10 ) 484 | begin 485 | XY_State <= #1 2'b00; 486 | XY_Ind <= #1 1'b0; 487 | end 488 | ISet <= #1 Prefix; 489 | end 490 | end 491 | else 492 | begin 493 | XY_State <= #1 2'b00; 494 | XY_Ind <= #1 1'b0; 495 | end 496 | end // if (tstate == 2 && wait_n == 1'b1 ) 497 | 498 | 499 | end 500 | else 501 | begin 502 | // either (mcycle > 1) OR (mcycle == 1 AND tstate > 3) 503 | 504 | if (mcycle[5] ) 505 | begin 506 | XY_Ind <= #1 1'b1; 507 | if (Prefix == 2'b01 ) 508 | begin 509 | ISet <= #1 2'b01; 510 | end 511 | end 512 | 513 | if (T_Res == 1'b1 ) 514 | begin 515 | BTR_r <= #1 (I_BT || I_BC || I_BTR) && ~ No_BTR; 516 | if (Jump == 1'b1 ) 517 | begin 518 | A[15:8] <= #1 DI_Reg; 519 | A[7:0] <= #1 TmpAddr[7:0]; 520 | PC[15:8] <= #1 DI_Reg; 521 | PC[7:0] <= #1 TmpAddr[7:0]; 522 | end 523 | else if (JumpXY == 1'b1 ) 524 | begin 525 | A <= #1 RegBusC; 526 | PC <= #1 RegBusC; 527 | end else if (Call == 1'b1 || RstP == 1'b1 ) 528 | begin 529 | A <= #1 TmpAddr; 530 | PC <= #1 TmpAddr; 531 | end 532 | else if (last_mcycle && NMICycle == 1'b1 ) 533 | begin 534 | A <= #1 16'b0000000001100110; 535 | PC <= #1 16'b0000000001100110; 536 | end 537 | else if (mcycle[2] && IntCycle == 1'b1 && IStatus == 2'b10 ) 538 | begin 539 | A[15:8] <= #1 I; 540 | A[7:0] <= #1 TmpAddr[7:0]; 541 | PC[15:8] <= #1 I; 542 | PC[7:0] <= #1 TmpAddr[7:0]; 543 | end 544 | else 545 | begin 546 | case (Set_Addr_To) 547 | aXY : 548 | begin 549 | if (XY_State == 2'b00 ) 550 | begin 551 | A <= #1 RegBusC; 552 | end 553 | else 554 | begin 555 | if (NextIs_XY_Fetch == 1'b1 ) 556 | begin 557 | A <= #1 PC; 558 | end 559 | else 560 | begin 561 | A <= #1 TmpAddr; 562 | end 563 | end // else: !if(XY_State == 2'b00 ) 564 | end // case: aXY 565 | 566 | aIOA : 567 | begin 568 | if (Mode == 3 ) 569 | begin 570 | // Memory map I/O on GBZ80 571 | A[15:8] <= #1 8'hFF; 572 | end 573 | else if (Mode == 2 ) 574 | begin 575 | // Duplicate I/O address on 8080 576 | A[15:8] <= #1 DI_Reg; 577 | end 578 | else 579 | begin 580 | A[15:8] <= #1 ACC; 581 | end 582 | A[7:0] <= #1 DI_Reg; 583 | end // case: aIOA 584 | 585 | 586 | aSP : 587 | begin 588 | A <= #1 SP; 589 | end 590 | 591 | aBC : 592 | begin 593 | if (Mode == 3 && iorq_i == 1'b1 ) 594 | begin 595 | // Memory map I/O on GBZ80 596 | A[15:8] <= #1 8'hFF; 597 | A[7:0] <= #1 RegBusC[7:0]; 598 | end 599 | else 600 | begin 601 | A <= #1 RegBusC; 602 | end 603 | end // case: aBC 604 | 605 | aDE : 606 | begin 607 | A <= #1 RegBusC; 608 | end 609 | 610 | aZI : 611 | begin 612 | if (Inc_WZ == 1'b1 ) 613 | begin 614 | A <= #1 TmpAddr + 1; 615 | end 616 | else 617 | begin 618 | A[15:8] <= #1 DI_Reg; 619 | A[7:0] <= #1 TmpAddr[7:0]; 620 | end 621 | end // case: aZI 622 | 623 | default : 624 | begin 625 | A <= #1 PC; 626 | end 627 | endcase // case(Set_Addr_To) 628 | 629 | end // else: !if(mcycle[2] && IntCycle == 1'b1 && IStatus == 2'b10 ) 630 | 631 | 632 | Save_ALU_r <= #1 Save_ALU; 633 | ALU_Op_r <= #1 ALU_Op; 634 | 635 | if (I_CPL == 1'b1 ) 636 | begin 637 | // CPL 638 | ACC <= #1 ~ ACC; 639 | F[Flag_Y] <= #1 ~ ACC[5]; 640 | F[Flag_H] <= #1 1'b1; 641 | F[Flag_X] <= #1 ~ ACC[3]; 642 | F[Flag_N] <= #1 1'b1; 643 | end 644 | if (I_CCF == 1'b1 ) 645 | begin 646 | // CCF 647 | F[Flag_C] <= #1 ~ F[Flag_C]; 648 | F[Flag_Y] <= #1 ACC[5]; 649 | F[Flag_H] <= #1 F[Flag_C]; 650 | F[Flag_X] <= #1 ACC[3]; 651 | F[Flag_N] <= #1 1'b0; 652 | end 653 | if (I_SCF == 1'b1 ) 654 | begin 655 | // SCF 656 | F[Flag_C] <= #1 1'b1; 657 | F[Flag_Y] <= #1 ACC[5]; 658 | F[Flag_H] <= #1 1'b0; 659 | F[Flag_X] <= #1 ACC[3]; 660 | F[Flag_N] <= #1 1'b0; 661 | end 662 | end // if (T_Res == 1'b1 ) 663 | 664 | 665 | if (tstate[2] && wait_n == 1'b1 ) 666 | begin 667 | if (ISet == 2'b01 && mcycle[6] ) 668 | begin 669 | IR <= #1 dinst; 670 | end 671 | if (JumpE == 1'b1 ) 672 | begin 673 | PC <= #1 PC16; 674 | end 675 | else if (Inc_PC == 1'b1 ) 676 | begin 677 | //PC <= #1 PC + 1; 678 | PC <= #1 PC16; 679 | end 680 | if (BTR_r == 1'b1 ) 681 | begin 682 | //PC <= #1 PC - 2; 683 | PC <= #1 PC16; 684 | end 685 | if (RstP == 1'b1 ) 686 | begin 687 | TmpAddr <= #1 { 10'h0, IR[5:3], 3'h0 }; 688 | //TmpAddr <= #1 (others =>1'b0); 689 | //TmpAddr[5:3] <= #1 IR[5:3]; 690 | end 691 | end 692 | if (tstate[3] && mcycle[5] ) 693 | begin 694 | TmpAddr <= #1 SP16; 695 | end 696 | 697 | if ((tstate[2] && wait_n == 1'b1) || (tstate[4] && mcycle[0]) ) 698 | begin 699 | if (IncDec_16[2:0] == 3'b111 ) 700 | begin 701 | SP <= #1 SP16; 702 | end 703 | end 704 | 705 | if (LDSPHL == 1'b1 ) 706 | begin 707 | SP <= #1 RegBusC; 708 | end 709 | if (ExchangeAF == 1'b1 ) 710 | begin 711 | Ap <= #1 ACC; 712 | ACC <= #1 Ap; 713 | Fp <= #1 F; 714 | F <= #1 Fp; 715 | end 716 | if (ExchangeRS == 1'b1 ) 717 | begin 718 | Alternate <= #1 ~ Alternate; 719 | end 720 | end // else: !if(mcycle == 3'b001 && tstate(2) == 1'b0 ) 721 | 722 | 723 | if (tstate[3] ) 724 | begin 725 | if (LDZ == 1'b1 ) 726 | begin 727 | TmpAddr[7:0] <= #1 DI_Reg; 728 | end 729 | if (LDW == 1'b1 ) 730 | begin 731 | TmpAddr[15:8] <= #1 DI_Reg; 732 | end 733 | 734 | if (Special_LD[2] == 1'b1 ) 735 | begin 736 | case (Special_LD[1:0]) 737 | 2'b00 : 738 | begin 739 | ACC <= #1 I; 740 | F[Flag_P] <= #1 IntE_FF2; 741 | end 742 | 743 | 2'b01 : 744 | begin 745 | ACC <= #1 R; 746 | F[Flag_P] <= #1 IntE_FF2; 747 | end 748 | 749 | 2'b10 : 750 | I <= #1 ACC; 751 | 752 | `ifdef TV80_REFRESH 753 | default : 754 | R <= #1 ACC; 755 | `else 756 | default : ; 757 | `endif 758 | endcase 759 | end 760 | end // if (tstate == 3 ) 761 | 762 | 763 | if ((I_DJNZ == 1'b0 && Save_ALU_r == 1'b1) || ALU_Op_r == 4'b1001 ) 764 | begin 765 | if (Mode == 3 ) 766 | begin 767 | F[6] <= #1 F_Out[6]; 768 | F[5] <= #1 F_Out[5]; 769 | F[7] <= #1 F_Out[7]; 770 | if (PreserveC_r == 1'b0 ) 771 | begin 772 | F[4] <= #1 F_Out[4]; 773 | end 774 | end 775 | else 776 | begin 777 | F[7:1] <= #1 F_Out[7:1]; 778 | if (PreserveC_r == 1'b0 ) 779 | begin 780 | F[Flag_C] <= #1 F_Out[0]; 781 | end 782 | end 783 | end // if ((I_DJNZ == 1'b0 && Save_ALU_r == 1'b1) || ALU_Op_r == 4'b1001 ) 784 | 785 | if (T_Res == 1'b1 && I_INRC == 1'b1 ) 786 | begin 787 | F[Flag_H] <= #1 1'b0; 788 | F[Flag_N] <= #1 1'b0; 789 | if (DI_Reg[7:0] == 8'b00000000 ) 790 | begin 791 | F[Flag_Z] <= #1 1'b1; 792 | end 793 | else 794 | begin 795 | F[Flag_Z] <= #1 1'b0; 796 | end 797 | F[Flag_S] <= #1 DI_Reg[7]; 798 | F[Flag_P] <= #1 ~ (^DI_Reg[7:0]); 799 | end // if (T_Res == 1'b1 && I_INRC == 1'b1 ) 800 | 801 | 802 | if (tstate[1] && Auto_Wait_t1 == 1'b0 ) 803 | begin 804 | do <= #1 BusB; 805 | if (I_RLD == 1'b1 ) 806 | begin 807 | do[3:0] <= #1 BusA[3:0]; 808 | do[7:4] <= #1 BusB[3:0]; 809 | end 810 | if (I_RRD == 1'b1 ) 811 | begin 812 | do[3:0] <= #1 BusB[7:4]; 813 | do[7:4] <= #1 BusA[3:0]; 814 | end 815 | end 816 | 817 | if (T_Res == 1'b1 ) 818 | begin 819 | Read_To_Reg_r[3:0] <= #1 Set_BusA_To; 820 | Read_To_Reg_r[4] <= #1 Read_To_Reg; 821 | if (Read_To_Acc == 1'b1 ) 822 | begin 823 | Read_To_Reg_r[3:0] <= #1 4'b0111; 824 | Read_To_Reg_r[4] <= #1 1'b1; 825 | end 826 | end 827 | 828 | if (tstate[1] && I_BT == 1'b1 ) 829 | begin 830 | F[Flag_X] <= #1 ALU_Q[3]; 831 | F[Flag_Y] <= #1 ALU_Q[1]; 832 | F[Flag_H] <= #1 1'b0; 833 | F[Flag_N] <= #1 1'b0; 834 | end 835 | if (I_BC == 1'b1 || I_BT == 1'b1 ) 836 | begin 837 | F[Flag_P] <= #1 IncDecZ; 838 | end 839 | 840 | if ((tstate[1] && Save_ALU_r == 1'b0 && Auto_Wait_t1 == 1'b0) || 841 | (Save_ALU_r == 1'b1 && ALU_Op_r != 4'b0111) ) 842 | begin 843 | case (Read_To_Reg_r) 844 | 5'b10111 : 845 | ACC <= #1 Save_Mux; 846 | 5'b10110 : 847 | do <= #1 Save_Mux; 848 | 5'b11000 : 849 | SP[7:0] <= #1 Save_Mux; 850 | 5'b11001 : 851 | SP[15:8] <= #1 Save_Mux; 852 | 5'b11011 : 853 | F <= #1 Save_Mux; 854 | endcase 855 | end // if ((tstate == 1 && Save_ALU_r == 1'b0 && Auto_Wait_t1 == 1'b0) ||... 856 | end // if (ClkEn == 1'b1 ) 857 | end // else: !if(reset_n == 1'b0 ) 858 | end 859 | 860 | 861 | //------------------------------------------------------------------------- 862 | // 863 | // BC('), DE('), HL('), IX && IY 864 | // 865 | //------------------------------------------------------------------------- 866 | always @ (posedge clk) 867 | begin 868 | if (ClkEn == 1'b1 ) 869 | begin 870 | // Bus A / Write 871 | RegAddrA_r <= #1 { Alternate, Set_BusA_To[2:1] }; 872 | if (XY_Ind == 1'b0 && XY_State != 2'b00 && Set_BusA_To[2:1] == 2'b10 ) 873 | begin 874 | RegAddrA_r <= #1 { XY_State[1], 2'b11 }; 875 | end 876 | 877 | // Bus B 878 | RegAddrB_r <= #1 { Alternate, Set_BusB_To[2:1] }; 879 | if (XY_Ind == 1'b0 && XY_State != 2'b00 && Set_BusB_To[2:1] == 2'b10 ) 880 | begin 881 | RegAddrB_r <= #1 { XY_State[1], 2'b11 }; 882 | end 883 | 884 | // Address from register 885 | RegAddrC <= #1 { Alternate, Set_Addr_To[1:0] }; 886 | // Jump (HL), LD SP,HL 887 | if ((JumpXY == 1'b1 || LDSPHL == 1'b1) ) 888 | begin 889 | RegAddrC <= #1 { Alternate, 2'b10 }; 890 | end 891 | if (((JumpXY == 1'b1 || LDSPHL == 1'b1) && XY_State != 2'b00) || (mcycle[5]) ) 892 | begin 893 | RegAddrC <= #1 { XY_State[1], 2'b11 }; 894 | end 895 | 896 | if (I_DJNZ == 1'b1 && Save_ALU_r == 1'b1 && Mode < 2 ) 897 | begin 898 | IncDecZ <= #1 F_Out[Flag_Z]; 899 | end 900 | if ((tstate[2] || (tstate[3] && mcycle[0])) && IncDec_16[2:0] == 3'b100 ) 901 | begin 902 | if (ID16 == 0 ) 903 | begin 904 | IncDecZ <= #1 1'b0; 905 | end 906 | else 907 | begin 908 | IncDecZ <= #1 1'b1; 909 | end 910 | end 911 | 912 | RegBusA_r <= #1 RegBusA; 913 | end 914 | 915 | end // always @ (posedge clk) 916 | 917 | 918 | always @(/*AUTOSENSE*/Alternate or ExchangeDH or IncDec_16 919 | or RegAddrA_r or RegAddrB_r or XY_State or mcycle or tstate) 920 | begin 921 | if ((tstate[2] || (tstate[3] && mcycle[0] && IncDec_16[2] == 1'b1)) && XY_State == 2'b00) 922 | RegAddrA = { Alternate, IncDec_16[1:0] }; 923 | else if ((tstate[2] || (tstate[3] && mcycle[0] && IncDec_16[2] == 1'b1)) && IncDec_16[1:0] == 2'b10) 924 | RegAddrA = { XY_State[1], 2'b11 }; 925 | else if (ExchangeDH == 1'b1 && tstate[3]) 926 | RegAddrA = { Alternate, 2'b10 }; 927 | else if (ExchangeDH == 1'b1 && tstate[4]) 928 | RegAddrA = { Alternate, 2'b01 }; 929 | else 930 | RegAddrA = RegAddrA_r; 931 | 932 | if (ExchangeDH == 1'b1 && tstate[3]) 933 | RegAddrB = { Alternate, 2'b01 }; 934 | else 935 | RegAddrB = RegAddrB_r; 936 | end // always @ * 937 | 938 | 939 | always @(/*AUTOSENSE*/ALU_Op_r or Auto_Wait_t1 or ExchangeDH 940 | or IncDec_16 or Read_To_Reg_r or Save_ALU_r or mcycle 941 | or tstate or wait_n) 942 | begin 943 | RegWEH = 1'b0; 944 | RegWEL = 1'b0; 945 | if ((tstate[1] && Save_ALU_r == 1'b0 && Auto_Wait_t1 == 1'b0) || 946 | (Save_ALU_r == 1'b1 && ALU_Op_r != 4'b0111) ) 947 | begin 948 | case (Read_To_Reg_r) 949 | 5'b10000 , 5'b10001 , 5'b10010 , 5'b10011 , 5'b10100 , 5'b10101 : 950 | begin 951 | RegWEH = ~ Read_To_Reg_r[0]; 952 | RegWEL = Read_To_Reg_r[0]; 953 | end 954 | endcase // case(Read_To_Reg_r) 955 | 956 | end // if ((tstate == 1 && Save_ALU_r == 1'b0 && Auto_Wait_t1 == 1'b0) ||... 957 | 958 | 959 | if (ExchangeDH == 1'b1 && (tstate[3] || tstate[4]) ) 960 | begin 961 | RegWEH = 1'b1; 962 | RegWEL = 1'b1; 963 | end 964 | 965 | if (IncDec_16[2] == 1'b1 && ((tstate[2] && wait_n == 1'b1 && mcycle != 3'b001) || (tstate[3] && mcycle[0])) ) 966 | begin 967 | case (IncDec_16[1:0]) 968 | 2'b00 , 2'b01 , 2'b10 : 969 | begin 970 | RegWEH = 1'b1; 971 | RegWEL = 1'b1; 972 | end 973 | endcase 974 | end 975 | end // always @ * 976 | 977 | 978 | always @(/*AUTOSENSE*/ExchangeDH or ID16 or IncDec_16 or RegBusA_r 979 | or RegBusB or Save_Mux or mcycle or tstate) 980 | begin 981 | RegDIH = Save_Mux; 982 | RegDIL = Save_Mux; 983 | 984 | if (ExchangeDH == 1'b1 && tstate[3] ) 985 | begin 986 | RegDIH = RegBusB[15:8]; 987 | RegDIL = RegBusB[7:0]; 988 | end 989 | else if (ExchangeDH == 1'b1 && tstate[4] ) 990 | begin 991 | RegDIH = RegBusA_r[15:8]; 992 | RegDIL = RegBusA_r[7:0]; 993 | end 994 | else if (IncDec_16[2] == 1'b1 && ((tstate[2] && mcycle != 3'b001) || (tstate[3] && mcycle[0])) ) 995 | begin 996 | RegDIH = ID16[15:8]; 997 | RegDIL = ID16[7:0]; 998 | end 999 | end 1000 | 1001 | tv80_reg i_reg 1002 | ( 1003 | .clk (clk), 1004 | .CEN (ClkEn), 1005 | .WEH (RegWEH), 1006 | .WEL (RegWEL), 1007 | .AddrA (RegAddrA), 1008 | .AddrB (RegAddrB), 1009 | .AddrC (RegAddrC), 1010 | .DIH (RegDIH), 1011 | .DIL (RegDIL), 1012 | .DOAH (RegBusA[15:8]), 1013 | .DOAL (RegBusA[7:0]), 1014 | .DOBH (RegBusB[15:8]), 1015 | .DOBL (RegBusB[7:0]), 1016 | .DOCH (RegBusC[15:8]), 1017 | .DOCL (RegBusC[7:0]), 1018 | .BC (BC), 1019 | .DE (DE), 1020 | .HL (HL) 1021 | ); 1022 | 1023 | //------------------------------------------------------------------------- 1024 | // 1025 | // Buses 1026 | // 1027 | //------------------------------------------------------------------------- 1028 | 1029 | always @ (posedge clk) 1030 | begin 1031 | if (ClkEn == 1'b1 ) 1032 | begin 1033 | case (Set_BusB_To) 1034 | 4'b0111 : 1035 | BusB <= #1 ACC; 1036 | 4'b0000 , 4'b0001 , 4'b0010 , 4'b0011 , 4'b0100 , 4'b0101 : 1037 | begin 1038 | if (Set_BusB_To[0] == 1'b1 ) 1039 | begin 1040 | BusB <= #1 RegBusB[7:0]; 1041 | end 1042 | else 1043 | begin 1044 | BusB <= #1 RegBusB[15:8]; 1045 | end 1046 | end 1047 | 4'b0110 : 1048 | BusB <= #1 DI_Reg; 1049 | 4'b1000 : 1050 | BusB <= #1 SP[7:0]; 1051 | 4'b1001 : 1052 | BusB <= #1 SP[15:8]; 1053 | 4'b1010 : 1054 | BusB <= #1 8'b00000001; 1055 | 4'b1011 : 1056 | BusB <= #1 F; 1057 | 4'b1100 : 1058 | BusB <= #1 PC[7:0]; 1059 | 4'b1101 : 1060 | BusB <= #1 PC[15:8]; 1061 | 4'b1110 : 1062 | BusB <= #1 8'b00000000; 1063 | default : 1064 | BusB <= #1 8'hxx; 1065 | endcase 1066 | 1067 | case (Set_BusA_To) 1068 | 4'b0111 : 1069 | BusA <= #1 ACC; 1070 | 4'b0000 , 4'b0001 , 4'b0010 , 4'b0011 , 4'b0100 , 4'b0101 : 1071 | begin 1072 | if (Set_BusA_To[0] == 1'b1 ) 1073 | begin 1074 | BusA <= #1 RegBusA[7:0]; 1075 | end 1076 | else 1077 | begin 1078 | BusA <= #1 RegBusA[15:8]; 1079 | end 1080 | end 1081 | 4'b0110 : 1082 | BusA <= #1 DI_Reg; 1083 | 4'b1000 : 1084 | BusA <= #1 SP[7:0]; 1085 | 4'b1001 : 1086 | BusA <= #1 SP[15:8]; 1087 | 4'b1010 : 1088 | BusA <= #1 8'b00000000; 1089 | default : 1090 | BusB <= #1 8'hxx; 1091 | endcase 1092 | end 1093 | end 1094 | 1095 | //------------------------------------------------------------------------- 1096 | // 1097 | // Generate external control signals 1098 | // 1099 | //------------------------------------------------------------------------- 1100 | `ifdef TV80_REFRESH 1101 | always @ (posedge clk) 1102 | begin 1103 | if (reset_n == 1'b0 ) 1104 | begin 1105 | rfsh_n <= #1 1'b1; 1106 | end 1107 | else 1108 | begin 1109 | if (cen == 1'b1 ) 1110 | begin 1111 | if (mcycle[0] && ((tstate[2] && wait_n == 1'b1) || tstate[3]) ) 1112 | begin 1113 | rfsh_n <= #1 1'b0; 1114 | end 1115 | else 1116 | begin 1117 | rfsh_n <= #1 1'b1; 1118 | end 1119 | end 1120 | end 1121 | end 1122 | `endif 1123 | 1124 | always @(/*AUTOSENSE*/BusAck or Halt_FF or I_DJNZ or IntCycle 1125 | or IntE_FF1 or di or iorq_i or mcycle or tstate) 1126 | begin 1127 | mc = mcycle; 1128 | ts = tstate; 1129 | DI_Reg = di; 1130 | halt_n = ~ Halt_FF; 1131 | busak_n = ~ BusAck; 1132 | intcycle_n = ~ IntCycle; 1133 | IntE = IntE_FF1; 1134 | iorq = iorq_i; 1135 | stop = I_DJNZ; 1136 | end 1137 | 1138 | //----------------------------------------------------------------------- 1139 | // 1140 | // Syncronise inputs 1141 | // 1142 | //----------------------------------------------------------------------- 1143 | 1144 | always @ (posedge clk) 1145 | begin : sync_inputs 1146 | 1147 | if (reset_n == 1'b0 ) 1148 | begin 1149 | BusReq_s <= #1 1'b0; 1150 | INT_s <= #1 1'b0; 1151 | NMI_s <= #1 1'b0; 1152 | Oldnmi_n <= #1 1'b0; 1153 | end 1154 | else 1155 | begin 1156 | if (cen == 1'b1 ) 1157 | begin 1158 | BusReq_s <= #1 ~ busrq_n; 1159 | INT_s <= #1 ~ int_n; 1160 | if (NMICycle == 1'b1 ) 1161 | begin 1162 | NMI_s <= #1 1'b0; 1163 | end 1164 | else if (nmi_n == 1'b0 && Oldnmi_n == 1'b1 ) 1165 | begin 1166 | NMI_s <= #1 1'b1; 1167 | end 1168 | Oldnmi_n <= #1 nmi_n; 1169 | end 1170 | end 1171 | end 1172 | 1173 | //----------------------------------------------------------------------- 1174 | // 1175 | // Main state machine 1176 | // 1177 | //----------------------------------------------------------------------- 1178 | 1179 | always @ (posedge clk) 1180 | begin 1181 | if (reset_n == 1'b0 ) 1182 | begin 1183 | mcycle <= #1 7'b0000001; 1184 | tstate <= #1 7'b0000001; 1185 | Pre_XY_F_M <= #1 3'b000; 1186 | Halt_FF <= #1 1'b0; 1187 | BusAck <= #1 1'b0; 1188 | NMICycle <= #1 1'b0; 1189 | IntCycle <= #1 1'b0; 1190 | IntE_FF1 <= #1 1'b0; 1191 | IntE_FF2 <= #1 1'b0; 1192 | No_BTR <= #1 1'b0; 1193 | Auto_Wait_t1 <= #1 1'b0; 1194 | Auto_Wait_t2 <= #1 1'b0; 1195 | m1_n <= #1 1'b1; 1196 | end 1197 | else 1198 | begin 1199 | if (cen == 1'b1 ) 1200 | begin 1201 | if (T_Res == 1'b1 ) 1202 | begin 1203 | Auto_Wait_t1 <= #1 1'b0; 1204 | end 1205 | else 1206 | begin 1207 | Auto_Wait_t1 <= #1 Auto_Wait || iorq_i; 1208 | end 1209 | Auto_Wait_t2 <= #1 Auto_Wait_t1; 1210 | No_BTR <= #1 (I_BT && (~ IR[4] || ~ F[Flag_P])) || 1211 | (I_BC && (~ IR[4] || F[Flag_Z] || ~ F[Flag_P])) || 1212 | (I_BTR && (~ IR[4] || F[Flag_Z])); 1213 | if (tstate[2] ) 1214 | begin 1215 | if (SetEI == 1'b1 ) 1216 | begin 1217 | IntE_FF1 <= #1 1'b1; 1218 | IntE_FF2 <= #1 1'b1; 1219 | end 1220 | if (I_RETN == 1'b1 ) 1221 | begin 1222 | IntE_FF1 <= #1 IntE_FF2; 1223 | end 1224 | end 1225 | if (tstate[3] ) 1226 | begin 1227 | if (SetDI == 1'b1 ) 1228 | begin 1229 | IntE_FF1 <= #1 1'b0; 1230 | IntE_FF2 <= #1 1'b0; 1231 | end 1232 | end 1233 | if (IntCycle == 1'b1 || NMICycle == 1'b1 ) 1234 | begin 1235 | Halt_FF <= #1 1'b0; 1236 | end 1237 | if (mcycle[0] && tstate[2] && wait_n == 1'b1 ) 1238 | begin 1239 | m1_n <= #1 1'b1; 1240 | end 1241 | if (BusReq_s == 1'b1 && BusAck == 1'b1 ) 1242 | begin 1243 | end 1244 | else 1245 | begin 1246 | BusAck <= #1 1'b0; 1247 | if (tstate[2] && wait_n == 1'b0 ) 1248 | begin 1249 | end 1250 | else if (T_Res == 1'b1 ) 1251 | begin 1252 | if (Halt == 1'b1 ) 1253 | begin 1254 | Halt_FF <= #1 1'b1; 1255 | end 1256 | if (BusReq_s == 1'b1 ) 1257 | begin 1258 | BusAck <= #1 1'b1; 1259 | end 1260 | else 1261 | begin 1262 | tstate <= #1 7'b0000010; 1263 | if (NextIs_XY_Fetch == 1'b1 ) 1264 | begin 1265 | mcycle <= #1 7'b0100000; 1266 | Pre_XY_F_M <= #1 mcycle; 1267 | if (IR == 8'b00110110 && Mode == 0 ) 1268 | begin 1269 | Pre_XY_F_M <= #1 3'b010; 1270 | end 1271 | end 1272 | else if ((mcycle[6]) || (mcycle[5] && Mode == 1 && ISet != 2'b01) ) 1273 | begin 1274 | mcycle <= #1 number_to_bitvec(Pre_XY_F_M + 1); 1275 | end 1276 | else if ((last_mcycle) || 1277 | No_BTR == 1'b1 || 1278 | (mcycle[1] && I_DJNZ == 1'b1 && IncDecZ == 1'b1) ) 1279 | begin 1280 | m1_n <= #1 1'b0; 1281 | mcycle <= #1 7'b0000001; 1282 | IntCycle <= #1 1'b0; 1283 | NMICycle <= #1 1'b0; 1284 | if (NMI_s == 1'b1 && Prefix == 2'b00 ) 1285 | begin 1286 | NMICycle <= #1 1'b1; 1287 | IntE_FF1 <= #1 1'b0; 1288 | end 1289 | else if ((IntE_FF1 == 1'b1 && INT_s == 1'b1) && Prefix == 2'b00 && SetEI == 1'b0 ) 1290 | begin 1291 | IntCycle <= #1 1'b1; 1292 | IntE_FF1 <= #1 1'b0; 1293 | IntE_FF2 <= #1 1'b0; 1294 | end 1295 | end 1296 | else 1297 | begin 1298 | mcycle <= #1 { mcycle[5:0], mcycle[6] }; 1299 | end 1300 | end 1301 | end 1302 | else 1303 | begin // verilog has no "nor" operator 1304 | if ( ~(Auto_Wait == 1'b1 && Auto_Wait_t2 == 1'b0) && 1305 | ~(IOWait == 1 && iorq_i == 1'b1 && Auto_Wait_t1 == 1'b0) ) 1306 | begin 1307 | tstate <= #1 { tstate[5:0], tstate[6] }; 1308 | end 1309 | end 1310 | end 1311 | if (tstate[0]) 1312 | begin 1313 | m1_n <= #1 1'b0; 1314 | end 1315 | end 1316 | end 1317 | end 1318 | 1319 | always @(/*AUTOSENSE*/BTR_r or DI_Reg or IncDec_16 or JumpE or PC 1320 | or RegBusA or RegBusC or SP or tstate) 1321 | begin 1322 | if (JumpE == 1'b1 ) 1323 | begin 1324 | PC16_B = { {8{DI_Reg[7]}}, DI_Reg }; 1325 | end 1326 | else if (BTR_r == 1'b1 ) 1327 | begin 1328 | PC16_B = -2; 1329 | end 1330 | else 1331 | begin 1332 | PC16_B = 1; 1333 | end 1334 | 1335 | if (tstate[3]) 1336 | begin 1337 | SP16_A = RegBusC; 1338 | SP16_B = { {8{DI_Reg[7]}}, DI_Reg }; 1339 | end 1340 | else 1341 | begin 1342 | // suspect that ID16 and SP16 could be shared 1343 | SP16_A = SP; 1344 | 1345 | if (IncDec_16[3] == 1'b1) 1346 | SP16_B = -1; 1347 | else 1348 | SP16_B = 1; 1349 | end 1350 | 1351 | if (IncDec_16[3]) 1352 | ID16_B = -1; 1353 | else 1354 | ID16_B = 1; 1355 | 1356 | ID16 = RegBusA + ID16_B; 1357 | PC16 = PC + PC16_B; 1358 | SP16 = SP16_A + SP16_B; 1359 | end // always @ * 1360 | 1361 | 1362 | always @(/*AUTOSENSE*/IntCycle or NMICycle or mcycle) 1363 | begin 1364 | Auto_Wait = 1'b0; 1365 | if (IntCycle == 1'b1 || NMICycle == 1'b1 ) 1366 | begin 1367 | if (mcycle[0] ) 1368 | begin 1369 | Auto_Wait = 1'b1; 1370 | end 1371 | end 1372 | end // always @ * 1373 | 1374 | // synopsys dc_script_begin 1375 | // set_attribute current_design "revision" "$Id: tv80_core.v,v 1.5 2005-01-26 18:55:47 ghutchis Exp $" -type string -quiet 1376 | // synopsys dc_script_end 1377 | endmodule // T80 1378 | 1379 | -------------------------------------------------------------------------------- /src/tv80/rtl/core/tv80_reg.v: -------------------------------------------------------------------------------- 1 | // 2 | // TV80 8-Bit Microprocessor Core 3 | // Based on the VHDL T80 core by Daniel Wallner (jesus@opencores.org) 4 | // 5 | // Copyright (c) 2004 Guy Hutchison (ghutchis@opencores.org) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a 8 | // copy of this software and associated documentation files (the "Software"), 9 | // to deal in the Software without restriction, including without limitation 10 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | // and/or sell copies of the Software, and to permit persons to whom the 12 | // Software is furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included 15 | // in all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | module tv80_reg (/*AUTOARG*/ 26 | // Outputs 27 | DOBH, DOAL, DOCL, DOBL, DOCH, DOAH, BC, DE, HL, 28 | // Inputs 29 | AddrC, AddrA, AddrB, DIH, DIL, clk, CEN, WEH, WEL 30 | ); 31 | input [2:0] AddrC; 32 | output [7:0] DOBH; 33 | input [2:0] AddrA; 34 | input [2:0] AddrB; 35 | input [7:0] DIH; 36 | output [7:0] DOAL; 37 | output [7:0] DOCL; 38 | input [7:0] DIL; 39 | output [7:0] DOBL; 40 | output [7:0] DOCH; 41 | output [7:0] DOAH; 42 | input clk, CEN, WEH, WEL; 43 | 44 | output [15:0] BC; 45 | output [15:0] DE; 46 | output [15:0] HL; 47 | 48 | reg [7:0] RegsH [0:7]; 49 | reg [7:0] RegsL [0:7]; 50 | 51 | always @(posedge clk) 52 | begin 53 | if (CEN) 54 | begin 55 | if (WEH) RegsH[AddrA] <= DIH; 56 | if (WEL) RegsL[AddrA] <= DIL; 57 | end 58 | end 59 | 60 | assign DOAH = RegsH[AddrA]; 61 | assign DOAL = RegsL[AddrA]; 62 | assign DOBH = RegsH[AddrB]; 63 | assign DOBL = RegsL[AddrB]; 64 | assign DOCH = RegsH[AddrC]; 65 | assign DOCL = RegsL[AddrC]; 66 | 67 | // break out ram bits for waveform debug 68 | wire [7:0] H = RegsH[2]; 69 | wire [7:0] L = RegsL[2]; 70 | 71 | assign BC = { RegsH[0], RegsL[0] }; 72 | assign DE = { RegsH[1], RegsL[1] }; 73 | assign HL = { RegsH[2], RegsL[2] }; 74 | 75 | // synopsys dc_script_begin 76 | // set_attribute current_design "revision" "$Id: tv80_reg.v,v 1.1 2004-05-16 17:39:57 ghutchis Exp $" -type string -quiet 77 | // synopsys dc_script_end 78 | endmodule 79 | 80 | -------------------------------------------------------------------------------- /src/tv80/rtl/core/tv80n.v: -------------------------------------------------------------------------------- 1 | // 2 | // TV80 8-Bit Microprocessor Core 3 | // Based on the VHDL T80 core by Daniel Wallner (jesus@opencores.org) 4 | // 5 | // Copyright (c) 2004 Guy Hutchison (ghutchis@opencores.org) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a 8 | // copy of this software and associated documentation files (the "Software"), 9 | // to deal in the Software without restriction, including without limitation 10 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | // and/or sell copies of the Software, and to permit persons to whom the 12 | // Software is furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included 15 | // in all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | // Negative-edge based wrapper allows memory wait_n signal to work 26 | // correctly without resorting to asynchronous logic. 27 | 28 | module tv80n (/*AUTOARG*/ 29 | // Outputs 30 | m1_n, mreq_n, iorq_n, rd_n, wr_n, rfsh_n, halt_n, busak_n, A, do, 31 | // Inputs 32 | reset_n, clk, wait_n, int_n, nmi_n, busrq_n, di 33 | ); 34 | 35 | parameter Mode = 0; // 0 => Z80, 1 => Fast Z80, 2 => 8080, 3 => GB 36 | parameter T2Write = 0; // 0 => wr_n active in T3, /=0 => wr_n active in T2 37 | parameter IOWait = 1; // 0 => Single cycle I/O, 1 => Std I/O cycle 38 | 39 | 40 | input reset_n; 41 | input clk; 42 | input wait_n; 43 | input int_n; 44 | input nmi_n; 45 | input busrq_n; 46 | output m1_n; 47 | output mreq_n; 48 | output iorq_n; 49 | output rd_n; 50 | output wr_n; 51 | output rfsh_n; 52 | output halt_n; 53 | output busak_n; 54 | output [15:0] A; 55 | input [7:0] di; 56 | output [7:0] do; 57 | 58 | reg mreq_n; 59 | reg iorq_n; 60 | reg rd_n; 61 | reg wr_n; 62 | reg nxt_mreq_n; 63 | reg nxt_iorq_n; 64 | reg nxt_rd_n; 65 | reg nxt_wr_n; 66 | 67 | wire cen; 68 | wire intcycle_n; 69 | wire no_read; 70 | wire write; 71 | wire iorq; 72 | reg [7:0] di_reg; 73 | wire [6:0] mcycle; 74 | wire [6:0] tstate; 75 | 76 | assign cen = 1; 77 | 78 | tv80_core #(Mode, IOWait) i_tv80_core 79 | ( 80 | .cen (cen), 81 | .m1_n (m1_n), 82 | .iorq (iorq), 83 | .no_read (no_read), 84 | .write (write), 85 | .rfsh_n (rfsh_n), 86 | .halt_n (halt_n), 87 | .wait_n (wait_n), 88 | .int_n (int_n), 89 | .nmi_n (nmi_n), 90 | .reset_n (reset_n), 91 | .busrq_n (busrq_n), 92 | .busak_n (busak_n), 93 | .clk (clk), 94 | .IntE (), 95 | .stop (), 96 | .A (A), 97 | .dinst (di), 98 | .di (di_reg), 99 | .do (do), 100 | .mc (mcycle), 101 | .ts (tstate), 102 | .intcycle_n (intcycle_n) 103 | ); 104 | 105 | always @* 106 | begin 107 | nxt_mreq_n = 1; 108 | nxt_rd_n = 1; 109 | nxt_iorq_n = 1; 110 | nxt_wr_n = 1; 111 | 112 | if (mcycle[0]) 113 | begin 114 | if (tstate[1] || tstate[2]) 115 | begin 116 | nxt_rd_n = ~ intcycle_n; 117 | nxt_mreq_n = ~ intcycle_n; 118 | nxt_iorq_n = intcycle_n; 119 | end 120 | end // if (mcycle[0]) 121 | else 122 | begin 123 | if ((tstate[1] || tstate[2]) && !no_read && !write) 124 | begin 125 | nxt_rd_n = 1'b0; 126 | nxt_iorq_n = ~ iorq; 127 | nxt_mreq_n = iorq; 128 | end 129 | if (T2Write == 0) 130 | begin 131 | if (tstate[2] && write) 132 | begin 133 | nxt_wr_n = 1'b0; 134 | nxt_iorq_n = ~ iorq; 135 | nxt_mreq_n = iorq; 136 | end 137 | end 138 | else 139 | begin 140 | if ((tstate[1] || (tstate[2] && !wait_n)) && write) 141 | begin 142 | nxt_wr_n = 1'b0; 143 | nxt_iorq_n = ~ iorq; 144 | nxt_mreq_n = iorq; 145 | end 146 | end // else: !if(T2write == 0) 147 | end // else: !if(mcycle[0]) 148 | end // always @ * 149 | 150 | always @(negedge clk) 151 | begin 152 | if (!reset_n) 153 | begin 154 | rd_n <= #1 1'b1; 155 | wr_n <= #1 1'b1; 156 | iorq_n <= #1 1'b1; 157 | mreq_n <= #1 1'b1; 158 | end 159 | else 160 | begin 161 | rd_n <= #1 nxt_rd_n; 162 | wr_n <= #1 nxt_wr_n; 163 | iorq_n <= #1 nxt_iorq_n; 164 | mreq_n <= #1 nxt_mreq_n; 165 | end // else: !if(!reset_n) 166 | end // always @ (posedge clk or negedge reset_n) 167 | 168 | always @(posedge clk) 169 | begin 170 | if (!reset_n) 171 | begin 172 | di_reg <= #1 0; 173 | end 174 | else 175 | begin 176 | if (tstate[2] && wait_n == 1'b1) 177 | di_reg <= #1 di; 178 | end // else: !if(!reset_n) 179 | end // always @ (posedge clk) 180 | 181 | endmodule // t80n 182 | 183 | -------------------------------------------------------------------------------- /src/tv80/rtl/core/tv80s.v: -------------------------------------------------------------------------------- 1 | // 2 | // TV80 8-Bit Microprocessor Core 3 | // Based on the VHDL T80 core by Daniel Wallner (jesus@opencores.org) 4 | // 5 | // Copyright (c) 2004 Guy Hutchison (ghutchis@opencores.org) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a 8 | // copy of this software and associated documentation files (the "Software"), 9 | // to deal in the Software without restriction, including without limitation 10 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | // and/or sell copies of the Software, and to permit persons to whom the 12 | // Software is furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included 15 | // in all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | module tv80s (/*AUTOARG*/ 26 | // Outputs 27 | m1_n, mreq_n, iorq_n, rd_n, wr_n, rfsh_n, halt_n, busak_n, A, do, 28 | BC, DE, HL, ACC, F, PC, SP, IntE_FF1, IntE_FF2, INT_s, 29 | // Inputs 30 | reset_n, clk, wait_n, int_n, nmi_n, busrq_n, di 31 | ); 32 | 33 | parameter Mode = 3; // 0 => Z80, 1 => Fast Z80, 2 => 8080, 3 => GB 34 | parameter T2Write = 1; // 0 => wr_n active in T3, /=0 => wr_n active in T2 35 | parameter IOWait = 1; // 0 => Single cycle I/O, 1 => Std I/O cycle 36 | 37 | 38 | input reset_n; 39 | input clk; 40 | input wait_n; 41 | input int_n; 42 | input nmi_n; 43 | input busrq_n; 44 | output m1_n; 45 | output mreq_n; 46 | output iorq_n; 47 | output rd_n; 48 | output wr_n; 49 | output rfsh_n; 50 | output halt_n; 51 | output busak_n; 52 | output [15:0] A; 53 | input [7:0] di; 54 | output [7:0] do; 55 | output [15:0] BC; 56 | output [15:0] DE; 57 | output [15:0] HL; 58 | output [7:0] F; 59 | output [7:0] ACC; 60 | output [15:0] PC; 61 | output [15:0] SP; 62 | output IntE_FF1; 63 | output IntE_FF2; 64 | output INT_s; 65 | 66 | reg mreq_n; 67 | reg iorq_n; 68 | reg rd_n; 69 | reg wr_n; 70 | 71 | wire cen; 72 | wire intcycle_n; 73 | wire no_read; 74 | wire write; 75 | wire iorq; 76 | reg [7:0] di_reg; 77 | wire [6:0] mcycle; 78 | wire [6:0] tstate; 79 | 80 | assign cen = 1; 81 | 82 | tv80_core #(Mode, IOWait) i_tv80_core 83 | ( 84 | .cen (cen), 85 | .m1_n (m1_n), 86 | .iorq (iorq), 87 | .no_read (no_read), 88 | .write (write), 89 | .rfsh_n (rfsh_n), 90 | .halt_n (halt_n), 91 | .wait_n (wait_n), 92 | .int_n (int_n), 93 | .nmi_n (nmi_n), 94 | .reset_n (reset_n), 95 | .busrq_n (busrq_n), 96 | .busak_n (busak_n), 97 | .clk (clk), 98 | .IntE (), 99 | .stop (), 100 | .A (A), 101 | .dinst (di), 102 | .di (di_reg), 103 | .do (do), 104 | .mc (mcycle), 105 | .ts (tstate), 106 | .intcycle_n (intcycle_n), 107 | .BC (BC), 108 | .DE (DE), 109 | .HL (HL), 110 | .F (F), 111 | .ACC (ACC), 112 | .PC (PC), 113 | .SP (SP), 114 | .IntE_FF1(IntE_FF1), 115 | .IntE_FF2(IntE_FF2), 116 | .INT_s(INT_s) 117 | ); 118 | 119 | always @(posedge clk) 120 | begin 121 | if (!reset_n) 122 | begin 123 | rd_n <= #1 1'b1; 124 | wr_n <= #1 1'b1; 125 | iorq_n <= #1 1'b1; 126 | mreq_n <= #1 1'b1; 127 | di_reg <= #1 0; 128 | end 129 | else 130 | begin 131 | rd_n <= #1 1'b1; 132 | wr_n <= #1 1'b1; 133 | iorq_n <= #1 1'b1; 134 | mreq_n <= #1 1'b1; 135 | if (mcycle[0]) 136 | begin 137 | if (tstate[1] || (tstate[2] && wait_n == 1'b0)) 138 | begin 139 | rd_n <= #1 ~ intcycle_n; 140 | mreq_n <= #1 ~ intcycle_n; 141 | iorq_n <= #1 intcycle_n; 142 | end 143 | `ifdef TV80_REFRESH 144 | if (tstate[3]) 145 | mreq_n <= #1 1'b0; 146 | `endif 147 | end // if (mcycle[0]) 148 | else 149 | begin 150 | if ((tstate[1] || (tstate[2] && wait_n == 1'b0)) && no_read == 1'b0 && write == 1'b0) 151 | begin 152 | rd_n <= #1 1'b0; 153 | iorq_n <= #1 ~ iorq; 154 | mreq_n <= #1 iorq; 155 | end 156 | if (T2Write == 0) 157 | begin 158 | if (tstate[2] && write == 1'b1) 159 | begin 160 | wr_n <= #1 1'b0; 161 | iorq_n <= #1 ~ iorq; 162 | mreq_n <= #1 iorq; 163 | end 164 | end 165 | else 166 | begin 167 | if ((tstate[1] || (tstate[2] && wait_n == 1'b0)) && write == 1'b1) 168 | begin 169 | wr_n <= #1 1'b0; 170 | iorq_n <= #1 ~ iorq; 171 | mreq_n <= #1 iorq; 172 | end 173 | end // else: !if(T2write == 0) 174 | 175 | end // else: !if(mcycle[0]) 176 | 177 | if (tstate[2] && wait_n == 1'b1) 178 | di_reg <= #1 di; 179 | end // else: !if(!reset_n) 180 | end // always @ (posedge clk or negedge reset_n) 181 | 182 | endmodule // t80s 183 | 184 | -------------------------------------------------------------------------------- /src/util/async_mem.v: -------------------------------------------------------------------------------- 1 | module async_mem (/*AUTOARG*/ 2 | // Outputs 3 | rd_data, 4 | // Inputs 5 | wr_clk, wr_data, wr_cs, addr, rd_cs 6 | ); 7 | 8 | parameter asz = 15, 9 | depth = 32768; 10 | 11 | input wr_clk; 12 | input [7:0] wr_data; 13 | input wr_cs; 14 | 15 | input [asz-1:0] addr; 16 | inout [7:0] rd_data; 17 | input rd_cs; 18 | 19 | reg [7:0] mem [0:depth-1]; 20 | 21 | always @(posedge wr_clk) 22 | begin 23 | if (wr_cs) 24 | mem[addr] <= #1 wr_data; 25 | end 26 | 27 | assign rd_data = (rd_cs) ? mem[addr] : {8{1'bz}}; 28 | 29 | endmodule // async_mem 30 | -------------------------------------------------------------------------------- /src/util/async_mem2.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | `timescale 1ns / 1ps 3 | 4 | module async_mem2( 5 | input wire clkA, 6 | input wire clkB, 7 | input wire [asz-1:0] addrA, 8 | input wire [asz-1:0] addrB, 9 | input wire wr_csA, 10 | input wire wr_csB, 11 | input wire [7:0] wr_dataA, 12 | input wire [7:0] wr_dataB, 13 | output wire [7:0] rd_dataA, 14 | output wire [7:0] rd_dataB 15 | ); 16 | 17 | parameter asz = 15; 18 | parameter depth = 32768; 19 | 20 | reg [7:0] mem [0:depth-1]; 21 | 22 | always @(posedge clkA) begin 23 | if (wr_csA) 24 | mem[addrA] <= wr_dataA; 25 | end 26 | 27 | always @(posedge clkB) begin 28 | if (wr_csB) 29 | mem[addrB] <= wr_dataB; 30 | end 31 | 32 | assign rd_dataA = mem[addrA]; 33 | assign rd_dataB = mem[addrB]; 34 | 35 | endmodule 36 | -------------------------------------------------------------------------------- /src/util/debounce.v: -------------------------------------------------------------------------------- 1 | module debounce (reset, clock, noisy, clean); 2 | parameter DELAY = 333333; // .01 sec with a 33.3333Mhz clock 3 | input reset, clock, noisy; 4 | output clean; 5 | 6 | reg [18:0] count; 7 | reg new, clean; 8 | 9 | always @(posedge clock) 10 | if (reset) 11 | begin 12 | count <= 0; 13 | new <= noisy; 14 | clean <= noisy; 15 | end 16 | else if (noisy != new) 17 | begin 18 | new <= noisy; 19 | count <= 0; 20 | end 21 | else if (count == DELAY) 22 | clean <= new; 23 | else 24 | count <= count+1; 25 | 26 | endmodule 27 | -------------------------------------------------------------------------------- /src/util/divider.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | `timescale 1ns / 1ps 3 | 4 | module divider #(parameter DELAY=50000000) ( 5 | input wire reset, 6 | input wire clock, 7 | output wire enable); 8 | 9 | reg [31:0] count; 10 | wire [31:0] next_count; 11 | 12 | always @(posedge clock) 13 | begin 14 | if (reset) 15 | count <= 32'b0; 16 | else 17 | count <= next_count; 18 | end 19 | 20 | assign enable = (count == DELAY - 1) ? 1'b1 : 1'b0; 21 | assign next_count = (count == DELAY - 1) ? 32'b0 : count + 1; 22 | 23 | endmodule 24 | --------------------------------------------------------------------------------