├── 3-plus-1.317053-01.bin ├── 3-plus-1.317054-01.bin ├── 318004-05.u24 ├── 318006-01.u23 ├── Diag264K_PAL.bin ├── Diag264_pal.bin ├── LICENSE ├── Plus4.v ├── Plus4_testbench.v ├── README.md ├── T65.vhd ├── T65_ALU.vhd ├── T65_MCode.vhd ├── T65_Pack.vhd ├── TEDwingPro.ucf ├── _config.yml ├── addrom.c ├── addrom.exe ├── basic.bin ├── basic_rom.v ├── bin2hex.pl ├── bitmerge.py ├── bootrom.wcfg ├── bootstrap.v ├── bootstrap.wcfg ├── boottest.v ├── boottest.wcfg ├── boottestrom.bin ├── c16_keymatrix.v ├── colors_to_rgb.v ├── configrom.bin ├── configrom_ntsc.bin ├── configrom_pal.bin ├── cpu65xx_e.vhd ├── cpu65xx_fast.vhd ├── fakerom.bin ├── fakerom2.bin ├── flashtest.v ├── flashtest.wcfg ├── function_high.bin ├── function_low.bin ├── kernal.318005-05.bin ├── kernal_ntsc.bin ├── kernal_pal.bin ├── kernal_rom.v ├── mos6529.v ├── mos8501.v ├── mos8501_t65.v ├── mt48lc4m16a2.v ├── plus4.wcfg ├── plus4_2.wcfg ├── plus4palroms.bin ├── ps2receiver.v ├── ram.v ├── rompack.bin ├── sdram_clk.v ├── sdram_controller.v ├── spiflash.v ├── ted.v └── testrompack.bin /3-plus-1.317053-01.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/3-plus-1.317053-01.bin -------------------------------------------------------------------------------- /3-plus-1.317054-01.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/3-plus-1.317054-01.bin -------------------------------------------------------------------------------- /318004-05.u24: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/318004-05.u24 -------------------------------------------------------------------------------- /318006-01.u23: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/318006-01.u23 -------------------------------------------------------------------------------- /Diag264K_PAL.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/Diag264K_PAL.bin -------------------------------------------------------------------------------- /Diag264_pal.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/Diag264_pal.bin -------------------------------------------------------------------------------- /Plus4.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Copyright 2013-2016 Istvan Hegedus 4 | // 5 | // FPGATED is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // FPGATED is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | // 19 | // Create Date: 12:02:05 16/09/2016 20 | // Design Name: Commodore Plus 4 in an FPGA 21 | // Module Name: PLUS4.v 22 | // Project Name: FPGATED Papilio Pro edition 23 | // 24 | // Description: 25 | // This module provides the top level framework for FPGATED. It implements a Commodore Plus 4 computer without expansion port. 26 | // It is written for Papilio FPGATED wing 1.x but can be easily modified for any other platforms. 27 | // 28 | // Revision history: 29 | // 0.1 16.09.2016 Commodore Plus 4 shell created, SDRAM based memory (Papilio Pro) 30 | // 0.2 15.12.2016 Bootstrap function implemented, loads ROMs to SDRAM 31 | // 1.0 27.03.2019 Released version. Onboard SPI flash access, config kernal, multiple ROM versions 32 | // 33 | // Comments: This module is based on c16.v which is part of the original FPGATED design and it makes use of Papilio Pro platform's sdram. 34 | // Using the sdram of Papilio Pro more ROM can be used thus it is possible to implement a Commodore Plus 4. 35 | // Note however that it is not a complete Plus 4 system; expansion port,user port and ACIA is not yet implemented 36 | // This code is specifically written for Papilio Pro platform with TEDWing extension module. It can be easily modified for other 37 | // platforms. Minimum requirement is however: onboard sdram, SPI flash with space for ROM images, Spartan 3E or Spartan 6 FPGA. 38 | // 39 | ////////////////////////////////////////////////////////////////////////////////// 40 | 41 | module Plus4( 42 | input wire CLK32, 43 | input wire RESET, 44 | output wire HSYNC, 45 | output wire VSYNC, 46 | output wire [3:0] RED, 47 | output wire [3:0] GREEN, 48 | output wire [3:0] BLUE, 49 | input PS2DAT, 50 | input PS2CLK, 51 | output IEC_DATAOUT, 52 | input IEC_DATAIN, 53 | output IEC_CLKOUT, 54 | input IEC_CLKIN, 55 | output IEC_ATNOUT, 56 | // input IEC_ATNIN, 57 | output IEC_RESET, 58 | output AUDIO_L, 59 | output AUDIO_R, 60 | // input RGBS, 61 | 62 | // SDRAM signals on Papilio Pro board 63 | output wire [11:0] SDRAM_ADDR, 64 | inout wire [15:0] SDRAM_DATA, 65 | output wire SDRAM_DQML, 66 | output wire SDRAM_DQMH, 67 | output wire [1:0] SDRAM_BA, 68 | output wire SDRAM_nWE, 69 | output wire SDRAM_nCAS, 70 | output wire SDRAM_nRAS, 71 | output wire SDRAM_CS, 72 | output wire SDRAM_CLK, 73 | output wire SDRAM_CKE, 74 | 75 | // FLASH chip signals on Papilio Pro board 76 | output wire FLASH_CS, 77 | output wire FLASH_CK, 78 | output wire FLASH_SI, 79 | input wire FLASH_SO 80 | ); 81 | 82 | wire CLK28; // This is the main system clock generated by DCM. It must be 4*dot clk so 28.375152MHz for PAL (1.6*PAL system's clock) and 28.63636 for NTSC (2*NTSC system's clock) 83 | wire phi0; 84 | reg phi0_prev; 85 | wire [15:0] plus4_addr; 86 | wire [15:0] ted_addr; 87 | wire [15:0] cpu_addr; 88 | wire [15:0] boot_addr; 89 | wire [5:0] boot_addrext; 90 | wire [5:0] plus4_addrext; 91 | wire [7:0] boot_data; 92 | wire [7:0] config_data; 93 | wire [7:0] plus4_data,ted_data,ram_data,cpu_data,port_in,port_out,keyport_data; 94 | wire [7:0] keyboard_row,kbus,key; 95 | wire [7:0] keyscancode; 96 | wire keyreceived; 97 | wire [6:0] plus4_color; 98 | wire mux; 99 | wire cpuenable; 100 | wire aec; 101 | wire rdy; 102 | wire sound; 103 | wire FD0x,FD1x,FD2x,FD3x,FDDx,FD9x; 104 | reg FDDx_prev,FD9x_prev; 105 | wire phi2; 106 | wire KERN; 107 | wire raminitdone; 108 | 109 | reg [3:0] romselect=0; // Plus4/C16 motherboard U21 ROM selector register 110 | reg [3:0] Kernalver=4'h0; // Kernal ROM alternative version selector 1-16 111 | reg [3:0] Basicver=4'h0; // Basic ROM alternative version selector 1-16 112 | reg [3:0] FunctionLver=4'h0; // Function ROM alternative version selector 1-16 (Low) 113 | reg [3:0] FunctionHver=4'h0; // Function ROM alternative version selector 1-16 (High) 114 | reg [3:0] C1Lver=4'h0; // Cartridge ROM1 alternative version selector 1-16 (Low) 115 | reg [3:0] C1Hver=4'h0; // Cartridge ROM1 alternative version selector 1-16 (Low) 116 | reg [3:0] C2Lver=4'h0; // Cartridge ROM2 alternative version selector 1-16 (Low) 117 | reg [3:0] C2Hver=4'h0; // Cartridge ROM2 alternative version selector 1-16 (High) 118 | reg [3:0] romversion; // Addressed ROM's version (1-16) 119 | reg [5:0] romaddrext; // ROM address extension 4M ROM area (see sdram controller) 120 | reg [5:0] ramaddrext=6'b000000; // RAM address extension 4M RAM (Hannes/Csory) 121 | reg romconfig=0; // ROM config mode enables a special kernal to configure ROM versions 122 | reg romconfreset=0; 123 | reg [7:0] romreg_data=8'hff; 124 | reg [7:0] plus4_datalatch=8'h0; 125 | reg sreset=1'b1; 126 | reg [23:0] resetcounter=24'b0; 127 | reg [15:0] plus4_addrlatch=16'b0; 128 | wire keyreset; 129 | wire key_esc; 130 | wire [4:0] joy0port,joy1port; // keyboard emulated joystick ports 131 | wire [4:0] joy0emu,joy1emu; // keyboard emulated joystick ports masked by select lines 132 | wire RAS; 133 | wire CAS; 134 | wire RW; 135 | wire cs0; 136 | wire cs1; 137 | wire [35:0] CONTROL0; 138 | wire [3:0] cycle; 139 | reg pla_arm; 140 | 141 | wire boot_cs0; 142 | wire boot_cs1; 143 | wire boot_rw; 144 | wire boot_done; 145 | wire cfg_done; 146 | wire sdram_cs0; 147 | wire sdram_cs1; 148 | wire sdram_rw; 149 | wire sdram_cas; 150 | wire [15:0] ram_addr; 151 | wire [5:0] sdram_addrext; 152 | wire [7:0] sdram_datain; 153 | wire flash_clken; 154 | wire trigger; 155 | 156 | 157 | 158 | // Instantiate the clock module, produce 28.375 Mhz clock for PAL Plus4 159 | palclockgen PAL_PLL 160 | (// Clock in ports 161 | .CLK_IN1(CLK32), // Papilio Pro platform's clock in 162 | // Clock out ports 163 | .CLK_OUT1(CLK28) // 28 Mhz clock 164 | // Status and control signals 165 | ); // IN 166 | 167 | 168 | // Generate SDRAM clock signal. It provides a 180 degree shifted clk from FPGA global clock 169 | // The module used here is Xilinx specific, for other FPGA vendors use different method to generate SDRAM_CLK 170 | // See FPGA documentation on how to generate a clock signal on a user IO pin 171 | sdram_clk ram_clk ( 172 | .clk(CLK28), 173 | .sdram_clk(SDRAM_CLK) 174 | ); 175 | 176 | // 8501 CPU 177 | /* mos8501 cpu ( // 8501 using FPGA64 cpu core 178 | .clk(CLK28), 179 | .reset(sreset), 180 | .enable(cpuenable), 181 | .irq_n(irq_n), 182 | .data_in(plus4_data), 183 | .data_out(cpu_data), 184 | .address(cpu_addr), 185 | .gate_in(mux), 186 | .rw(RW), // rw=high read, rw=low write 187 | .port_in(port_in), 188 | .port_out(port_out), 189 | .rdy(rdy), 190 | .aec(aec) 191 | ); */ 192 | 193 | mos8501_t65 cpu ( // 8501 using T65 core 194 | .clk(CLK28), 195 | .reset(sreset), 196 | .enable(cpuenable), 197 | .irq_n(irq_n), 198 | .data_in(plus4_data), 199 | .data_out(cpu_data), 200 | .address(cpu_addr), 201 | .gate_in(mux), 202 | .rw(RW), // rw=high read, rw=low write 203 | .port_in(port_in), 204 | .port_out(port_out), 205 | .rdy(rdy), 206 | .aec(aec) 207 | ); 208 | 209 | // TED 8360 instance 210 | 211 | ted mos8360( 212 | .clk(CLK28), 213 | .addr_in(plus4_addr), 214 | .addr_out(ted_addr), 215 | .data_in(plus4_data), 216 | .data_out(ted_data), 217 | .rw(RW), 218 | .cpuclk(phi0), // phi0 is used for a real external 8501 CPU and internal/external PLA 219 | .color(plus4_color), 220 | .csync(HSYNC), 221 | .irq(irq_n), 222 | .ba(rdy), 223 | .mux(mux), 224 | .ras(RAS), 225 | .cas(CAS), 226 | .cs0(cs0), 227 | .cs1(cs1), 228 | .aec(aec), 229 | .k(kbus), 230 | .snd(sound), 231 | .cpuenable(cpuenable), 232 | .pal() 233 | ); 234 | 235 | // SDRAM controller 236 | sdram_controller ram_ctrl( 237 | .sdram_addr(SDRAM_ADDR), 238 | .sdram_data(SDRAM_DATA), 239 | .sdram_dqm({SDRAM_DQMH,SDRAM_DQML}), 240 | .sdram_ba(SDRAM_BA), 241 | .sdram_we(SDRAM_nWE), 242 | .sdram_ras(SDRAM_nRAS), 243 | .sdram_cas(SDRAM_nCAS), 244 | .sdram_cs(SDRAM_CS), 245 | .sdram_cke(SDRAM_CKE), 246 | .clk(CLK28), 247 | .plus4_addr(ram_addr), 248 | .plus4_addrext(sdram_addrext), 249 | .plus4_ras(RAS), 250 | .plus4_cas(sdram_cas), 251 | .plus4_rw(sdram_rw), 252 | .plus4_cs0(sdram_cs0), 253 | .plus4_cs1(sdram_cs1), 254 | .ram_datain(sdram_datain), 255 | .ram_dataout(ram_data), 256 | .initdone(raminitdone) 257 | ); 258 | 259 | // SDRAM connection multiplexers 260 | 261 | assign ram_addr=(cfg_done)?plus4_addr:boot_addr; 262 | assign sdram_addrext=(boot_done)?plus4_addrext:boot_addrext; 263 | assign sdram_cs0=(boot_done)?cs0:boot_cs0; 264 | assign sdram_cs1=(boot_done)?cs1:boot_cs1; 265 | assign sdram_rw=(boot_done)?RW:boot_rw; 266 | assign sdram_datain=(boot_done)?plus4_data:boot_data; 267 | assign sdram_cas=(boot_done)?CAS:1'b1; 268 | 269 | assign plus4_addrext=(~cs0|~cs1)?romaddrext:ramaddrext; // set ROM or RAM address extension 270 | 271 | 272 | // Color decoder to 12bit RGB 273 | 274 | colors_to_rgb colordecode ( 275 | .clk(CLK28), 276 | .color(plus4_color), 277 | .red(RED), 278 | .green(GREEN), 279 | .blue(BLUE) 280 | ); 281 | 282 | // keyboard part 283 | 284 | ps2receiver ps2rcv( 285 | .clk(CLK28), 286 | .ps2_clk(PS2CLK), 287 | .ps2_data(PS2DAT), 288 | .rx_done(keyreceived), 289 | .ps2scancode(keyscancode) 290 | ); 291 | 292 | c16_keymatrix keyboard( 293 | .clk(CLK28), 294 | .scancode(keyscancode), 295 | .receiveflag(keyreceived), 296 | .row(keyboard_row), 297 | .kbus(key), 298 | .keyreset(keyreset), 299 | .joy0(joy0port), 300 | .joy1(joy1port), 301 | .esc(key_esc) 302 | ); 303 | 304 | mos6529 keyport( 305 | .clk(CLK28), 306 | .data_in(plus4_data), 307 | .data_out(keyport_data), 308 | .port_in(keyboard_row), // keyport 6529 in C16/Plus4 is unidirectional however if we read it the last written data is read back so we feed back its output. 309 | .port_out(keyboard_row), 310 | .rw(RW), 311 | .cs(FD3x) 312 | ); 313 | 314 | // Bootstrap uploads ROM images and CFG registers from Papilio Pro board's SPI flash chip to SDRAM 315 | 316 | bootstrap boot( 317 | // SPI flash signals 318 | .flash_cs(FLASH_CS), 319 | .flash_ck(FLASH_CK), 320 | .flash_si(FLASH_SI), 321 | .flash_so(FLASH_SO), 322 | // generated ROM signals 323 | .cs0(boot_cs0), 324 | .cs1(boot_cs1), 325 | .rw_out(boot_rw), 326 | .addr_out(boot_addr), 327 | .addr_ext(boot_addrext), 328 | .data_out(boot_data), 329 | 330 | .reset(1'b0), 331 | .boot_enable(raminitdone), 332 | .boot_done(boot_done), 333 | .cfg_done(cfg_done), 334 | .phi(phi0), 335 | .clk(CLK28), 336 | // signals for SPI FLASH communication via Plus4 bus 337 | .cs(boot_cs), 338 | .rw_in(RW), 339 | .data_in(plus4_data), 340 | .addr_in(plus4_addr[2:0]) 341 | ); 342 | 343 | 344 | 345 | assign AUDIO_R=sound; 346 | assign AUDIO_L=sound; 347 | assign VSYNC=1'b1; // set scart mode to RGB for TV 348 | 349 | // PLA functions derived from TED System Hardware Manual equation table 350 | 351 | always @(posedge CLK28) begin // arm function needs to be registered 352 | pla_arm<=mux|(~RAS&phi0&pla_arm); 353 | end 354 | 355 | assign KERN=(plus4_addr[15:8]==8'hfc)?1'b1:1'b0; 356 | assign FD3x=((plus4_addr[15:4]==12'hfd3) & pla_arm & phi0 & ~RAS)?1'b1:1'b0; // KEYPORT 357 | assign FDDx=((plus4_addr[15:4]==12'hfdd) & pla_arm & phi0 & ~RAS)?1'b1:1'b0; // ADDR CLK 358 | assign FD0x=((plus4_addr[15:4]==12'hfd0) & phi0)?1'b1:1'b0; // 6551 359 | assign FD1x=((plus4_addr[15:4]==12'hfd1) & pla_arm & phi0 & ~RAS)?1'b1:1'b0; // 6529 360 | assign phi2=~RAS & pla_arm & phi0; // PHI2 CLK not used at the moment 361 | assign FD2x=((plus4_addr[15:4]==12'hfd2) & phi0 & ~RAS); //SPEECH $FD2X is not used in Plus4 (used for Commodore 364) 362 | assign FD9x=((plus4_addr[15:4]==12'hfd9) & phi0 & ~RAS); // FPGATED configuration register 363 | 364 | // ROM MMU 365 | 366 | always @(posedge CLK28) begin // Plus4 motherboard ROM selector register (U21) 367 | FDDx_prev<=FDDx; 368 | if(sreset) 369 | romselect<=4'h0; 370 | else if(~FDDx_prev & FDDx & ~RW) 371 | romselect<=plus4_addr[3:0]; 372 | end 373 | 374 | always @* begin // generating ROM address extension for different ROM versions 375 | if(~cs0) begin // low ROM 376 | case(romselect[1:0]) // based on romselect register set romversion to the active rom version (version 1-16) 377 | 2'b00: romversion=Basicver; 378 | 2'b01: romversion=FunctionLver; 379 | 2'b10: romversion=C1Lver; 380 | 2'b11: romversion=C2Lver; 381 | endcase 382 | romaddrext={romversion,romselect[1:0]}; 383 | end 384 | else begin // high ROM 385 | case(romselect[3:2]) 386 | 2'b00: romversion=Kernalver; 387 | 2'b01: romversion=FunctionHver; 388 | 2'b10: romversion=C1Hver; 389 | 2'b11: romversion=C2Hver; 390 | endcase 391 | romaddrext=(romconfig)?{4'hf,2'b00}:(KERN)?{Kernalver,2'b00}:{romversion,romselect[3:2]}; 392 | end 393 | end 394 | 395 | // ROM config mode flag 396 | 397 | always @(posedge CLK28) 398 | begin 399 | if(sreset&key_esc) // activate ROM configuration mode when ESC key is pressed during bootstrap 400 | romconfig<=1'b1; 401 | else if(sreset) // inactivate ROM configuration mode at beginning of hard reset 402 | romconfig<=1'b0; 403 | end 404 | 405 | // FPGATED ROM config register (could be placed to a separate module) 406 | 407 | always @(posedge CLK28) 408 | begin 409 | FD9x_prev<=FD9x; 410 | phi0_prev<=phi0; 411 | end 412 | 413 | 414 | always @(posedge CLK28) begin 415 | romreg_data<=8'hff; 416 | romconfreset<=1'b0; 417 | if(FD9x & RW) begin // ROM and FPGATED config registers read 418 | case(plus4_addr[3:0]) 419 | 4'h0: romreg_data<={Kernalver,Basicver}; 420 | 4'h1: romreg_data<={FunctionHver,FunctionLver}; 421 | 4'h2: romreg_data<={C1Hver,C1Lver}; 422 | 4'h3: romreg_data<={C2Hver,C2Lver}; 423 | default:romreg_data<=8'hff; 424 | endcase 425 | end 426 | // ROM and FPGATED config registers write (only allowed when RomConfig mode is enabled) 427 | // this part is connected to bootstrap data and address buses during FPGATED configuration in order to load initial values 428 | // during normal operation it is connected to Plus4 data and address buses so it can be modified via Plus4 bus cycles 429 | else if((FD9x_prev & ~FD9x & ~RW & romconfig) || (boot_done & ~cfg_done & phi0_prev & ~phi0 & ~boot_rw )) 430 | begin 431 | case(ram_addr[3:0]) // ram_addr is boot_addr during bootstrap, plus4_address after FPGTAED is configured 432 | 4'h0: begin 433 | Kernalver<=config_data[7:4]; // config_data is boot_data during bootstrap, plus4_datalatch after FPGATED is configured 434 | Basicver<=config_data[3:0]; 435 | end 436 | 4'h1: begin 437 | FunctionHver<=config_data[7:4]; 438 | FunctionLver<=config_data[3:0]; 439 | end 440 | 4'h2: begin 441 | C1Hver<=config_data[7:4]; 442 | C1Lver<=config_data[3:0]; 443 | end 444 | 4'h3: begin 445 | C2Hver<=config_data[7:4]; 446 | C2Lver<=config_data[3:0]; 447 | end 448 | 4'h4: begin // Config register 1 449 | // add config register write here 450 | end 451 | 4'h5: begin // Config register 2 452 | // add config register write here 453 | end 454 | 4'h7: begin 455 | romconfreset<=1'b1; // Reset system when writing to this address 456 | end 457 | endcase 458 | end 459 | end 460 | 461 | assign boot_cs=FD9x&plus4_addr[3]&(~cfg_done|romconfig); // FPGATED boot chipselect signal 462 | assign config_data=(cfg_done)?plus4_datalatch:boot_data; // data for config registers write is taken from Plus4 databus or boot databus 463 | 464 | // Plus4 reset circuit 465 | 466 | always @(posedge CLK28) // reset tries to emulate the length of a real reset 467 | begin 468 | if(RESET|keyreset|romconfreset) // reset can be triggered by reset button , CTRL+ALT+DEL from keyboard or from ROM config kernal 469 | begin 470 | resetcounter<=0; // start reset length counter 471 | sreset<=1; // set synchronous reset for CPU 472 | end 473 | else begin 474 | if(resetcounter==24'd16777215) begin 475 | if(boot_done & cfg_done) 476 | sreset<=0; // end of reset after approximately 590ms 477 | end 478 | else begin 479 | resetcounter<=resetcounter+24'b1; 480 | sreset<=1; 481 | end 482 | end 483 | end 484 | 485 | 486 | // Motherboard bus connections 487 | 488 | assign plus4_addr=(~mux)?plus4_addrlatch:cpu_addr&ted_addr; // Plus4 address bus 489 | assign plus4_data=(mux)?plus4_datalatch:cpu_data&ted_data&ram_data&keyport_data&romreg_data&boot_data; // Plus4 data bus using sdram for ROM 490 | 491 | always @(posedge CLK28) // address and data bus latching emulates dynamic memory behaviour of these buses 492 | begin 493 | plus4_datalatch<=plus4_data; 494 | plus4_addrlatch<=plus4_addr; 495 | end 496 | 497 | // Joystick and Keyboard connection to keybus 498 | 499 | assign joy0emu=(~plus4_data[2])?joy0port:5'b11111; // keyboard emulated joy0 port is allowed to kbus only when its select line is active (D2 bit) 500 | assign joy1emu=(~plus4_data[1])?joy1port:5'b11111; // keyboard emulated joy1 port is allowed to kbus only when its select line is active (D1 bit) 501 | 502 | assign kbus={key[7]&joy1emu[4],key[6]&joy0emu[4],key[5:4],key[3]&joy0emu[3]&joy1emu[3],key[2]&joy0emu[2]&joy1emu[2],key[1]&joy0emu[1]&joy1emu[1],key[0]&joy0emu[0]&joy1emu[0]}; 503 | 504 | // connect IEC bus 505 | 506 | assign IEC_DATAOUT=port_out[0]; 507 | assign port_in[7]=IEC_DATAIN; 508 | assign IEC_CLKOUT=port_out[1]; 509 | assign port_in[6]=IEC_CLKIN; 510 | assign IEC_ATNOUT=port_out[2]; 511 | //assign ATN=IEC_ATNIN; 512 | assign IEC_RESET=sreset; 513 | 514 | endmodule 515 | -------------------------------------------------------------------------------- /Plus4_testbench.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | ////////////////////////////////////////////////////////////////////////////////// 4 | // Copyright 2013-2016 Istvan Hegedus 5 | // 6 | // FPGATED is free software: you can redistribute it and/or modify 7 | // it under the terms of the GNU General Public License as published by 8 | // the Free Software Foundation, either version 3 of the License, or 9 | // (at your option) any later version. 10 | // 11 | // FPGATED is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program. If not, see . 18 | // 19 | // 20 | // Create Date: 12:02:05 16/09/2016 21 | // Design Name: Commodore Plus 4 in an FPGA 22 | // Module Name: PLUS4_testbench.v 23 | // Project Name: FPGATED Papilio Pro edition 24 | // 25 | // Description: 26 | // This module is the testbench for FPGATED Plus4.v 27 | // 28 | // 29 | // Revision history: 30 | // 0.1 16.09.2016 Testbench created 31 | // 32 | // Comments: This module is based on c16_testbench.v which is part of the original FPGATED design and it makes use of Papilio Pro platform's sdram. 33 | // 34 | ////////////////////////////////////////////////////////////////////////////////// 35 | 36 | module Plus4_testbench; 37 | 38 | reg CLK28; 39 | wire phi0; 40 | reg phi0_prev; 41 | reg phi_prev; 42 | reg sreset=0; 43 | reg RESET=0; 44 | reg [7:0] port_in=0; 45 | wire [7:0] port_out; 46 | wire [7:0] datain; 47 | wire aec; 48 | wire rdy; 49 | reg enable=0; 50 | 51 | 52 | wire irq_n; 53 | wire [7:0] dataout; 54 | wire [15:0] addr; 55 | wire RW; 56 | wire [6:0] color; 57 | wire [3:0] red,green,blue; 58 | wire csync; 59 | wire RAS,CAS,mux,cs0,cs1; 60 | 61 | wire [15:0] plus4_addr,ted_addr,cpu_addr; 62 | wire [7:0] plus4_data,ted_data,ram_data,A,cpu_data,basic_data,kernal_data,rom_data; 63 | wire [7:0] keyboard_row,keyport_data,key,kbus; 64 | reg [7:0] romreg_data; 65 | reg [7:0] plus4_datalatch=0; 66 | reg [7:0] keyscancode; 67 | wire [6:0] plus4_color; 68 | reg [12:0] resetcounter=0; 69 | reg [15:0] plus4_addrlatch=0; 70 | wire keyreset; 71 | wire [4:0] joy0port,joy1port; // keyboard emulated joystick ports 72 | wire [4:0] joy0emu,joy1emu; // keyboard emulated joystick ports masked by select lines 73 | reg keyreceived=0; 74 | wire cpuenable; 75 | reg pla_arm; 76 | wire FD3x; 77 | wire FDDx; 78 | reg FDDx_prev=0; 79 | wire FD1x; 80 | wire FD0x; 81 | reg [3:0] romselect=0; // Plus4/C16 motherboard U21 ROM selector register 82 | reg [3:0] Kernalver=4'h0; // Kernal ROM alternative version selector 1-16 83 | reg [3:0] Basicver=4'h0; // Basic ROM alternative version selector 1-16 84 | reg [3:0] FunctionLver=4'h0; // Function ROM alternative version selector 1-16 (Low) 85 | reg [3:0] FunctionHver=4'h0; // Function ROM alternative version selector 1-16 (High) 86 | reg [3:0] C1Lver=4'h0; // Cartridge ROM1 alternative version selector 1-16 (Low) 87 | reg [3:0] C1Hver=4'h0; // Cartridge ROM1 alternative version selector 1-16 (High) 88 | reg [3:0] C2Lver=4'h0; // Cartridge ROM2 alternative version selector 1-16 (Low) 89 | reg [3:0] C2Hver=4'h0; // Cartridge ROM2 alternative version selector 1-16 (High) 90 | reg [3:0] romversion; // Addressed ROM's version (1-16) 91 | reg [5:0] romaddrext; // ROM address extension 4M ROM area (see sdram controller) 92 | reg [5:0] ramaddrext=6'b000000; // RAM address extension 4M RAM (Hannes/Csory) 93 | wire [5:0] plus4_addrext; 94 | reg romconfig=0; // ROM config mode enables a special kernal to configure ROM versions 95 | reg romconfreset=0; 96 | reg FD9x_prev=0; 97 | wire boot_cs; 98 | 99 | wire [11:0] SDRAM_ADDR; 100 | wire [15:0] SDRAM_DATA; 101 | wire SDRAM_DQML; 102 | wire SDRAM_DQMH; 103 | wire [1:0] SDRAM_BA; 104 | wire SDRAM_nWE; 105 | wire SDRAM_nCAS; 106 | wire SDRAM_nRAS; 107 | wire SDRAM_CS; 108 | wire SDRAM_CKE; 109 | 110 | wire FLASH_SI; 111 | wire FLASH_SO; 112 | wire FLASH_CK; 113 | wire FLASH_CS; 114 | wire boot_cs0; 115 | wire boot_cs1; 116 | wire boot_rw; 117 | wire [15:0] boot_addr; 118 | wire [5:0] boot_addrext; 119 | wire [7:0] boot_data; 120 | wire [7:0] config_data; 121 | wire boot_done; 122 | 123 | wire sdram_cs0; 124 | wire sdram_cs1; 125 | wire sdram_rw; 126 | wire [15:0] ram_addr; 127 | wire [5:0] sdram_addrext; 128 | wire [7:0] sdram_datain; 129 | 130 | initial begin 131 | // Initialize Inputs 132 | CLK28=0; 133 | keyscancode=7'hff; 134 | keyreceived=1; 135 | file=$fopen("fakerom.bin","rb"); 136 | // Wait for global reset to finish 137 | #150000; 138 | port_in=8'hff; 139 | 140 | // Add stimulus here 141 | 142 | end 143 | 144 | // 8501 CPU 145 | mos8501 cpu ( 146 | .clk(CLK28), 147 | .reset(sreset), 148 | .enable(cpuenable), 149 | .irq_n(irq_n), 150 | .data_in(plus4_data), 151 | .data_out(cpu_data), 152 | .address(cpu_addr), 153 | .gate_in(mux), 154 | .rw(RW), // rw=high read, rw=low write 155 | .port_in(port_in), 156 | .port_out(port_out), 157 | .rdy(rdy), 158 | .aec(aec) 159 | ); 160 | 161 | // TED 162 | ted mos8360( 163 | .clk(CLK28), 164 | .addr_in(plus4_addr), 165 | .addr_out(ted_addr), 166 | .data_in(plus4_data), 167 | .data_out(ted_data), 168 | .rw(RW), 169 | .cpuclk(phi0), 170 | .color(color), 171 | .csync(csync), 172 | .irq(irq_n), 173 | .ba(rdy), 174 | .mux(mux), 175 | .ras(RAS), 176 | .cas(CAS), 177 | .cs0(cs0), 178 | .cs1(cs1), 179 | .aec(aec), 180 | .k(kbus), 181 | .snd(sound), 182 | .cpuenable(cpuenable) 183 | // .pal(pal) 184 | ); 185 | 186 | // SDRAM controller 187 | sdram_controller ram_ctrl( 188 | .sdram_addr(SDRAM_ADDR), 189 | .sdram_data(SDRAM_DATA), 190 | .sdram_dqm({SDRAM_DQMH,SDRAM_DQML}), 191 | .sdram_ba(SDRAM_BA), 192 | .sdram_we(SDRAM_nWE), 193 | .sdram_ras(SDRAM_nRAS), 194 | .sdram_cas(SDRAM_nCAS), 195 | .sdram_cs(SDRAM_CS), 196 | .sdram_cke(SDRAM_CKE), 197 | .clk(CLK28), 198 | .plus4_addr(ram_addr), 199 | .plus4_addrext(sdram_addrext), 200 | .plus4_ras(RAS), 201 | .plus4_cas(CAS), 202 | .plus4_rw(sdram_rw), 203 | .plus4_cs0(sdram_cs0), 204 | .plus4_cs1(sdram_cs1), 205 | .ram_datain(sdram_datain), 206 | .ram_dataout(ram_data), 207 | .initdone(raminitdone) 208 | ); 209 | 210 | // SDRAM connection multiplexers 211 | 212 | assign ram_addr=(cfg_done)?plus4_addr:boot_addr; 213 | assign sdram_addrext=(boot_done)?plus4_addrext:boot_addrext; 214 | assign sdram_cs0=(boot_done)?cs0:boot_cs0; 215 | assign sdram_cs1=(boot_done)?cs1:boot_cs1; 216 | assign sdram_rw=(boot_done)?RW:boot_rw; 217 | assign sdram_datain=(boot_done)?plus4_data:boot_data; 218 | 219 | assign plus4_addrext=(~cs0|~cs1)?romaddrext:ramaddrext; // set ROM or RAM address extension 220 | 221 | mt48lc4m16a2 sdram( 222 | .Dq(SDRAM_DATA), 223 | .Addr(SDRAM_ADDR), 224 | .Ba(SDRAM_BA), 225 | .Clk(~CLK28), 226 | .Cke(SDRAM_CKE), 227 | .Cs_n(SDRAM_CS), 228 | .Ras_n(SDRAM_nRAS), 229 | .Cas_n(SDRAM_nCAS), 230 | .We_n(SDRAM_nWE), 231 | .Dqm({SDRAM_DQMH,SDRAM_DQML}) 232 | ); 233 | 234 | // Kernal rom (testbench) 235 | kernal_rom kernal( 236 | .clk(CLK28), 237 | .address_in(plus4_addr[13:0]), 238 | .data_out(kernal_data), 239 | .cs(cs1) 240 | ); 241 | 242 | // Basic rom (testbench) 243 | basic_rom basic( 244 | .clk(CLK28), 245 | .address_in(plus4_addr[13:0]), 246 | .data_out(basic_data), 247 | .cs(cs0) 248 | ); 249 | 250 | // Color decoder to 12bit RGB (testbench) 251 | colors_to_rgb colordecode( 252 | .clk(CLK28), 253 | .color(color), 254 | .red(red), 255 | .green(green), 256 | .blue(blue)); 257 | 258 | // keyboard part (testbench) 259 | 260 | /* 261 | ps2receiver ps2rcv( 262 | .clk(CLK28), 263 | .ps2_clk(ps2clk), 264 | .ps2_data(ps2dat), 265 | .rx_done(keyreceived), 266 | .ps2scancode(keyscancode) 267 | ); 268 | */ 269 | 270 | c16_keymatrix keyboard( 271 | .clk(CLK28), 272 | .scancode(keyscancode), 273 | .receiveflag(keyreceived), 274 | .row(keyboard_row), 275 | .kbus(key), 276 | .keyreset(keyreset), 277 | .joy0(joy0port), 278 | .joy1(joy1port), 279 | .esc(key_esc) 280 | ); 281 | 282 | mos6529 keyport( 283 | .clk(CLK28), 284 | .data_in(plus4_data), 285 | .data_out(keyport_data), 286 | .port_in(8'hff), 287 | .port_out(keyboard_row), 288 | .rw(RW), 289 | .cs(FD3x) 290 | ); 291 | 292 | // Bootstrap uploads ROM images from FPGA flash chip to SDRAM (testbench) 293 | 294 | bootstrap boot( 295 | // SPI flash signals 296 | .flash_cs(FLASH_CS), 297 | .flash_ck(FLASH_CK), 298 | .flash_si(FLASH_SI), 299 | .flash_so(FLASH_SO), 300 | // generated ROM signals 301 | .cs0(boot_cs0), 302 | .cs1(boot_cs1), 303 | .rw_out(boot_rw), 304 | .addr_out(boot_addr), 305 | .addr_ext(boot_addrext), 306 | .data_out(boot_data), 307 | 308 | .reset(1'b0), 309 | .boot_enable(raminitdone), 310 | .boot_done(boot_done), 311 | .cfg_done(cfg_done), 312 | .phi(phi0), 313 | .clk(CLK28), 314 | // signals for SPI FLASH communication via Plus4 bus 315 | .cs(boot_cs), 316 | .rw_in(RW), 317 | .data_in(plus4_data), 318 | .addr_in(plus4_addr[2:0]) 319 | ); 320 | 321 | 322 | // PLA functions (testbench) 323 | 324 | always @(posedge CLK28) begin // arm function needs to be registered 325 | pla_arm<=mux|(~RAS&phi0&pla_arm); 326 | end 327 | 328 | assign KERN=(plus4_addr[15:8]==8'hfc)?1'b1:1'b0; 329 | assign FD3x=((plus4_addr[15:4]==12'hfd3) & pla_arm & phi0 & ~RAS)?1'b1:1'b0; // KEYPORT 330 | assign FDDx=((plus4_addr[15:4]==12'hfdd) & pla_arm & phi0 & ~RAS)?1'b1:1'b0; // ADDR CLK 331 | assign FD0x=((plus4_addr[15:4]==12'hfd0) & phi0)?1'b1:1'b0; // 6551 332 | assign FD1x=((plus4_addr[15:4]==12'hfd1) & pla_arm & phi0 & ~RAS)?1'b1:1'b0; // 6529 333 | assign phi2=~RAS & pla_arm & phi0; // PHI2 CLK not used at the moment 334 | assign FD2x=((plus4_addr[15:4]==12'hfd2) & phi0 & ~RAS); // SPEECH $FD2X is not used in Plus4 (used for Commodore 364) 335 | assign FD9x=((plus4_addr[15:4]==12'hfd9) & phi0 & ~RAS); // FPGATED configuration register 336 | 337 | // ROM MMU (testbench) 338 | 339 | always @(posedge CLK28) begin // Plus4 motherboard ROM selector register (U21) 340 | FDDx_prev<=FDDx; 341 | if(~FDDx_prev&FDDx&~RW) 342 | romselect<=plus4_addr[3:0]; 343 | end 344 | 345 | always @* begin // generating ROM address extension for different ROM versions (based on motherboard schematic) 346 | if(~cs0) begin // low ROM 347 | case(romselect[1:0]) // based on romselect register set romversion to the active rom version (version 1-16) 348 | 2'b00: romversion=Basicver; 349 | 2'b01: romversion=FunctionLver; 350 | 2'b10: romversion=C1Lver; 351 | 2'b11: romversion=C2Lver; 352 | endcase 353 | romaddrext={romversion,romselect[1:0]}; 354 | end 355 | else begin // high ROM 356 | case(romselect[3:2]) 357 | 2'b00: romversion=Kernalver; 358 | 2'b01: romversion=FunctionHver; 359 | 2'b10: romversion=C1Hver; 360 | 2'b11: romversion=C2Hver; 361 | endcase 362 | romaddrext=(romconfig)?{4'hf,2'b00}:(KERN)?{Kernalver,2'b00}:{romversion,romselect[3:2]}; 363 | end 364 | end 365 | 366 | // ROM config mode flag 367 | 368 | always @(posedge CLK28) 369 | begin 370 | if(sreset&key_esc) // activate ROM configuration mode when ESC key is pressed during bootstrap or Romconfig Kernal is active 371 | romconfig<=1; 372 | else if(sreset) // inactivate ROM configuration mode at beginning of hard reset 373 | romconfig<=0; 374 | end 375 | 376 | 377 | 378 | // FPGATED ROM config register (could be placed to a separate module) 379 | 380 | always @(posedge CLK28) 381 | begin 382 | FD9x_prev<=FD9x; 383 | phi0_prev<=phi0; 384 | end 385 | 386 | 387 | always @(posedge CLK28) begin 388 | romreg_data<=8'hff; 389 | romconfreset<=1'b0; 390 | if(FD9x & RW) begin // ROM and FPGATED config registers read 391 | case(plus4_addr[3:0]) 392 | 4'h0: romreg_data<={Kernalver,Basicver}; 393 | 4'h1: romreg_data<={FunctionHver,FunctionLver}; 394 | 4'h2: romreg_data<={C1Hver,C1Lver}; 395 | 4'h3: romreg_data<={C2Hver,C2Lver}; 396 | default:romreg_data<=8'hff; 397 | endcase 398 | end 399 | // ROM and FPGATED config registers write (only allowed when RomConfig mode is enabled) 400 | // this part is connected to bootstrap data and address buses during FPGATED configuration in order to load initial values 401 | // during normal operation it is connected to Plus4 data and address buses so it can be modified via Plus4 bus cycles 402 | else if((FD9x_prev & ~FD9x & ~RW & romconfig) || (boot_done & ~cfg_done & phi0_prev & ~phi0 & ~boot_rw )) 403 | begin 404 | case(ram_addr[3:0]) // ram_addr is boot_addr during bootstrap, plus4_address after FPGTAED is configured 405 | 4'h0: begin 406 | Kernalver<=config_data[7:4]; // config_data is boot_data during bootstrap, plus4_datalatch after FPGATED is configured 407 | Basicver<=config_data[3:0]; 408 | end 409 | 4'h1: begin 410 | FunctionHver<=config_data[7:4]; 411 | FunctionLver<=config_data[3:0]; 412 | end 413 | 4'h2: begin 414 | C1Hver<=config_data[7:4]; 415 | C1Lver<=config_data[3:0]; 416 | end 417 | 4'h3: begin 418 | C2Hver<=config_data[7:4]; 419 | C2Lver<=config_data[3:0]; 420 | end 421 | 4'h4: begin // Config register 1 422 | // add config register write here 423 | end 424 | 4'h5: begin // Config register 2 425 | // add config register write here 426 | end 427 | 4'h7: begin 428 | romconfreset<=1'b1; // Reset system when writing to this address 429 | end 430 | endcase 431 | end 432 | end 433 | 434 | assign boot_cs=FD9x&plus4_addr[3]&(~cfg_done|romconfig); // FPGATED boot chipselect signal 435 | assign config_data=(cfg_done)?plus4_datalatch:boot_data; // data for config registers write is taken from Plus4 databus or boot databus 436 | 437 | 438 | // Plus4 reset circuit (testbench) 439 | 440 | always @(posedge CLK28) // reset tries to emulate the length of a real reset 441 | begin 442 | if(RESET|keyreset|romconfreset) // reset can be triggered by reset button or CTRL+ALT+DEL from keyboard 443 | begin 444 | resetcounter<=0; // start reset length counter 445 | sreset<=1; // set synchronous reset for CPU 446 | end 447 | else begin 448 | if(resetcounter==24'd5000) begin 449 | if(boot_done) 450 | sreset<=0; // end of reset after approximately 590ms 451 | end 452 | else begin 453 | resetcounter<=resetcounter+1; 454 | sreset<=1; 455 | end 456 | end 457 | end 458 | 459 | // Motherboard bus connections (testbench) 460 | 461 | assign rom_data=kernal_data&basic_data; 462 | 463 | 464 | assign plus4_addr=(~mux)?plus4_addrlatch:cpu_addr&ted_addr; 465 | assign plus4_data=(mux)?plus4_datalatch:cpu_data&ted_data&keyport_data&romreg_data&((~cs0|~cs1)?rom_data:ram_data)&boot_data; 466 | 467 | 468 | always @(posedge CLK28) 469 | begin 470 | plus4_datalatch<=plus4_data; 471 | plus4_addrlatch<=plus4_addr; 472 | end 473 | 474 | // Joystick and Keyboard connection to keybus (testbench) 475 | 476 | assign joy0emu=(~plus4_data[2])?joy0port:5'b11111; // keyboard emulated joy0 port is allowed to kbus only when its select line is active (D2 bit) 477 | assign joy1emu=(~plus4_data[1])?joy1port:5'b11111; // keyboard emulated joy1 port is allowed to kbus only when its select line is active (D1 bit) 478 | 479 | assign kbus={key[7]&joy1emu[4],key[6]&joy0emu[4],key[5:4],key[3]&joy0emu[3]&joy1emu[3],key[2]&joy0emu[2]&joy1emu[2],key[1]&joy0emu[1]&joy1emu[1],key[0]&joy0emu[0]&joy1emu[0]}; 480 | 481 | // connect IEC bus 482 | // this part is left out from TB 483 | 484 | 485 | // Generating system clock 28.288 Mhz 486 | 487 | always 488 | begin 489 | #17.675 CLK28<=~CLK28; 490 | end 491 | 492 | always @(plus4_addr) 493 | begin 494 | if (plus4_addr == 16'he6e2) 495 | $finish; 496 | end 497 | 498 | //-------------------------------------------------------------- 499 | // Bootstrap stimulus 500 | 501 | reg [2:0] bytecount=0; 502 | reg [2:0] bitcount=7; 503 | reg [2:0] cbitcount=0; 504 | reg [7:0] flashreg=8'h03; 505 | integer file; 506 | reg command=1; 507 | 508 | always @(negedge FLASH_CK) begin 509 | if (~FLASH_CS) begin 510 | if (~command) begin 511 | bitcount<=bitcount+1; 512 | if(bitcount==7) 513 | flashreg<=$fgetc(file); 514 | else flashreg[7:0]<={flashreg[6:0],1'b0}; 515 | end 516 | 517 | end 518 | end 519 | 520 | always @(posedge FLASH_CK) begin 521 | if(command) begin 522 | cbitcount<=cbitcount+1; 523 | if(cbitcount==7) 524 | if(bytecount==3) 525 | command<=0; 526 | else bytecount=bytecount+1; 527 | end 528 | end 529 | 530 | assign FLASH_SO=flashreg[7]; 531 | 532 | always @(posedge cfg_done) begin 533 | $fclose(file); 534 | end 535 | 536 | 537 | 538 | endmodule 539 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # plus4 2 | FPGATED based Plus4 implementation using Papilio Pro platform 3 | 4 | 5 | This is FPGAPlus4 based on my FPGATED verilog core. 6 | 7 | v1.0 27/03/2019 release 8 | 9 | v1.1rc 02/03/2019 Using TED core v1.1 which fixes FLI problems. DMA counter (videocounter) latch conditions are fixed. Now FLI compatible. 10 | v1.2 13/01/2021 New TED core v1.3 which fixes DMA delay issues. Alpharay, Pets Rescue games work fine now. 11 | 12 | Features: 13 | - sdram controller synchronized to Plus4 phi0 clock 14 | - multiple rom images stored in onboard sdram 15 | - bootstrap code uploads rom images from FPGA SPI config flash 16 | - ROM images stored in FPGA config flash together with bitstream 17 | - a config kernal written in assembly (source not yet included) 18 | - multiple 6502 cores (T65 or FPGA64) choosable before synthesis 19 | - onboard SPI flash accessible from Plus4 20 | - rom config registers and SPI flash base I/O address $fd90 21 | 22 | The sdram controller contains an address extension mechanism for future ram expansions and current ROM images store. 23 | This part still needs documentation, however the controller's source file comment already contains valuable information 24 | on the address extension format. 25 | The bootstrap mechanism and the rompack format stored in SPI flash has also some information in the bootstrap source header, 26 | however it needs some more documentation as well. 27 | 28 | More information will be added 29 | -------------------------------------------------------------------------------- /T65.vhd: -------------------------------------------------------------------------------- 1 | -- **** 2 | -- T65(b) core. In an effort to merge and maintain bug fixes .... 3 | -- 4 | -- Ver 313 WoS January 2015 5 | -- Fixed issue that NMI has to be first if issued the same time as a BRK instruction is latched in 6 | -- Now all Lorenz CPU tests on FPGAARCADE C64 core (sources used: SVN version 1021) are OK! :D :D :D 7 | -- This is just a starting point to go for optimizations and detailed fixes (the Lorenz test can't find) 8 | -- 9 | -- Ver 312 WoS January 2015 10 | -- Undoc opcode timing fixes for $B3 (LAX iy) and $BB (LAS ay) 11 | -- Added comments in MCode section to find handling of individual opcodes more easily 12 | -- All "basic" Lorenz instruction test (individual functional checks, CPUTIMING check) work now with 13 | -- actual FPGAARCADE C64 core (sources used: SVN version 1021). 14 | -- 15 | -- Ver 305, 306, 307, 308, 309, 310, 311 WoS January 2015 16 | -- Undoc opcode fixes (now all Lorenz test on instruction functionality working, except timing issues on $B3 and $BB): 17 | -- SAX opcode 18 | -- SHA opcode 19 | -- SHX opcode 20 | -- SHY opcode 21 | -- SHS opcode 22 | -- LAS opcode 23 | -- alternate SBC opcode 24 | -- fixed NOP with immediate param (caused Lorenz trap test to fail) 25 | -- IRQ and NMI timing fixes (in conjuction with branches) 26 | -- 27 | -- Ver 304 WoS December 2014 28 | -- Undoc opcode fixes: 29 | -- ARR opcode 30 | -- ANE/XAA opcode 31 | -- Corrected issue with NMI/IRQ prio (when asserted the same time) 32 | -- 33 | -- Ver 303 ost(ML) July 2014 34 | -- (Sorry for some scratchpad comments that may make little sense) 35 | -- Mods and some 6502 undocumented instructions. 36 | -- Not correct opcodes acc. to Lorenz tests (incomplete list): 37 | -- NOPN (nop) 38 | -- NOPZX (nop + byte 172) 39 | -- NOPAX (nop + word da ... da: byte 0) 40 | -- ASOZ (byte $07 + byte 172) 41 | -- 42 | -- Ver 303,302 WoS April 2014 43 | -- Bugfixes for NMI from foft 44 | -- Bugfix for BRK command (and its special flag) 45 | -- 46 | -- Ver 300,301 WoS January 2014 47 | -- More merging 48 | -- Bugfixes by ehenciak added, started tidyup *bust* 49 | -- 50 | -- MikeJ March 2005 51 | -- Latest version from www.fpgaarcade.com (original www.opencores.org) 52 | -- **** 53 | -- 54 | -- 65xx compatible microprocessor core 55 | -- 56 | -- FPGAARCADE SVN: $Id: T65.vhd 1347 2015-05-27 20:07:34Z wolfgang.scherr $ 57 | -- 58 | -- Copyright (c) 2002...2015 59 | -- Daniel Wallner (jesus opencores org) 60 | -- Mike Johnson (mikej fpgaarcade com) 61 | -- Wolfgang Scherr (WoS pin4 at> 62 | -- Morten Leikvoll () 63 | -- 64 | -- All rights reserved 65 | -- 66 | -- Redistribution and use in source and synthezised forms, with or without 67 | -- modification, are permitted provided that the following conditions are met: 68 | -- 69 | -- Redistributions of source code must retain the above copyright notice, 70 | -- this list of conditions and the following disclaimer. 71 | -- 72 | -- Redistributions in synthesized form must reproduce the above copyright 73 | -- notice, this list of conditions and the following disclaimer in the 74 | -- documentation and/or other materials provided with the distribution. 75 | -- 76 | -- Neither the name of the author nor the names of other contributors may 77 | -- be used to endorse or promote products derived from this software without 78 | -- specific prior written permission. 79 | -- 80 | -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 81 | -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 82 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 83 | -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 84 | -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 85 | -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 86 | -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 87 | -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 88 | -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 89 | -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 90 | -- POSSIBILITY OF SUCH DAMAGE. 91 | -- 92 | -- Please report bugs to the author(s), but before you do so, please 93 | -- make sure that this is not a derivative work and that 94 | -- you have the latest version of this file. 95 | -- 96 | -- ----- IMPORTANT NOTES ----- 97 | -- 98 | -- Limitations: 99 | -- 65C02 and 65C816 modes are incomplete (and definitely untested after all 6502 undoc fixes) 100 | -- 65C02 supported : inc, dec, phx, plx, phy, ply 101 | -- 65D02 missing : bra, ora, lda, cmp, sbc, tsb*2, trb*2, stz*2, bit*2, wai, stp, jmp, bbr*8, bbs*8 102 | -- Some interface signals behave incorrect 103 | -- NMI interrupt handling not nice, needs further rework (to cycle-based encoding). 104 | -- 105 | -- Usage: 106 | -- The enable signal allows clock gating / throttling without using the ready signal. 107 | -- Set it to constant '1' when using the Clk input as the CPU clock directly. 108 | -- 109 | -- TAKE CARE you route the DO signal back to the DI signal while R_W_n='0', 110 | -- otherwise some undocumented opcodes won't work correctly. 111 | -- EXAMPLE: 112 | -- CPU : entity work.T65 113 | -- port map ( 114 | -- R_W_n => cpu_rwn_s, 115 | -- [....all other ports....] 116 | -- DI => cpu_din_s, 117 | -- DO => cpu_dout_s 118 | -- ); 119 | -- cpu_din_s <= cpu_dout_s when cpu_rwn_s='0' else 120 | -- [....other sources from peripherals and memories...] 121 | -- 122 | -- ----- IMPORTANT NOTES ----- 123 | -- 124 | 125 | library IEEE; 126 | use IEEE.std_logic_1164.all; 127 | use IEEE.numeric_std.all; 128 | use work.T65_Pack.all; 129 | 130 | entity T65 is 131 | port( 132 | Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65C816 133 | Res_n : in std_logic; 134 | Enable : in std_logic; 135 | Clk : in std_logic; 136 | Rdy : in std_logic; 137 | Abort_n : in std_logic; 138 | IRQ_n : in std_logic; 139 | NMI_n : in std_logic; 140 | SO_n : in std_logic; 141 | R_W_n : out std_logic; 142 | Sync : out std_logic; 143 | EF : out std_logic; 144 | MF : out std_logic; 145 | XF : out std_logic; 146 | ML_n : out std_logic; 147 | VP_n : out std_logic; 148 | VDA : out std_logic; 149 | VPA : out std_logic; 150 | A : out std_logic_vector(23 downto 0); 151 | DI : in std_logic_vector(7 downto 0); 152 | DO : out std_logic_vector(7 downto 0); 153 | DEBUG : out T_t65_dbg 154 | ); 155 | end T65; 156 | 157 | architecture rtl of T65 is 158 | 159 | -- Registers 160 | signal ABC, X, Y, D : std_logic_vector(15 downto 0); 161 | signal P, AD, DL : std_logic_vector(7 downto 0) := x"00"; 162 | signal PwithB : std_logic_vector(7 downto 0);--ML:New way to push P with correct B state to stack 163 | signal BAH : std_logic_vector(7 downto 0); 164 | signal BAL : std_logic_vector(8 downto 0); 165 | signal PBR : std_logic_vector(7 downto 0); 166 | signal DBR : std_logic_vector(7 downto 0); 167 | signal PC : unsigned(15 downto 0); 168 | signal S : unsigned(15 downto 0); 169 | signal EF_i : std_logic; 170 | signal MF_i : std_logic; 171 | signal XF_i : std_logic; 172 | 173 | signal IR : std_logic_vector(7 downto 0); 174 | signal MCycle : std_logic_vector(2 downto 0); 175 | 176 | signal Mode_r : std_logic_vector(1 downto 0); 177 | signal ALU_Op_r : T_ALU_Op; 178 | signal Write_Data_r : T_Write_Data; 179 | signal Set_Addr_To_r : T_Set_Addr_To; 180 | signal PCAdder : unsigned(8 downto 0); 181 | 182 | signal RstCycle : std_logic; 183 | signal IRQCycle : std_logic; 184 | signal NMICycle : std_logic; 185 | 186 | signal SO_n_o : std_logic; 187 | signal IRQ_n_o : std_logic; 188 | signal NMI_n_o : std_logic; 189 | signal NMIAct : std_logic; 190 | 191 | signal Break : std_logic; 192 | 193 | -- ALU signals 194 | signal BusA : std_logic_vector(7 downto 0); 195 | signal BusA_r : std_logic_vector(7 downto 0); 196 | signal BusB : std_logic_vector(7 downto 0); 197 | signal BusB_r : std_logic_vector(7 downto 0); 198 | signal ALU_Q : std_logic_vector(7 downto 0); 199 | signal P_Out : std_logic_vector(7 downto 0); 200 | 201 | -- Micro code outputs 202 | signal LCycle : std_logic_vector(2 downto 0); 203 | signal ALU_Op : T_ALU_Op; 204 | signal Set_BusA_To : T_Set_BusA_To; 205 | signal Set_Addr_To : T_Set_Addr_To; 206 | signal Write_Data : T_Write_Data; 207 | signal Jump : std_logic_vector(1 downto 0); 208 | signal BAAdd : std_logic_vector(1 downto 0); 209 | signal BreakAtNA : std_logic; 210 | signal ADAdd : std_logic; 211 | signal AddY : std_logic; 212 | signal PCAdd : std_logic; 213 | signal Inc_S : std_logic; 214 | signal Dec_S : std_logic; 215 | signal LDA : std_logic; 216 | signal LDP : std_logic; 217 | signal LDX : std_logic; 218 | signal LDY : std_logic; 219 | signal LDS : std_logic; 220 | signal LDDI : std_logic; 221 | signal LDALU : std_logic; 222 | signal LDAD : std_logic; 223 | signal LDBAL : std_logic; 224 | signal LDBAH : std_logic; 225 | signal SaveP : std_logic; 226 | signal Write : std_logic; 227 | 228 | signal Res_n_i : std_logic; 229 | signal Res_n_d : std_logic; 230 | 231 | signal really_rdy : std_logic; 232 | signal WRn_i : std_logic; 233 | 234 | signal NMI_entered : std_logic; 235 | 236 | begin 237 | -- gate Rdy with read/write to make an "OK, it's really OK to stop the processor 238 | really_rdy <= Rdy or not(WRn_i); 239 | Sync <= '1' when MCycle = "000" else '0'; 240 | EF <= EF_i; 241 | MF <= MF_i; 242 | XF <= XF_i; 243 | R_W_n <= WRn_i; 244 | ML_n <= '0' when IR(7 downto 6) /= "10" and IR(2 downto 1) = "11" and MCycle(2 downto 1) /= "00" else '1'; 245 | VP_n <= '0' when IRQCycle = '1' and (MCycle = "101" or MCycle = "110") else '1'; 246 | VDA <= '1' when Set_Addr_To_r /= Set_Addr_To_PBR else '0'; 247 | VPA <= '1' when Jump(1) = '0' else '0'; 248 | 249 | -- debugging signals 250 | DEBUG.I <= IR; 251 | DEBUG.A <= ABC(7 downto 0); 252 | DEBUG.X <= X(7 downto 0); 253 | DEBUG.Y <= Y(7 downto 0); 254 | DEBUG.S <= std_logic_vector(S(7 downto 0)); 255 | DEBUG.P <= P; 256 | 257 | mcode : entity work.T65_MCode 258 | port map( 259 | --inputs 260 | Mode => Mode_r, 261 | IR => IR, 262 | MCycle => MCycle, 263 | P => P, 264 | --outputs 265 | LCycle => LCycle, 266 | ALU_Op => ALU_Op, 267 | Set_BusA_To => Set_BusA_To, 268 | Set_Addr_To => Set_Addr_To, 269 | Write_Data => Write_Data, 270 | Jump => Jump, 271 | BAAdd => BAAdd, 272 | BreakAtNA => BreakAtNA, 273 | ADAdd => ADAdd, 274 | AddY => AddY, 275 | PCAdd => PCAdd, 276 | Inc_S => Inc_S, 277 | Dec_S => Dec_S, 278 | LDA => LDA, 279 | LDP => LDP, 280 | LDX => LDX, 281 | LDY => LDY, 282 | LDS => LDS, 283 | LDDI => LDDI, 284 | LDALU => LDALU, 285 | LDAD => LDAD, 286 | LDBAL => LDBAL, 287 | LDBAH => LDBAH, 288 | SaveP => SaveP, 289 | Write => Write 290 | ); 291 | 292 | alu : entity work.T65_ALU 293 | port map( 294 | Mode => Mode_r, 295 | Op => ALU_Op_r, 296 | BusA => BusA_r, 297 | BusB => BusB, 298 | P_In => P, 299 | P_Out => P_Out, 300 | Q => ALU_Q 301 | ); 302 | 303 | -- the 65xx design requires at least two clock cycles before 304 | -- starting its reset sequence (according to datasheet) 305 | process (Res_n_i, Clk) 306 | begin 307 | if Res_n = '0' then 308 | Res_n_i <= '0'; 309 | Res_n_d <= '0'; 310 | elsif Clk'event and Clk = '1' then 311 | Res_n_i <= Res_n_d; 312 | Res_n_d <= '1'; 313 | end if; 314 | end process; 315 | 316 | process (Res_n_i, Clk) 317 | begin 318 | if Res_n_i = '0' then 319 | PC <= (others => '0'); -- Program Counter 320 | IR <= "00000000"; 321 | S <= (others => '0'); -- Dummy 322 | D <= (others => '0'); 323 | PBR <= (others => '0'); 324 | DBR <= (others => '0'); 325 | 326 | Mode_r <= (others => '0'); 327 | ALU_Op_r <= ALU_OP_BIT; 328 | Write_Data_r <= Write_Data_DL; 329 | Set_Addr_To_r <= Set_Addr_To_PBR; 330 | 331 | WRn_i <= '1'; 332 | EF_i <= '1'; 333 | MF_i <= '1'; 334 | XF_i <= '1'; 335 | 336 | elsif Clk'event and Clk = '1' then 337 | if (Enable = '1') then 338 | if (really_rdy = '1') then 339 | WRn_i <= not Write or RstCycle; 340 | 341 | D <= (others => '1'); -- Dummy 342 | PBR <= (others => '1'); -- Dummy 343 | DBR <= (others => '1'); -- Dummy 344 | EF_i <= '0'; -- Dummy 345 | MF_i <= '0'; -- Dummy 346 | XF_i <= '0'; -- Dummy 347 | 348 | if MCycle = "000" then 349 | Mode_r <= Mode; 350 | 351 | if IRQCycle = '0' and NMICycle = '0' then 352 | PC <= PC + 1; 353 | end if; 354 | 355 | if IRQCycle = '1' or NMICycle = '1' then 356 | IR <= "00000000"; 357 | else 358 | IR <= DI; 359 | end if; 360 | 361 | if LDS = '1' then -- LAS won't work properly if not limited to machine cycle 0 362 | S(7 downto 0) <= unsigned(ALU_Q); 363 | end if; 364 | end if; 365 | 366 | ALU_Op_r <= ALU_Op; 367 | Write_Data_r <= Write_Data; 368 | if Break = '1' then 369 | Set_Addr_To_r <= Set_Addr_To_PBR; 370 | else 371 | Set_Addr_To_r <= Set_Addr_To; 372 | end if; 373 | 374 | if Inc_S = '1' then 375 | S <= S + 1; 376 | end if; 377 | if Dec_S = '1' and RstCycle = '0' then 378 | S <= S - 1; 379 | end if; 380 | 381 | if IR = "00000000" and MCycle = "001" and IRQCycle = '0' and NMICycle = '0' then 382 | PC <= PC + 1; 383 | end if; 384 | -- 385 | -- jump control logic 386 | -- 387 | case Jump is 388 | when "01" => 389 | PC <= PC + 1; 390 | when "10" => 391 | PC <= unsigned(DI & DL); 392 | when "11" => 393 | if PCAdder(8) = '1' then 394 | if DL(7) = '0' then 395 | PC(15 downto 8) <= PC(15 downto 8) + 1; 396 | else 397 | PC(15 downto 8) <= PC(15 downto 8) - 1; 398 | end if; 399 | end if; 400 | PC(7 downto 0) <= PCAdder(7 downto 0); 401 | when others => null; 402 | end case; 403 | end if; 404 | end if; 405 | end if; 406 | end process; 407 | 408 | PCAdder <= resize(PC(7 downto 0),9) + resize(unsigned(DL(7) & DL),9) when PCAdd = '1' 409 | else "0" & PC(7 downto 0); 410 | 411 | process (Res_n_i, Clk) 412 | variable tmpP:std_logic_vector(7 downto 0);--Lets try to handle loading P at mcycle=0 and set/clk flags at same cycle 413 | begin 414 | if Res_n_i = '0' then 415 | P <= x"00"; -- ensure we have nothing set on reset 416 | elsif Clk'event and Clk = '1' then 417 | tmpP:=P; 418 | if (Enable = '1') then 419 | if (really_rdy = '1') then 420 | if MCycle = "000" then 421 | if LDA = '1' then 422 | ABC(7 downto 0) <= ALU_Q; 423 | end if; 424 | if LDX = '1' then 425 | X(7 downto 0) <= ALU_Q; 426 | end if; 427 | if LDY = '1' then 428 | Y(7 downto 0) <= ALU_Q; 429 | end if; 430 | if (LDA or LDX or LDY) = '1' then 431 | tmpP:=P_Out; 432 | end if; 433 | end if; 434 | if SaveP = '1' then 435 | tmpP:=P_Out; 436 | end if; 437 | if LDP = '1' then 438 | tmpP:=ALU_Q; 439 | end if; 440 | if IR(4 downto 0) = "11000" then 441 | case IR(7 downto 5) is 442 | when "000" =>--0x18(clc) 443 | tmpP(Flag_C) := '0'; 444 | when "001" =>--0x38(sec) 445 | tmpP(Flag_C) := '1'; 446 | when "010" =>--0x58(cli) 447 | tmpP(Flag_I) := '0'; 448 | when "011" =>--0x78(sei) 449 | tmpP(Flag_I) := '1'; 450 | when "101" =>--0xb8(clv) 451 | tmpP(Flag_V) := '0'; 452 | when "110" =>--0xd8(cld) 453 | tmpP(Flag_D) := '0'; 454 | when "111" =>--0xf8(sed) 455 | tmpP(Flag_D) := '1'; 456 | when others => 457 | end case; 458 | end if; 459 | tmpP(Flag_B) := '1'; 460 | if IR = "00000000" and MCycle = "100" and RstCycle = '0' then 461 | --This should happen after P has been pushed to stack 462 | tmpP(Flag_I) := '1'; 463 | end if; 464 | if SO_n_o = '1' and SO_n = '0' then 465 | tmpP(Flag_V) := '1'; 466 | end if; 467 | if RstCycle = '1' then 468 | tmpP(Flag_I) := '1'; -- changed from 0 to 1 due to a bug. During reset I flag was not set. 469 | tmpP(Flag_D) := '0'; 470 | end if; 471 | tmpP(Flag_1) := '1'; 472 | 473 | P<=tmpP;--new way 474 | 475 | SO_n_o <= SO_n; 476 | if IR(4 downto 0)/="10000" or Jump/="01" then -- delay interrupts during branches (checked with Lorenz test and real 6510), not best way yet, though - but works... 477 | IRQ_n_o <= IRQ_n; 478 | end if; 479 | end if; 480 | -- detect nmi even if not rdy 481 | if IR(4 downto 0)/="10000" or Jump/="01" then -- delay interrupts during branches (checked with Lorenz test and real 6510) not best way yet, though - but works... 482 | NMI_n_o <= NMI_n; 483 | end if; 484 | end if; 485 | end if; 486 | end process; 487 | 488 | --------------------------------------------------------------------------- 489 | -- 490 | -- Buses 491 | -- 492 | --------------------------------------------------------------------------- 493 | 494 | process (Res_n_i, Clk) 495 | begin 496 | if Res_n_i = '0' then 497 | BusA_r <= (others => '0'); 498 | BusB <= (others => '0'); 499 | BusB_r <= (others => '0'); 500 | AD <= (others => '0'); 501 | BAL <= (others => '0'); 502 | BAH <= (others => '0'); 503 | DL <= (others => '0'); 504 | elsif Clk'event and Clk = '1' then 505 | if (Enable = '1') then 506 | NMI_entered <= '0'; 507 | if (really_rdy = '1') then 508 | BusA_r <= BusA; 509 | BusB <= DI; 510 | 511 | -- not really nice, but no better way found yet ! 512 | if Set_Addr_To_r = Set_Addr_To_PBR or Set_Addr_To_r = Set_Addr_To_ZPG then 513 | BusB_r <= std_logic_vector(unsigned(DI(7 downto 0)) + 1); -- required for SHA 514 | end if; 515 | 516 | case BAAdd is 517 | when "01" => 518 | -- BA Inc 519 | AD <= std_logic_vector(unsigned(AD) + 1); 520 | BAL <= std_logic_vector(unsigned(BAL) + 1); 521 | when "10" => 522 | -- BA Add 523 | BAL <= std_logic_vector(resize(unsigned(BAL(7 downto 0)),9) + resize(unsigned(BusA),9)); 524 | when "11" => 525 | -- BA Adj 526 | if BAL(8) = '1' then 527 | BAH <= std_logic_vector(unsigned(BAH) + 1); 528 | end if; 529 | when others => 530 | end case; 531 | 532 | -- modified to use Y register as well 533 | if ADAdd = '1' then 534 | if (AddY = '1') then 535 | AD <= std_logic_vector(unsigned(AD) + unsigned(Y(7 downto 0))); 536 | else 537 | AD <= std_logic_vector(unsigned(AD) + unsigned(X(7 downto 0))); 538 | end if; 539 | end if; 540 | 541 | if IR = "00000000" then 542 | BAL <= (others => '1'); 543 | BAH <= (others => '1'); 544 | if RstCycle = '1' then 545 | BAL(2 downto 0) <= "100"; 546 | elsif NMICycle = '1' or (NMIAct = '1' and MCycle="100") or NMI_entered='1' then 547 | BAL(2 downto 0) <= "010"; 548 | if MCycle="100" then 549 | NMI_entered <= '1'; 550 | end if; 551 | else 552 | BAL(2 downto 0) <= "110"; 553 | end if; 554 | if Set_addr_To_r = Set_Addr_To_BA then 555 | BAL(0) <= '1'; 556 | end if; 557 | end if; 558 | 559 | if LDDI = '1' then 560 | DL <= DI; 561 | end if; 562 | if LDALU = '1' then 563 | DL <= ALU_Q; 564 | end if; 565 | if LDAD = '1' then 566 | AD <= DI; 567 | end if; 568 | if LDBAL = '1' then 569 | BAL(7 downto 0) <= DI; 570 | end if; 571 | if LDBAH = '1' then 572 | BAH <= DI; 573 | end if; 574 | end if; 575 | end if; 576 | end if; 577 | end process; 578 | 579 | Break <= (BreakAtNA and not BAL(8)) or (PCAdd and not PCAdder(8)); 580 | 581 | with Set_BusA_To select 582 | BusA <= 583 | DI when Set_BusA_To_DI, 584 | ABC(7 downto 0) when Set_BusA_To_ABC, 585 | X(7 downto 0) when Set_BusA_To_X, 586 | Y(7 downto 0) when Set_BusA_To_Y, 587 | std_logic_vector(S(7 downto 0)) when Set_BusA_To_S, 588 | P when Set_BusA_To_P, 589 | ABC(7 downto 0) and DI when Set_BusA_To_DA, 590 | (ABC(7 downto 0) or x"ee") and DI when Set_BusA_To_DAO,--ee for OAL instruction. constant may be different on other platforms.TODO:Move to generics 591 | (ABC(7 downto 0) or x"ee") and DI and X(7 downto 0) when Set_BusA_To_DAX,--XAA, ee for OAL instruction. constant may be different on other platforms.TODO:Move to generics 592 | ABC(7 downto 0) and X(7 downto 0) when Set_BusA_To_AAX,--SAX, SHA 593 | (others => '-') when Set_BusA_To_DONTCARE;--Can probably remove this 594 | 595 | with Set_Addr_To_r select 596 | A <= 597 | "0000000000000001" & std_logic_vector(S(7 downto 0)) when Set_Addr_To_SP, 598 | DBR & "00000000" & AD when Set_Addr_To_ZPG, 599 | "00000000" & BAH & BAL(7 downto 0) when Set_Addr_To_BA, 600 | PBR & std_logic_vector(PC(15 downto 8)) & std_logic_vector(PCAdder(7 downto 0)) when Set_Addr_To_PBR; 601 | 602 | -- This is the P that gets pushed on stack with correct B flag. I'm not sure if NMI also clears B, but I guess it does. 603 | PwithB<=(P and x"ef") when (IRQCycle='1' or NMICycle='1') else P; 604 | 605 | with Write_Data_r select 606 | DO <= 607 | DL when Write_Data_DL, 608 | ABC(7 downto 0) when Write_Data_ABC, 609 | X(7 downto 0) when Write_Data_X, 610 | Y(7 downto 0) when Write_Data_Y, 611 | std_logic_vector(S(7 downto 0)) when Write_Data_S, 612 | PwithB when Write_Data_P, 613 | std_logic_vector(PC(7 downto 0)) when Write_Data_PCL, 614 | std_logic_vector(PC(15 downto 8)) when Write_Data_PCH, 615 | ABC(7 downto 0) and X(7 downto 0) when Write_Data_AX, 616 | ABC(7 downto 0) and X(7 downto 0) and BusB_r(7 downto 0) when Write_Data_AXB, -- no better way found yet... 617 | X(7 downto 0) and BusB_r(7 downto 0) when Write_Data_XB, -- no better way found yet... 618 | Y(7 downto 0) and BusB_r(7 downto 0) when Write_Data_YB, -- no better way found yet... 619 | (others=>'-') when Write_Data_DONTCARE;--Can probably remove this 620 | 621 | 622 | ------------------------------------------------------------------------- 623 | -- 624 | -- Main state machine 625 | -- 626 | ------------------------------------------------------------------------- 627 | 628 | process (Res_n_i, Clk) 629 | begin 630 | if Res_n_i = '0' then 631 | MCycle <= "001"; 632 | RstCycle <= '1'; 633 | IRQCycle <= '0'; 634 | NMICycle <= '0'; 635 | NMIAct <= '0'; 636 | elsif Clk'event and Clk = '1' then 637 | if (Enable = '1') then 638 | if (really_rdy = '1') then 639 | if MCycle = LCycle or Break = '1' then 640 | MCycle <= "000"; 641 | RstCycle <= '0'; 642 | IRQCycle <= '0'; 643 | NMICycle <= '0'; 644 | if NMIAct = '1' and IR/=x"00" then -- delay NMI further if we just executed a BRK 645 | NMICycle <= '1'; 646 | NMIAct <= '0'; -- reset NMI edge detector if we start processing the NMI 647 | elsif IRQ_n_o = '0' and P(Flag_I) = '0' then 648 | IRQCycle <= '1'; 649 | end if; 650 | else 651 | MCycle <= std_logic_vector(unsigned(MCycle) + 1); 652 | end if; 653 | end if; 654 | --detect NMI even if not rdy 655 | if NMI_n_o = '1' and (NMI_n = '0' and (IR(4 downto 0)/="10000" or Jump/="01")) then -- branches have influence on NMI start (not best way yet, though - but works...) 656 | NMIAct <= '1'; 657 | end if; 658 | -- we entered NMI during BRK instruction 659 | if NMI_entered='1' then 660 | NMIAct <= '0'; 661 | end if; 662 | end if; 663 | end if; 664 | end process; 665 | 666 | end; 667 | -------------------------------------------------------------------------------- /T65_ALU.vhd: -------------------------------------------------------------------------------- 1 | -- **** 2 | -- T65(b) core. In an effort to merge and maintain bug fixes .... 3 | -- 4 | -- See list of changes in T65 top file (T65.vhd)... 5 | -- 6 | -- **** 7 | -- 65xx compatible microprocessor core 8 | -- 9 | -- FPGAARCADE SVN: $Id: T65_ALU.vhd 2653 2018-06-05 18:14:10Z gary.mups $ 10 | -- 11 | -- Copyright (c) 2002...2015 12 | -- Daniel Wallner (jesus opencores org) 13 | -- Mike Johnson (mikej fpgaarcade com) 14 | -- Wolfgang Scherr (WoS pin4 at> 15 | -- Morten Leikvoll () 16 | -- 17 | -- All rights reserved 18 | -- 19 | -- Redistribution and use in source and synthezised forms, with or without 20 | -- modification, are permitted provided that the following conditions are met: 21 | -- 22 | -- Redistributions of source code must retain the above copyright notice, 23 | -- this list of conditions and the following disclaimer. 24 | -- 25 | -- Redistributions in synthesized form must reproduce the above copyright 26 | -- notice, this list of conditions and the following disclaimer in the 27 | -- documentation and/or other materials provided with the distribution. 28 | -- 29 | -- Neither the name of the author nor the names of other contributors may 30 | -- be used to endorse or promote products derived from this software without 31 | -- specific prior written permission. 32 | -- 33 | -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 34 | -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 35 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 36 | -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 37 | -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 38 | -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 39 | -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 40 | -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 41 | -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 42 | -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 43 | -- POSSIBILITY OF SUCH DAMAGE. 44 | -- 45 | -- Please report bugs to the author(s), but before you do so, please 46 | -- make sure that this is not a derivative work and that 47 | -- you have the latest version of this file. 48 | -- 49 | -- Limitations : 50 | -- See in T65 top file (T65.vhd)... 51 | 52 | library IEEE; 53 | use IEEE.std_logic_1164.all; 54 | use IEEE.numeric_std.all; 55 | use work.T65_Pack.all; 56 | 57 | entity T65_ALU is 58 | port( 59 | Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65816 60 | Op : in T_ALU_OP; 61 | BusA : in std_logic_vector(7 downto 0); 62 | BusB : in std_logic_vector(7 downto 0); 63 | P_In : in std_logic_vector(7 downto 0); 64 | P_Out : out std_logic_vector(7 downto 0); 65 | Q : out std_logic_vector(7 downto 0) 66 | ); 67 | end T65_ALU; 68 | 69 | architecture rtl of T65_ALU is 70 | 71 | -- AddSub variables (temporary signals) 72 | signal ADC_Z : std_logic; 73 | signal ADC_C : std_logic; 74 | signal ADC_V : std_logic; 75 | signal ADC_N : std_logic; 76 | signal ADC_Q : std_logic_vector(7 downto 0); 77 | signal SBC_Z : std_logic; 78 | signal SBC_C : std_logic; 79 | signal SBC_V : std_logic; 80 | signal SBC_N : std_logic; 81 | signal SBC_Q : std_logic_vector(7 downto 0); 82 | signal SBX_Q : std_logic_vector(7 downto 0); 83 | 84 | begin 85 | 86 | process (P_In, BusA, BusB) 87 | variable AL : unsigned(6 downto 0); 88 | variable AH : unsigned(6 downto 0); 89 | variable C : std_logic; 90 | begin 91 | AL := resize(unsigned(BusA(3 downto 0) & P_In(Flag_C)), 7) + resize(unsigned(BusB(3 downto 0) & "1"), 7); 92 | AH := resize(unsigned(BusA(7 downto 4) & AL(5)), 7) + resize(unsigned(BusB(7 downto 4) & "1"), 7); 93 | 94 | -- pragma translate_off 95 | if is_x(std_logic_vector(AL)) then AL := "0000000"; end if; 96 | if is_x(std_logic_vector(AH)) then AH := "0000000"; end if; 97 | -- pragma translate_on 98 | 99 | if AL(4 downto 1) = 0 and AH(4 downto 1) = 0 then 100 | ADC_Z <= '1'; 101 | else 102 | ADC_Z <= '0'; 103 | end if; 104 | 105 | if AL(5 downto 1) > 9 and P_In(Flag_D) = '1' then 106 | AL(6 downto 1) := AL(6 downto 1) + 6; 107 | end if; 108 | 109 | C := AL(6) or AL(5); 110 | AH := resize(unsigned(BusA(7 downto 4) & C), 7) + resize(unsigned(BusB(7 downto 4) & "1"), 7); 111 | 112 | ADC_N <= AH(4); 113 | ADC_V <= (AH(4) xor BusA(7)) and not (BusA(7) xor BusB(7)); 114 | 115 | -- pragma translate_off 116 | if is_x(std_logic_vector(AH)) then AH := "0000000"; end if; 117 | -- pragma translate_on 118 | 119 | if AH(5 downto 1) > 9 and P_In(Flag_D) = '1' then 120 | AH(6 downto 1) := AH(6 downto 1) + 6; 121 | end if; 122 | 123 | ADC_C <= AH(6) or AH(5); 124 | 125 | ADC_Q <= std_logic_vector(AH(4 downto 1) & AL(4 downto 1)); 126 | end process; 127 | 128 | process (Op, P_In, BusA, BusB) 129 | variable AL : unsigned(6 downto 0); 130 | variable AH : unsigned(5 downto 0); 131 | variable C : std_logic; 132 | variable CT : std_logic; 133 | begin 134 | CT:='0'; 135 | if( Op=ALU_OP_AND or --"0001" These OpCodes used to have LSB set 136 | Op=ALU_OP_ADC or --"0011" 137 | Op=ALU_OP_EQ2 or --"0101" 138 | Op=ALU_OP_SBC or --"0111" 139 | Op=ALU_OP_ROL or --"1001" 140 | Op=ALU_OP_ROR or --"1011" 141 | -- Op=ALU_OP_EQ3 or --"1101" 142 | Op=ALU_OP_INC --"1111" 143 | ) then 144 | CT:='1'; 145 | end if; 146 | 147 | C := P_In(Flag_C) or not CT;--was: or not Op(0); 148 | AL := resize(unsigned(BusA(3 downto 0) & C), 7) - resize(unsigned(BusB(3 downto 0) & "1"), 6); 149 | AH := resize(unsigned(BusA(7 downto 4) & "0"), 6) - resize(unsigned(BusB(7 downto 4) & AL(5)), 6); 150 | 151 | -- pragma translate_off 152 | if is_x(std_logic_vector(AL)) then AL := "0000000"; end if; 153 | if is_x(std_logic_vector(AH)) then AH := "000000"; end if; 154 | -- pragma translate_on 155 | 156 | if AL(4 downto 1) = 0 and AH(4 downto 1) = 0 then 157 | SBC_Z <= '1'; 158 | else 159 | SBC_Z <= '0'; 160 | end if; 161 | 162 | SBC_C <= not AH(5); 163 | SBC_V <= (AH(4) xor BusA(7)) and (BusA(7) xor BusB(7)); 164 | SBC_N <= AH(4); 165 | 166 | SBX_Q <= std_logic_vector(AH(4 downto 1) & AL(4 downto 1)); 167 | 168 | if P_In(Flag_D) = '1' then 169 | if AL(5) = '1' then 170 | AL(5 downto 1) := AL(5 downto 1) - 6; 171 | end if; 172 | AH := resize(unsigned(BusA(7 downto 4) & "0"), 6) - resize(unsigned(BusB(7 downto 4) & AL(6)), 6); 173 | if AH(5) = '1' then 174 | AH(5 downto 1) := AH(5 downto 1) - 6; 175 | end if; 176 | end if; 177 | 178 | SBC_Q <= std_logic_vector(AH(4 downto 1) & AL(4 downto 1)); 179 | end process; 180 | 181 | process (Op, P_In, BusA, BusB, 182 | ADC_Z, ADC_C, ADC_V, ADC_N, ADC_Q, 183 | SBC_Z, SBC_C, SBC_V, SBC_N, SBC_Q) 184 | variable Q_t : std_logic_vector(7 downto 0); 185 | variable Q2_t : std_logic_vector(7 downto 0); 186 | begin 187 | -- ORA, AND, EOR, ADC, NOP, LD, CMP, SBC 188 | -- ASL, ROL, LSR, ROR, BIT, LD, DEC, INC 189 | P_Out <= P_In; 190 | Q_t := BusA; 191 | Q2_t := BusA; 192 | case Op is 193 | when ALU_OP_OR=> 194 | Q_t := BusA or BusB; 195 | when ALU_OP_AND=> 196 | Q_t := BusA and BusB; 197 | when ALU_OP_EOR=> 198 | Q_t := BusA xor BusB; 199 | when ALU_OP_ADC=> 200 | P_Out(Flag_V) <= ADC_V; 201 | P_Out(Flag_C) <= ADC_C; 202 | Q_t := ADC_Q; 203 | when ALU_OP_CMP=> 204 | P_Out(Flag_C) <= SBC_C; 205 | when ALU_OP_SAX=> 206 | P_Out(Flag_C) <= SBC_C; 207 | Q_t := SBX_Q; -- undoc: subtract (A & X) - (immediate) 208 | when ALU_OP_SBC=> 209 | P_Out(Flag_V) <= SBC_V; 210 | P_Out(Flag_C) <= SBC_C; 211 | Q_t := SBC_Q; -- undoc: subtract (A & X) - (immediate), then decimal correction 212 | when ALU_OP_ASL=> 213 | Q_t := BusA(6 downto 0) & "0"; 214 | P_Out(Flag_C) <= BusA(7); 215 | when ALU_OP_ROL=> 216 | Q_t := BusA(6 downto 0) & P_In(Flag_C); 217 | P_Out(Flag_C) <= BusA(7); 218 | when ALU_OP_LSR=> 219 | Q_t := "0" & BusA(7 downto 1); 220 | P_Out(Flag_C) <= BusA(0); 221 | when ALU_OP_ROR=> 222 | Q_t := P_In(Flag_C) & BusA(7 downto 1); 223 | P_Out(Flag_C) <= BusA(0); 224 | when ALU_OP_ARR=> 225 | Q_t := P_In(Flag_C) & (BusA(7 downto 1) and BusB(7 downto 1)); 226 | P_Out(Flag_V) <= Q_t(5) xor Q_t(6); 227 | Q2_t := Q_t; 228 | if P_In(Flag_D)='1' then 229 | if (BusA(3 downto 0) and BusB(3 downto 0)) > "0100" then 230 | Q2_t(3 downto 0) := std_logic_vector(unsigned(Q_t(3 downto 0)) + x"6"); 231 | end if; 232 | if (BusA(7 downto 4) and BusB(7 downto 4)) > "0100" then 233 | Q2_t(7 downto 4) := std_logic_vector(unsigned(Q_t(7 downto 4)) + x"6"); 234 | P_Out(Flag_C) <= '1'; 235 | else 236 | P_Out(Flag_C) <= '0'; 237 | end if; 238 | else 239 | P_Out(Flag_C) <= Q_t(6); 240 | end if; 241 | when ALU_OP_BIT=> 242 | P_Out(Flag_V) <= BusB(6); 243 | when ALU_OP_DEC=> 244 | Q_t := std_logic_vector(unsigned(BusA) - 1); 245 | when ALU_OP_INC=> 246 | Q_t := std_logic_vector(unsigned(BusA) + 1); 247 | when others => 248 | null; 249 | --EQ1,EQ2,EQ3 passes BusA to Q_t and P_in to P_out 250 | end case; 251 | 252 | case Op is 253 | when ALU_OP_ADC=> 254 | P_Out(Flag_N) <= ADC_N; 255 | P_Out(Flag_Z) <= ADC_Z; 256 | when ALU_OP_CMP|ALU_OP_SBC|ALU_OP_SAX=> 257 | P_Out(Flag_N) <= SBC_N; 258 | P_Out(Flag_Z) <= SBC_Z; 259 | when ALU_OP_EQ1=>--dont touch P 260 | when ALU_OP_BIT=> 261 | P_Out(Flag_N) <= BusB(7); 262 | if (BusA and BusB) = "00000000" then 263 | P_Out(Flag_Z) <= '1'; 264 | else 265 | P_Out(Flag_Z) <= '0'; 266 | end if; 267 | when ALU_OP_ANC=> 268 | P_Out(Flag_N) <= Q_t(7); 269 | P_Out(Flag_C) <= Q_t(7); 270 | if Q_t = "00000000" then 271 | P_Out(Flag_Z) <= '1'; 272 | else 273 | P_Out(Flag_Z) <= '0'; 274 | end if; 275 | when others => 276 | P_Out(Flag_N) <= Q_t(7); 277 | if Q_t = "00000000" then 278 | P_Out(Flag_Z) <= '1'; 279 | else 280 | P_Out(Flag_Z) <= '0'; 281 | end if; 282 | end case; 283 | 284 | if Op=ALU_OP_ARR then 285 | -- handled above in ARR code 286 | Q <= Q2_t; 287 | else 288 | Q <= Q_t; 289 | end if; 290 | end process; 291 | 292 | end; 293 | -------------------------------------------------------------------------------- /T65_Pack.vhd: -------------------------------------------------------------------------------- 1 | -- **** 2 | -- T65(b) core. In an effort to merge and maintain bug fixes .... 3 | -- 4 | -- See list of changes in T65 top file (T65.vhd)... 5 | -- 6 | -- **** 7 | -- 65xx compatible microprocessor core 8 | -- 9 | -- FPGAARCADE SVN: $Id: T65_Pack.vhd 1234 2015-02-28 20:14:50Z wolfgang.scherr $ 10 | -- 11 | -- Copyright (c) 2002...2015 12 | -- Daniel Wallner (jesus opencores org) 13 | -- Mike Johnson (mikej fpgaarcade com) 14 | -- Wolfgang Scherr (WoS pin4 at> 15 | -- Morten Leikvoll () 16 | -- 17 | -- All rights reserved 18 | -- 19 | -- Redistribution and use in source and synthezised forms, with or without 20 | -- modification, are permitted provided that the following conditions are met: 21 | -- 22 | -- Redistributions of source code must retain the above copyright notice, 23 | -- this list of conditions and the following disclaimer. 24 | -- 25 | -- Redistributions in synthesized form must reproduce the above copyright 26 | -- notice, this list of conditions and the following disclaimer in the 27 | -- documentation and/or other materials provided with the distribution. 28 | -- 29 | -- Neither the name of the author nor the names of other contributors may 30 | -- be used to endorse or promote products derived from this software without 31 | -- specific prior written permission. 32 | -- 33 | -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 34 | -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 35 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 36 | -- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE 37 | -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 38 | -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 39 | -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 40 | -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 41 | -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 42 | -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 43 | -- POSSIBILITY OF SUCH DAMAGE. 44 | -- 45 | -- Please report bugs to the author(s), but before you do so, please 46 | -- make sure that this is not a derivative work and that 47 | -- you have the latest version of this file. 48 | -- 49 | -- Limitations : 50 | -- See in T65 top file (T65.vhd)... 51 | 52 | library IEEE; 53 | use IEEE.std_logic_1164.all; 54 | 55 | package T65_Pack is 56 | 57 | constant Flag_C : integer := 0; 58 | constant Flag_Z : integer := 1; 59 | constant Flag_I : integer := 2; 60 | constant Flag_D : integer := 3; 61 | constant Flag_B : integer := 4; 62 | constant Flag_1 : integer := 5; 63 | constant Flag_V : integer := 6; 64 | constant Flag_N : integer := 7; 65 | 66 | subtype T_Lcycle is std_logic_vector(2 downto 0); 67 | constant Cycle_sync :T_Lcycle:="000"; 68 | constant Cycle_1 :T_Lcycle:="001"; 69 | constant Cycle_2 :T_Lcycle:="010"; 70 | constant Cycle_3 :T_Lcycle:="011"; 71 | constant Cycle_4 :T_Lcycle:="100"; 72 | constant Cycle_5 :T_Lcycle:="101"; 73 | constant Cycle_6 :T_Lcycle:="110"; 74 | constant Cycle_7 :T_Lcycle:="111"; 75 | 76 | function CycleNext(c:T_Lcycle) return T_Lcycle; 77 | 78 | type T_Set_BusA_To is 79 | ( 80 | Set_BusA_To_DI, 81 | Set_BusA_To_ABC, 82 | Set_BusA_To_X, 83 | Set_BusA_To_Y, 84 | Set_BusA_To_S, 85 | Set_BusA_To_P, 86 | Set_BusA_To_DA, 87 | Set_BusA_To_DAO, 88 | Set_BusA_To_DAX, 89 | Set_BusA_To_AAX, 90 | Set_BusA_To_DONTCARE 91 | ); 92 | 93 | type T_Set_Addr_To is 94 | ( 95 | Set_Addr_To_SP, 96 | Set_Addr_To_ZPG, 97 | Set_Addr_To_PBR, 98 | Set_Addr_To_BA 99 | ); 100 | 101 | type T_Write_Data is 102 | ( 103 | Write_Data_DL, 104 | Write_Data_ABC, 105 | Write_Data_X, 106 | Write_Data_Y, 107 | Write_Data_S, 108 | Write_Data_P, 109 | Write_Data_PCL, 110 | Write_Data_PCH, 111 | Write_Data_AX, 112 | Write_Data_AXB, 113 | Write_Data_XB, 114 | Write_Data_YB, 115 | Write_Data_DONTCARE 116 | ); 117 | 118 | type T_ALU_OP is 119 | ( 120 | ALU_OP_OR, --"0000" 121 | ALU_OP_AND, --"0001" 122 | ALU_OP_EOR, --"0010" 123 | ALU_OP_ADC, --"0011" 124 | ALU_OP_EQ1, --"0100" EQ1 does not change N,Z flags, EQ2/3 does. 125 | ALU_OP_EQ2, --"0101" Not sure yet whats the difference between EQ2&3. They seem to do the same ALU op 126 | ALU_OP_CMP, --"0110" 127 | ALU_OP_SBC, --"0111" 128 | ALU_OP_ASL, --"1000" 129 | ALU_OP_ROL, --"1001" 130 | ALU_OP_LSR, --"1010" 131 | ALU_OP_ROR, --"1011" 132 | ALU_OP_BIT, --"1100" 133 | -- ALU_OP_EQ3, --"1101" 134 | ALU_OP_DEC, --"1110" 135 | ALU_OP_INC, --"1111" 136 | ALU_OP_ARR, 137 | ALU_OP_ANC, 138 | ALU_OP_SAX, 139 | ALU_OP_XAA 140 | -- ALU_OP_UNDEF--"----"--may be replaced with any? 141 | ); 142 | 143 | type T_t65_dbg is record 144 | I : std_logic_vector(7 downto 0); -- instruction 145 | A : std_logic_vector(7 downto 0); -- A reg 146 | X : std_logic_vector(7 downto 0); -- X reg 147 | Y : std_logic_vector(7 downto 0); -- Y reg 148 | S : std_logic_vector(7 downto 0); -- stack pointer 149 | P : std_logic_vector(7 downto 0); -- processor flags 150 | end record; 151 | 152 | end; 153 | 154 | package body T65_Pack is 155 | 156 | function CycleNext(c:T_Lcycle) return T_Lcycle is 157 | begin 158 | case(c) is 159 | when Cycle_sync=> 160 | return Cycle_1; 161 | when Cycle_1=> 162 | return Cycle_2; 163 | when Cycle_2=> 164 | return Cycle_3; 165 | when Cycle_3=> 166 | return Cycle_4; 167 | when Cycle_4=> 168 | return Cycle_5; 169 | when Cycle_5=> 170 | return Cycle_6; 171 | when Cycle_6=> 172 | return Cycle_7; 173 | when Cycle_7=> 174 | return Cycle_sync; 175 | when others=> 176 | return Cycle_sync; 177 | end case; 178 | end CycleNext; 179 | 180 | end T65_Pack; -------------------------------------------------------------------------------- /TEDwingPro.ucf: -------------------------------------------------------------------------------- 1 | ################################################################################## 2 | ## Copyright 2013-2016 Istvan Hegedus 3 | ## 4 | ## FPGATED is free software: you can redistribute it and/or modify 5 | ## it under the terms of the GNU General Public License as published by 6 | ## the Free Software Foundation, either version 3 of the License, or 7 | ## (at your option) any later version. 8 | ## 9 | ## FPGATED is distributed in the hope that it will be useful, 10 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | ## GNU General Public License for more details. 13 | ## 14 | ## You should have received a copy of the GNU General Public License 15 | ## along with this program. If not, see . 16 | ## 17 | ## 18 | ## Contains assignment and iostandard information for Papilio TEDWing v1.x using Papilio Pro platform 19 | ## 20 | ################################################################################## 21 | 22 | # Main Papilio Pro board wing pin [] to FPGA pin Pxx map 23 | # -------C------- -------B------- -------A------- 24 | # [GND] [C00] P114 [GND] [B00] P99 P100 [A15] 25 | # [2V5] [C01] P115 [2V5] [B01] P97 P98 [A14] 26 | # [3V3] [C02] P116 [3V3] [B02] P92 P93 [A13] 27 | # [5V0] [C03] P117 [5V0] [B03] P87 P88 [A12] 28 | # [C04] P118 [B04] P84 P85 [A11] [5V0] 29 | # [C05] P119 [B05] P82 P83 [A10] [3V3] 30 | # [C06] P120 [B06] P80 P81 [A09] [2V5] 31 | # [C07] P121 [B07] P78 P79 [A08] [GND] 32 | # [GND] [C08] P123 [GND] [B08] P74 P75 [A07] 33 | # [2V5] [C09] P124 [2V5] [B09] P95 P67 [A06] 34 | # [3V3] [C10] P126 [3V3] [B10] P62 P66 [A05] 35 | # [5V0] [C11] P127 [5V0] [B11] P59 P61 [A04] 36 | # [C12] P131 [B12] P57 P58 [A03] [5V0] 37 | # [C13] P132 [B13] P55 P56 [A02] [3V3] 38 | # [C14] P133 [B14] P50 P51 [A01] [2V5] 39 | # [C15] P134 [B15] P47 P48 [A00] [GND] 40 | 41 | ## Prohibit the automatic placement of pins that are connected to VCC or GND for configuration. 42 | CONFIG PROHIBIT=P144; 43 | CONFIG PROHIBIT=P69; 44 | CONFIG PROHIBIT=P60; 45 | 46 | # Crystal Clock - use 32MHz onboard oscillator 47 | NET "CLK32" LOC = "P94" | IOSTANDARD = LVTTL | PERIOD = 31.25ns ; 48 | 49 | # Wing1 Column A 50 | #NET RGBS LOC = "P48" | IOSTANDARD = LVTTL; 51 | #NET RS232_RX LOC = "P51" | IOSTANDARD = LVTTL; 52 | #NET RS232_TX LOC = "P56" | IOSTANDARD = LVTTL; 53 | NET RESET LOC = "P58" | IOSTANDARD = LVTTL; 54 | NET AUDIO_R LOC = "P61" | IOSTANDARD = LVTTL; 55 | NET AUDIO_L LOC = "P66" | IOSTANDARD = LVTTL; 56 | #NET RAS LOC = "P67" | IOSTANDARD = LVTTL; 57 | #NET RW LOC = "P75" | IOSTANDARD = LVTTL; 58 | #NET CAS LOC = "P79" | IOSTANDARD = LVTTL; 59 | NET IEC_DATAOUT LOC = "P81" | IOSTANDARD = LVTTL; 60 | NET IEC_DATAIN LOC = "P83" | IOSTANDARD = LVTTL; 61 | NET IEC_CLKOUT LOC = "P85" | IOSTANDARD = LVTTL; 62 | NET IEC_CLKIN LOC = "P88" | IOSTANDARD = LVTTL; 63 | NET IEC_ATNOUT LOC = "P93" | IOSTANDARD = LVTTL; 64 | #NET IEC_ATNIN LOC = "P98" | IOSTANDARD = LVTTL; 65 | NET IEC_RESET LOC = "P100" | IOSTANDARD = LVTTL; 66 | 67 | # Wing1 Column B 68 | #NET D[0] LOC = "P99" | IOSTANDARD = LVTTL; 69 | #NET D[1] LOC = "P97" | IOSTANDARD = LVTTL; 70 | #NET D[2] LOC = "P92" | IOSTANDARD = LVTTL; 71 | #NET D[3] LOC = "P87" | IOSTANDARD = LVTTL; 72 | #NET D[4] LOC = "P84" | IOSTANDARD = LVTTL; 73 | #NET D[5] LOC = "P82" | IOSTANDARD = LVTTL; 74 | #NET D[6] LOC = "P80" | IOSTANDARD = LVTTL; 75 | #NET D[7] LOC = "P78" | IOSTANDARD = LVTTL; 76 | #NET A[0] LOC = "P74" | IOSTANDARD = LVTTL; 77 | #NET A[1] LOC = "P95" | IOSTANDARD = LVTTL; 78 | #NET A[2] LOC = "P62" | IOSTANDARD = LVTTL; 79 | #NET A[3] LOC = "P59" | IOSTANDARD = LVTTL; 80 | #NET A[4] LOC = "P57" | IOSTANDARD = LVTTL; 81 | #NET A[5] LOC = "P55" | IOSTANDARD = LVTTL; 82 | #NET A[6] LOC = "P50" | IOSTANDARD = LVTTL; 83 | #NET A[7] LOC = "P47" | IOSTANDARD = LVTTL; 84 | 85 | # Wing2 Column C 86 | NET VSYNC LOC = "P114" | IOSTANDARD = LVTTL; 87 | NET HSYNC LOC = "P115" | IOSTANDARD = LVTTL; 88 | NET RED[0] LOC = "P116" | IOSTANDARD = LVTTL; 89 | NET RED[1] LOC = "P117" | IOSTANDARD = LVTTL; 90 | NET RED[2] LOC = "P118" | IOSTANDARD = LVTTL; 91 | NET RED[3] LOC = "P119" | IOSTANDARD = LVTTL; 92 | NET GREEN[0] LOC = "P120" | IOSTANDARD = LVTTL; 93 | NET GREEN[1] LOC = "P121" | IOSTANDARD = LVTTL; 94 | NET GREEN[2] LOC = "P123" | IOSTANDARD = LVTTL; 95 | NET GREEN[3] LOC = "P124" | IOSTANDARD = LVTTL; 96 | NET BLUE[0] LOC = "P126" | IOSTANDARD = LVTTL; 97 | NET BLUE[1] LOC = "P127" | IOSTANDARD = LVTTL; 98 | NET BLUE[2] LOC = "P131" | IOSTANDARD = LVTTL; 99 | NET BLUE[3] LOC = "P132" | IOSTANDARD = LVTTL; 100 | NET PS2DAT LOC = "P133" | IOSTANDARD = LVTTL; 101 | NET PS2CLK LOC = "P134" | IOSTANDARD = LVTTL; 102 | 103 | # Papilo Pro non wing related pinouts 104 | 105 | #RS232 106 | #NET RX LOC="P101" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # RX 107 | #NET TX LOC="P105" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST | PULLUP; # TX 108 | 109 | # SDRAM related pins 110 | NET SDRAM_ADDR(0) LOC="P140" | IOSTANDARD=LVTTL; # SDRAM_ADDR0 111 | NET SDRAM_ADDR(1) LOC="P139" | IOSTANDARD=LVTTL; # SDRAM_ADDR1 112 | NET SDRAM_ADDR(2) LOC="P138" | IOSTANDARD=LVTTL; # SDRAM_ADDR2 113 | NET SDRAM_ADDR(3) LOC="P137" | IOSTANDARD=LVTTL; # SDRAM_ADDR3 114 | NET SDRAM_ADDR(4) LOC="P46" | IOSTANDARD=LVTTL; # SDRAM_ADDR4 115 | NET SDRAM_ADDR(5) LOC="P45" | IOSTANDARD=LVTTL; # SDRAM_ADDR5 116 | NET SDRAM_ADDR(6) LOC="P44" | IOSTANDARD=LVTTL; # SDRAM_ADDR6 117 | NET SDRAM_ADDR(7) LOC="P43" | IOSTANDARD=LVTTL; # SDRAM_ADDR7 118 | NET SDRAM_ADDR(8) LOC="P41" | IOSTANDARD=LVTTL; # SDRAM_ADDR8 119 | NET SDRAM_ADDR(9) LOC="P40" | IOSTANDARD=LVTTL; # SDRAM_ADDR9 120 | NET SDRAM_ADDR(10) LOC="P141" | IOSTANDARD=LVTTL; # SDRAM_ADDR10 121 | NET SDRAM_ADDR(11) LOC="P35" | IOSTANDARD=LVTTL; # SDRAM_ADDR11 122 | #NET SDRAM_ADDR(12) LOC="P34" | IOSTANDARD=LVTTL; # SDRAM_ADDR12 is tied to GND on Papilio Pro with MT48LC4M16A2 chip 123 | NET SDRAM_DATA(0) LOC="P9" | IOSTANDARD=LVTTL; # SDRAM_DATA0 124 | NET SDRAM_DATA(1) LOC="P10" | IOSTANDARD=LVTTL; # SDRAM_DATA1 125 | NET SDRAM_DATA(2) LOC="P11" | IOSTANDARD=LVTTL; # SDRAM_DATA2 126 | NET SDRAM_DATA(3) LOC="P12" | IOSTANDARD=LVTTL; # SDRAM_DATA3 127 | NET SDRAM_DATA(4) LOC="P14" | IOSTANDARD=LVTTL; # SDRAM_DATA4 128 | NET SDRAM_DATA(5) LOC="P15" | IOSTANDARD=LVTTL; # SDRAM_DATA5 129 | NET SDRAM_DATA(6) LOC="P16" | IOSTANDARD=LVTTL; # SDRAM_DATA6 130 | NET SDRAM_DATA(7) LOC="P8" | IOSTANDARD=LVTTL; # SDRAM_DATA7 131 | NET SDRAM_DATA(8) LOC="P21" | IOSTANDARD=LVTTL; # SDRAM_DATA8 132 | NET SDRAM_DATA(9) LOC="P22" | IOSTANDARD=LVTTL; # SDRAM_DATA9 133 | NET SDRAM_DATA(10) LOC="P23" | IOSTANDARD=LVTTL; # SDRAM_DATA10 134 | NET SDRAM_DATA(11) LOC="P24" | IOSTANDARD=LVTTL; # SDRAM_DATA11 135 | NET SDRAM_DATA(12) LOC="P26" | IOSTANDARD=LVTTL; # SDRAM_DATA12 136 | NET SDRAM_DATA(13) LOC="P27" | IOSTANDARD=LVTTL; # SDRAM_DATA13 137 | NET SDRAM_DATA(14) LOC="P29" | IOSTANDARD=LVTTL; # SDRAM_DATA14 138 | NET SDRAM_DATA(15) LOC="P30" | IOSTANDARD=LVTTL; # SDRAM_DATA15 139 | NET SDRAM_DQML LOC="P7" | IOSTANDARD=LVTTL; # SDRAM_DQML 140 | NET SDRAM_DQMH LOC="P17" | IOSTANDARD=LVTTL; # SDRAM_DQMH 141 | NET SDRAM_BA(0) LOC="P143" | IOSTANDARD=LVTTL; # SDRAM_BA0 142 | NET SDRAM_BA(1) LOC="P142" | IOSTANDARD=LVTTL; # SDRAM_BA1 143 | NET SDRAM_nWE LOC="P6" | IOSTANDARD=LVTTL; # SDRAM_nWE 144 | NET SDRAM_nCAS LOC="P5" | IOSTANDARD=LVTTL; # SDRAM_nCAS 145 | NET SDRAM_nRAS LOC="P2" | IOSTANDARD=LVTTL; # SDRAM_nRAS 146 | NET SDRAM_CS LOC="P1" | IOSTANDARD=LVTTL; # SDRAM_CS 147 | NET SDRAM_CLK LOC="P32" | IOSTANDARD=LVTTL; # SDRAM_CLK 148 | NET SDRAM_CKE LOC="P33" | IOSTANDARD=LVTTL; # SDRAM_CKE 149 | 150 | # End User LED 151 | #NET LED1 LOC="P112" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=SLOW; # LED1 152 | 153 | # JTAG pins 154 | #NET JTAG_TMS LOC="P107" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # JTAG_TMS 155 | #NET JTAG_TCK LOC="P109" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # JTAG_TCK 156 | #NET JTAG_TDI LOC="P110" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # JTAG_TDI 157 | #NET JTAG_TDO LOC="P106" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # JTAG_TDO 158 | 159 | # Flash memory pins 160 | NET FLASH_CS LOC="P38" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # FLASH_CS 161 | NET FLASH_CK LOC="P70" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # FLASH_CK 162 | NET FLASH_SI LOC="P64" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # FLASH_SI 163 | NET FLASH_SO LOC="P65" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST | PULLUP; # FLASH_SO -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-time-machine -------------------------------------------------------------------------------- /addrom.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "wingetopt.h" 5 | 6 | void usage(void) 7 | { 8 | printf("\nAppend a binary ROM to a rompack file for FPGATED use"); 9 | printf("\n\nUsage: addrom -t romtype -p romposition -v romversion outputfile inputfile "); 10 | printf("\n\n-t\tROM type. Valid values are"); 11 | printf("\n\tInt\tInternal ROM location (Kernal or Basic)"); 12 | printf("\n\tFunc\tFunction ROM location"); 13 | printf("\n\tC1\tCartridge1 ROM location"); 14 | printf("\n\tC2\tCartridge2 ROM location"); 15 | printf("\n\n-p\tROM position. Valid values are Low or High based on ROM position"); 16 | printf("\n\n-v\tAlternative ROM version. Valid values are from 0-15."); 17 | printf("\n\tIt is used for storing different ROM versions of the same ROM type."); 18 | printf("\n\tDefault value is 0 which is the ROM accessed at device power on.\n"); 19 | printf("\nVersion 1.0\n\n"); 20 | exit(1); 21 | } 22 | 23 | int main(int argc, char *argv[]) 24 | { 25 | char romtype=0; 26 | char optflag = 0; 27 | short romsize=0; 28 | int c; 29 | int i; 30 | FILE *outfile, *infile; 31 | 32 | opterr = 0; 33 | 34 | // identifying options 35 | 36 | while ((c = getopt(argc, argv, "t:p:v:")) != -1) 37 | { 38 | switch (c) { 39 | case 't': 40 | if (!strcmp(optarg, "int") || !strcmp(optarg, "Int")) 41 | romtype = romtype & 0xFC; 42 | else if (!strcmp(optarg, "func") || !strcmp(optarg, "Func")) 43 | romtype = (romtype & 0xFC) | 0x01; 44 | else if (!strcmp(optarg, "c1") || !strcmp(optarg, "C1")) 45 | romtype = (romtype & 0xFC) | 0x02; 46 | else if (!strcmp(optarg, "c2") || !strcmp(optarg, "C2")) 47 | romtype = (romtype & 0xFC) | 0x03; 48 | else usage(); 49 | optflag = optflag|0x01; 50 | break; 51 | case 'p': 52 | if (!strcmp(optarg, "low") || !strcmp(optarg, "Low")) 53 | romtype = romtype & 0xBF; 54 | else if (!strcmp(optarg, "high") || !strcmp(optarg, "High")) 55 | romtype = (romtype & 0xBF) | 0x40; 56 | else usage(); 57 | optflag = optflag | 0x02; 58 | break; 59 | case 'v': 60 | if (atoi(optarg) < 16) 61 | romtype = (romtype & 0xC3) | (atoi(optarg) << 2); 62 | else usage(); 63 | optflag = optflag | 0x04; 64 | break; 65 | } 66 | } 67 | 68 | if (!(optflag & 0x01)) 69 | { 70 | printf("ROM type parameter is missing!\n"); 71 | usage(); 72 | } 73 | else if (!(optflag & 0x02)) 74 | { 75 | printf("ROM position parameter is missing!\n"); 76 | usage(); 77 | } 78 | else if (!(optflag & 0x04)) 79 | { 80 | printf("ROM image version parameter is missing!\n"); 81 | usage(); 82 | } 83 | 84 | // checking filename parameters 85 | 86 | if (argv[optind] == NULL || argv[optind + 1] == NULL) { 87 | printf("Input or Output file name is missing!\n"); 88 | exit(-1); 89 | } 90 | 91 | // opening files for read and write 92 | 93 | if ((infile = fopen(argv[optind + 1], "rb")) == NULL) 94 | { 95 | printf("Error: %s", strerror(errno)); 96 | exit(-1); 97 | } 98 | else if ((outfile = fopen(argv[optind], "r+b")) == NULL) 99 | { 100 | if ((outfile = fopen(argv[optind], "ab")) == NULL) 101 | { 102 | printf("Error: %s", strerror(errno)); 103 | fclose(infile); 104 | exit(-1); 105 | } 106 | } 107 | else fseek(outfile, -1L, SEEK_END); // if output file already contains a rom image, seek back one byte to remove the rom stream closing byte 108 | 109 | // get input file size 110 | fseek(infile, 0L, SEEK_END); 111 | if ((romsize = ftell(infile)-1) > 16383) 112 | { 113 | printf("Error: ROM size must not be larger than 16Kbyte;"); 114 | fclose(infile); 115 | fclose(outfile); 116 | exit(-1); 117 | } 118 | 119 | fseek(infile, 0L, SEEK_SET); 120 | 121 | // writing new ROM's header to rompack file 122 | 123 | fputc(romtype, outfile); // write 1 byte romtype 124 | fwrite(&romsize, sizeof(romsize), 1, outfile); // write 2 bytes romsize 125 | 126 | while ((c = fgetc(infile)) != EOF) 127 | { 128 | fputc(c, outfile); 129 | } 130 | 131 | fputc(0x80, outfile); 132 | printf("\nNew ROM image is added to file %s.\n%d bytes have been written.", argv[optind], romsize); 133 | printf("\nRomtype byte is:%X", romtype); 134 | fclose(infile); 135 | fclose(outfile); 136 | return 0; 137 | } 138 | -------------------------------------------------------------------------------- /addrom.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/addrom.exe -------------------------------------------------------------------------------- /basic.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/basic.bin -------------------------------------------------------------------------------- /basic_rom.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Copyright 2013-2016 Istvan Hegedus 4 | // 5 | // FPGATED is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // FPGATED is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | // Create Date: 22:20:09 12/09/2014 19 | // Module Name: basic_rom.v 20 | // Project Name: FPGATED 21 | // Target Devices: Xilinx Spartan 3E 22 | // 23 | // Description: 24 | // Basic ROM synthetised to FPGA's internal SRAM. Xilinx ISE requires 25 | // ROM_STYLE="BLOCK" parameter next to kernal array. For other vendor's 26 | // device syntax refer to the FPGA vendor's documentation. 27 | // 28 | // 29 | // Dependencies: 30 | // 31 | // Revision: 32 | // Revision 0.01 - File Created 33 | // Additional Comments: 34 | // 35 | ////////////////////////////////////////////////////////////////////////////////// 36 | module basic_rom( 37 | input wire clk, 38 | input wire [13:0] address_in, 39 | output wire [7:0] data_out, 40 | input wire cs 41 | ); 42 | 43 | (* ROM_STYLE="BLOCK" *) 44 | reg [7:0] basic [0:16383]; 45 | reg [7:0] data; 46 | reg cs_prev=1'b1; 47 | wire enable; 48 | 49 | always@(posedge clk) 50 | if(enable) 51 | data<=basic[address_in]; 52 | 53 | always@(posedge clk) 54 | cs_prev<=cs; 55 | 56 | assign enable=~cs&cs_prev; // cs falling edge detection 57 | assign data_out=(~cs)?data:8'hff; 58 | 59 | initial begin 60 | $readmemh("basic.hex",basic); 61 | end 62 | 63 | endmodule 64 | -------------------------------------------------------------------------------- /bin2hex.pl: -------------------------------------------------------------------------------- 1 | #- Bin2Hex.pl 2 | #- Copyright (c) 1995 by Dr. Herong Yang, http://www.herongyang.com/ 3 | # 4 | ($in, $out) = @ARGV; 5 | die "Missing input file name.\n" unless $in; 6 | die "Missing output file name.\n" unless $out; 7 | $byteCount = 0; 8 | open(IN, "< $in"); 9 | binmode(IN); 10 | open(OUT, "> $out"); 11 | while (read(IN,$b,1)) { 12 | $n = length($b); 13 | $byteCount += $n; 14 | $s = 2*$n; 15 | print (OUT unpack("H$s", $b), "\n"); 16 | } 17 | close(IN); 18 | close(OUT); 19 | print "Number of bytes converted = $byteCount\n"; 20 | exit; 21 | -------------------------------------------------------------------------------- /bitmerge.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # To run this script, use Python version 2.7 not version 3.x 3 | import argparse 4 | import struct 5 | 6 | #Standard MX25L6445E FLASH size of 64Mbits 7 | flash_size = 8388608 8 | #Standard size of bitstream for a Spartan 6 LX9 9 | bit_size = 340*1024 10 | 11 | parser = argparse.ArgumentParser(description='Concatenates an FPGA .bit file and a user supplied binary file together.\nProduces a valid .bit file that can be written to a platform flash using\nstandard tools.') 12 | parser.add_argument('ifile', type=argparse.FileType('rb'), help='source FPGA .bit file') 13 | parser.add_argument('bfile', type=argparse.FileType('rb'), help='source binary file') 14 | parser.add_argument('ofile', type=argparse.FileType('wb'), help='destination merged FPGA .bit + binary file') 15 | args = parser.parse_args() 16 | 17 | #seek to end 18 | args.bfile.seek(0,2) 19 | #get size of user binary file to merge 20 | bsize = args.bfile.tell() 21 | #seek to start 22 | args.bfile.seek(0,0) 23 | 24 | data = args.ifile.read(2) 25 | args.ofile.write(data) 26 | (length,) = struct.unpack(">H", data) 27 | assert length == 9, "Invalid .bit file magic length." 28 | 29 | #check bit file magic marker 30 | data = args.ifile.read(length) 31 | args.ofile.write(data) 32 | (n1,n2,n3,n4,n5,) = struct.unpack("H", data) 38 | assert length==1, "Unexpected value." 39 | 40 | #loop through the bit file sections 'a' through 'd' and print out stats 41 | section="" 42 | while section != 'd': 43 | section = args.ifile.read(1) 44 | args.ofile.write(section) 45 | data = args.ifile.read(2) 46 | args.ofile.write(data) 47 | (length,) = struct.unpack(">H", data) 48 | desc = args.ifile.read(length) 49 | args.ofile.write(desc) 50 | print "Section '%c' (size %6d) '%s'" % (section, length, desc) 51 | 52 | #process section 'e' (main bit file data) 53 | section = args.ifile.read(1) 54 | args.ofile.write(section) 55 | assert section=="e", "Unexpected section" 56 | data = args.ifile.read(4) 57 | #this is the actual size of the FPGA bit stream contents 58 | (length,) = struct.unpack(">L", data) 59 | print "Section '%c' (size %6d) '%s'" % (section, length, "FPGA bitstream") 60 | 61 | #we can't merge a "merged" file, well..., we could, but we won't 62 | assert length<=bit_size, "Section 'e' length of %d seems unreasonably long\nCould this file have already been merged with a binary file?" %length 63 | 64 | #calculate padding because user data starts at 0x100000 65 | padding_cfg = 1044480 - length 66 | padding_bitstream = 4096 - 6 67 | 68 | #check that both files will fit in flash 69 | assert (length+padding_cfg+bsize) <= flash_size, "Combined files sizes of %d would exceed flash capacity of %d bytes" % ((length+bsize), flash_size) 70 | print "Merged user data begins at FLASH address 0x%06X" %(length+padding_cfg) 71 | 72 | #write recalculated section length 73 | data = struct.pack(">L", length+padding_cfg+6+padding_bitstream+bsize) 74 | args.ofile.write(data) 75 | 76 | #read FPGA bitstream and write to output file 77 | data = args.ifile.read(length) 78 | args.ofile.write(data) 79 | 80 | # write padding until configuration memory area 81 | for i in xrange(padding_cfg): 82 | args.ofile.write(b'\xff') 83 | # write zeros to 6 configuration bytes 84 | for i in range(6): 85 | args.ofile.write(b'\x00') 86 | # write padding until FPGATED rom image area 87 | for i in xrange(padding_bitstream): 88 | args.ofile.write(b'\xff') 89 | 90 | #read user provided binary data and append to file 91 | data = args.bfile.read(bsize) 92 | args.ofile.write(data) 93 | 94 | #close up files and exit 95 | args.ifile.close() 96 | args.bfile.close() 97 | args.ofile.close() 98 | -------------------------------------------------------------------------------- /bootrom.wcfg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | flash_cs 16 | flash_cs 17 | 18 | 19 | clk 20 | clk 21 | 22 | 23 | flash_ck 24 | flash_ck 25 | 26 | 27 | flash_so 28 | flash_so 29 | 30 | 31 | flash_si 32 | flash_si 33 | 34 | 35 | cs0 36 | cs0 37 | 38 | 39 | cs1 40 | cs1 41 | 42 | 43 | rw 44 | rw 45 | 46 | 47 | address_out[15:0] 48 | address_out[15:0] 49 | 50 | 51 | address_ext[5:0] 52 | address_ext[5:0] 53 | 54 | 55 | dataout[7:0] 56 | dataout[7:0] 57 | 58 | 59 | bootstrap_done 60 | bootstrap_done 61 | 62 | 63 | phi 64 | phi 65 | 66 | 67 | boot internal 68 | label 69 | 70 | flash_clken 71 | flash_clken 72 | 73 | 74 | flash_cs 75 | flash_cs 76 | 77 | 78 | clk 79 | clk 80 | 81 | 82 | flash_ck 83 | flash_ck 84 | 85 | 86 | shiftreg[7:0] 87 | shiftreg[7:0] 88 | 89 | 90 | shiftcount[2:0] 91 | shiftcount[2:0] 92 | 93 | 94 | flash_so 95 | flash_so 96 | 97 | 98 | flash_so_reg 99 | flash_so_reg 100 | 101 | 102 | flash_si 103 | flash_si 104 | 105 | 106 | rw 107 | rw 108 | 109 | 110 | flash_state[7:0] 111 | flash_state[7:0] 112 | 113 | 114 | flash_state_next[7:0] 115 | flash_state_next[7:0] 116 | 117 | 118 | romdata[7:0] 119 | romdata[7:0] 120 | 121 | 122 | start_shift 123 | start_shift 124 | 125 | 126 | 127 | shift 128 | shift 129 | 130 | 131 | -------------------------------------------------------------------------------- /bootstrap.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Copyright 2013-2018 Istvan Hegedus 4 | // 5 | // FPGATED is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // FPGATED is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | // Create Date: 19/01/2018 19 | // Design Name: Bootstrap 20 | // Module Name: bootstrap.v 21 | // Project Name: FPGATED 22 | // Description: This module takes care of uploading the Plus4 ROMs from SPI flash to the FPGA board's memory at startup. 23 | // It handles the SPI flash of the FPGA board and provides access to flash from the Plus4. 24 | // 25 | // ROM dataformat inside Xilinx bitfile following FPGA bitstream: 26 | // 27 | // [Xilinx FPGA bitstream][3 bytes ROM header|1st ROM data][ROM header|2nd ROM data]...[8'hFF] 28 | // 29 | 30 | // ROM header: 1 byte Type followed by 2 bytes Length 31 | // 1st byte (Type) 32 | // bit 7 0=valid ROM 1=no more ROM in bitstream 33 | // bit 6 0=Low ROM, 1=High ROM 34 | // bit 2-5 ROM version number (alternative ROM ID 0-15) 35 | // bit 0-1 ROM type values: 00=Internal ROM, 01=Function ROM, 10=Cartridge1 ROM, 11=Cartridge2 ROM 36 | // 2nd-3rd bytes (Length) Length of ROM bitdata in bytes (max 65536 bytes). Little Endian coding (LSB first MSB next) 37 | // 38 | // Revision history: 39 | // 40 | ////////////////////////////////////////////////////////////////////////////////// 41 | module bootstrap( 42 | 43 | output wire flash_cs, 44 | output wire flash_ck, 45 | output wire flash_si, 46 | input wire flash_so, 47 | output cs0, 48 | output cs1, 49 | output reg rw_out, 50 | output reg [15:0] addr_out, // generated address for sdram 51 | output [5:0] addr_ext, // generated address extension for sdram 52 | output [7:0] data_out, 53 | input reset, 54 | input boot_enable, 55 | output reg boot_done, 56 | output reg cfg_done, 57 | input phi, 58 | input clk, 59 | input cs, // active on $FD98-$FDFF IO range (used for flash commands from Plus4) 60 | input rw_in, 61 | input [7:0] data_in, 62 | input [2:0] addr_in 63 | ); 64 | 65 | wire [23:0] flash_address; 66 | reg [23:0] flash_address_reg; 67 | reg [7:0] flash_reg; 68 | reg [7:0] data_reg; 69 | reg [7:0] rcv_reg; 70 | wire [7:0] flash_cmd; 71 | reg [7:0] flash_cmd_reg; 72 | wire [7:0] flash_data; 73 | reg [7:0] flash_data_reg=8'hff; 74 | reg flash_active=1'b0; 75 | reg flash_ack=1'b0; 76 | reg phi_prev=1'b0; 77 | reg cs_prev=1'b0; 78 | wire flash_busy; 79 | reg [6:0] romtype=7'h0; 80 | reg [15:0] romlength=16'h0; 81 | reg [15:0] countbytes=16'h0; 82 | reg [3:0] cfgbyte=4'h0; 83 | reg length_h=1'b0; 84 | reg [1:0] rxcount=2'b0; 85 | 86 | 87 | initial begin 88 | boot_done=1'b0; 89 | cfg_done=1'b0; 90 | rw_out=1'b1; 91 | addr_out=16'hffff; 92 | end 93 | 94 | //parameter ROM_ADDR=24'h0534A8; // start of Plus4 ROM data in SPI flash 95 | parameter ROM_ADDR=24'h100000; // start of Plus4 ROM data in SPI flash 96 | parameter CFG_ADDR=24'h0ff000; // start of Config data location 97 | 98 | reg [8:0] boot_state=IDLE; 99 | localparam IDLE = 9'b000000001; 100 | localparam LOAD_TYPE = 9'b000000010; 101 | localparam LOAD_LENGTH = 9'b000000100; 102 | localparam LOAD_ROM = 9'b000001000; 103 | localparam LOAD_CFG = 9'b000010000; 104 | localparam WAIT_CMD = 9'b000100000; 105 | localparam SEND = 9'b001000000; 106 | localparam RECEIVE = 9'b010000000; 107 | localparam CMD_ONLY = 9'b100000000; 108 | 109 | localparam PP=8'h02; 110 | localparam READ=8'h03; 111 | localparam RDSR=8'h05; 112 | localparam RDSCUR=8'h2b; 113 | localparam RDID=8'h9f; 114 | 115 | 116 | spiflash flash( 117 | .clk(clk), 118 | .din(data_reg), 119 | .dout(flash_data), 120 | .Addr(flash_address), 121 | .cmd(flash_cmd), 122 | .active(flash_active), 123 | .ack(flash_ack), 124 | .reset(reset), 125 | .busy(flash_busy), 126 | .flash_ck(flash_ck), 127 | .flash_cs(flash_cs), 128 | .flash_si(flash_si), 129 | .flash_so(flash_so) 130 | ); 131 | 132 | always @(posedge clk) begin 133 | phi_prev<=phi; 134 | cs_prev<=cs; 135 | end 136 | 137 | always @(posedge clk) 138 | begin 139 | flash_ack<=1'b0; // ACK signal default state is low, 140 | if(reset|~boot_enable) 141 | begin 142 | boot_state<=IDLE; 143 | flash_active<=1'b0; 144 | end 145 | else if(phi_prev & ~phi) // FSM synced to phi clock 146 | begin 147 | case(boot_state) 148 | IDLE: 149 | begin 150 | if(~boot_done) 151 | begin 152 | boot_state<=LOAD_TYPE; 153 | flash_active<=1'b1; 154 | flash_ack<=1'b1; 155 | end 156 | else 157 | begin 158 | boot_state<=WAIT_CMD; 159 | end 160 | end 161 | LOAD_TYPE: 162 | begin 163 | if(~flash_busy) 164 | begin 165 | rw_out<=1'b1; // RAM write cycle must be disabled 166 | if(flash_data[7]) 167 | begin 168 | boot_state<=LOAD_CFG; 169 | boot_done<=1'b1; 170 | flash_active<=1'b0; 171 | flash_ack<=1'b1; 172 | cfgbyte<=4'hf; 173 | end 174 | else 175 | begin 176 | romtype<=flash_data[6:0]; // store ROM type 177 | flash_ack<=1'b1; 178 | boot_state<=LOAD_LENGTH; 179 | length_h<=1'b0; // set length lower byte indicator 180 | end 181 | end 182 | end 183 | LOAD_LENGTH: 184 | begin 185 | if(~flash_busy) 186 | begin 187 | if(~length_h) // ROM length low byte 188 | begin 189 | romlength[7:0]<=flash_data; 190 | flash_ack<=1'b1; 191 | length_h<=1'b1; // next one is length high byte 192 | end 193 | else 194 | begin // ROM length high byte 195 | romlength[15:8]<=flash_data; 196 | flash_ack<=1'b1; 197 | boot_state<=LOAD_ROM; 198 | countbytes<=16'h0; 199 | end 200 | end 201 | end 202 | LOAD_ROM: 203 | begin 204 | if(~flash_busy) 205 | begin 206 | rw_out<=1'b0; // RAM write enable 207 | flash_data_reg<=flash_data; // Place flash data to databus 208 | addr_out<=countbytes; // ROM address 209 | if(countbytes==romlength) 210 | begin 211 | flash_ack<=1'b1; 212 | boot_state<=LOAD_TYPE; // After ROM load go back and check whether there are more ROMs or this is the end 213 | end 214 | else 215 | begin 216 | flash_ack<=1'b1; 217 | countbytes<=countbytes+16'b1; // Next byte can come, stay in LOAD_ROM state 218 | end 219 | end 220 | end 221 | LOAD_CFG: 222 | begin 223 | addr_out[15:0]<={12'hFD9,cfgbyte}; 224 | if(~flash_busy) 225 | begin 226 | if(cfgbyte==4'hf) 227 | begin 228 | flash_active<=1'b1; 229 | end 230 | else if(cfgbyte==4'h6) 231 | begin 232 | rw_out<=1'b1; 233 | boot_state<=IDLE; 234 | flash_active<=1'b0; 235 | flash_ack<=1'b1; 236 | cfg_done<=1'b1; 237 | end 238 | else 239 | begin 240 | rw_out<=1'b0; 241 | flash_data_reg<=flash_data; 242 | end 243 | flash_ack<=1'b1; 244 | cfgbyte<=cfgbyte+4'b1; 245 | end 246 | end 247 | WAIT_CMD: // waiting for command from Plus4 databus 248 | begin 249 | flash_data_reg<=8'hff; // remove the bootstrap data register from databus 250 | if(cs_prev & ~rw_in & addr_in==3'h0) // if the CMD register was written 251 | begin 252 | flash_active<=1'b1; // start flash operation 253 | flash_ack<=1'b1; 254 | if(data_in==PP) 255 | begin 256 | boot_state<=SEND; 257 | end 258 | else if(data_in==RDSR || data_in==RDSCUR || data_in==RDID || data_in==READ) 259 | begin 260 | boot_state<=RECEIVE; 261 | rxcount<=2'b0; // signals the 1st byte receive 262 | end 263 | else 264 | begin 265 | boot_state<=CMD_ONLY; 266 | end 267 | end 268 | end 269 | SEND: 270 | begin 271 | if(cs_prev & ~rw_in & ~flash_busy) 272 | begin 273 | case(addr_in) 274 | 3'h0: begin // writing to command register stops transfer 275 | boot_state<=WAIT_CMD; 276 | flash_active<=1'b0; 277 | flash_ack<=1'b1; 278 | end 279 | 3'h4: begin 280 | flash_ack<=1; 281 | end 282 | endcase 283 | end 284 | end 285 | RECEIVE: 286 | begin 287 | if (~flash_busy) 288 | begin 289 | rcv_reg<=flash_data; 290 | if ((flash_cmd_reg==RDID && rxcount==2'd2) || (cs_prev & ~rw_in & addr_in==3'h0) || flash_cmd_reg==RDSCUR || flash_cmd_reg==RDSR ) 291 | begin 292 | boot_state<=WAIT_CMD; 293 | flash_active<=1'b0; 294 | flash_ack<=1'b1; 295 | end 296 | else if(cs_prev & rw_in & addr_in==3'h4) 297 | begin 298 | flash_ack<=1'b1; 299 | rxcount<=rxcount+2'b1; // rxcount counts the number of received bytes for RDID command 300 | end 301 | end 302 | end 303 | CMD_ONLY: 304 | begin 305 | if (~flash_busy) 306 | begin 307 | boot_state<=WAIT_CMD; 308 | flash_active<=1'b0; 309 | flash_ack<=1'b0; 310 | end 311 | end 312 | endcase 313 | end 314 | end 315 | 316 | // Plus4 flash registers 317 | 318 | always @(posedge clk) // writing flash registers 319 | begin 320 | if (cs_prev & ~cs & ~rw_in) // take data from databus on the falling edge of cs 321 | begin 322 | case(addr_in) 323 | 3'h0: begin 324 | flash_cmd_reg<=data_in; 325 | end 326 | 3'h1: begin 327 | flash_address_reg[23:16]<=data_in; 328 | end 329 | 3'h2: begin 330 | flash_address_reg[15:8]<=data_in; 331 | end 332 | 3'h3: begin 333 | flash_address_reg[7:0]<=data_in; 334 | end 335 | 3'h4: begin 336 | data_reg<=data_in; 337 | end 338 | endcase 339 | end 340 | end 341 | 342 | always @* // reading flash registers 343 | begin 344 | flash_reg=8'hff; 345 | if(cs_prev & rw_in) // cs_prev helps to meet hold time during read 346 | begin 347 | case(addr_in) 348 | 3'h0: begin 349 | flash_reg={6'b0,flash_active,flash_busy}; // $FD98 350 | end 351 | 3'h1: begin 352 | flash_reg=flash_address[23:16]; // $FD99 353 | end 354 | 3'h2: begin 355 | flash_reg=flash_address[15:8]; // $FD9A 356 | end 357 | 3'h3: begin 358 | flash_reg=flash_address[7:0]; // $FD9B 359 | end 360 | 3'h4: begin 361 | flash_reg=rcv_reg; // $FD9C 362 | end 363 | endcase 364 | end 365 | end 366 | 367 | 368 | assign cs0=romtype[6]; 369 | assign cs1=~romtype[6]; 370 | assign addr_ext=romtype[5:0]; 371 | assign flash_address=(boot_state==LOAD_TYPE)?ROM_ADDR: 372 | (boot_state==LOAD_CFG)?CFG_ADDR: 373 | flash_address_reg; 374 | assign flash_cmd=(cfg_done)?flash_cmd_reg:READ; 375 | assign data_out=flash_reg&flash_data_reg; 376 | endmodule 377 | -------------------------------------------------------------------------------- /bootstrap.wcfg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | clk 16 | clk 17 | 18 | 19 | phi 20 | phi 21 | 22 | 23 | Flash Chip Signals 24 | label 25 | 26 | flash_ck 27 | flash_ck 28 | 29 | 30 | flash_cs 31 | flash_cs 32 | 33 | 34 | flash_si 35 | flash_si 36 | 37 | 38 | flash_so 39 | flash_so 40 | 41 | 42 | 43 | RAM signals 44 | label 45 | 46 | address_ext[5:0] 47 | address_ext[5:0] 48 | HEXRADIX 49 | 50 | 51 | address_out[15:0] 52 | address_out[15:0] 53 | HEXRADIX 54 | 55 | 56 | rw 57 | rw 58 | 59 | 60 | cs1 61 | cs1 62 | 63 | 64 | cs0 65 | cs0 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /boottest.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | //////////////////////////////////////////////////////////////////////////////// 4 | // 5 | // Create Date: 20:27:09 10/25/2016 6 | // Design Name: bootstrap testbench 7 | // Module Name: C:/Users/ISHE/Documents/Cloud/FPGAdev/Plus4/boottest.v 8 | // Project Name: Plus4 9 | // Description: 10 | // 11 | // Verilog Test Fixture created for testing FPGATED bootstrap function 12 | // 13 | // Dependencies: A binary rompack file must exist. 14 | // 15 | // Revision: 16 | // 1.0 17 | // 18 | //////////////////////////////////////////////////////////////////////////////// 19 | 20 | module boottest; 21 | 22 | // Inputs 23 | wire flash_so; 24 | reg ram_initdone; 25 | reg read_enable; 26 | reg clk; 27 | reg [3:0] phicounter=0; 28 | 29 | // Outputs 30 | wire flash_cs; 31 | wire flash_ck; 32 | wire flash_si; 33 | wire cs0; 34 | wire cs1; 35 | wire rw; 36 | wire [15:0] address_out; 37 | wire [5:0] address_ext; 38 | wire [7:0] dataout; 39 | wire bootstrap_done; 40 | 41 | // Instantiate the Unit Under Test (UUT) 42 | bootstrap uut ( 43 | .flash_cs(flash_cs), 44 | .flash_ck(flash_ck), 45 | .flash_si(flash_si), 46 | .flash_so(flash_so), 47 | .cs0(cs0), 48 | .cs1(cs1), 49 | .rw_out(rw), 50 | .addr_out(address_out), 51 | .addr_ext(address_ext), 52 | .data_out(dataout), 53 | .reset(1'b0), 54 | .boot_enable(read_enable), 55 | .boot_done(bootstrap_done), 56 | .phi(phicounter[3]), 57 | .clk(clk), 58 | .cs(), 59 | .rw_in(), 60 | .data_in(), 61 | .addr_in() 62 | ); 63 | 64 | 65 | initial begin 66 | // Initialize Inputs 67 | read_enable = 0; 68 | clk = 0; 69 | file=$fopen("fakerom2.bin","rb"); 70 | 71 | // Wait 100 ns for global reset to finish 72 | #100; 73 | // Add stimulus here 74 | ram_initdone = 1; 75 | read_enable=1; 76 | end 77 | 78 | // 28.288 Mhz 79 | always 80 | begin 81 | #17.675 clk<=~clk; 82 | end 83 | 84 | always @(posedge clk) 85 | begin 86 | phicounter<=phicounter+1; 87 | end 88 | //-------------------------------------------------------------- 89 | 90 | reg [2:0] bytecount=0; 91 | reg [2:0] bitcount=7; 92 | reg [2:0] cbitcount=0; 93 | reg [7:0] flashreg=8'h03; 94 | integer file; 95 | reg command=1; 96 | 97 | always @(negedge flash_ck) begin 98 | if (~flash_cs) begin 99 | if (~command) begin 100 | bitcount<=bitcount+1; 101 | if(bitcount==7) 102 | flashreg<=$fgetc(file); 103 | else flashreg[7:0]<={flashreg[6:0],1'b0}; 104 | end 105 | 106 | end 107 | end 108 | 109 | always @(posedge flash_ck) begin 110 | if(command) begin 111 | cbitcount<=cbitcount+1; 112 | if(cbitcount==7) 113 | if(bytecount==3) 114 | command<=0; 115 | else bytecount=bytecount+1; 116 | end 117 | end 118 | 119 | assign flash_so=flashreg[7]; 120 | 121 | always @(posedge bootstrap_done) begin 122 | $fclose(file); 123 | end 124 | 125 | endmodule 126 | -------------------------------------------------------------------------------- /boottest.wcfg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | phi_prev 16 | phi_prev 17 | 18 | 19 | flash_state[6:0] 20 | flash_state[6:0] 21 | 22 | 23 | boot_state[8:0] 24 | boot_state[8:0] 25 | BINARYRADIX 26 | 27 | 28 | flash_active 29 | flash_active 30 | 31 | 32 | flash_ack 33 | flash_ack 34 | 35 | 36 | flash_busy 37 | flash_busy 38 | 39 | 40 | flash_address[23:0] 41 | flash_address[23:0] 42 | HEXRADIX 43 | 44 | 45 | flash_address_reg[23:0] 46 | flash_address_reg[23:0] 47 | HEXRADIX 48 | 49 | 50 | flash_data[7:0] 51 | flash_data[7:0] 52 | HEXRADIX 53 | 54 | 55 | flash_cmd[7:0] 56 | flash_cmd[7:0] 57 | HEXRADIX 58 | 59 | 60 | countbytes[15:0] 61 | countbytes[15:0] 62 | HEXRADIX 63 | 64 | 65 | length_h 66 | length_h 67 | 68 | 69 | FLASH 70 | label 71 | 72 | flash_cs 73 | flash_cs 74 | 75 | 76 | flash_so 77 | flash_so 78 | 79 | 80 | flash_si 81 | flash_si 82 | 83 | 84 | flash_ck 85 | flash_ck 86 | 87 | 88 | 89 | romtype[6:0] 90 | romtype[6:0] 91 | HEXRADIX 92 | 93 | 94 | romlength[15:0] 95 | romlength[15:0] 96 | HEXRADIX 97 | 98 | 99 | command 100 | command 101 | 102 | 103 | bytecount[2:0] 104 | bytecount[2:0] 105 | 106 | 107 | data_reg[7:0] 108 | data_reg[7:0] 109 | HEXRADIX 110 | 111 | 112 | Bootstrap input 113 | label 114 | 115 | reset 116 | reset 117 | 118 | 119 | boot_enable 120 | boot_enable 121 | 122 | 123 | phi 124 | phi 125 | true 126 | #0000ff 127 | 128 | 129 | clk 130 | clk 131 | 132 | 133 | cs 134 | cs 135 | 136 | 137 | rw_in 138 | rw_in 139 | 140 | 141 | data_in[7:0] 142 | data_in[7:0] 143 | HEXRADIX 144 | 145 | 146 | addr_in[2:0] 147 | addr_in[2:0] 148 | HEXRADIX 149 | 150 | 151 | 152 | Boostrap outputs 153 | label 154 | 155 | boot_done 156 | boot_done 157 | 158 | 159 | cfg_done 160 | cfg_done 161 | 162 | 163 | addr_out[15:0] 164 | addr_out[15:0] 165 | HEXRADIX 166 | 167 | 168 | addr_ext[5:0] 169 | addr_ext[5:0] 170 | HEXRADIX 171 | 172 | 173 | cs0 174 | cs0 175 | 176 | 177 | cs1 178 | cs1 179 | 180 | 181 | rw_out 182 | rw_out 183 | 184 | 185 | data_out[7:0] 186 | data_out[7:0] 187 | HEXRADIX 188 | 189 | 190 | 191 | -------------------------------------------------------------------------------- /boottestrom.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/boottestrom.bin -------------------------------------------------------------------------------- /c16_keymatrix.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Copyright 2013-2016 Istvan Hegedus 4 | // 5 | // FPGATED is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // FPGATED is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | // Create Date: 19:38:44 12/16/2015 19 | // Module Name: c16_keymatrix.v 20 | // Project Name: FPGATED 21 | // 22 | // Description: C16/Plus4 keyboard matrix emulation for PS2 keyboards. 23 | // 24 | // Revisions: 25 | // 1.0 07.14.2016 first release 26 | // 1.1 17.08.2016 Joystick emulation implemented. Choose joy0 or joy1 with F11. Joystick is on numeric keypad. 27 | // 1.2 18.04.2017 ESC key flag added to output (for ROM setup purposes during bootstrap) 28 | ////////////////////////////////////////////////////////////////////////////////// 29 | module c16_keymatrix( 30 | input clk, 31 | input [7:0] scancode, 32 | input receiveflag, 33 | input [7:0] row, 34 | output [7:0] kbus, 35 | output keyreset, 36 | output [4:0] joy0, // joystick port mini din pin mappings bit0=pin1, bit1=pin2, bit2=pin3, bit3=pin4, bit4=pin6 37 | output [4:0] joy1, 38 | output esc 39 | ); 40 | 41 | reg releaseflag=0; 42 | reg extendedflag=0; 43 | reg [7:0] colsel=0; 44 | reg key_A=0,key_B=0,key_C=0,key_D=0,key_E=0,key_F=0,key_G=0,key_H=0,key_I=0,key_J=0,key_K=0,key_L=0,key_M=0,key_N=0,key_O=0,key_P=0,key_Q=0,key_R=0,key_S=0,key_T=0,key_U=0,key_V=0,key_W=0,key_X=0,key_Y=0,key_Z=0; 45 | reg key_1=0,key_2=0,key_3=0,key_4=0,key_5=0,key_6=0,key_7=0,key_8=0,key_9=0,key_0=0,key_del=0,key_return=0,key_help=0,key_F1=0,key_F2=0,key_F3=0,key_AT=0,key_shift=0,key_comma=0,key_dot=0; 46 | reg key_minus=0,key_colon=0,key_star=0,key_semicolon=0,key_esc=0,key_equal=0,key_plus=0,key_slash=0,key_control=0,key_space=0,key_runstop=0; 47 | reg key_pound=0,key_down=0,key_up=0,key_left=0,key_right=0,key_home=0,key_commodore=0,key_alt=0; 48 | reg joy_left=0,joy_right=0,joy_up=0,joy_down=0,joy_fire=0; 49 | reg joysel=0; 50 | 51 | wire [7:0] rowsel; 52 | 53 | assign rowsel=~row; 54 | assign keyreset=key_control&key_alt&key_del; 55 | 56 | always @(posedge clk) 57 | begin 58 | if(receiveflag) 59 | begin 60 | if(scancode==8'hF0) 61 | releaseflag<=1; 62 | else if (scancode==8'hE0) 63 | extendedflag<=1; 64 | else 65 | begin 66 | releaseflag<=0; 67 | if (~extendedflag) // base code keys 68 | begin 69 | case(scancode) 70 | 8'h1C: key_A<=~releaseflag; 71 | 8'h32: key_B<=~releaseflag; 72 | 8'h21: key_C<=~releaseflag; 73 | 8'h23: key_D<=~releaseflag; 74 | 8'h24: key_E<=~releaseflag; 75 | 8'h2B: key_F<=~releaseflag; 76 | 8'h34: key_G<=~releaseflag; 77 | 8'h33: key_H<=~releaseflag; 78 | 8'h43: key_I<=~releaseflag; 79 | 8'h3B: key_J<=~releaseflag; 80 | 8'h42: key_K<=~releaseflag; 81 | 8'h4B: key_L<=~releaseflag; 82 | 8'h3A: key_M<=~releaseflag; 83 | 8'h31: key_N<=~releaseflag; 84 | 8'h44: key_O<=~releaseflag; 85 | 8'h4D: key_P<=~releaseflag; 86 | 8'h15: key_Q<=~releaseflag; 87 | 8'h2D: key_R<=~releaseflag; 88 | 8'h1B: key_S<=~releaseflag; 89 | 8'h2C: key_T<=~releaseflag; 90 | 8'h3C: key_U<=~releaseflag; 91 | 8'h2A: key_V<=~releaseflag; 92 | 8'h1D: key_W<=~releaseflag; 93 | 8'h22: key_X<=~releaseflag; 94 | 8'h35: key_Y<=~releaseflag; 95 | 8'h1A: key_Z<=~releaseflag; 96 | // 8'h69, 97 | 8'h16: key_1<=~releaseflag; 98 | 8'h72: joy_down<=~releaseflag; 99 | 8'h1E: key_2<=~releaseflag; 100 | // 8'h7A, 101 | 8'h26: key_3<=~releaseflag; 102 | 8'h6B: joy_left<=~releaseflag; 103 | 8'h25: key_4<=~releaseflag; 104 | // 8'h73, 105 | 8'h2E: key_5<=~releaseflag; 106 | 8'h74: joy_right<=~releaseflag; 107 | 8'h36: key_6<=~releaseflag; 108 | // 8'h6C, 109 | 8'h3D: key_7<=~releaseflag; 110 | 8'h75: joy_up<=~releaseflag; 111 | 8'h3E: key_8<=~releaseflag; 112 | // 8'h7D, 113 | 8'h46: key_9<=~releaseflag; 114 | 8'h70: joy_fire<=~releaseflag; 115 | 8'h45: key_0<=~releaseflag; 116 | 8'h66: key_del<=~releaseflag; 117 | 8'h5A: key_return<=~releaseflag; 118 | 8'h0C: key_help<=~releaseflag; 119 | 8'h05: key_F1<=~releaseflag; 120 | 8'h06: key_F2<=~releaseflag; 121 | 8'h04: key_F3<=~releaseflag; 122 | 8'h54: key_AT<=~releaseflag; 123 | 8'h12, 124 | 8'h59: key_shift<=~releaseflag; 125 | 8'h41: key_comma<=~releaseflag; 126 | 8'h49: key_dot<=~releaseflag; 127 | 8'h7B, 128 | 8'h4E: key_minus<=~releaseflag; 129 | 8'h4C: key_colon<=~releaseflag; 130 | 8'h7C, 131 | 8'h5B: key_star<=~releaseflag; 132 | 8'h52: key_semicolon<=~releaseflag; 133 | 8'h76: key_esc<=~releaseflag; 134 | 8'h5D: key_equal<=~releaseflag; 135 | 8'h79, 136 | 8'h55: key_plus<=~releaseflag; 137 | 8'h4A: key_slash<=~releaseflag; 138 | 8'h14: key_control<=~releaseflag; 139 | 8'h29: key_space<=~releaseflag; 140 | 8'h0D: key_runstop<=~releaseflag; 141 | 8'h11: key_alt<=~releaseflag; 142 | 8'h78: if(~releaseflag) 143 | joysel<=~joysel; 144 | default:; 145 | endcase 146 | end 147 | else begin // extended code keys 148 | extendedflag<=0; 149 | case(scancode) 150 | 8'h2F: key_pound<=~releaseflag; 151 | 8'h72: key_down<=~releaseflag; 152 | 8'h75: key_up<=~releaseflag; 153 | 8'h6B: key_left<=~releaseflag; 154 | 8'h74: key_right<=~releaseflag; 155 | 8'h6C: key_home<=~releaseflag; 156 | 8'h14: key_control<=~releaseflag; 157 | 8'h1F: key_commodore<=~releaseflag; 158 | 8'h4A: key_slash<=~releaseflag; 159 | 8'h5A: key_return<=~releaseflag; 160 | 8'h71: key_del<=~releaseflag; 161 | 8'h11: key_alt<=~releaseflag; 162 | default:; 163 | endcase 164 | end 165 | end 166 | end 167 | end 168 | 169 | always @(posedge clk) 170 | begin 171 | colsel[0]<=(key_del & rowsel[0]) | (key_3 & rowsel[1]) | (key_5 & rowsel[2]) | (key_7 & rowsel[3]) | (key_9 & rowsel[4]) | (key_down & rowsel[5]) | (key_left & rowsel[6]) | (key_1 & rowsel[7]); 172 | colsel[1]<=(key_return & rowsel[0]) | (key_W & rowsel[1]) | (key_R & rowsel[2]) | (key_Y & rowsel[3]) | (key_I & rowsel[4]) | (key_P & rowsel[5]) | (key_star & rowsel[6]) | (key_home & rowsel[7]); 173 | colsel[2]<=(key_pound & rowsel[0]) | (key_A & rowsel[1]) | (key_D & rowsel[2]) | (key_G & rowsel[3]) | (key_J & rowsel[4]) | (key_L & rowsel[5]) | (key_semicolon & rowsel[6]) | (key_control & rowsel[7]); 174 | colsel[3]<=(key_help & rowsel[0]) | (key_4 & rowsel[1]) | (key_6 & rowsel[2]) | (key_8 & rowsel[3]) | (key_0 & rowsel[4]) | (key_up & rowsel[5]) | (key_right & rowsel[6]) | (key_2 & rowsel[7]); 175 | colsel[4]<=(key_F1 & rowsel[0]) | (key_Z & rowsel[1]) | (key_C & rowsel[2]) | (key_B & rowsel[3]) | (key_M & rowsel[4]) | (key_dot & rowsel[5]) | (key_esc & rowsel[6]) | (key_space & rowsel[7]); 176 | colsel[5]<=(key_F2 & rowsel[0]) | (key_S & rowsel[1]) | (key_F & rowsel[2]) | (key_H & rowsel[3]) | (key_K & rowsel[4]) | (key_colon & rowsel[5]) | (key_equal & rowsel[6]) | (key_commodore & rowsel[7]); 177 | colsel[6]<=(key_F3 & rowsel[0]) | (key_E & rowsel[1]) | (key_T & rowsel[2]) | (key_U & rowsel[3]) | (key_O & rowsel[4]) | (key_minus & rowsel[5]) | (key_plus & rowsel[6]) | (key_Q & rowsel[7]); 178 | colsel[7]<=(key_AT & rowsel[0]) | (key_shift & rowsel[1]) | (key_X & rowsel[2]) | (key_V & rowsel[3]) | (key_N & rowsel[4]) | (key_comma & rowsel[5]) | (key_slash & rowsel[6]) | (key_runstop & rowsel[7]); 179 | end 180 | 181 | assign kbus=~colsel; 182 | 183 | assign joy0=(~joysel)?~{joy_fire,joy_right,joy_left,joy_down,joy_up}:5'b11111; 184 | assign joy1=(joysel)?~{joy_fire,joy_right,joy_left,joy_down,joy_up}:5'b11111; 185 | assign esc=key_esc; 186 | 187 | endmodule 188 | -------------------------------------------------------------------------------- /colors_to_rgb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Copyright 2013-2016 Istvan Hegedus 4 | // 5 | // FPGATED is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // FPGATED is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | // Create Date: 22:03:30 11/20/2014 19 | // Design Name: Commodore Plus/4 color value conversion to 12bit RGB values 20 | // Module Name: colors_to_rgb.v 21 | // Project Name: FPGATED 22 | // Target Devices: Xilinx Spartan 3E 23 | // 24 | // Description: 25 | // Converts TED's 7 bit color codes to 12 bit RGB values used by video DAC. 26 | // 12 bit DAC values from Jozsef Laszlo 27 | // 28 | // Revisions: 29 | // Revision 0.1 - File Created 30 | // 31 | ////////////////////////////////////////////////////////////////////////////////// 32 | module colors_to_rgb( 33 | input clk, 34 | input [6:0] color, 35 | output [3:0] red, 36 | output [3:0] green, 37 | output [3:0] blue 38 | ); 39 | reg [11:0] color_lut [127:0]; 40 | reg [11:0] rgbcolor; 41 | 42 | initial 43 | begin 44 | color_lut[0]=12'b0000_0000_0000; 45 | color_lut[1]=12'b0010_0010_0010; 46 | color_lut[2]=12'b0101_0000_0000; 47 | color_lut[3]=12'b0000_0011_0011; 48 | color_lut[4]=12'b0100_0000_0101; 49 | color_lut[5]=12'b0000_0100_0000; 50 | color_lut[6]=12'b0001_0001_0111; 51 | color_lut[7]=12'b0010_0010_0000; 52 | color_lut[8]=12'b0100_0001_0000; 53 | color_lut[9]=12'b0011_0010_0000; 54 | color_lut[10]=12'b0001_0011_0000; 55 | color_lut[11]=12'b0101_0000_0010; 56 | color_lut[12]=12'b0000_0011_0001; 57 | color_lut[13]=12'b0000_0010_0110; 58 | color_lut[14]=12'b0001_0001_0111; 59 | color_lut[15]=12'b0000_0011_0000; 60 | color_lut[16]=12'b0000_0000_0000; 61 | color_lut[17]=12'b0010_0010_0010; 62 | color_lut[18]=12'b0110_0001_0001; 63 | color_lut[19]=12'b0000_0100_0100; 64 | color_lut[20]=12'b0101_0000_0110; 65 | color_lut[21]=12'b0000_0100_0000; 66 | color_lut[22]=12'b0010_0010_1000; 67 | color_lut[23]=12'b0011_0011_0000; 68 | color_lut[24]=12'b0101_0010_0000; 69 | color_lut[25]=12'b0100_0010_0000; 70 | color_lut[26]=12'b0010_0100_0000; 71 | color_lut[27]=12'b0110_0001_0011; 72 | color_lut[28]=12'b0000_0100_0010; 73 | color_lut[29]=12'b0000_0011_0111; 74 | color_lut[30]=12'b0010_0001_1000; 75 | color_lut[31]=12'b0001_0100_0000; 76 | color_lut[32]=12'b0000_0000_0000; 77 | color_lut[33]=12'b0011_0011_0011; 78 | color_lut[34]=12'b0110_0010_0010; 79 | color_lut[35]=12'b0000_0101_0101; 80 | color_lut[36]=12'b0110_0001_0111; 81 | color_lut[37]=12'b0000_0101_0000; 82 | color_lut[38]=12'b0010_0011_1001; 83 | color_lut[39]=12'b0100_0100_0000; 84 | color_lut[40]=12'b0110_0010_0000; 85 | color_lut[41]=12'b0101_0011_0000; 86 | color_lut[42]=12'b0010_0101_0000; 87 | color_lut[43]=12'b0110_0001_0100; 88 | color_lut[44]=12'b0000_0101_0011; 89 | color_lut[45]=12'b0001_0011_1000; 90 | color_lut[46]=12'b0011_0010_1001; 91 | color_lut[47]=12'b0001_0101_0000; 92 | color_lut[48]=12'b0000_0000_0000; 93 | color_lut[49]=12'b0100_0100_0100; 94 | color_lut[50]=12'b0111_0011_0011; 95 | color_lut[51]=12'b0001_0110_0110; 96 | color_lut[52]=12'b0111_0010_1000; 97 | color_lut[53]=12'b0001_0110_0010; 98 | color_lut[54]=12'b0100_0100_1010; 99 | color_lut[55]=12'b0101_0101_0000; 100 | color_lut[56]=12'b0111_0100_0001; 101 | color_lut[57]=12'b0110_0100_0000; 102 | color_lut[58]=12'b0011_0110_0000; 103 | color_lut[59]=12'b0111_0011_0101; 104 | color_lut[60]=12'b0001_0110_0100; 105 | color_lut[61]=12'b0010_0100_1001; 106 | color_lut[62]=12'b0100_0011_1010; 107 | color_lut[63]=12'b0011_0110_0000; 108 | color_lut[64]=12'b0000_0000_0000; 109 | color_lut[65]=12'b0110_0110_0110; 110 | color_lut[66]=12'b1010_0101_0101; 111 | color_lut[67]=12'b0011_1000_1000; 112 | color_lut[68]=12'b1001_0100_1010; 113 | color_lut[69]=12'b0100_1000_0100; 114 | color_lut[70]=12'b0110_0110_1100; 115 | color_lut[71]=12'b0111_0111_0001; 116 | color_lut[72]=12'b1001_0110_0011; 117 | color_lut[73]=12'b1000_0110_0010; 118 | color_lut[74]=12'b0110_1000_0001; 119 | color_lut[75]=12'b1010_0101_0111; 120 | color_lut[76]=12'b0011_1000_0110; 121 | color_lut[77]=12'b0100_0111_1011; 122 | color_lut[78]=12'b0110_0101_1100; 123 | color_lut[79]=12'b0101_1000_0010; 124 | color_lut[80]=12'b0000_0000_0000; 125 | color_lut[81]=12'b1000_1000_1000; 126 | color_lut[82]=12'b1011_0111_0111; 127 | color_lut[83]=12'b0101_1001_1001; 128 | color_lut[84]=12'b1011_0110_1011; 129 | color_lut[85]=12'b0101_1010_0101; 130 | color_lut[86]=12'b0111_0111_1110; 131 | color_lut[87]=12'b1001_1001_0010; 132 | color_lut[88]=12'b1011_0111_0101; 133 | color_lut[89]=12'b1010_1000_0011; 134 | color_lut[90]=12'b0111_1001_0010; 135 | color_lut[91]=12'b1011_0110_1001; 136 | color_lut[92]=12'b0101_1010_1000; 137 | color_lut[93]=12'b0110_1000_1101; 138 | color_lut[94]=12'b1000_0111_1110; 139 | color_lut[95]=12'b0110_1010_0011; 140 | color_lut[96]=12'b0000_0000_0000; 141 | color_lut[97]=12'b1011_1011_1011; 142 | color_lut[98]=12'b1110_1001_1001; 143 | color_lut[99]=12'b1000_1100_1100; 144 | color_lut[100]=12'b1101_1001_1110; 145 | color_lut[101]=12'b1000_1101_1000; 146 | color_lut[102]=12'b1010_1010_1111; 147 | color_lut[103]=12'b1011_1011_0101; 148 | color_lut[104]=12'b1101_1010_1000; 149 | color_lut[105]=12'b1100_1011_0110; 150 | color_lut[106]=12'b1010_1100_0101; 151 | color_lut[107]=12'b1110_1001_1011; 152 | color_lut[108]=12'b0111_1100_1010; 153 | color_lut[109]=12'b1001_1011_1111; 154 | color_lut[110]=12'b1010_1010_1111; 155 | color_lut[111]=12'b1001_1100_0110; 156 | color_lut[112]=12'b0000_0000_0000; 157 | color_lut[113]=12'b1110_1110_1110; 158 | color_lut[114]=12'b1111_1101_1101; 159 | color_lut[115]=12'b1011_1111_1111; 160 | color_lut[116]=12'b1111_1100_1111; 161 | color_lut[117]=12'b1100_1111_1100; 162 | color_lut[118]=12'b1110_1110_1111; 163 | color_lut[119]=12'b1111_1111_1001; 164 | color_lut[120]=12'b1111_1110_1011; 165 | color_lut[121]=12'b1111_1110_1010; 166 | color_lut[122]=12'b1110_1111_1001; 167 | color_lut[123]=12'b1111_1101_1111; 168 | color_lut[124]=12'b1011_1111_1110; 169 | color_lut[125]=12'b1100_1110_1111; 170 | color_lut[126]=12'b1110_1101_1111; 171 | color_lut[127]=12'b1101_1111_1010; 172 | end 173 | 174 | always @(posedge clk) 175 | begin 176 | rgbcolor<=color_lut[color]; 177 | end 178 | 179 | assign red=rgbcolor[11:8]; 180 | assign green=rgbcolor[7:4]; 181 | assign blue=rgbcolor[3:0]; 182 | 183 | endmodule 184 | -------------------------------------------------------------------------------- /configrom.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/configrom.bin -------------------------------------------------------------------------------- /configrom_ntsc.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/configrom_ntsc.bin -------------------------------------------------------------------------------- /configrom_pal.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/configrom_pal.bin -------------------------------------------------------------------------------- /cpu65xx_e.vhd: -------------------------------------------------------------------------------- 1 | -- ----------------------------------------------------------------------- 2 | -- 3 | -- FPGA 64 4 | -- 5 | -- A fully functional commodore 64 implementation in a single FPGA 6 | -- 7 | -- ----------------------------------------------------------------------- 8 | -- Copyright 2005-2008 by Peter Wendrich (pwsoft@syntiac.com) 9 | -- http://www.syntiac.com/fpga64.html 10 | -- ----------------------------------------------------------------------- 11 | -- 12 | -- Interface to 6502/6510 core 13 | -- 14 | -- ----------------------------------------------------------------------- 15 | 16 | library IEEE; 17 | use ieee.std_logic_1164.ALL; 18 | use ieee.numeric_std.ALL; 19 | 20 | -- ----------------------------------------------------------------------- 21 | 22 | entity cpu65xx is 23 | generic ( 24 | pipelineOpcode : boolean; 25 | pipelineAluMux : boolean; 26 | pipelineAluOut : boolean 27 | ); 28 | port ( 29 | clk : in std_logic; 30 | enable : in std_logic; 31 | reset : in std_logic; 32 | nmi_n : in std_logic; 33 | irq_n : in std_logic; 34 | so_n : in std_logic := '1'; 35 | 36 | di : in unsigned(7 downto 0); 37 | do : out unsigned(7 downto 0); 38 | addr : out unsigned(15 downto 0); 39 | we : out std_logic; 40 | 41 | debugOpcode : out unsigned(7 downto 0); 42 | debugPc : out unsigned(15 downto 0); 43 | debugA : out unsigned(7 downto 0); 44 | debugX : out unsigned(7 downto 0); 45 | debugY : out unsigned(7 downto 0); 46 | debugS : out unsigned(7 downto 0) 47 | ); 48 | end cpu65xx; 49 | -------------------------------------------------------------------------------- /fakerom.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/fakerom.bin -------------------------------------------------------------------------------- /fakerom2.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/fakerom2.bin -------------------------------------------------------------------------------- /flashtest.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | //////////////////////////////////////////////////////////////////////////////// 4 | // Company: 5 | // Engineer: 6 | // 7 | // Create Date: 13:14:00 01/18/2018 8 | // Design Name: spiflash 9 | // Module Name: C:/Users/ishe/Documents/Cloud/FPGAdev/Plus4/flashtest.v 10 | // Project Name: Plus4 11 | // Target Device: 12 | // Tool versions: 13 | // Description: 14 | // 15 | // Verilog Test Fixture created by ISE for module: spiflash 16 | // 17 | // Dependencies: 18 | // 19 | // Revision: 20 | // Revision 0.01 - File Created 21 | // Additional Comments: 22 | // 23 | //////////////////////////////////////////////////////////////////////////////// 24 | 25 | module flashtest; 26 | 27 | // Inputs 28 | reg clk; 29 | reg [7:0] din; 30 | reg [23:0] Addr; 31 | reg [7:0] cmd; 32 | reg active; 33 | reg ack; 34 | reg reset; 35 | wire flash_so; 36 | 37 | // Outputs 38 | wire [7:0] dout; 39 | wire busy; 40 | wire flash_ck; 41 | wire flash_cs; 42 | wire flash_si; 43 | 44 | // Instantiate the Unit Under Test (UUT) 45 | spiflash uut ( 46 | .clk(clk), 47 | .din(din), 48 | .dout(dout), 49 | .Addr(Addr), 50 | .cmd(cmd), 51 | .active(active), 52 | .ack(ack), 53 | .reset(reset), 54 | .busy(busy), 55 | .flash_ck(flash_ck), 56 | .flash_cs(flash_cs), 57 | .flash_si(flash_si), 58 | .flash_so(flash_so) 59 | ); 60 | initial begin 61 | // Initialize Inputs 62 | clk = 0; 63 | din = 0; 64 | Addr = 24'h000000; 65 | cmd = 8'h00; 66 | active = 0; 67 | ack = 0; 68 | reset = 0; 69 | 70 | // Wait 100 ns for global reset to finish 71 | #100; 72 | // Add stimulus here 73 | Addr = 24'h3fe512; 74 | cmd=8'h03; 75 | active=1; 76 | file=$fopen("fakerom.bin","rb"); 77 | 78 | end 79 | 80 | // 28.288 Mhz 81 | always 82 | begin 83 | #17.675 clk<=~clk; 84 | end 85 | //-------------------------------------------------------------- 86 | 87 | reg [2:0] bytecount=0; 88 | reg [2:0] bitcount=7; 89 | reg [2:0] cbitcount=0; 90 | reg [7:0] flashreg=8'h00; 91 | integer file; 92 | reg command=1; 93 | 94 | always @(negedge flash_ck) begin 95 | if (~flash_cs) begin 96 | if (~command) begin 97 | bitcount<=bitcount+1; 98 | if(bitcount==7) 99 | flashreg<=$fgetc(file); 100 | else flashreg[7:0]<={flashreg[6:0],1'b0}; 101 | end 102 | 103 | end 104 | end 105 | 106 | always @(posedge flash_ck) begin 107 | if(command) begin 108 | cbitcount<=cbitcount+1; 109 | if(cbitcount==7) 110 | if(bytecount==3) 111 | command<=0; 112 | else bytecount=bytecount+1; 113 | end 114 | end 115 | 116 | assign flash_so=flashreg[7]; 117 | 118 | always @(negedge active) begin 119 | $fclose(file); 120 | end 121 | 122 | 123 | endmodule 124 | 125 | -------------------------------------------------------------------------------- /flashtest.wcfg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | clk 16 | clk 17 | 18 | 19 | active 20 | active 21 | 22 | 23 | ack 24 | ack 25 | 26 | 27 | busy 28 | busy 29 | 30 | 31 | flash_clken 32 | flash_clken 33 | 34 | 35 | flash_cs 36 | flash_cs 37 | 38 | 39 | flash_ck 40 | flash_ck 41 | 42 | 43 | shiftreg[7:0] 44 | shiftreg[7:0] 45 | HEXRADIX 46 | 47 | 48 | flash_si 49 | flash_si 50 | 51 | 52 | flash_so 53 | flash_so 54 | 55 | 56 | din[7:0] 57 | din[7:0] 58 | HEXRADIX 59 | 60 | 61 | dout[7:0] 62 | dout[7:0] 63 | HEXRADIX 64 | 65 | 66 | cmd[7:0] 67 | cmd[7:0] 68 | HEXRADIX 69 | 70 | 71 | flash_state[6:0] 72 | flash_state[6:0] 73 | BINARYRADIX 74 | 75 | 76 | shiftcount[2:0] 77 | shiftcount[2:0] 78 | 79 | 80 | Addr[23:0] 81 | Addr[23:0] 82 | HEXRADIX 83 | 84 | 85 | -------------------------------------------------------------------------------- /function_high.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/function_high.bin -------------------------------------------------------------------------------- /function_low.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/function_low.bin -------------------------------------------------------------------------------- /kernal.318005-05.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/kernal.318005-05.bin -------------------------------------------------------------------------------- /kernal_ntsc.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/kernal_ntsc.bin -------------------------------------------------------------------------------- /kernal_pal.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/kernal_pal.bin -------------------------------------------------------------------------------- /kernal_rom.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Copyright 2013-2016 Istvan Hegedus 4 | // 5 | // FPGATED is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // FPGATED is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | // Create Date: 17:12:57 12/05/2014 19 | // Design Name: Commodore 16/Plus 4 Kernal ROM 20 | // Module Name: kernal_rom 21 | // Project Name: FPGATED 22 | // Description: 23 | // Kernal ROM synthetised to FPGA's internal SRAM. Xilinx ISE requires 24 | // ROM_STYLE="BLOCK" parameter next to kernal array. For other vendor's 25 | // device syntax refer to the FPGA vendor's documentation. 26 | // 27 | // Choose the proper Kernal file version depending on NTSC or PAL system 28 | // and comment out the ones which are not needed. 29 | // If you want to convert your own kernal image to compatible version use 30 | // bin2hex.pl perl script to convert it to .hex format. 31 | ////////////////////////////////////////////////////////////////////////////////// 32 | module kernal_rom( 33 | input wire clk, 34 | input wire [13:0] address_in, 35 | output wire [7:0] data_out, 36 | input wire cs 37 | ); 38 | 39 | (* ROM_STYLE="BLOCK" *) 40 | reg [7:0] kernal [0:16383]; 41 | reg [7:0] data; 42 | reg cs_prev=1'b1; 43 | wire enable; 44 | 45 | initial begin 46 | // uncomment the Kernal version to use 47 | 48 | //$readmemh("Diag264_PAL.hex",kernal); 49 | 50 | //$readmemh("Diag264_NTSC.hex",kernal); 51 | 52 | $readmemh("kernal_PAL.hex",kernal); 53 | 54 | //$readmemh("kernal_NTSC.hex",kernal); 55 | 56 | //$readmemh("Jiffy_PAL.hex",kernal); 57 | // Note that Jiffy DOS is not free so Jiffy_PAL.hex is not included with FPGATED source code 58 | 59 | end 60 | 61 | always@(posedge clk) 62 | if(enable) 63 | data<=kernal[address_in]; 64 | 65 | always@(posedge clk) 66 | cs_prev<=cs; 67 | 68 | assign enable=~cs&cs_prev; // cs falling edge detection 69 | assign data_out=(~cs)?data:8'hff; 70 | 71 | 72 | endmodule 73 | -------------------------------------------------------------------------------- /mos6529.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Copyright 2013-2016 Istvan Hegedus 4 | // 5 | // FPGATED is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // FPGATED is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | // Create Date: 09:08:17 12/17/2015 19 | // Design Name: FPGATED 20 | // Module Name: mos6529.v 21 | // Description: MOS 6529 IC emulation. 22 | // 23 | // Revision: 24 | // 0.1 first release 25 | // 1.0 chip read bug fixed 5/04/2016 26 | // 27 | // Additional Comments: 28 | // CS signal is high active while in real IC it is low active. 29 | ////////////////////////////////////////////////////////////////////////////////// 30 | 31 | module mos6529( 32 | input clk, 33 | input [7:0] data_in, 34 | output wire [7:0] data_out, 35 | input [7:0] port_in, 36 | output wire [7:0] port_out, 37 | input rw, 38 | input cs 39 | ); 40 | 41 | reg [7:0] iodata=0; 42 | 43 | assign port_out=iodata; 44 | assign data_out=(cs & rw)?iodata:8'hff; 45 | 46 | always @(posedge clk) 47 | begin 48 | if(cs) 49 | if(rw) 50 | iodata<=port_in; 51 | else 52 | iodata<=data_in; 53 | end 54 | endmodule 55 | -------------------------------------------------------------------------------- /mos8501.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Copyright 2013-2016 Istvan Hegedus 4 | // 5 | // FPGATED is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // FPGATED is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | // Create Date: 16:36:31 12/10/2014 19 | // Module Name: mos8501 20 | // Project Name: FPGATED 21 | // Target Devices: Xilinx Spartan 3E 22 | // 23 | // Description: 24 | // 25 | // Dependencies: 26 | // This module contains an instance of Peter Wendrich's 6502 CPU core from FPGA64 project. 27 | // The CPU core is used and included with Peter's permission and not developed by me. 28 | // The mos8501 shell around the CPU core is written by me, but inspired by fpga64 6510 CPU 29 | // shell. It might shows certain similarities. 30 | // 31 | // Revision history: 32 | // 0.1 first release using incorrect 6502 core from fpga64 project 33 | // 1.0 CPU core replaced to cpu65xx_fast.vhd from fpga64 project 34 | // 35 | ////////////////////////////////////////////////////////////////////////////////// 36 | module mos8501( 37 | input clk, 38 | input reset, 39 | input enable, 40 | input irq_n, 41 | input [7:0] data_in, 42 | output wire [7:0] data_out, 43 | output [15:0] address, 44 | input gate_in, 45 | output rw, 46 | input [7:0] port_in, 47 | output [7:0] port_out, 48 | input rdy, 49 | input aec 50 | ); 51 | 52 | wire we,enable_cpu; 53 | wire [15:0] core_address; 54 | wire [7:0] core_data_out; 55 | wire port_access; 56 | reg [7:0] data_out_reg,core_data_in,port_io; 57 | reg [7:0] port_dir=8'b0; 58 | reg [7:0] port_data=8'b0; 59 | reg rw_reg,aec_reg; 60 | 61 | // 6502 CPU core 62 | 63 | cpu65xx #(.pipelineOpcode(0),.pipelineAluMux(0),.pipelineAluOut(0)) 64 | cpu_core( 65 | .clk(clk), 66 | .reset(reset), 67 | .enable(enable_cpu), 68 | .nmi_n(1'b1), 69 | .irq_n(irq_n), 70 | .di(core_data_in), 71 | .do(core_data_out), 72 | .addr(core_address), 73 | .we(we), 74 | .so_n(1'b1), 75 | .debugOpcode(), 76 | .debugPc(), 77 | .debugA(), 78 | .debugX(), 79 | .debugY(), 80 | .debugS() 81 | ); 82 | 83 | assign address=(aec)?core_address:16'hffff; // address tri state emulated for easy bus signal combining 84 | 85 | always @(posedge clk) 86 | begin 87 | if(gate_in) 88 | begin 89 | if(port_access==1'b1 && we==1'b1) 90 | if(address[0]==1'b0) // when port direction register is written, data on bus is last read byte which is 0x00 91 | data_out_reg<=8'h00; 92 | else // when port register is written, data on bus is last read byte which is 0x01 93 | data_out_reg<=8'h01; 94 | else 95 | data_out_reg<=core_data_out; // when mux is high, data out register is updated 96 | end 97 | else 98 | begin 99 | data_out_reg<=data_out_reg; // hold off data out during write cycle 100 | end 101 | end 102 | 103 | always @(posedge clk) 104 | begin 105 | if(gate_in) 106 | rw_reg<=~we; 107 | end 108 | 109 | always @(posedge clk) // registering aec for 1 clk cycle delay 110 | begin 111 | aec_reg<=aec; 112 | end 113 | 114 | assign rw=(~aec_reg)?1'b1:rw_reg; 115 | 116 | assign data_out=(~aec_reg | gate_in | rw)?8'hff:data_out_reg; // when mux is low data out register is allowed to outside 117 | assign port_access=(address[15:1]==0)?1'b1:1'b0; 118 | 119 | // IO port part of cpu 120 | 121 | always @(posedge clk) //writing port registers 122 | begin 123 | if(reset) 124 | begin 125 | port_dir<=0; 126 | port_data<=0; 127 | end 128 | else if (enable) 129 | if(port_access & we) 130 | if(address[0]==0) 131 | port_dir<=core_data_out; 132 | else 133 | port_data<=core_data_out; 134 | end 135 | 136 | always @* // reading port registers 137 | begin 138 | core_data_in=data_in; 139 | if (port_access & ~we) 140 | if(address[0]==0) 141 | core_data_in=port_dir; 142 | else 143 | core_data_in=port_io; 144 | end 145 | 146 | // if direction bit is 0 then data is from chip's port 147 | // if direction bit is 1 then data is from data port register filled earlier by CPU 148 | 149 | always @* 150 | begin 151 | if(port_dir[0]==1'b0) 152 | port_io[0]=port_in[0]; 153 | else 154 | port_io[0]=port_data[0]; 155 | if(port_dir[1]==1'b0) 156 | port_io[1]=port_in[1]; 157 | else 158 | port_io[1]=port_data[1]; 159 | if(port_dir[2]==1'b0) 160 | port_io[2]=port_in[2]; 161 | else 162 | port_io[2]=port_data[2]; 163 | if(port_dir[3]==1'b0) 164 | port_io[3]=port_in[3]; 165 | else 166 | port_io[3]=port_data[3]; 167 | if(port_dir[4]==1'b0) 168 | port_io[4]=port_in[4]; 169 | else 170 | port_io[4]=port_data[4]; 171 | if(port_dir[5]==1'b0) 172 | port_io[5]=port_in[5]; 173 | else 174 | port_io[5]=port_data[5]; 175 | if(port_dir[6]==1'b0) 176 | port_io[6]=port_in[6]; 177 | else 178 | port_io[6]=port_data[6]; 179 | if(port_dir[7]==1'b0) 180 | port_io[7]=port_in[7]; 181 | else 182 | port_io[7]=port_data[7]; 183 | end 184 | 185 | assign port_out=port_data; 186 | assign enable_cpu=(~rdy & ~we)?1'b0:enable; // When RDY is low and cpu would do a read, halt cpu 187 | 188 | endmodule 189 | -------------------------------------------------------------------------------- /mos8501_t65.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Copyright 2013-2019 Istvan Hegedus 4 | // 5 | // FPGATED is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // FPGATED is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | // Create Date: 16:36:31 12/10/2014 19 | // Module Name: mos8501 20 | // Project Name: FPGATED 21 | // Target Devices: Xilinx Spartan 3E 22 | // 23 | // Description: 24 | // 25 | // Dependencies: 26 | // This module contains an instance of T65 CPU core which was bug fixed by FPGAARCADE team. 27 | // See the CPU core's source file for licensing information. 28 | // The mos8501 shell around the CPU core is written by me, but inspired by fpga64 6510 CPU 29 | // shell. It might show certain similarities. The shell was modified from earlier FPGA64 CPU 30 | // core version to work with T65. 31 | // 32 | // Revision history: 33 | // 0.1 first release using incorrect 6502 core from fpga64 project 34 | // 1.0 CPU core replaced to cpu65xx_fast.vhd from fpga64 project 35 | // 2.0 CPU core replaced to T65 from fpgaarcade 36 | // 37 | ////////////////////////////////////////////////////////////////////////////////// 38 | module mos8501_t65( 39 | input clk, 40 | input reset, 41 | input enable, 42 | input irq_n, 43 | input [7:0] data_in, 44 | output wire [7:0] data_out, 45 | output [15:0] address, 46 | input gate_in, 47 | output rw, 48 | input [7:0] port_in, 49 | output [7:0] port_out, 50 | input rdy, 51 | input aec 52 | ); 53 | 54 | wire we,enable_cpu; 55 | wire [15:0] core_address; 56 | wire [7:0] core_data_out; 57 | wire port_access; 58 | reg [7:0] data_out_reg,core_data_in,port_io; 59 | reg [7:0] port_dir=8'b0; 60 | reg [7:0] port_data=8'b0; 61 | reg rw_reg,aec_reg; 62 | 63 | T65 cpu_core( 64 | .Mode(2'b00), 65 | .Res_n(~reset), 66 | .Enable(enable), 67 | .Clk(clk), 68 | .Rdy(rdy), 69 | .Abort_n(), 70 | .IRQ_n(irq_n), 71 | .NMI_n(1'b1), 72 | .SO_n(1'b1), 73 | .R_W_n(we), 74 | .A(core_address), 75 | .DI(core_data_in), 76 | .DO(core_data_out) 77 | ); 78 | 79 | assign address=(aec)?core_address:16'hffff; // address tri state emulated for easy bus signal combining 80 | 81 | always @(posedge clk) 82 | begin 83 | if(gate_in) 84 | begin 85 | if(port_access==1'b1 && we==1'b0) 86 | if(address[0]==1'b0) // when port direction register is written, data on bus is last read byte which is 0x00 87 | data_out_reg<=8'h00; 88 | else // when port register is written, data on bus is last read byte which is 0x01 89 | data_out_reg<=8'h01; 90 | else 91 | data_out_reg<=core_data_out; // when mux is high, data out register is updated 92 | end 93 | else 94 | begin 95 | data_out_reg<=data_out_reg; // hold off data out during write cycle 96 | end 97 | end 98 | 99 | always @(posedge clk) 100 | begin 101 | if(gate_in) 102 | rw_reg<=we; 103 | end 104 | 105 | always @(posedge clk) // registering aec for 1 clk cycle delay 106 | begin 107 | aec_reg<=aec; 108 | end 109 | 110 | assign rw=(~aec_reg)?1'b1:rw_reg; 111 | 112 | assign data_out=(~aec_reg | gate_in | rw)?8'hff:data_out_reg; // when mux is low data out register is allowed to outside 113 | assign port_access=(address[15:1]==0)?1'b1:1'b0; 114 | 115 | // IO port part of cpu 116 | 117 | always @(posedge clk) //writing port registers 118 | begin 119 | if(reset) 120 | begin 121 | port_dir<=0; 122 | port_data<=0; 123 | end 124 | else if (enable) 125 | if(port_access & ~we) 126 | if(address[0]==0) 127 | port_dir<=core_data_out; 128 | else 129 | port_data<=core_data_out; 130 | end 131 | 132 | always @* // reading port registers 133 | begin 134 | core_data_in=data_in; 135 | if (port_access & we) 136 | if(address[0]==0) 137 | core_data_in=port_dir; 138 | else 139 | core_data_in=port_io; 140 | end 141 | 142 | // if direction bit is 0 then data is from chip's port 143 | // if direction bit is 1 then data is from data port register filled earlier by CPU 144 | 145 | always @* 146 | begin 147 | if(port_dir[0]==1'b0) 148 | port_io[0]=port_in[0]; 149 | else 150 | port_io[0]=port_data[0]; 151 | if(port_dir[1]==1'b0) 152 | port_io[1]=port_in[1]; 153 | else 154 | port_io[1]=port_data[1]; 155 | if(port_dir[2]==1'b0) 156 | port_io[2]=port_in[2]; 157 | else 158 | port_io[2]=port_data[2]; 159 | if(port_dir[3]==1'b0) 160 | port_io[3]=port_in[3]; 161 | else 162 | port_io[3]=port_data[3]; 163 | if(port_dir[4]==1'b0) 164 | port_io[4]=port_in[4]; 165 | else 166 | port_io[4]=port_data[4]; 167 | if(port_dir[5]==1'b0) 168 | port_io[5]=port_in[5]; 169 | else 170 | port_io[5]=port_data[5]; 171 | if(port_dir[6]==1'b0) 172 | port_io[6]=port_in[6]; 173 | else 174 | port_io[6]=port_data[6]; 175 | if(port_dir[7]==1'b0) 176 | port_io[7]=port_in[7]; 177 | else 178 | port_io[7]=port_data[7]; 179 | end 180 | 181 | assign port_out=port_data; 182 | 183 | endmodule 184 | -------------------------------------------------------------------------------- /mt48lc4m16a2.v: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/mt48lc4m16a2.v -------------------------------------------------------------------------------- /plus4_2.wcfg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | SDRAM 16 | label 17 | 18 | 19 | CLK32 20 | CLK32 21 | 22 | 23 | CLK28 24 | CLK28 25 | 26 | 27 | -------------------------------------------------------------------------------- /plus4palroms.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/plus4palroms.bin -------------------------------------------------------------------------------- /ps2receiver.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Copyright 2013-2016 Istvan Hegedus 4 | // 5 | // FPGATED is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // FPGATED is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | // Create Date: 11:30:06 12/14/2015 19 | // Module Name: ps2receiver.v 20 | // Project Name: FPGATED 21 | // Description: PS2 keyboard receiver 22 | // 23 | // 24 | // 25 | // Revision: 26 | // Revision 1.0 - File Created 27 | // 1.0.1 shiftreg size fixed for storing scancode 28 | // 29 | ////////////////////////////////////////////////////////////////////////////////// 30 | module ps2receiver( 31 | input clk, 32 | input ps2_clk, 33 | input ps2_data, 34 | output reg rx_done, 35 | output reg [7:0] ps2scancode 36 | ); 37 | 38 | reg ps2clkreg=1'b0,prev_ps2clkreg=1'b0; 39 | reg [3:0] receivedbits=4'b0; 40 | reg [11:0] watchdog=12'd2900; // ~ 100us watchdog period with 28MHz clock 41 | reg [7:0] ps2clkfilter; 42 | reg [10:0] shiftreg; 43 | 44 | always @(posedge clk) // filtering ps2 clock line glitches 45 | begin 46 | ps2clkfilter<={ps2clkfilter[6:0],ps2_clk}; 47 | if(ps2clkfilter==8'h00) 48 | ps2clkreg<=0; 49 | else if (ps2clkfilter==8'hff) 50 | ps2clkreg<=1; 51 | prev_ps2clkreg<=ps2clkreg; // this is needed for clock edge detection 52 | end 53 | 54 | always @(posedge clk) 55 | begin 56 | rx_done<=0; // rx_done is active only for one clk cycle 57 | if(watchdog==0) // when watchdog timer expires, reset received bits 58 | receivedbits<=0; 59 | else watchdog<=watchdog-12'd1; 60 | 61 | if(prev_ps2clkreg & ~ps2clkreg) // falling edge of ps2 clock 62 | begin 63 | watchdog<=12'd2900; // reload watchdog timer 64 | shiftreg<={ps2_data,shiftreg[10:1]}; 65 | receivedbits<=receivedbits+4'd1; 66 | end 67 | 68 | if(receivedbits==4'd11) 69 | begin 70 | ps2scancode<=shiftreg[8:1]; 71 | rx_done<=1; 72 | receivedbits<=0; 73 | end 74 | end 75 | 76 | endmodule 77 | -------------------------------------------------------------------------------- /ram.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Engineer: 4 | // 5 | // Create Date: 6 | // Design Name: 7 | // Module Name: ram 8 | // Project Name: 9 | // Target Devices: 10 | // Tool versions: 11 | // Description: RAM used for simulation purposes only 12 | // 13 | // Dependencies: This is only for simulation. Real DRAM is on FPGATED board 14 | // 15 | // Revision: 16 | // Revision 0.01 - File Created 17 | // Additional Comments: 18 | // 19 | ////////////////////////////////////////////////////////////////////////////////// 20 | module ram( 21 | input wire [7:0] address, 22 | input wire ras, 23 | input wire cas, 24 | input wire [7:0] data_in, 25 | output wire [7:0] data_out, 26 | input wire rw 27 | ); 28 | 29 | reg [7:0] memory[65535:0]; 30 | reg [7:0] q; 31 | reg [15:0] ramaddress; 32 | integer i; 33 | 34 | always @(negedge ras) 35 | ramaddress[7:0]=address; 36 | 37 | always @(negedge cas) 38 | begin 39 | ramaddress[15:8]=address; 40 | if (rw==0) 41 | memory[ramaddress]=data_in; 42 | else 43 | q=memory[ramaddress]; 44 | end 45 | 46 | assign data_out=(!cas && rw)?q:8'hff; 47 | 48 | initial begin 49 | for (i=0;i<=65535;i=i+2) 50 | begin 51 | memory[i]=8'h00; 52 | memory[i+1]=8'hff; 53 | end 54 | end 55 | endmodule 56 | -------------------------------------------------------------------------------- /rompack.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/rompack.bin -------------------------------------------------------------------------------- /sdram_clk.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Create Date: 21:49:28 04/09/2017 4 | // Design Name: Plus4 5 | // Module Name: sdram_clk 6 | // Project Name: FPGATED 7 | // Target Devices: Xilinx Spartan6 8 | // Description: Xilinx specific SDRAM clock output generator using DDR2 register 9 | // 10 | // Revision: 11 | // Revision 0.01 - File Created 12 | // Additional Comments: 13 | // 14 | ////////////////////////////////////////////////////////////////////////////////// 15 | 16 | module sdram_clk( 17 | input clk, 18 | output sdram_clk 19 | ); 20 | 21 | ODDR2 #( 22 | .DDR_ALIGNMENT("NONE"), // Sets output alignment to "NONE", "C0" or "C1" 23 | .INIT(1'b0), // Sets initial state of the Q output to 1'b0 or 1'b1 24 | .SRTYPE("SYNC") // Specifies "SYNC" or "ASYNC" set/reset 25 | ) ODDR2_sdram ( 26 | .Q(sdram_clk), // SDRAM's clock output from FPGA 27 | .C0(clk), // FPGA's global clock 28 | .C1(~clk), // FPGA's global clock 29 | .CE(1'b1), // 1-bit clock enable input 30 | .D0(1'b0), // 1-bit data input (associated with C0) 31 | .D1(1'b1), // 1-bit data input (associated with C1) 32 | .R(1'b0), // 1-bit reset input (no reset) 33 | .S(1'b0) // 1-bit set input (no set) 34 | ); 35 | 36 | endmodule 37 | -------------------------------------------------------------------------------- /sdram_controller.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Copyright 2013-2016 Istvan Hegedus 4 | // 5 | // FPGATED is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // FPGATED is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program. If not, see . 17 | // 18 | // Create Date: 28/09/2016 19 | // Design Name: SDRAM controller 20 | // Module Name: sdram_controller.v 21 | // Project Name: FPGATED 22 | // Description: FPGATED SDRAM controller for Papilio Pro board 23 | // 24 | // Revision history: 25 | // Revision 1.0 26 | // 27 | // Additional Comments: 28 | // 29 | // SDRAM can be used as RAM and ROM. ROM must be uploaded by a bootstrap code from SPI flash or SD card if that is available (no SD card for Papilio Pro). 30 | // Using special paging we can have more than 64k RAM for the Plus4 and we can change ROM banks. See Csory and Hannes RAM extensions for more details. 31 | // This sdram controller uses an extended address which is mapped from Plus4 address bus and some additional signals. It is the higher level module's 32 | // responsibility to do the address mapping and provide an extended 22 bits long address however the controller can distuinguish RAM access from ROM access. 33 | // 34 | // Address mapping in case of RAM access (A15-A0 is Plus4 address bits) 35 | // 36 | // [A11 - A0] RAM access row address 37 | // [A13-A12] SDRAM bank selector 38 | // [0|6 bits address extension|A15] RAM access column address. 6 bits extension can be used for RAM expansion (Csory/Hannes) 39 | // DQM=A14 High/Low data byte selector on the 16 bits data bus of sdram 40 | // 41 | // Address mapping in case of ROM access 42 | // 43 | // [A11 - A0] ROM access row address 44 | // [A13-A12] SDRAM bank selector 45 | // [1|0|4 bits address extension|ROM type] ROM access column address. See ROM type values below. 4 bits extension allows 16 ROM versions inside one type. 46 | // DQM=CS0 high/low ROM selector 47 | // 48 | // ROM type values: 00=Internal ROM, 01=Function ROM, 10=Cartridge 1, 11=Cartridge 2 49 | // 50 | // 51 | ////////////////////////////////////////////////////////////////////////////////// 52 | module sdram_controller( 53 | output reg [11:0] sdram_addr, 54 | inout [15:0] sdram_data, 55 | output reg [1:0] sdram_dqm, 56 | output reg [1:0] sdram_ba, 57 | output sdram_we, 58 | output sdram_ras, 59 | output sdram_cas, 60 | output sdram_cs, 61 | output reg sdram_cke, 62 | input clk, 63 | input [15:0] plus4_addr, 64 | input [5:0] plus4_addrext, // RAM/ROM address extension bits 65 | input plus4_ras, 66 | input plus4_cas, 67 | input plus4_rw, 68 | input plus4_cs0, 69 | input plus4_cs1, 70 | input [7:0] ram_datain, 71 | output [7:0] ram_dataout, 72 | output reg initdone // signals when sdram init is done 73 | ); 74 | 75 | reg [7:0] initcycle=8'd182; // this is the duration of the whole sdram initialization sequence (units are TED double clk cycles) 76 | reg [3:0] cycle=0; // sdram cycle counter 77 | reg plus4_ras_prev=1; 78 | reg [3:0] sdram_cmd=4'b0000; 79 | reg [7:0] dataout; 80 | 81 | localparam CMD_INHIBIT = 4'b1xxx; 82 | localparam CMD_LOADMODE = 4'b0000; 83 | localparam CMD_AUTOREFRESH = 4'b0001; 84 | localparam CMD_PRECHARGE = 4'b0010; 85 | localparam CMD_ACTIVE = 4'b0011; 86 | localparam CMD_WRITE = 4'b0100; 87 | localparam CMD_READ = 4'b0101; 88 | localparam CMD_NOP = 4'b0111; 89 | 90 | 91 | localparam BURST_LENGTH = 3'b000; 92 | localparam BURST_TYPE = 1'b0; 93 | localparam CAS_LATENCY = 3'b010; // CL=2 94 | localparam WRITE_BURST = 1'b1; // single location access 95 | localparam MODE = {3'b000, WRITE_BURST, 2'b00, CAS_LATENCY, BURST_TYPE, BURST_LENGTH}; 96 | 97 | assign sdram_cs = sdram_cmd[3]; 98 | assign sdram_ras = sdram_cmd[2]; 99 | assign sdram_cas = sdram_cmd[1]; 100 | assign sdram_we = sdram_cmd[0]; 101 | 102 | 103 | initial 104 | begin 105 | sdram_cke=0; 106 | initdone=0; 107 | end 108 | 109 | always @(posedge clk) 110 | begin 111 | if(cycle==4'd14) 112 | begin 113 | if(initcycle!=0) 114 | initcycle<=initcycle-1'b1; 115 | else initdone<=1'b1; // for clean startup synchronize initdone signal to memory cycle beginning 116 | end 117 | end 118 | 119 | 120 | always @(posedge clk) // memory cycle counter 121 | begin 122 | plus4_ras_prev<=plus4_ras; 123 | if(~plus4_ras & plus4_ras_prev) // RAS falling edge detection 124 | cycle<=0; // synchronize memory cycle counter to RAS beginning ( 1 cycle delay!) 125 | else cycle<=cycle+4'b1; 126 | end 127 | 128 | 129 | always @(posedge clk) 130 | begin 131 | sdram_cmd<=CMD_INHIBIT; 132 | if(!initdone) // sdram initialization 133 | begin 134 | sdram_ba<=2'b00; 135 | sdram_dqm<=2'b00; 136 | if(initcycle==9'd90) // enable sdram clock at about half of the 100us wait time 137 | sdram_cke<=1; 138 | else if(initcycle==9'd1) // after 100us start the setup sequence 139 | case (cycle) 140 | 0: begin 141 | sdram_addr<=12'b010000000000; 142 | sdram_cmd<=CMD_PRECHARGE; 143 | end 144 | 2: sdram_cmd<=CMD_AUTOREFRESH; 145 | 4: sdram_cmd<=CMD_AUTOREFRESH; 146 | 6: begin 147 | sdram_addr<=MODE; 148 | sdram_cmd<=CMD_LOADMODE; 149 | end 150 | default: sdram_cmd<=CMD_NOP; 151 | endcase 152 | end 153 | else begin // normal sdram operation after initialization 154 | sdram_cmd<=CMD_NOP; 155 | sdram_dqm<=2'b11; // by default we mask output 156 | case (cycle) 157 | 15: begin // activate row in each CPU cycle 158 | sdram_addr<=plus4_addr[11:0]; 159 | sdram_ba<=plus4_addr[13:12]; 160 | sdram_cmd<=CMD_ACTIVE; 161 | end 162 | 1: begin 163 | if(plus4_rw) // READ 164 | begin 165 | sdram_dqm<=2'b00; // for reads we don't need to mask output as mux and data latching will take care of getting proper data 166 | if(~plus4_cas) // RAM read 167 | begin 168 | sdram_addr<={4'b0100,1'b0,plus4_addrext,plus4_addr[15]}; 169 | sdram_cmd<=CMD_READ; 170 | end 171 | else if(~plus4_cs0|~plus4_cs1) // ROM read 172 | begin 173 | sdram_addr<={4'b0100,2'b10,plus4_addrext}; 174 | sdram_cmd<=CMD_READ; 175 | end 176 | end 177 | end 178 | 3: begin 179 | if(plus4_rw) // if READ command was issued, latch result 2 Clocks later (CL=2) 180 | begin 181 | if(~plus4_cas) // RAM data latch 182 | dataout<=(plus4_addr[14])?sdram_data[15:8]:sdram_data[7:0]; 183 | else if(~plus4_cs0|~plus4_cs1) // ROM data latch 184 | dataout<=(plus4_cs0)?sdram_data[15:8]:sdram_data[7:0]; 185 | end 186 | end 187 | 4: if(plus4_cas&plus4_cs0&plus4_cs1) // if row was activated in vain because of TED read/write or io read/write close row 188 | sdram_cmd<=CMD_PRECHARGE; // it must be done not earlier than cycle 4 because write CAS activates later than read CAS 189 | 6: if(~plus4_rw) // if write cycle 190 | begin 191 | if(~plus4_cas) // RAM write 192 | begin 193 | sdram_addr<={4'b0100,1'b0,plus4_addrext,plus4_addr[15]}; 194 | sdram_dqm<=(plus4_addr[14])?2'b01:2'b10; 195 | sdram_cmd<=CMD_WRITE; 196 | end 197 | else if(~plus4_cs0|~plus4_cs1) // ROM write. It is only used at the initial ROM upload. In normal operatin this should not happen. 198 | begin 199 | sdram_addr<={4'b0100,2'b10,plus4_addrext}; 200 | sdram_dqm<=(plus4_cs0)?2'b01:2'b10; 201 | sdram_cmd<=CMD_WRITE; 202 | end 203 | end 204 | 10: sdram_cmd<=CMD_AUTOREFRESH; 205 | 206 | endcase 207 | end 208 | end 209 | 210 | // assign ram_dataout=(~plus4_cas&plus4_rw)?dataout:8'hff; // data out assignment when only RAM is used from sdram 211 | assign ram_dataout=(plus4_rw&(~plus4_cas|~plus4_cs0|~plus4_cs1))?dataout:8'hff; // data out assignment when RAM and ROM is used from sdram 212 | 213 | assign sdram_data=(sdram_cmd==CMD_WRITE)?{ram_datain,ram_datain}:16'bZZZZZZZZZZZZZZZZ; 214 | 215 | 216 | 217 | endmodule 218 | 219 | -------------------------------------------------------------------------------- /spiflash.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // 4 | // Create Date: 01/19/2018 5 | // Created by: Istvan Hegedus 6 | // Design Name: SPI flash driver for FPGA plus4 7 | // Module Name: spiflash 8 | // Project Name: FPGATED, FPGAplus4 9 | // Target Devices: Xilinx Spartan 3E, 6A 10 | // 11 | // Description: 12 | // 13 | // SPI flash driver supports the following flash commands: READ, RDID, RDSR, RDSCUR, PP, SE, WREN, WRDI, CLSR 14 | // Driver usage: 15 | // Set the 24 bit flash address (Addr), command (cmd) and if needed the byte to send (din) by the higher level module. 16 | // Driver is controlled by active and ack signals. During operation active must be high. A one cycle pulse on ack initiates operation when active is high. 17 | // Busy signal will be active during operation and become inactive as soon as driver has finished the requested operation. 18 | // If the command implies reading a byte or more, the result will be in dout. 19 | // In case of READ, RDID or PP commands more bytes might need to be read or sent so the driver will be still active when busy signal inactivates. 20 | // Two possible actions can follow: 21 | // 1. There are more bytes to be read/written so a one cycle ack signal acknowledges that the previous byte was taken and more are needed (active=high, ack=one cycle pulse) 22 | // 2. There are no more bytes to read/write so active must be driven low and a one cycle ack signal informs driver that operation can end (active=low, ack=one cycle pulse) 23 | // 24 | // 25 | // Revision: 1.0 26 | // 27 | ////////////////////////////////////////////////////////////////////////////////// 28 | module spiflash( 29 | input clk, 30 | input [7:0] din, 31 | output [7:0] dout, 32 | input [23:0] Addr, 33 | input [7:0] cmd, 34 | input active, 35 | input ack, 36 | input reset, 37 | output busy, 38 | output flash_ck, 39 | output reg flash_cs, 40 | output flash_si, 41 | input wire flash_so 42 | ); 43 | 44 | initial 45 | begin 46 | flash_cs=1'b1; 47 | end 48 | 49 | reg [6:0] flash_state=IDLE; 50 | reg [7:0] shiftreg; 51 | reg [2:0] shiftcount=0; 52 | reg flash_clken=1'b0; 53 | reg flash_so_reg; 54 | 55 | // FSM states (one hot) 56 | localparam IDLE= 7'b0000001; 57 | localparam CMD = 7'b0000010; 58 | localparam AH = 7'b0000100; 59 | localparam AM = 7'b0001000; 60 | localparam AL = 7'b0010000; 61 | localparam TX = 7'b0100000; 62 | localparam RX = 7'b1000000; 63 | 64 | localparam PP=8'h02; 65 | localparam READ=8'h03; 66 | localparam WRDI=8'h04; 67 | localparam RDSR=8'h05; 68 | localparam WREN=8'h06; 69 | localparam SE=8'h20; 70 | localparam RDSCUR=8'h2b; 71 | localparam CLSR=8'h30; 72 | localparam RDID=8'h9f; 73 | localparam DP=8'hb9; 74 | localparam RDP=8'hab; 75 | 76 | always @(posedge clk) 77 | begin 78 | if(reset) 79 | flash_state<=IDLE; 80 | else 81 | case(flash_state) 82 | IDLE: begin 83 | if(active & ack) // signals start of flash command 84 | begin 85 | flash_state<=CMD; 86 | flash_clken<=1'b1; 87 | flash_cs<=1'b0; 88 | shiftreg<=cmd; 89 | end 90 | else 91 | begin 92 | flash_clken<=1'b0; 93 | end 94 | end 95 | CMD: begin 96 | shiftreg[7:0]<={shiftreg[6:0],flash_so_reg}; 97 | shiftcount<=shiftcount+3'b1; 98 | if(shiftcount==3'b111) 99 | begin 100 | if(cmd==READ || cmd==PP || cmd==SE) 101 | begin 102 | flash_state<=AH; 103 | shiftreg<=Addr[23:16]; 104 | end 105 | else if(cmd==RDSR || cmd==RDSCUR || cmd==RDID) 106 | begin 107 | flash_state<=RX; 108 | end 109 | else 110 | begin 111 | flash_state<=IDLE; // unknown commands are sent but after that we return to IDLE, don't handle them. Undefined command only commands however work. 112 | flash_clken<=1'b0; 113 | flash_cs<=1'b1; 114 | end 115 | end 116 | end 117 | AH: begin 118 | shiftreg[7:0]<={shiftreg[6:0],flash_so_reg}; 119 | shiftcount<=shiftcount+3'b1; 120 | if(shiftcount==3'b111) 121 | begin 122 | flash_state<=AM; 123 | shiftreg<=Addr[15:8]; 124 | end 125 | end 126 | AM: begin 127 | shiftreg[7:0]<={shiftreg[6:0],flash_so_reg}; 128 | shiftcount<=shiftcount+3'b1; 129 | if(shiftcount==3'b111) 130 | begin 131 | flash_state<=AL; 132 | shiftreg<=Addr[7:0]; 133 | end 134 | end 135 | AL: begin 136 | shiftreg[7:0]<={shiftreg[6:0],flash_so_reg}; 137 | shiftcount<=shiftcount+3'b1; 138 | if(shiftcount==3'b111) 139 | begin 140 | if(cmd==PP) 141 | begin 142 | flash_state<=TX; 143 | shiftreg<=din; 144 | end 145 | if(cmd==READ) 146 | begin 147 | flash_state<=RX; 148 | end 149 | if(cmd==SE) 150 | begin 151 | flash_state<=IDLE; 152 | flash_clken<=1'b0; 153 | flash_cs<=1'b1; 154 | end 155 | end 156 | end 157 | TX: begin 158 | if(flash_clken) // TX enabled 159 | begin 160 | shiftreg[7:0]<={shiftreg[6:0],flash_so_reg}; 161 | shiftcount<=shiftcount+3'b1; 162 | if(shiftcount==3'b111) // pause transfer after 8 bits shift 163 | begin 164 | flash_clken<=1'b0; 165 | end 166 | end 167 | else // TX paused 168 | begin 169 | if(active & ack) // when byte acknowledged continue with next byte 170 | begin 171 | flash_clken<=1'b1; 172 | flash_state<=TX; 173 | shiftreg<=din; 174 | end 175 | if(~active & ack) // when byte acknowledged but end signalled, go to IDLE 176 | begin 177 | flash_state<=IDLE; 178 | flash_cs<=1'b1; 179 | end 180 | end 181 | end 182 | RX: begin 183 | if(flash_clken) // RX enabled 184 | begin 185 | shiftreg[7:0]<={shiftreg[6:0],flash_so_reg}; 186 | shiftcount<=shiftcount+3'b1; 187 | if(shiftcount==3'b111) // pause transfer after 8 bits 188 | begin 189 | flash_clken<=1'b0; 190 | end 191 | end 192 | else // RX paused 193 | begin 194 | if(active & ack) // ACK and continue with next byte 195 | begin 196 | flash_clken<=1'b1; 197 | flash_state<=RX; 198 | end 199 | if(~active & ack) // End of RX 200 | begin 201 | flash_state<=IDLE; 202 | flash_cs<=1'b1; 203 | end 204 | end 205 | end 206 | endcase 207 | end 208 | 209 | // Latch data from Flash on rising edge of flash clock (falling edge of system clock) 210 | always @(negedge clk) begin 211 | if(flash_clken) 212 | flash_so_reg<=flash_so; 213 | end 214 | 215 | assign busy=flash_clken; 216 | assign flash_si=shiftreg[7]; 217 | assign dout=shiftreg; 218 | 219 | // Connect FLASH's clock signal. It provides a 180 degree shifted clk 220 | ODDR2 #( 221 | .DDR_ALIGNMENT("NONE"), // Sets output alignment to "NONE", "C0" or "C1" 222 | .INIT(1'b0), // Sets initial state of the Q output to 1'b0 or 1'b1 223 | .SRTYPE("SYNC") // Specifies "SYNC" or "ASYNC" set/reset 224 | ) ODDR2_sdram ( 225 | .Q(flash_ck), // 1-bit DDR output data 226 | .C0(clk), // 1-bit clock input 227 | .C1(~clk), // 1-bit clock input 228 | .CE(flash_clken), // 1-bit clock enable input 229 | .D0(1'b0), // 1-bit data input (associated with C0) 230 | .D1(1'b1), // 1-bit data input (associated with C1) 231 | .R(1'b0), // 1-bit reset input (no reset) 232 | .S(1'b0) // 1-bit set input (no set) 233 | ); 234 | 235 | 236 | 237 | endmodule 238 | -------------------------------------------------------------------------------- /testrompack.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ishe/plus4/3a51c37a4b45438b4a8a0dd795c3eb10fdc0a955/testrompack.bin --------------------------------------------------------------------------------