├── 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
--------------------------------------------------------------------------------