diff --git a/.github/scripts/buildRelease.sh b/.github/scripts/buildRelease.sh index 33faf8c..da59a2c 100755 --- a/.github/scripts/buildRelease.sh +++ b/.github/scripts/buildRelease.sh @@ -35,7 +35,9 @@ make \ BUILD=Release \ PREFIX="$TOOLCHAIN_DIR/bin/mipsel-none-elf" \ FORMAT=elf32-littlemips \ - FASTBOOT=true \ + BOARD=system573 \ + BOOT_MODE=psexe \ + SPLASH_SCREEN=true \ EMBED_PSEXE="$PROJECT_DIR/build/${RELEASE_NAME}-tiny.psexe" \ || exit 2 diff --git a/data/fpga.bit b/data/fpga.bit index b4dfd29..e576432 100644 Binary files a/data/fpga.bit and b/data/fpga.bit differ diff --git a/doc/fpga.md b/doc/fpga.md index 01bc44d..7894c7b 100644 --- a/doc/fpga.md +++ b/doc/fpga.md @@ -79,28 +79,27 @@ Note that the number is different from the one used by Konami (`0x1234`). | 14 | W | Output D2 (0 = grounded, 1 = high-z) | | 15 | W | Output D3 (0 = grounded, 1 = high-z) | -### `0x1f6400ee` (FPGA, DDR/Mambo bitstream): **1-wire bus** +### `0x1f6400ee`: **1-wire bus** When read: | Bits | RW | Description | | ----: | :- | :------------------------ | -| 0-11 | | _Unused_ | +| 0-7 | | _Unused_ | +| 8 | R | DS2433 1-wire bus readout | +| 9-11 | | _Unused_ | | 12 | R | DS2401 1-wire bus readout | -| 13 | R | DS2433 1-wire bus readout | -| 14-15 | | _Unused_ | +| 13-15 | | _Unused_ | When written: | Bits | RW | Description | | ----: | :- | :----------------------------------------------------------- | -| 0-11 | | _Unused_ | +| 0-7 | | _Unused_ | +| 8 | W | Drive DS2433 1-wire bus low (1 = pull to ground, 0 = high-z) | +| 9-11 | | _Unused_ | | 12 | W | Drive DS2401 1-wire bus low (1 = pull to ground, 0 = high-z) | -| 13 | W | Drive DS2433 1-wire bus low (1 = pull to ground, 0 = high-z) | -| 14-15 | | _Unused_ | - -Bit 13 is mapped to the bus of the (normally unpopulated) DS2433 footprint. It -is currently unclear whether and how Konami's bitstreams expose this bus. +| 13-15 | | _Unused_ | ## Building the bitstream diff --git a/fpga/fpga.ucf b/fpga/fpga.ucf index 65c0b22..2592043 100644 --- a/fpga/fpga.ucf +++ b/fpga/fpga.ucf @@ -5,252 +5,199 @@ CONFIG PROHIBIT = "P154"; # DOUT ## System clocks +TIMESPEC "TS_clock29M" = PERIOD "clock29M" 29.4500 MHz HIGH 50 %; +#TIMESPEC "TS_clock19M" = PERIOD "clock19M" 19.6608 MHz HIGH 50 %; + NET "clockIn29M" LOC = "P160"; +NET "clock29M" TNM = "clock29M"; #NET "clockIn19M" LOC = "P207"; +#NET "clock19M" TNM = "clock19M"; ## Host interface NET "nHostRead" LOC = "P146"; -NET "nHostRead" NODELAY; NET "nHostWrite" LOC = "P145"; -NET "nHostWrite" NODELAY; NET "nHostEnable" LOC = "P142"; -NET "nHostEnable" NODELAY; NET "hostAddress[0]" LOC = "P117"; -NET "hostAddress[0]" NODELAY; NET "hostAddress[1]" LOC = "P116"; -NET "hostAddress[1]" NODELAY; NET "hostAddress[2]" LOC = "P115"; -NET "hostAddress[2]" NODELAY; NET "hostAddress[3]" LOC = "P114"; -NET "hostAddress[3]" NODELAY; NET "hostAddress[4]" LOC = "P113"; -NET "hostAddress[4]" NODELAY; NET "hostAddress[5]" LOC = "P112"; -NET "hostAddress[5]" NODELAY; NET "hostAddress[6]" LOC = "P110"; -NET "hostAddress[6]" NODELAY; NET "hostData[0]" LOC = "P138"; -NET "hostData[0]" FAST; -NET "hostData[0]" DRIVE = 12; -NET "hostData[0]" NODELAY; NET "hostData[1]" LOC = "P137"; -NET "hostData[1]" FAST; -NET "hostData[1]" DRIVE = 12; -NET "hostData[1]" NODELAY; NET "hostData[2]" LOC = "P136"; -NET "hostData[2]" FAST; -NET "hostData[2]" DRIVE = 12; -NET "hostData[2]" NODELAY; NET "hostData[3]" LOC = "P135"; -NET "hostData[3]" FAST; -NET "hostData[3]" DRIVE = 12; -NET "hostData[3]" NODELAY; NET "hostData[4]" LOC = "P134"; -NET "hostData[4]" FAST; -NET "hostData[4]" DRIVE = 12; -NET "hostData[4]" NODELAY; NET "hostData[5]" LOC = "P133"; -NET "hostData[5]" FAST; -NET "hostData[5]" DRIVE = 12; -NET "hostData[5]" NODELAY; NET "hostData[6]" LOC = "P132"; -NET "hostData[6]" FAST; -NET "hostData[6]" DRIVE = 12; -NET "hostData[6]" NODELAY; NET "hostData[7]" LOC = "P129"; -NET "hostData[7]" FAST; -NET "hostData[7]" DRIVE = 12; -NET "hostData[7]" NODELAY; NET "hostData[8]" LOC = "P128"; -NET "hostData[8]" FAST; -NET "hostData[8]" DRIVE = 12; -NET "hostData[8]" NODELAY; NET "hostData[9]" LOC = "P127"; -NET "hostData[9]" FAST; -NET "hostData[9]" DRIVE = 12; -NET "hostData[9]" NODELAY; NET "hostData[10]" LOC = "P126"; -NET "hostData[10]" FAST; -NET "hostData[10]" DRIVE = 12; -NET "hostData[10]" NODELAY; NET "hostData[11]" LOC = "P125"; -NET "hostData[11]" FAST; -NET "hostData[11]" DRIVE = 12; -NET "hostData[11]" NODELAY; NET "hostData[12]" LOC = "P124"; -NET "hostData[12]" FAST; -NET "hostData[12]" DRIVE = 12; -NET "hostData[12]" NODELAY; NET "hostData[13]" LOC = "P123"; -NET "hostData[13]" FAST; -NET "hostData[13]" DRIVE = 12; -NET "hostData[13]" NODELAY; NET "hostData[14]" LOC = "P122"; -NET "hostData[14]" FAST; -NET "hostData[14]" DRIVE = 12; -NET "hostData[14]" NODELAY; NET "hostData[15]" LOC = "P120"; -NET "hostData[15]" FAST; -NET "hostData[15]" DRIVE = 12; -NET "hostData[15]" NODELAY; ## SRAM interface NET "nSRAMRead" LOC = "P40"; NET "nSRAMRead" FAST; -NET "nSRAMRead" DRIVE = 12; NET "nSRAMWrite" LOC = "P55"; NET "nSRAMWrite" FAST; -NET "nSRAMWrite" DRIVE = 12; NET "nSRAMEnable" LOC = "P34"; NET "nSRAMEnable" FAST; -NET "nSRAMEnable" DRIVE = 12; NET "sramAddress[0]" LOC = "P30"; -NET "sramAddress[0]" FAST; -NET "sramAddress[0]" DRIVE = 12; NET "sramAddress[1]" LOC = "P32"; -NET "sramAddress[1]" FAST; -NET "sramAddress[1]" DRIVE = 12; NET "sramAddress[2]" LOC = "P35"; -NET "sramAddress[2]" FAST; -NET "sramAddress[2]" DRIVE = 12; NET "sramAddress[3]" LOC = "P37"; -NET "sramAddress[3]" FAST; -NET "sramAddress[3]" DRIVE = 12; NET "sramAddress[4]" LOC = "P41"; -NET "sramAddress[4]" FAST; -NET "sramAddress[4]" DRIVE = 12; NET "sramAddress[5]" LOC = "P43"; -NET "sramAddress[5]" FAST; -NET "sramAddress[5]" DRIVE = 12; NET "sramAddress[6]" LOC = "P45"; -NET "sramAddress[6]" FAST; -NET "sramAddress[6]" DRIVE = 12; NET "sramAddress[7]" LOC = "P47"; -NET "sramAddress[7]" FAST; -NET "sramAddress[7]" DRIVE = 12; NET "sramAddress[8]" LOC = "P46"; -NET "sramAddress[8]" FAST; -NET "sramAddress[8]" DRIVE = 12; NET "sramAddress[9]" LOC = "P44"; -NET "sramAddress[9]" FAST; -NET "sramAddress[9]" DRIVE = 12; NET "sramAddress[10]" LOC = "P36"; -NET "sramAddress[10]" FAST; -NET "sramAddress[10]" DRIVE = 12; NET "sramAddress[11]" LOC = "P42"; -NET "sramAddress[11]" FAST; -NET "sramAddress[11]" DRIVE = 12; NET "sramAddress[12]" LOC = "P49"; -NET "sramAddress[12]" FAST; -NET "sramAddress[12]" DRIVE = 12; NET "sramAddress[13]" LOC = "P48"; -NET "sramAddress[13]" FAST; -NET "sramAddress[13]" DRIVE = 12; NET "sramAddress[14]" LOC = "P56"; -NET "sramAddress[14]" FAST; -NET "sramAddress[14]" DRIVE = 12; NET "sramAddress[15]" LOC = "P58"; -NET "sramAddress[15]" FAST; -NET "sramAddress[15]" DRIVE = 12; NET "sramAddress[16]" LOC = "P57"; -NET "sramAddress[16]" FAST; -NET "sramAddress[16]" DRIVE = 12; NET "sramData[0]" LOC = "P28"; -NET "sramData[0]" FAST; -NET "sramData[0]" DRIVE = 12; -NET "sramData[0]" NODELAY; NET "sramData[1]" LOC = "P24"; -NET "sramData[1]" FAST; -NET "sramData[1]" DRIVE = 12; -NET "sramData[1]" NODELAY; NET "sramData[2]" LOC = "P22"; -NET "sramData[2]" FAST; -NET "sramData[2]" DRIVE = 12; -NET "sramData[2]" NODELAY; NET "sramData[3]" LOC = "P21"; -NET "sramData[3]" FAST; -NET "sramData[3]" DRIVE = 12; -NET "sramData[3]" NODELAY; NET "sramData[4]" LOC = "P23"; -NET "sramData[4]" FAST; -NET "sramData[4]" DRIVE = 12; -NET "sramData[4]" NODELAY; NET "sramData[5]" LOC = "P27"; -NET "sramData[5]" FAST; -NET "sramData[5]" DRIVE = 12; -NET "sramData[5]" NODELAY; NET "sramData[6]" LOC = "P29"; -NET "sramData[6]" FAST; -NET "sramData[6]" DRIVE = 12; -NET "sramData[6]" NODELAY; NET "sramData[7]" LOC = "P31"; -NET "sramData[7]" FAST; -NET "sramData[7]" DRIVE = 12; -NET "sramData[7]" NODELAY; + +## DRAM interface + +# TODO: trace these pins out +NET "dramControl[0]" LOC = "P188"; +NET "dramControl[1]" LOC = "P189"; +NET "dramControl[2]" LOC = "P190"; +NET "dramControl[3]" LOC = "P191"; +NET "dramControl[4]" LOC = "P193"; +NET "dramControl[5]" LOC = "P194"; +NET "dramControl[6]" LOC = "P196"; +NET "dramControl[7]" LOC = "P197"; +NET "dramControl[8]" LOC = "P198"; +NET "dramControl[9]" LOC = "P199"; +NET "dramControl[10]" LOC = "P200"; +NET "dramControl[11]" LOC = "P201"; + +NET "dramAddress[0]" LOC = "P186"; +NET "dramAddress[1]" LOC = "P184"; +NET "dramAddress[2]" LOC = "P180"; +NET "dramAddress[3]" LOC = "P178"; +NET "dramAddress[4]" LOC = "P176"; +NET "dramAddress[5]" LOC = "P174"; +NET "dramAddress[6]" LOC = "P175"; +NET "dramAddress[7]" LOC = "P177"; +NET "dramAddress[8]" LOC = "P179"; +NET "dramAddress[9]" LOC = "P181"; +NET "dramAddress[10]" LOC = "P185"; +NET "dramAddress[11]" LOC = "P187"; + +NET "dramData[0]" LOC = "P15"; +NET "dramData[1]" LOC = "P14"; +NET "dramData[2]" LOC = "P10"; +NET "dramData[3]" LOC = "P8"; +NET "dramData[4]" LOC = "P2"; +NET "dramData[5]" LOC = "P206"; +NET "dramData[6]" LOC = "P205"; +NET "dramData[7]" LOC = "P204"; +NET "dramData[8]" LOC = "P3"; +NET "dramData[9]" LOC = "P4"; +NET "dramData[10]" LOC = "P5"; +NET "dramData[11]" LOC = "P9"; +NET "dramData[12]" LOC = "P11"; +NET "dramData[13]" LOC = "P17"; +NET "dramData[14]" LOC = "P19"; +NET "dramData[15]" LOC = "P20"; + +## MP3 decoder interface + +NET "mp3Reset" LOC = "P152"; +NET "mp3Ready" LOC = "P159"; +NET "mp3ClockIn" LOC = "P163"; +NET "mp3ClockOut" LOC = "P162"; +NET "mp3SDA" LOC = "P150"; +NET "mp3SCL" LOC = "P151"; + +NET "mp3StatusCS" LOC = "P149"; +NET "mp3StatusError" LOC = "P168"; +NET "mp3StatusFrameSync" LOC = "P161"; +NET "mp3StatusDataReq" LOC = "P148"; + +NET "mp3InSDIN" LOC = "P167"; +NET "mp3InBCLK" LOC = "P164"; +NET "mp3InLRCK" LOC = "P166"; +NET "mp3OutSDOUT" LOC = "P172"; +NET "mp3OutBCLK" LOC = "P169"; +NET "mp3OutLRCK" LOC = "P171"; + +## I2S audio output + +NET "dacSDIN" LOC = "P96"; +NET "dacBCLK" LOC = "P94"; +NET "dacLRCK" LOC = "P95"; +NET "dacMCLK" LOC = "P97"; ## Light outputs -# TODO: figure out the actual pin order of the outputs -NET "lightBankA[0]" LOC = "P69"; -NET "lightBankA[0]" SLOW; -NET "lightBankA[0]" DRIVE = 24; -NET "lightBankA[1]" LOC = "P70"; -NET "lightBankA[1]" SLOW; -NET "lightBankA[1]" DRIVE = 24; -NET "lightBankA[2]" LOC = "P72"; -NET "lightBankA[2]" SLOW; -NET "lightBankA[2]" DRIVE = 24; -NET "lightBankA[3]" LOC = "P73"; -NET "lightBankA[3]" SLOW; -NET "lightBankA[3]" DRIVE = 24; -NET "lightBankA[4]" LOC = "P74"; -NET "lightBankA[4]" SLOW; -NET "lightBankA[4]" DRIVE = 24; -NET "lightBankA[5]" LOC = "P75"; -NET "lightBankA[5]" SLOW; -NET "lightBankA[5]" DRIVE = 24; -NET "lightBankA[6]" LOC = "P76"; -NET "lightBankA[6]" SLOW; -NET "lightBankA[6]" DRIVE = 24; -NET "lightBankA[7]" LOC = "P80"; -NET "lightBankA[7]" SLOW; -NET "lightBankA[7]" DRIVE = 24; -NET "lightBankB[0]" LOC = "P81"; -NET "lightBankB[0]" SLOW; -NET "lightBankB[0]" DRIVE = 24; -NET "lightBankB[1]" LOC = "P82"; -NET "lightBankB[1]" SLOW; -NET "lightBankB[1]" DRIVE = 24; -NET "lightBankB[2]" LOC = "P83"; -NET "lightBankB[2]" SLOW; -NET "lightBankB[2]" DRIVE = 24; -NET "lightBankB[3]" LOC = "P84"; -NET "lightBankB[3]" SLOW; -NET "lightBankB[3]" DRIVE = 24; +NET "lightBankAH[0]" LOC = "P84"; +NET "lightBankAH[1]" LOC = "P83"; +NET "lightBankAH[2]" LOC = "P82"; +NET "lightBankAH[3]" LOC = "P81"; + +NET "lightBankAL[0]" LOC = "P80"; +NET "lightBankAL[1]" LOC = "P76"; +NET "lightBankAL[2]" LOC = "P75"; +NET "lightBankAL[3]" LOC = "P74"; + +NET "lightBankBH[0]" LOC = "P73"; +NET "lightBankBH[1]" LOC = "P72"; +NET "lightBankBH[2]" LOC = "P70"; +NET "lightBankBH[3]" LOC = "P69"; + NET "lightBankD[0]" LOC = "P68"; -NET "lightBankD[0]" SLOW; -NET "lightBankD[0]" DRIVE = 24; NET "lightBankD[1]" LOC = "P67"; -NET "lightBankD[1]" SLOW; -NET "lightBankD[1]" DRIVE = 24; NET "lightBankD[2]" LOC = "P60"; -NET "lightBankD[2]" SLOW; -NET "lightBankD[2]" DRIVE = 24; NET "lightBankD[3]" LOC = "P59"; -NET "lightBankD[3]" SLOW; -NET "lightBankD[3]" DRIVE = 24; + +## General-purpose inputs (unused) + +#NET "inputBank[0]" LOC = "P61"; +#NET "inputBank[1]" LOC = "P62"; +#NET "inputBank[2]" LOC = "P63"; +#NET "inputBank[3]" LOC = "P64"; + +## Serial interfaces + +# TODO: are pins 98 and 99 swapped? +NET "networkTXEnable" LOC = "P98"; +NET "networkTX" LOC = "P99"; +NET "networkRX" LOC = "P100"; + +NET "serialTX" LOC = "P89"; +NET "serialRX" LOC = "P88"; +NET "serialRTS" LOC = "P93"; +NET "serialCTS" LOC = "P90"; +NET "serialDTR" LOC = "P87"; +NET "serialDSR" LOC = "P85"; ## 1-wire bus -NET "ds2401" LOC = "P109"; -NET "ds2401" SLOW; -NET "ds2401" DRIVE = 24; NET "ds2433" LOC = "P107"; -NET "ds2433" SLOW; -NET "ds2433" DRIVE = 24; +NET "ds2401" LOC = "P109"; diff --git a/fpga/fpga.ys b/fpga/fpga.ys index a1d9b72..40f0991 100644 --- a/fpga/fpga.ys +++ b/fpga/fpga.ys @@ -6,6 +6,7 @@ ## Input and preliminary optimization read_verilog src/main.v +read_verilog src/spartanxl.v hierarchy -check -top FPGA proc @@ -39,23 +40,23 @@ clean ## FPGA-specific mapping dfflegalize -cell $_DFFE_PP?P_ r -cell $_DLATCH_PP?_ r - opt_expr -mux_undef -noclkinv abc -g gates -techmap -map src/techmap.v -clean - xilinx_dffopt -lut4 -clkbufmap -buf BUFGLS O:I -iopadmap -bits -inpad IBUF O:I -outpad OBUF I:O -toutpad OBUFT ~T:I:O -tinoutpad IOBUFT ~T:O:I:IO -ignore IFDX D -ignore IFDXI D -ignore OFDX Q -ignore OFDXI Q -ignore OFDTX O -ignore OFDTXI O + +#clkbufmap -buf BUFGLS O:I +iopadmap -bits -inpad IBUF O:I -ignore IPAD IPAD -ignore OPAD OPAD -ignore IOPAD IOPAD -ignore IFDX D -ignore IFDXI D -ignore BUFGLS I +iopadmap -bits -outpad OBUF I:O -toutpad OBUFT ~T:I:O -tinoutpad IOBUFT ~T:O:I:IO -ignore IPAD IPAD -ignore OPAD OPAD -ignore IOPAD IOPAD -ignore OFDX Q -ignore OFDXI Q -ignore OFDTX O -ignore OFDTXI O extractinv -inv INV O:I techmap -map src/techmap.v clean ## Output +# FIXME: for some reason invoking hierarchy here results in $or/$reduce_or +# primitives being added back when using wired-or +#hierarchy -check autoname -hierarchy -check stat -tech xilinx check -noinit blackbox =A:whitebox diff --git a/fpga/runISE.bat b/fpga/runISE.bat index e0a1e4a..62d5861 100755 --- a/fpga/runISE.bat +++ b/fpga/runISE.bat @@ -20,7 +20,7 @@ ngdbuild synth.edf synth.ngd ^ -uc ..\fpga.ucf ^ -p %TARGET% ^ || exit /b 2 -map -o mapped.ncd synth.ngd ^ +map -o mapped.ncd synth.ngd mapped.pcf ^ -p %TARGET% ^ -cm %COVER_MODE% ^ -os %OPTIMIZATION_MODE% ^ @@ -29,7 +29,7 @@ map -o mapped.ncd synth.ngd ^ -detail ^ || exit /b 2 -par mapped.ncd fpga.ncd ^ +par mapped.ncd fpga.ncd mapped.pcf ^ -w ^ -detail ^ || exit /b 3 diff --git a/fpga/src/main.v b/fpga/src/main.v index 38b5423..66a0028 100644 --- a/fpga/src/main.v +++ b/fpga/src/main.v @@ -1,40 +1,11 @@ -/* Spartan-XL primitive library */ - -module BUF (input I, output O); endmodule -module INV (input I, output O); endmodule -module AND2 (input I0, input I1, output O); endmodule -module NAND2 (input I0, input I1, output O); endmodule -module AND2B1 (input I0, input I1, output O); endmodule -module OR2 (input I0, input I1, output O); endmodule -module NOR2 (input I0, input I1, output O); endmodule -module OR2B1 (input I0, input I1, output O); endmodule -module XOR2 (input I0, input I1, output O); endmodule -module XNOR2 (input I0, input I1, output O); endmodule -module BUFT (input I, input T, output O); endmodule -module FDCE (input D, input C, input CLR, input CE, output Q); endmodule -module FDPE (input D, input C, input PRE, input CE, output Q); endmodule -module LDCE_1 (input D, input G, input CLR, input GE, output Q); endmodule -module LDPE_1 (input D, input G, input PRE, input GE, output Q); endmodule - -module IPAD (output IPAD); endmodule -module OPAD (input OPAD); endmodule -module IOPAD (inout IOPAD); endmodule -module IBUF (input I, output O); endmodule -module OBUF (input I, output O); endmodule -module OBUFT (input I, input T, output O); endmodule -module IOBUFT (input I, input T, output O, inout IO); endmodule -module BUFGLS (input I, output O); endmodule -module IFDX (input D, input C, input CE, output Q); endmodule -module IFDXI (input D, input C, input CE, output Q); endmodule -module OFDX (input D, input C, input CE, output Q); endmodule -module OFDXI (input D, input C, input CE, output Q); endmodule -module OFDTX (input D, input C, input CE, input T, output O); endmodule -module OFDTXI (input D, input C, input CE, input T, output O); endmodule - -/* Top-level module */ - module FPGA ( + // These are technically inputs, however they are already wired up to pad + // primitives within the module. They are only exposed here in order to + // allow for a testbench to inject the clocks during simulation. + inout clockIn29M, + inout clockIn19M, + input nHostRead, input nHostWrite, input nHostEnable, @@ -47,54 +18,161 @@ module FPGA ( output [16:0] sramAddress, inout [7:0] sramData, - output [7:0] lightBankA, - output [3:0] lightBankB, + output [11:0] dramControl, + output [11:0] dramAddress, + inout [15:0] dramData, + + output mp3Reset, + input mp3Ready, + output mp3ClockIn, + input mp3ClockOut, + inout mp3SDA, + inout mp3SCL, + + output mp3StatusCS, + input mp3StatusError, + input mp3StatusFrameSync, + input mp3StatusDataReq, + + output mp3InSDIN, + output mp3InBCLK, + output mp3InLRCK, + input mp3OutSDOUT, + input mp3OutBCLK, + input mp3OutLRCK, + + output dacSDIN, + output dacBCLK, + output dacLRCK, + output dacMCLK, + + output [3:0] lightBankAH, + output [3:0] lightBankAL, + output [3:0] lightBankBH, output [3:0] lightBankD, - inout ds2401, - inout ds2433 + output networkTXEnable, + output networkTX, + input networkRX, + + output serialTX, + input serialRX, + output serialRTS, + input serialCTS, + output serialDTR, + input serialDSR, + + inout ds2433, + inout ds2401 ); genvar i; + /* Register definitions */ + + localparam SYS573D_FPGA_MAGIC = 8'h80; + + localparam SYS573D_FPGA_MP3_PTR_H = 8'ha0; + localparam SYS573D_FPGA_MP3_PTR_L = 8'ha2; + localparam SYS573D_FPGA_MP3_ENDPTR_H = 8'ha4; + localparam SYS573D_FPGA_MP3_ENDPTR_L = 8'ha6; + localparam SYS573D_FPGA_MP3_COUNTER = 8'ha8; + localparam SYS573D_FPGA_MP3_KEY1 = 8'ha8; + localparam SYS573D_FPGA_MP3_FEED_STAT = 8'haa; + localparam SYS573D_FPGA_MP3_I2C = 8'hac; + localparam SYS573D_FPGA_MP3_FEED_CTRL = 8'hae; + + localparam SYS573D_FPGA_DRAM_WRPTR_H = 8'hb0; + localparam SYS573D_FPGA_DRAM_WRPTR_L = 8'hb2; + localparam SYS573D_FPGA_DRAM_DATA = 8'hb4; + localparam SYS573D_FPGA_DRAM_RDPTR_H = 8'hb6; + localparam SYS573D_FPGA_DRAM_RDPTR_L = 8'hb8; + + localparam SYS573D_FPGA_NET_DATA = 8'hc0; + localparam SYS573D_FPGA_DAC_COUNTER_H = 8'hca; + localparam SYS573D_FPGA_DAC_COUNTER_L = 8'hcc; + localparam SYS573D_FPGA_DAC_COUNTER_D = 8'hce; + + localparam SYS573D_FPGA_LIGHTS_AH = 8'he0; + localparam SYS573D_FPGA_LIGHTS_AL = 8'he2; + localparam SYS573D_FPGA_LIGHTS_BH = 8'he4; + localparam SYS573D_FPGA_LIGHTS_D = 8'he6; + localparam SYS573D_FPGA_INIT = 8'he8; + localparam SYS573D_FPGA_MP3_KEY2 = 8'hea; + localparam SYS573D_FPGA_MP3_KEY3 = 8'hec; + localparam SYS573D_FPGA_DS_BUS = 8'hee; + /* System clocks */ - wire clockIn29M, _clock29M; - wire clockIn19M, _clock19M; + wire clock29M, clock19M; - IPAD _clockPad29M ( .IPAD(clockIn29M) ); - IPAD _clockPad19M ( .IPAD(clockIn19M) ); - BUFGLS _clockBuf29M ( .I(clockIn29M), .O(_clock29M) ); - BUFGLS _clockBuf19M ( .I(clockIn19M), .O(_clock19M) ); + // ISE rejects global buffer primitives unless they are wired either to an + // IBUF (which results in suboptimal routing, as the dedicated IOB clock + // output is left unused) or directly to a pad primitive. + IPAD clockPad29M (.IPAD(clockIn29M)); + IPAD clockPad19M (.IPAD(clockIn19M)); + BUFGLS clockBuf29M (.I(clockIn29M), .O(clock29M)); + BUFGLS clockBuf19M (.I(clockIn19M), .O(clock19M)); + + /* Host address decoding */ + + // The FPGA shall only respond to addresses in 0x80-0xef range, as 0xf0-0xff + // is used by the CPLD and 0x00-0x7f seems to be reserved for debugging + // hardware. Bit 0 of the 573's address bus is not wired to the FPGA as all + // registers are 16 bits wide. + wire hostAddrValid = hostAddress[6] & (hostAddress[5:3] != 3'b111); + wire hostRegRead = ~nHostEnable & ~nHostRead & nHostWrite; + wire hostRegWrite = ~nHostEnable & nHostRead & ~nHostWrite; + + wire [7:0] hostRegister = { 1'b1, hostAddress[5:0], 1'b0 }; /* Host interface */ - wire _nHostRead, _nHostWrite, _nHostEnable; - wire [6:0] _hostAddress; - wire [15:0] _hostDataIn; - wire [15:0] _hostDataOut; + reg [2:0] _delayedHostRegRead = 3'b000; + wire _hostDataInClock; - wire _nHostReadFPGA = _nHostRead || _nHostEnable; - wire _nHostWriteFPGA = _nHostWrite || _nHostEnable; + wire [15:0] hostDataIn; + wor [15:0] hostDataOut; - // IOB flip-flop primitives (IFDX, OFDX) are explicitly used whenever - // possible in order to minimize propagation delays and CLB usage. - IFDX _nHostReadBuf ( .C(_clock29M), .D(nHostRead), .Q(_nHostRead), .CE(1'b1) ); - IFDX _nHostWriteBuf ( .C(_clock29M), .D(nHostWrite), .Q(_nHostWrite), .CE(1'b1) ); - IFDX _nHostEnableBuf ( .C(_clock29M), .D(nHostEnable), .Q(_nHostEnable), .CE(1'b1) ); + reg hostDataInValid = 1'b0; + reg hostDataOutValid = 1'b0; + + // Data is latched in the input flip flops once the 573 *deasserts* either + // the chip select or the write strobe. Konami's bitstream routes this + // signal through a global net (_hostDataInClock), possibly since it is + // asynchronous and not tied to the main clock. + BUFGLS hostDataInUpdateBuf(.I(hostRegWrite), .O(_hostDataInClock)); + + wire hostDataInPending = ~hostRegWrite & hostDataInValid; + + always @(posedge clock29M) begin + // Konami's bitstream pulls the output flip flops' clock enable low + // after 3 cycles if the register being read is in 0xa0-0xaf range (i.e. + // MP3 status and counters), in order to prevent any further updates + // while the counters are running. A 3-bit shift register is used to + // implement the delay. + _delayedHostRegRead <= { _delayedHostRegRead[1:0], hostRegRead }; + + // The direction of the bus is only changed on clock edges in order to + // prevent any data from being output before the output flip flops are + // updated. + hostDataInValid <= hostRegWrite; + hostDataOutValid <= hostAddrValid & hostRegRead; + end generate - for (i = 0; i < 7; i++) - IFDX _hostAddressBuf ( - .C(_clock29M), .D(hostAddress[i]), .Q(_hostAddress[i]) + for (i = 0; i < 16; i = i + 1) begin + IFDX hostDataInReg ( + .D(hostData[i]), + .C(~_hostDataInClock), + .CE(1'b1), + .Q(hostDataIn[i]) ); - - for (i = 0; i < 16; i++) begin - IFDX _hostDataInBuf ( - .C(_clock29M), .D(hostData[i]), .Q(_hostDataIn[i]), .CE(1'b1) - ); - OFDTX _hostDataOutBuf ( - .C(_clock29M), .O(hostData[i]), .D(_hostDataOut[i]), - .CE(~_nHostReadFPGA), .T(_nHostReadFPGA) + OFDTX hostDataOutReg ( + .D(hostDataOut[i]), + .C(clock29M), + .CE(~_delayedHostRegRead[2]), + .T(~hostDataOutValid), + .O(hostData[i]) ); end endgenerate @@ -105,71 +183,107 @@ module FPGA ( assign nSRAMWrite = 1'b1; assign nSRAMEnable = 1'b1; assign sramAddress = 17'h1ffff; - assign sramData = 8'hff; + + /* DRAM interface (currently unused) */ + + assign dramControl = 12'hfff; + assign dramAddress = 12'hfff; + + /* MP3 decoder interface (currently unused) */ + + assign mp3Reset = 1'b1; + assign mp3ClockIn = 1'b1; + assign mp3StatusCS = 1'b1; + + assign mp3InSDIN = 1'b1; + assign mp3InBCLK = 1'b1; + assign mp3InLRCK = 1'b1; + + assign hostDataOut = (hostRegister == SYS573D_FPGA_MP3_I2C) + ? { 2'h0, mp3SCL, mp3SDA, 12'h000 } + : 16'h0000; + + reg mp3SDAState = 1'b0; + reg mp3SCLState = 1'b0; + + always @(posedge clock29M) + if (hostDataInPending & (hostRegister == SYS573D_FPGA_MP3_I2C)) begin + mp3SDAState <= hostDataIn[12]; + mp3SCLState <= hostDataIn[13]; + end + + assign mp3SDA = mp3SDAState ? 1'bz : 1'b0; + assign mp3SCL = mp3SCLState ? 1'bz : 1'b0; + + /* I2S audio output */ + + assign dacSDIN = mp3OutSDOUT; + assign dacBCLK = mp3OutBCLK; + assign dacLRCK = mp3OutLRCK; + assign dacMCLK = mp3ClockOut; + + /* Magic number */ + + assign hostDataOut = (hostRegister == SYS573D_FPGA_MAGIC) + ? 16'h573f + : 16'h0000; /* Light outputs */ - wire [3:0] _lightBankData = _hostDataIn[15:12]; - - wire _lightBankA0Write = ~_nHostWriteFPGA & (_hostAddress == 7'h70); - wire _lightBankA1Write = ~_nHostWriteFPGA & (_hostAddress == 7'h71); - wire _lightBankBWrite = ~_nHostWriteFPGA & (_hostAddress == 7'h72); - wire _lightBankDWrite = ~_nHostWriteFPGA & (_hostAddress == 7'h73); - generate - for (i = 0; i < 4; i++) begin - // Use "inverted" flip-flops so that all lights are turned off on - // startup. - OFDXI _lightBankA0Buf ( - .C(_clock29M), .Q(lightBankA[i + 4]), .D(_lightBankData[i]), - .CE(_lightBankA0Write) - ); - OFDXI _lightBankA1Buf ( - .C(_clock29M), .Q(lightBankA[i]), .D(_lightBankData[i]), - .CE(_lightBankA1Write) - ); - OFDXI _lightBankBBuf ( - .C(_clock29M), .Q(lightBankB[i]), .D(_lightBankData[i]), - .CE(_lightBankBWrite) - ); - OFDXI _lightBankDBuf ( - .C(_clock29M), .Q(lightBankD[i]), .D(_lightBankData[i]), - .CE(_lightBankDWrite) - ); + for (i = 0; i < 4; i = i + 1) begin + reg [3:0] lightBankState = 4'b1111; + + wire dataIn = hostDataIn[i + 12]; + + always @(posedge clock29M) + if (hostDataInPending) + case (hostRegister) + SYS573D_FPGA_LIGHTS_AH: + lightBankState[0] <= dataIn; + SYS573D_FPGA_LIGHTS_AL: + lightBankState[1] <= dataIn; + SYS573D_FPGA_LIGHTS_BH: + lightBankState[2] <= dataIn; + SYS573D_FPGA_LIGHTS_D: + lightBankState[3] <= dataIn; + endcase + + // Note that XCS40XL IOBs actually have a tristate flip flop, but + // there seems to be no primitive exposed by ISE to force its usage. + assign lightBankAH[i] = lightBankState[0] ? 1'bz : 1'b0; + assign lightBankAL[i] = lightBankState[1] ? 1'bz : 1'b0; + assign lightBankBH[i] = lightBankState[2] ? 1'bz : 1'b0; + assign lightBankD[i] = lightBankState[3] ? 1'bz : 1'b0; end endgenerate + /* Serial interfaces (currently unused) */ + + assign networkTXEnable = 1'b1; + assign networkTX = 1'b1; + + assign serialTX = 1'b1; + assign serialRTS = 1'b1; + assign serialDTR = 1'b1; + /* 1-wire bus */ - wire _ds2401In, _ds2433In; - reg _ds2401Out, _ds2433Out; + assign hostDataOut = (hostRegister == SYS573D_FPGA_DS_BUS) + ? { 3'h0, ds2401, 3'h0, ds2433, 8'h00 } + : 16'h0000; - // Note that the 1-wire pins are open drain and pulled low by writing 1 - // (rather than 0) to the respective register bits, but not inverted when - // read. - IFDX _ds2401InBuf ( .C(_clock29M), .D(ds2401), .Q(_ds2401In), .CE(1'b1) ); - IFDX _ds2433InBuf ( .C(_clock29M), .D(ds2433), .Q(_ds2433In), .CE(1'b1) ); - OBUFT _ds2401OutBuf ( .O(ds2401), .I(1'b0), .T(~_ds2401Out) ); - OBUFT _ds2433OutBuf ( .O(ds2433), .I(1'b0), .T(~_ds2433Out) ); + reg ds2433State = 1'b0; + reg ds2401State = 1'b0; - wire _dsBusWrite = ~_nHostWriteFPGA & (_hostAddress == 7'h77); - - always @(posedge _clock29M) - if (_dsBusWrite) begin - _ds2401Out <= _hostDataIn[12]; - _ds2433Out <= _hostDataIn[13]; + always @(posedge clock29M) + if (hostDataInPending & (hostRegister == SYS573D_FPGA_DS_BUS)) begin + ds2433State <= hostDataIn[8]; + ds2401State <= hostDataIn[12]; end - /* Readable registers */ - - wire [15:0] _magicNumberData = 16'h573f; - wire [15:0] _dsBusData = { 2'h0, _ds2433In, _ds2401In, 12'h000 }; - - wire _magicNumberRead = ~_nHostReadFPGA & (_hostAddress == 7'h40); - wire _dsBusRead = ~_nHostReadFPGA & (_hostAddress == 7'h77); - - assign _hostDataOut = - _magicNumberRead ? _magicNumberData : - _dsBusRead ? _dsBusData : - 16'h0000; + // The 1-wire pins are pulled low by writing 1 (rather than 0) to the + // respective register bits, but not inverted when read. + assign ds2433 = ds2433State ? 1'b0 : 1'bz; + assign ds2401 = ds2401State ? 1'b0 : 1'bz; endmodule diff --git a/fpga/src/spartanxl.v b/fpga/src/spartanxl.v new file mode 100644 index 0000000..c90839c --- /dev/null +++ b/fpga/src/spartanxl.v @@ -0,0 +1,368 @@ + +/* Logic primitives */ + +module BUF (input I, output O); +`ifndef SYNTHESIS + assign O = I; +`endif +endmodule + +module INV (input I, output O); +`ifndef SYNTHESIS + assign O = ~I; +`endif +endmodule + +module AND2 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = I0 & I1; +`endif +endmodule + +module NAND2 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = ~(I0 & I1); +`endif +endmodule + +module AND2B1 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = I0 & ~I1; +`endif +endmodule + +module OR2 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = I0 | I1; +`endif +endmodule + +module NOR2 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = ~(I0 | I1); +`endif +endmodule + +module OR2B1 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = I0 | ~I1; +`endif +endmodule + +module XOR2 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = (I0 != I1); +`endif +endmodule + +module XNOR2 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = (I0 == I1); +`endif +endmodule + +module BUFT (input I, input T, output O); +`ifndef SYNTHESIS + assign O = T ? 1'bz : I; +`endif +endmodule + +module FDCE (input D, input C, input CLR, input CE, output Q); +`ifndef SYNTHESIS + reg data; + assign Q = data; + + initial + data = 1'b0; + always @(CLR) + data <= 1'b0; + always @(posedge C) + data <= CE ? D : data; +`endif +endmodule + +module FDPE (input D, input C, input PRE, input CE, output Q); +`ifndef SYNTHESIS + reg data; + assign Q = data; + + initial + data = 1'b1; + always @(PRE) + data <= 1'b1; + always @(posedge C) + data <= CE ? D : data; +`endif +endmodule + +module LDCE_1 (input D, input G, input CLR, input GE, output Q); +`ifndef SYNTHESIS + reg data; + assign Q = data; + + initial + data = 1'b0; + always @(CLR) + data <= 1'b0; + always @(~G) + data <= GE ? D : data; +`endif +endmodule + +module LDPE_1 (input D, input G, input PRE, input GE, output Q); +`ifndef SYNTHESIS + reg data; + assign Q = data; + + initial + data = 1'b1; + always @(PRE) + data <= 1'b1; + always @(~G) + data <= GE ? D : data; +`endif +endmodule + +/* I/O primitives */ + +(* keep *) module BUFGLS (input I, output O); +`ifndef SYNTHESIS + BUF buffer (.I(I), .O(O)); +`endif +endmodule + +(* keep *) module IBUF (input I, output O); +`ifndef SYNTHESIS + BUF buffer (.I(I), .O(O)); +`endif +endmodule + +(* keep *) module OBUF (input I, output O); +`ifndef SYNTHESIS + BUF buffer (.I(I), .O(O)); +`endif +endmodule + +(* keep *) module OBUFT (input I, input T, output O); +`ifndef SYNTHESIS + BUFT buffer (.I(I), .T(T), .O(O)); +`endif +endmodule + +(* keep *) module IOBUFT (input I, input T, output O, inout IO); +`ifndef SYNTHESIS + assign O = IO; + + BUFT buffer (.I(I), .T(T), .O(IO)); +`endif +endmodule + +(* keep *) module IFDX (input D, input C, input CE, output Q); +`ifndef SYNTHESIS + reg data; + assign Q = data; + + initial + data = 1'b0; + always @(posedge C) + data <= CE ? D : data; +`endif +endmodule + +(* keep *) module IFDXI (input D, input C, input CE, output Q); +`ifndef SYNTHESIS + reg data; + assign Q = data; + + initial + data = 1'b1; + always @(posedge C) + data <= CE ? D : data; +`endif +endmodule + +(* keep *) module OFDX (input D, input C, input CE, output Q); +`ifndef SYNTHESIS + IFDX ff (.D(D), .C(C), .CE(CE), .Q(Q)); +`endif +endmodule + +(* keep *) module OFDXI (input D, input C, input CE, output Q); +`ifndef SYNTHESIS + IFDXI ff (.D(D), .C(C), .CE(CE), .Q(Q)); +`endif +endmodule + +(* keep *) module OFDTX (input D, input C, input CE, input T, output O); +`ifndef SYNTHESIS + wire Q; + + IFDX ff (.D(D), .C(C), .CE(CE), .Q(Q)); + BUFT buffer (.I(Q), .T(T), .O(O)); +`endif +endmodule + +(* keep *) module OFDTXI (input D, input C, input CE, input T, output O); +`ifndef SYNTHESIS + wire Q; + + IFDXI ff (.D(D), .C(C), .CE(CE), .Q(Q)); + BUFT buffer (.I(Q), .T(T), .O(O)); +`endif +endmodule + +/* I/O pads */ + +(* keep *) module IPAD (output IPAD); +endmodule + +(* keep *) module OPAD (input OPAD); +endmodule + +(* keep *) module IOPAD (inout IOPAD); +endmodule + +(* keep *) module UPAD (inout UPAD); +endmodule + +(* keep *) module TDI (inout I); +endmodule + +(* keep *) module TDO (input O); +endmodule + +(* keep *) module TCK (inout I); +endmodule + +(* keep *) module TMS (inout I); +endmodule + +/* Fixed-function blocks (not simulated) */ + +(* keep *) module STARTUP ( + input GSR, + input GTS, + input CLK, + + output DONEIN, + output Q1Q4, + output Q2, + output Q3 +); +endmodule + +(* keep *) module OSC4 ( + output F8M, + output F500K, + output F16K, + output F490, + output F15 +); +endmodule + +(* keep *) module BSCAN( + input TDI, + input TDO1, + input TDO2, + input TCK, + input TMS, + + output TDO, + output DRCK, + output IDLE, + output SEL1, + output SEL2 +); +endmodule + +(* keep *) module RDBK (input TRIG, output DATA, output RIP); +endmodule + +(* keep *) module RDCLK (input I); +endmodule + +/* ISE built-in macros */ + +module CC8CE ( + input C, input CLR, input CE, output [7:0] Q, output CEO, output TC +); +`ifndef SYNTHESIS + reg [7:0] data; + + assign Q = data; + assign TC = &data; + assign CEO = TC & CE; + + initial + data = 8'h00; + always @(CLR) + data <= 8'h00; + always @(posedge C) + data <= data + CE; +`endif +endmodule + +module CC8CLE ( + input [7:0] D, input L, input C, input CLR, input CE, output [7:0] Q, + output CEO, output TC +); +`ifndef SYNTHESIS + reg [7:0] data; + + assign Q = data; + assign TC = &data; + assign CEO = TC & CE; + + initial + data = 8'h00; + always @(CLR) + data <= 8'h00; + always @(posedge C) + if (L) + data <= D; + else + data <= data + CE; +`endif +endmodule + +module CC16CE ( + input C, input CLR, input CE, output [15:0] Q, output CEO, output TC +); +`ifndef SYNTHESIS + reg [15:0] data; + + assign Q = data; + assign TC = &data; + assign CEO = TC & CE; + + initial + data = 16'h0000; + always @(CLR) + data <= 16'h0000; + always @(posedge C) + data <= data + CE; +`endif +endmodule + +module CC16CLE ( + input [15:0] D, input L, input C, input CLR, input CE, output [15:0] Q, + output CEO, output TC +); +`ifndef SYNTHESIS + reg [15:0] data; + + assign Q = data; + assign TC = &data; + assign CEO = TC & CE; + + initial + data = 16'h0000; + always @(CLR) + data <= 16'h0000; + always @(posedge C) + if (L) + data <= D; + else + data <= data + CE; +`endif +endmodule diff --git a/fpga/src/techmap.v b/fpga/src/techmap.v index a746d77..ad4b590 100644 --- a/fpga/src/techmap.v +++ b/fpga/src/techmap.v @@ -6,82 +6,85 @@ */ (* techmap_celltype = "IOBUFT" *) -module _ISE_IOBUFT (inout IO, input I, output O, input T); - IBUF _TECHMAP_REPLACE_.ibuf ( .I(IO), .O(O) ); - OBUFT _TECHMAP_REPLACE_.obuf ( .O(IO), .I(I), .T(T) ); +module _ISE_IOBUFT (input I, input T, output O, inout IO); + IBUF _TECHMAP_REPLACE_.ibuf (.I(IO), .O(O)); + OBUFT _TECHMAP_REPLACE_.obuf (.O(IO), .I(I), .T(T)); endmodule (* techmap_celltype = "$_BUF_" *) module _ISE_BUF (input A, output Y); - BUF _TECHMAP_REPLACE_ ( .I(A), .O(Y) ); + BUF _TECHMAP_REPLACE_ (.I(A), .O(Y)); endmodule (* techmap_celltype = "$_NOT_" *) module _ISE_INV (input A, output Y); - INV _TECHMAP_REPLACE_ ( .I(A), .O(Y) ); + INV _TECHMAP_REPLACE_ (.I(A), .O(Y)); endmodule (* techmap_celltype = "$_AND_" *) module _ISE_AND2 (input A, input B, output Y); - AND2 _TECHMAP_REPLACE_ ( .I0(A), .I1(B), .O(Y) ); + AND2 _TECHMAP_REPLACE_ (.I0(A), .I1(B), .O(Y)); endmodule (* techmap_celltype = "$_NAND_" *) module _ISE_NAND2 (input A, input B, output Y); - NAND2 _TECHMAP_REPLACE_ ( .I0(A), .I1(B), .O(Y) ); + NAND2 _TECHMAP_REPLACE_ (.I0(A), .I1(B), .O(Y)); endmodule (* techmap_celltype = "$_ANDNOT_" *) module _ISE_AND2B1 (input A, input B, output Y); - AND2B1 _TECHMAP_REPLACE_ ( .I0(A), .I1(B), .O(Y) ); + AND2B1 _TECHMAP_REPLACE_ (.I0(A), .I1(B), .O(Y)); endmodule (* techmap_celltype = "$_OR_" *) module _ISE_OR2 (input A, input B, output Y); - OR2 _TECHMAP_REPLACE_ ( .I0(A), .I1(B), .O(Y) ); + OR2 _TECHMAP_REPLACE_ (.I0(A), .I1(B), .O(Y)); endmodule (* techmap_celltype = "$_NOR_" *) module _ISE_NOR2 (input A, input B, output Y); - NOR2 _TECHMAP_REPLACE_ ( .I0(A), .I1(B), .O(Y) ); + NOR2 _TECHMAP_REPLACE_ (.I0(A), .I1(B), .O(Y)); endmodule (* techmap_celltype = "$_ORNOT_" *) module _ISE_OR2B1 (input A, input B, output Y); - OR2B1 _TECHMAP_REPLACE_ ( .I0(A), .I1(B), .O(Y) ); + OR2B1 _TECHMAP_REPLACE_ (.I0(A), .I1(B), .O(Y)); endmodule (* techmap_celltype = "$_XOR_" *) module _ISE_XOR2 (input A, input B, output Y); - XOR2 _TECHMAP_REPLACE_ ( .I0(A), .I1(B), .O(Y) ); + XOR2 _TECHMAP_REPLACE_ (.I0(A), .I1(B), .O(Y)); endmodule (* techmap_celltype = "$_XNOR_" *) module _ISE_XNOR2 (input A, input B, output Y); - XNOR2 _TECHMAP_REPLACE_ ( .I0(A), .I1(B), .O(Y) ); + XNOR2 _TECHMAP_REPLACE_ (.I0(A), .I1(B), .O(Y)); endmodule (* techmap_celltype = "$_TBUF_" *) module _ISE_BUFT (input A, input E, output Y); - BUFT _TECHMAP_REPLACE_ ( .I(A), .T(~E), .O(Y) ); + wire T; + + INV _TECHMAP_REPLACE_.inv (.I(E), .O(T)); + BUFT _TECHMAP_REPLACE_.buffer (.I(A), .T(T), .O(Y)); endmodule (* techmap_celltype = "$_DFFE_PP0P_" *) module _ISE_FDCE (input D, input C, input R, input E, output Q); - FDCE _TECHMAP_REPLACE_ ( .D(D), .C(C), .CLR(R), .CE(E), .Q(Q) ); + FDCE _TECHMAP_REPLACE_ (.D(D), .C(C), .CLR(R), .CE(E), .Q(Q)); endmodule (* techmap_celltype = "$_DFFE_PP1P_" *) module _ISE_FDPE (input D, input C, input R, input E, output Q); - FDPE _TECHMAP_REPLACE_ ( .D(D), .C(C), .PRE(R), .CE(E), .Q(Q) ); + FDPE _TECHMAP_REPLACE_ (.D(D), .C(C), .PRE(R), .CE(E), .Q(Q)); endmodule (* techmap_celltype = "$_DLATCH_PP0_" *) module _ISE_LDCE_1 (input E, input R, input D, output Q); - LDCE_1 _TECHMAP_REPLACE_ ( .D(D), .G(E), .CLR(R), .GE(1'b1), .Q(Q) ); + LDCE_1 _TECHMAP_REPLACE_ (.D(D), .G(E), .CLR(R), .GE(1'b1), .Q(Q)); endmodule (* techmap_celltype = "$_DLATCH_PP1_" *) module _ISE_LDPE_1 (input E, input R, input D, output Q); - LDPE_1 _TECHMAP_REPLACE_ ( .D(D), .G(E), .PRE(R), .GE(1'b1), .Q(Q) ); + LDPE_1 _TECHMAP_REPLACE_ (.D(D), .G(E), .PRE(R), .GE(1'b1), .Q(Q)); endmodule diff --git a/src/common/io.cpp b/src/common/io.cpp index 583feae..9f5083b 100644 --- a/src/common/io.cpp +++ b/src/common/io.cpp @@ -13,8 +13,12 @@ uint16_t _bankSwitchReg, _cartOutputReg, _miscOutputReg; /* System initialization */ -static constexpr int _RESET_DELAY = 5000; -static constexpr int _FPGA_INIT_DELAY = 1000; +static constexpr int _IDE_RESET_ASSERT_DELAY = 5000; +static constexpr int _IDE_RESET_CLEAR_DELAY = 50000; + +static constexpr int _FPGA_RESET_DELAY = 5000; +static constexpr int _FPGA_STARTUP_DELAY = 50000; +static constexpr int _FPGA_INIT_REG_DELAY = 5000; void init(void) { // Remapping the base address is required in order for IDE DMA to work @@ -62,9 +66,9 @@ void initIOBoard(void) { // Some of the digital I/O board's light outputs are controlled by the FPGA // and cannot be turned off until the FPGA is initialized. if (isDigitalIOPresent()) { - //SYS573D_CPLD_LIGHTS_B0 = 0xf000; - SYS573D_CPLD_LIGHTS_C0 = 0xf000; - SYS573D_CPLD_LIGHTS_C1 = 0xf000; + SYS573D_CPLD_LIGHTS_BL = 0xf000; + SYS573D_CPLD_LIGHTS_CL = 0xf000; + SYS573D_CPLD_LIGHTS_CH = 0xf000; } else { SYS573A_LIGHTS_A = 0x00ff; SYS573A_LIGHTS_B = 0x00ff; @@ -75,10 +79,10 @@ void initIOBoard(void) { void resetIDEDevices(void) { SYS573_IDE_RESET = 0; - delayMicroseconds(_RESET_DELAY); + delayMicroseconds(_IDE_RESET_ASSERT_DELAY); SYS573_IDE_RESET = 1; - delayMicroseconds(_RESET_DELAY); + delayMicroseconds(_IDE_RESET_CLEAR_DELAY); } /* JAMMA and RTC functions */ @@ -231,6 +235,8 @@ bool loadRawBitstream(const uint8_t *data, size_t length) { else return false; + const uint16_t mask = SYS573D_CPLD_STAT_INIT | SYS573D_CPLD_STAT_DONE; + for (int i = 3; i; i--) { SYS573D_CPLD_UNK_RESET = 0; @@ -243,22 +249,18 @@ bool loadRawBitstream(const uint8_t *data, size_t length) { | SYS573D_CPLD_CTRL_DONE | SYS573D_CPLD_CTRL_PROGRAM | SYS573D_CPLD_CTRL_UNKNOWN; + delayMicroseconds(_FPGA_RESET_DELAY); - delayMicroseconds(_RESET_DELAY); - - if (!(SYS573D_CPLD_STAT & SYS573D_CPLD_STAT_INIT)) + if ((SYS573D_CPLD_STAT & mask) != SYS573D_CPLD_STAT_INIT) continue; writeFunc(data, length); + delayMicroseconds(_FPGA_STARTUP_DELAY); - const uint16_t mask = SYS573D_CPLD_STAT_INIT | SYS573D_CPLD_STAT_DONE; + if ((SYS573D_CPLD_STAT & mask) != mask) + continue; - for (int j = 15; j; j--) { - if ((SYS573D_CPLD_STAT & mask) == mask) - return true; - - delayMicroseconds(_FPGA_INIT_DELAY); - } + return true; } return false; @@ -267,19 +269,19 @@ bool loadRawBitstream(const uint8_t *data, size_t length) { void initKonamiBitstream(void) { SYS573D_FPGA_INIT = 0xf000; SYS573D_FPGA_INIT = 0x0000; - delayMicroseconds(_FPGA_INIT_DELAY); + delayMicroseconds(_FPGA_INIT_REG_DELAY); SYS573D_FPGA_INIT = 0xf000; - delayMicroseconds(_FPGA_INIT_DELAY); + delayMicroseconds(_FPGA_INIT_REG_DELAY); // Turn off all lights including the ones that were left on by init(). - SYS573D_FPGA_LIGHTS_A0 = 0xf000; - SYS573D_FPGA_LIGHTS_A1 = 0xf000; - SYS573D_CPLD_LIGHTS_B0 = 0xf000; - SYS573D_FPGA_LIGHTS_B1 = 0xf000; - SYS573D_CPLD_LIGHTS_C0 = 0xf000; - SYS573D_CPLD_LIGHTS_C1 = 0xf000; - SYS573D_FPGA_LIGHTS_D0 = 0xf000; + SYS573D_FPGA_LIGHTS_AL = 0xf000; + SYS573D_FPGA_LIGHTS_AH = 0xf000; + SYS573D_CPLD_LIGHTS_BL = 0xf000; + SYS573D_FPGA_LIGHTS_BH = 0xf000; + SYS573D_CPLD_LIGHTS_CL = 0xf000; + SYS573D_CPLD_LIGHTS_CH = 0xf000; + SYS573D_FPGA_LIGHTS_D = 0xf000; } /* I2C driver */ diff --git a/src/common/io.hpp b/src/common/io.hpp index c83bc30..1f474b6 100644 --- a/src/common/io.hpp +++ b/src/common/io.hpp @@ -153,11 +153,11 @@ static inline bool isDigitalIOPresent(void) { } static inline bool getDIO1Wire(void) { - return (SYS573D_FPGA_DS2401 >> 12) & 1; + return (SYS573D_FPGA_DS_BUS / SYS573D_FPGA_DS_BUS_DS2401) & 1; } static inline void setDIO1Wire(bool value) { - SYS573D_FPGA_DS2401 = (value ^ 1) << 12; + SYS573D_FPGA_DS_BUS = (value ^ 1) * SYS573D_FPGA_DS_BUS_DS2401; } /* Other APIs */ diff --git a/src/main/app/miscworkers.cpp b/src/main/app/miscworkers.cpp index f573c81..6458dc6 100644 --- a/src/main/app/miscworkers.cpp +++ b/src/main/app/miscworkers.cpp @@ -268,8 +268,11 @@ bool App::_atapiEjectWorker(void) { if (!(dev.flags & ide::DEVICE_ATAPI)) continue; - auto error = - ide::devices[0].startStopUnit(ide::START_STOP_MODE_OPEN_TRAY); + auto error = ide::DISC_CHANGED; + + while (error == ide::DISC_CHANGED) + error = + ide::devices[0].startStopUnit(ide::START_STOP_MODE_OPEN_TRAY); if (error) { _messageScreen.setMessage( diff --git a/src/ps1/registers573.h b/src/ps1/registers573.h index 7e91216..651f0e2 100644 --- a/src/ps1/registers573.h +++ b/src/ps1/registers573.h @@ -137,18 +137,47 @@ typedef enum { SYS573D_CPLD_CTRL_UNKNOWN = 1 << 15 } Sys573DCPLDControlFlag; -#define SYS573D_FPGA_MAGIC _MMIO16(DEV0_BASE | 0x640080) -#define SYS573D_FPGA_LIGHTS_A1 _MMIO16(DEV0_BASE | 0x6400e0) -#define SYS573D_FPGA_LIGHTS_A0 _MMIO16(DEV0_BASE | 0x6400e2) -#define SYS573D_FPGA_LIGHTS_B1 _MMIO16(DEV0_BASE | 0x6400e4) -#define SYS573D_FPGA_LIGHTS_D0 _MMIO16(DEV0_BASE | 0x6400e6) +typedef enum { + SYS573D_FPGA_DS_BUS_DS2433 = 1 << 8, + SYS573D_FPGA_DS_BUS_DS2401 = 1 << 12 +} Sys573DFPGADSBusFlag; + +#define SYS573D_FPGA_MAGIC _MMIO16(DEV0_BASE | 0x640080) + +#define SYS573D_FPGA_MP3_PTR_H _MMIO16(DEV0_BASE | 0x6400a0) +#define SYS573D_FPGA_MP3_PTR_L _MMIO16(DEV0_BASE | 0x6400a2) +#define SYS573D_FPGA_MP3_ENDPTR_H _MMIO16(DEV0_BASE | 0x6400a4) +#define SYS573D_FPGA_MP3_ENDPTR_L _MMIO16(DEV0_BASE | 0x6400a6) +#define SYS573D_FPGA_MP3_COUNTER _MMIO16(DEV0_BASE | 0x6400a8) +#define SYS573D_FPGA_MP3_KEY1 _MMIO16(DEV0_BASE | 0x6400a8) +#define SYS573D_FPGA_MP3_FEED_STAT _MMIO16(DEV0_BASE | 0x6400aa) +#define SYS573D_FPGA_MP3_I2C _MMIO16(DEV0_BASE | 0x6400ac) +#define SYS573D_FPGA_MP3_FEED_CTRL _MMIO16(DEV0_BASE | 0x6400ae) + +#define SYS573D_FPGA_DRAM_WRPTR_H _MMIO16(DEV0_BASE | 0x6400b0) +#define SYS573D_FPGA_DRAM_WRPTR_L _MMIO16(DEV0_BASE | 0x6400b2) +#define SYS573D_FPGA_DRAM_DATA _MMIO16(DEV0_BASE | 0x6400b4) +#define SYS573D_FPGA_DRAM_RDPTR_H _MMIO16(DEV0_BASE | 0x6400b6) +#define SYS573D_FPGA_DRAM_RDPTR_L _MMIO16(DEV0_BASE | 0x6400b8) + +#define SYS573D_FPGA_NET_DATA _MMIO16(DEV0_BASE | 0x6400c0) +#define SYS573D_FPGA_DAC_COUNTER_H _MMIO16(DEV0_BASE | 0x6400ca) +#define SYS573D_FPGA_DAC_COUNTER_L _MMIO16(DEV0_BASE | 0x6400cc) +#define SYS573D_FPGA_DAC_COUNTER_D _MMIO16(DEV0_BASE | 0x6400ce) + +#define SYS573D_FPGA_LIGHTS_AH _MMIO16(DEV0_BASE | 0x6400e0) +#define SYS573D_FPGA_LIGHTS_AL _MMIO16(DEV0_BASE | 0x6400e2) +#define SYS573D_FPGA_LIGHTS_BH _MMIO16(DEV0_BASE | 0x6400e4) +#define SYS573D_FPGA_LIGHTS_D _MMIO16(DEV0_BASE | 0x6400e6) #define SYS573D_FPGA_INIT _MMIO16(DEV0_BASE | 0x6400e8) -#define SYS573D_FPGA_DS2401 _MMIO16(DEV0_BASE | 0x6400ee) +#define SYS573D_FPGA_MP3_KEY2 _MMIO16(DEV0_BASE | 0x6400ea) +#define SYS573D_FPGA_MP3_KEY3 _MMIO16(DEV0_BASE | 0x6400ec) +#define SYS573D_FPGA_DS_BUS _MMIO16(DEV0_BASE | 0x6400ee) #define SYS573D_CPLD_UNK_RESET _MMIO16(DEV0_BASE | 0x6400f4) #define SYS573D_CPLD_STAT _MMIO16(DEV0_BASE | 0x6400f6) #define SYS573D_CPLD_CTRL _MMIO16(DEV0_BASE | 0x6400f6) #define SYS573D_CPLD_BITSTREAM _MMIO16(DEV0_BASE | 0x6400f8) -#define SYS573D_CPLD_LIGHTS_C0 _MMIO16(DEV0_BASE | 0x6400fa) -#define SYS573D_CPLD_LIGHTS_C1 _MMIO16(DEV0_BASE | 0x6400fc) -#define SYS573D_CPLD_LIGHTS_B0 _MMIO16(DEV0_BASE | 0x6400fe) +#define SYS573D_CPLD_LIGHTS_CL _MMIO16(DEV0_BASE | 0x6400fa) +#define SYS573D_CPLD_LIGHTS_CH _MMIO16(DEV0_BASE | 0x6400fc) +#define SYS573D_CPLD_LIGHTS_BL _MMIO16(DEV0_BASE | 0x6400fe)