diff --git a/data/fpga.bit b/data/fpga.bit index e576432..5b27f29 100644 Binary files a/data/fpga.bit and b/data/fpga.bit differ diff --git a/fpga/fpga.ucf b/fpga/fpga.ucf index 2592043..9ab0eef 100644 --- a/fpga/fpga.ucf +++ b/fpga/fpga.ucf @@ -8,151 +8,262 @@ CONFIG PROHIBIT = "P154"; # DOUT 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"; +NET "clockIn29M" LOC = "P160"; +NET "clock29M" TNM_NET = "clock29M"; +NET "clockIn19M" LOC = "P207"; +#NET "clock19M" TNM_NET = "clock19M"; ## Host interface -NET "nHostRead" LOC = "P146"; -NET "nHostWrite" LOC = "P145"; -NET "nHostEnable" LOC = "P142"; +TIMESPEC "TS_hostAddress" = FROM "hostAddress" TO "FFS" "TS_clock29M" / 1; +TIMESPEC "TS_hostDataIn" = FROM "hostData" TO "FFS" "TS_clock29M" / 1; +TIMESPEC "TS_hostDataOut" = FROM "FFS" TO "hostData" "TS_clock29M" / 1; -NET "hostAddress[0]" LOC = "P117"; -NET "hostAddress[1]" LOC = "P116"; -NET "hostAddress[2]" LOC = "P115"; -NET "hostAddress[3]" LOC = "P114"; -NET "hostAddress[4]" LOC = "P113"; -NET "hostAddress[5]" LOC = "P112"; -NET "hostAddress[6]" LOC = "P110"; +NET "nHostRead" LOC = "P146"; +NET "nHostRead" TNM_NET = "hostControl"; +NET "nHostWrite" LOC = "P145"; +NET "nHostWrite" TNM_NET = "hostControl"; +NET "nHostEnable" LOC = "P142"; +NET "nHostEnable" TNM_NET = "hostControl"; -NET "hostData[0]" LOC = "P138"; -NET "hostData[1]" LOC = "P137"; -NET "hostData[2]" LOC = "P136"; -NET "hostData[3]" LOC = "P135"; -NET "hostData[4]" LOC = "P134"; -NET "hostData[5]" LOC = "P133"; -NET "hostData[6]" LOC = "P132"; -NET "hostData[7]" LOC = "P129"; -NET "hostData[8]" LOC = "P128"; -NET "hostData[9]" LOC = "P127"; -NET "hostData[10]" LOC = "P126"; -NET "hostData[11]" LOC = "P125"; -NET "hostData[12]" LOC = "P124"; -NET "hostData[13]" LOC = "P123"; -NET "hostData[14]" LOC = "P122"; -NET "hostData[15]" LOC = "P120"; +NET "hostAddress[0]" LOC = "P117"; +NET "hostAddress[0]" TNM_NET = "hostAddress"; +NET "hostAddress[1]" LOC = "P116"; +NET "hostAddress[1]" TNM_NET = "hostAddress"; +NET "hostAddress[2]" LOC = "P115"; +NET "hostAddress[2]" TNM_NET = "hostAddress"; +NET "hostAddress[3]" LOC = "P114"; +NET "hostAddress[3]" TNM_NET = "hostAddress"; +NET "hostAddress[4]" LOC = "P113"; +NET "hostAddress[4]" TNM_NET = "hostAddress"; +NET "hostAddress[5]" LOC = "P112"; +NET "hostAddress[5]" TNM_NET = "hostAddress"; +NET "hostAddress[6]" LOC = "P110"; +NET "hostAddress[6]" TNM_NET = "hostAddress"; + +NET "hostData[0]" LOC = "P138"; +NET "hostData[0]" TNM_NET = "hostData"; +NET "hostData[1]" LOC = "P137"; +NET "hostData[1]" TNM_NET = "hostData"; +NET "hostData[2]" LOC = "P136"; +NET "hostData[2]" TNM_NET = "hostData"; +NET "hostData[3]" LOC = "P135"; +NET "hostData[3]" TNM_NET = "hostData"; +NET "hostData[4]" LOC = "P134"; +NET "hostData[4]" TNM_NET = "hostData"; +NET "hostData[5]" LOC = "P133"; +NET "hostData[5]" TNM_NET = "hostData"; +NET "hostData[6]" LOC = "P132"; +NET "hostData[6]" TNM_NET = "hostData"; +NET "hostData[7]" LOC = "P129"; +NET "hostData[7]" TNM_NET = "hostData"; +NET "hostData[8]" LOC = "P128"; +NET "hostData[8]" TNM_NET = "hostData"; +NET "hostData[9]" LOC = "P127"; +NET "hostData[9]" TNM_NET = "hostData"; +NET "hostData[10]" LOC = "P126"; +NET "hostData[10]" TNM_NET = "hostData"; +NET "hostData[11]" LOC = "P125"; +NET "hostData[11]" TNM_NET = "hostData"; +NET "hostData[12]" LOC = "P124"; +NET "hostData[12]" TNM_NET = "hostData"; +NET "hostData[13]" LOC = "P123"; +NET "hostData[13]" TNM_NET = "hostData"; +NET "hostData[14]" LOC = "P122"; +NET "hostData[14]" TNM_NET = "hostData"; +NET "hostData[15]" LOC = "P120"; +NET "hostData[15]" TNM_NET = "hostData"; ## SRAM interface -NET "nSRAMRead" LOC = "P40"; +NET "nSRAMRead" LOC = "P40"; +NET "nSRAMRead" TNM_NET = "sramControl"; NET "nSRAMRead" FAST; -NET "nSRAMWrite" LOC = "P55"; +NET "nSRAMWrite" LOC = "P55"; +NET "nSRAMWrite" TNM_NET = "sramControl"; NET "nSRAMWrite" FAST; -NET "nSRAMEnable" LOC = "P34"; +NET "nSRAMEnable" LOC = "P34"; +NET "nSRAMEnable" TNM_NET = "sramControl"; NET "nSRAMEnable" FAST; -NET "sramAddress[0]" LOC = "P30"; -NET "sramAddress[1]" LOC = "P32"; -NET "sramAddress[2]" LOC = "P35"; -NET "sramAddress[3]" LOC = "P37"; -NET "sramAddress[4]" LOC = "P41"; -NET "sramAddress[5]" LOC = "P43"; -NET "sramAddress[6]" LOC = "P45"; -NET "sramAddress[7]" LOC = "P47"; -NET "sramAddress[8]" LOC = "P46"; -NET "sramAddress[9]" LOC = "P44"; -NET "sramAddress[10]" LOC = "P36"; -NET "sramAddress[11]" LOC = "P42"; -NET "sramAddress[12]" LOC = "P49"; -NET "sramAddress[13]" LOC = "P48"; -NET "sramAddress[14]" LOC = "P56"; -NET "sramAddress[15]" LOC = "P58"; -NET "sramAddress[16]" LOC = "P57"; +NET "sramAddress[0]" LOC = "P30"; +NET "sramAddress[0]" TNM_NET = "sramAddress"; +NET "sramAddress[1]" LOC = "P32"; +NET "sramAddress[0]" TNM_NET = "sramAddress"; +NET "sramAddress[2]" LOC = "P35"; +NET "sramAddress[0]" TNM_NET = "sramAddress"; +NET "sramAddress[3]" LOC = "P37"; +NET "sramAddress[0]" TNM_NET = "sramAddress"; +NET "sramAddress[4]" LOC = "P41"; +NET "sramAddress[0]" TNM_NET = "sramAddress"; +NET "sramAddress[5]" LOC = "P43"; +NET "sramAddress[0]" TNM_NET = "sramAddress"; +NET "sramAddress[6]" LOC = "P45"; +NET "sramAddress[0]" TNM_NET = "sramAddress"; +NET "sramAddress[7]" LOC = "P47"; +NET "sramAddress[0]" TNM_NET = "sramAddress"; +NET "sramAddress[8]" LOC = "P46"; +NET "sramAddress[0]" TNM_NET = "sramAddress"; +NET "sramAddress[9]" LOC = "P44"; +NET "sramAddress[0]" TNM_NET = "sramAddress"; +NET "sramAddress[10]" LOC = "P36"; +NET "sramAddress[10]" TNM_NET = "sramAddress"; +NET "sramAddress[11]" LOC = "P42"; +NET "sramAddress[11]" TNM_NET = "sramAddress"; +NET "sramAddress[12]" LOC = "P49"; +NET "sramAddress[12]" TNM_NET = "sramAddress"; +NET "sramAddress[13]" LOC = "P48"; +NET "sramAddress[13]" TNM_NET = "sramAddress"; +NET "sramAddress[14]" LOC = "P56"; +NET "sramAddress[14]" TNM_NET = "sramAddress"; +NET "sramAddress[15]" LOC = "P58"; +NET "sramAddress[15]" TNM_NET = "sramAddress"; +NET "sramAddress[16]" LOC = "P57"; +NET "sramAddress[16]" TNM_NET = "sramAddress"; -NET "sramData[0]" LOC = "P28"; -NET "sramData[1]" LOC = "P24"; -NET "sramData[2]" LOC = "P22"; -NET "sramData[3]" LOC = "P21"; -NET "sramData[4]" LOC = "P23"; -NET "sramData[5]" LOC = "P27"; -NET "sramData[6]" LOC = "P29"; -NET "sramData[7]" LOC = "P31"; +NET "sramData[0]" LOC = "P28"; +NET "sramData[0]" TNM_NET = "sramData"; +NET "sramData[1]" LOC = "P24"; +NET "sramData[1]" TNM_NET = "sramData"; +NET "sramData[2]" LOC = "P22"; +NET "sramData[2]" TNM_NET = "sramData"; +NET "sramData[3]" LOC = "P21"; +NET "sramData[3]" TNM_NET = "sramData"; +NET "sramData[4]" LOC = "P23"; +NET "sramData[4]" TNM_NET = "sramData"; +NET "sramData[5]" LOC = "P27"; +NET "sramData[5]" TNM_NET = "sramData"; +NET "sramData[6]" LOC = "P29"; +NET "sramData[6]" TNM_NET = "sramData"; +NET "sramData[7]" LOC = "P31"; +NET "sramData[7]" TNM_NET = "sramData"; ## 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 "dramControl[0]" LOC = "P188"; +NET "dramControl[0]" TNM_NET = "dramControl"; +NET "dramControl[1]" LOC = "P189"; +NET "dramControl[1]" TNM_NET = "dramControl"; +NET "dramControl[2]" LOC = "P190"; +NET "dramControl[2]" TNM_NET = "dramControl"; +NET "dramControl[3]" LOC = "P191"; +NET "dramControl[3]" TNM_NET = "dramControl"; +NET "dramControl[4]" LOC = "P193"; +NET "dramControl[4]" TNM_NET = "dramControl"; +NET "dramControl[5]" LOC = "P194"; +NET "dramControl[5]" TNM_NET = "dramControl"; +NET "dramControl[6]" LOC = "P196"; +NET "dramControl[6]" TNM_NET = "dramControl"; +NET "dramControl[7]" LOC = "P197"; +NET "dramControl[7]" TNM_NET = "dramControl"; +NET "dramControl[8]" LOC = "P198"; +NET "dramControl[8]" TNM_NET = "dramControl"; +NET "dramControl[9]" LOC = "P199"; +NET "dramControl[9]" TNM_NET = "dramControl"; +NET "dramControl[10]" LOC = "P200"; +NET "dramControl[10]" TNM_NET = "dramControl"; +NET "dramControl[11]" LOC = "P201"; +NET "dramControl[11]" TNM_NET = "dramControl"; -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 "dramAddress[0]" LOC = "P186"; +NET "dramAddress[0]" TNM_NET = "dramAddress"; +NET "dramAddress[1]" LOC = "P184"; +NET "dramAddress[1]" TNM_NET = "dramAddress"; +NET "dramAddress[2]" LOC = "P180"; +NET "dramAddress[2]" TNM_NET = "dramAddress"; +NET "dramAddress[3]" LOC = "P178"; +NET "dramAddress[3]" TNM_NET = "dramAddress"; +NET "dramAddress[4]" LOC = "P176"; +NET "dramAddress[4]" TNM_NET = "dramAddress"; +NET "dramAddress[5]" LOC = "P174"; +NET "dramAddress[5]" TNM_NET = "dramAddress"; +NET "dramAddress[6]" LOC = "P175"; +NET "dramAddress[6]" TNM_NET = "dramAddress"; +NET "dramAddress[7]" LOC = "P177"; +NET "dramAddress[7]" TNM_NET = "dramAddress"; +NET "dramAddress[8]" LOC = "P179"; +NET "dramAddress[8]" TNM_NET = "dramAddress"; +NET "dramAddress[9]" LOC = "P181"; +NET "dramAddress[9]" TNM_NET = "dramAddress"; +NET "dramAddress[10]" LOC = "P185"; +NET "dramAddress[10]" TNM_NET = "dramAddress"; +NET "dramAddress[11]" LOC = "P187"; +NET "dramAddress[11]" TNM_NET = "dramAddress"; -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"; +NET "dramData[0]" LOC = "P15"; +NET "dramData[0]" TNM_NET = "dramData"; +NET "dramData[1]" LOC = "P14"; +NET "dramData[1]" TNM_NET = "dramData"; +NET "dramData[2]" LOC = "P10"; +NET "dramData[2]" TNM_NET = "dramData"; +NET "dramData[3]" LOC = "P8"; +NET "dramData[3]" TNM_NET = "dramData"; +NET "dramData[4]" LOC = "P2"; +NET "dramData[4]" TNM_NET = "dramData"; +NET "dramData[5]" LOC = "P206"; +NET "dramData[5]" TNM_NET = "dramData"; +NET "dramData[6]" LOC = "P205"; +NET "dramData[6]" TNM_NET = "dramData"; +NET "dramData[7]" LOC = "P204"; +NET "dramData[7]" TNM_NET = "dramData"; +NET "dramData[8]" LOC = "P3"; +NET "dramData[8]" TNM_NET = "dramData"; +NET "dramData[9]" LOC = "P4"; +NET "dramData[9]" TNM_NET = "dramData"; +NET "dramData[10]" LOC = "P5"; +NET "dramData[10]" TNM_NET = "dramData"; +NET "dramData[11]" LOC = "P9"; +NET "dramData[11]" TNM_NET = "dramData"; +NET "dramData[12]" LOC = "P11"; +NET "dramData[12]" TNM_NET = "dramData"; +NET "dramData[13]" LOC = "P17"; +NET "dramData[13]" TNM_NET = "dramData"; +NET "dramData[14]" LOC = "P19"; +NET "dramData[14]" TNM_NET = "dramData"; +NET "dramData[15]" LOC = "P20"; +NET "dramData[15]" TNM_NET = "dramData"; ## 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 "mp3ClockIn" LOC = "P163"; +NET "mp3ClockIn" TNM_NET = "mp3Clock"; +NET "mp3ClockOut" LOC = "P162"; +NET "mp3ClockOut" TNM_NET = "mp3Clock"; + +NET "mp3Reset" LOC = "P152"; +NET "mp3Ready" LOC = "P159"; +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"; +NET "mp3InSDIN" LOC = "P167"; +NET "mp3InSDIN" TNM_NET = "mp3Data"; +NET "mp3InBCLK" LOC = "P164"; +NET "mp3InBCLK" TNM_NET = "mp3Data"; +NET "mp3InLRCK" LOC = "P166"; +NET "mp3InLRCK" TNM_NET = "mp3Data"; +NET "mp3OutSDOUT" LOC = "P172"; +NET "mp3OutSDOUT" TNM_NET = "mp3Data"; +NET "mp3OutBCLK" LOC = "P169"; +NET "mp3OutBCLK" TNM_NET = "mp3Data"; +NET "mp3OutLRCK" LOC = "P171"; +NET "mp3OutLRCK" TNM_NET = "mp3Data"; ## I2S audio output -NET "dacSDIN" LOC = "P96"; -NET "dacBCLK" LOC = "P94"; -NET "dacLRCK" LOC = "P95"; -NET "dacMCLK" LOC = "P97"; +NET "dacSDIN" LOC = "P96"; +NET "dacSDIN" TNM_NET = "dacData"; +NET "dacBCLK" LOC = "P94"; +NET "dacBCLK" TNM_NET = "dacData"; +NET "dacLRCK" LOC = "P95"; +NET "dacLRCK" TNM_NET = "dacData"; +NET "dacMCLK" LOC = "P97"; +NET "dacMCLK" TNM_NET = "dacData"; ## Light outputs @@ -186,16 +297,25 @@ NET "lightBankD[3]" LOC = "P59"; ## Serial interfaces # TODO: are pins 98 and 99 swapped? -NET "networkTXEnable" LOC = "P98"; -NET "networkTX" LOC = "P99"; -NET "networkRX" LOC = "P100"; +NET "networkTXEnable" LOC = "P98"; +NET "networkTXEnable" TNM_NET = "network"; +NET "networkTX" LOC = "P99"; +NET "networkTX" TNM_NET = "network"; +NET "networkRX" LOC = "P100"; +NET "networkRX" TNM_NET = "network"; -NET "serialTX" LOC = "P89"; -NET "serialRX" LOC = "P88"; -NET "serialRTS" LOC = "P93"; -NET "serialCTS" LOC = "P90"; -NET "serialDTR" LOC = "P87"; -NET "serialDSR" LOC = "P85"; +NET "serialTX" LOC = "P89"; +NET "serialTX" TNM_NET = "serial"; +NET "serialRX" LOC = "P88"; +NET "serialRX" TNM_NET = "serial"; +NET "serialRTS" LOC = "P93"; +NET "serialRTS" TNM_NET = "serial"; +NET "serialCTS" LOC = "P90"; +NET "serialCTS" TNM_NET = "serial"; +NET "serialDTR" LOC = "P87"; +NET "serialDTR" TNM_NET = "serial"; +NET "serialDSR" LOC = "P85"; +NET "serialDSR" TNM_NET = "serial"; ## 1-wire bus diff --git a/fpga/fpga.ys b/fpga/fpga.ys index 40f0991..bf8e291 100644 --- a/fpga/fpga.ys +++ b/fpga/fpga.ys @@ -1,16 +1,17 @@ # This script is roughly similar to the built-in synth_xilinx command, with the # appropriate modifications made in order to output gate netlists rather than -# precompiled LUTs. Note that more advanced features such as fast carry or -# distributed LUT RAM are not yet supported. +# precompiled LUTs (which are not supported by the ISE mapper for Spartan-XL +# devices). Note that more advanced features such as fast carry or distributed +# LUT RAMs are not yet supported. ## Input and preliminary optimization read_verilog src/main.v -read_verilog src/spartanxl.v +read_verilog src/spartanxl/primitives.v hierarchy -check -top FPGA proc -flatten -noscopeinfo +flatten tribuf -logic deminout opt_expr @@ -25,15 +26,16 @@ opt_clean ## Conversion to gate-level representation +techmap -D LUT_WIDTH=4 -map +/cmp2lut.v -map +/cmp2lcu.v alumacc share opt memory -nomap opt_clean - +memory_map opt -full -simplemap -techmap -D NOLUT -D LUT_SIZE=4 -map +/techmap.v -map +/xilinx/arith_map.v + +techmap -map +/techmap.v opt -fast clean @@ -41,25 +43,26 @@ clean dfflegalize -cell $_DFFE_PP?P_ r -cell $_DLATCH_PP?_ r opt_expr -mux_undef -noclkinv -abc -g gates -xilinx_dffopt -lut4 +abc -liberty src/spartanxl/primitives.lib +clean -#clkbufmap -buf BUFGLS O:I +#hilomap -hicell VCC P -locell GND G 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 +iopadmap -bits -outpad OBUF I:O -toutpad OBUFE E:I:O -tinoutpad IOBUFE E:O:I:IO -ignore IPAD IPAD -ignore OPAD OPAD -ignore IOPAD IOPAD -ignore OFDX Q -ignore OFDXI Q -ignore OFDTX O -ignore OFDTXI O +clkbufmap -buf BUFGLS O:I +#extractinv -inv INV O:I + +techmap -map src/spartanxl/map.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 +hierarchy -check autoname stat -tech xilinx check -noinit blackbox =A:whitebox +show -notitle -colors 1 -format dot -viewer none -prefix build/synth write_verilog -noattr build/synth.v write_edif -top FPGA -pvector bra -lsbidx build/synth.edf diff --git a/fpga/runISE.bat b/fpga/runISE.bat index 62d5861..c8663c8 100755 --- a/fpga/runISE.bat +++ b/fpga/runISE.bat @@ -2,9 +2,9 @@ setlocal set TARGET=xcs40xl-pq208-4 -set COVER_MODE=area +set COVER_MODE=speed set OPTIMIZATION_MODE=speed -set OPTIMIZATION_LEVEL=high +set OPTIMIZATION_LEVEL=normal if not exist "%XILINX%\bin\nt\" ( echo The XILINX environment variable must be set to the root of a valid ^ diff --git a/fpga/src/main.v b/fpga/src/main.v index 66a0028..a2770f7 100644 --- a/fpga/src/main.v +++ b/fpga/src/main.v @@ -22,10 +22,11 @@ module FPGA ( output [11:0] dramAddress, inout [15:0] dramData, - output mp3Reset, - input mp3Ready, output mp3ClockIn, input mp3ClockOut, + + output mp3Reset, + input mp3Ready, inout mp3SDA, inout mp3SCL, @@ -69,113 +70,99 @@ module FPGA ( /* Register definitions */ - localparam SYS573D_FPGA_MAGIC = 8'h80; + function automatic [5:0] _hostReg (input [7:0] address); + _hostReg = address[6:1]; + endfunction - 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_MAGIC = _hostReg(8'h80); + localparam SYS573D_FPGA_VERSION = _hostReg(8'h82); - 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_MP3_PTR_H = _hostReg(8'ha0); + localparam SYS573D_FPGA_MP3_PTR_L = _hostReg(8'ha2); + localparam SYS573D_FPGA_MP3_ENDPTR_H = _hostReg(8'ha4); + localparam SYS573D_FPGA_MP3_ENDPTR_L = _hostReg(8'ha6); + localparam SYS573D_FPGA_MP3_COUNTER = _hostReg(8'ha8); + localparam SYS573D_FPGA_MP3_KEY1 = _hostReg(8'ha8); + localparam SYS573D_FPGA_MP3_FEED_STAT = _hostReg(8'haa); + localparam SYS573D_FPGA_MP3_I2C = _hostReg(8'hac); + localparam SYS573D_FPGA_MP3_FEED_CTRL = _hostReg(8'hae); - 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_DRAM_WRPTR_H = _hostReg(8'hb0); + localparam SYS573D_FPGA_DRAM_WRPTR_L = _hostReg(8'hb2); + localparam SYS573D_FPGA_DRAM_DATA = _hostReg(8'hb4); + localparam SYS573D_FPGA_DRAM_RDPTR_H = _hostReg(8'hb6); + localparam SYS573D_FPGA_DRAM_RDPTR_L = _hostReg(8'hb8); - 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; + localparam SYS573D_FPGA_NET_DATA = _hostReg(8'hc0); + localparam SYS573D_FPGA_DAC_COUNTER_H = _hostReg(8'hca); + localparam SYS573D_FPGA_DAC_COUNTER_L = _hostReg(8'hcc); + localparam SYS573D_FPGA_DAC_COUNTER_D = _hostReg(8'hce); + + localparam SYS573D_FPGA_LIGHTS_AH = _hostReg(8'he0); + localparam SYS573D_FPGA_LIGHTS_AL = _hostReg(8'he2); + localparam SYS573D_FPGA_LIGHTS_BH = _hostReg(8'he4); + localparam SYS573D_FPGA_LIGHTS_D = _hostReg(8'he6); + localparam SYS573D_FPGA_INIT = _hostReg(8'he8); + localparam SYS573D_FPGA_MP3_KEY2 = _hostReg(8'hea); + localparam SYS573D_FPGA_MP3_KEY3 = _hostReg(8'hec); + localparam SYS573D_FPGA_DS_BUS = _hostReg(8'hee); /* System clocks */ - wire clock29M, 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)); + wire clock29M; + IPAD _clockPad29M (.IPAD(clockIn29M)); + BUFGLS _clockBuf29M (.I(clockIn29M), .O(clock29M)); - /* Host address decoding */ + wire clock19M; + IPAD _clockPad19M (.IPAD(clockIn19M)); + BUFGLS _clockBuf19M (.I(clockIn19M), .O(clock19M)); + + /* Host interface */ + + wire _hostWriteLatchIn = ~nHostWrite & ~nHostEnable; + wire _hostWriteLatch; + BUFGLS _hostWriteLatchBuf (.I(_hostWriteLatchIn), .O(_hostWriteLatch)); + + reg [6:0] hostRegAddress; + reg [15:0] hostReadData; + reg [15:0] hostWriteData; + + always @(posedge clock29M) + hostRegAddress <= hostAddress; + always @(negedge _hostWriteLatch) + hostWriteData <= hostData; + + /* Read/write strobe edge detector */ + + reg [1:0] _hostReadState = 2'b00; + reg [1:0] _hostWriteState = 2'b00; + + always @(posedge clock29M) begin + _hostReadState <= { _hostReadState[0], ~nHostRead & ~nHostEnable }; + _hostWriteState <= { _hostWriteState[0], ~nHostWrite & ~nHostEnable }; + end + + wire hostReadAsserted = (_hostReadState == 2'b01); + wire hostReadReleased = (_hostReadState == 2'b10); + wire hostWriteAsserted = (_hostWriteState == 2'b01); + wire hostWriteReleased = (_hostWriteState == 2'b10); // 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; + reg _hostDataDir = 1'b0; + assign hostData = _hostDataDir ? hostReadData : 16'hzzzz; - wire [7:0] hostRegister = { 1'b1, hostAddress[5:0], 1'b0 }; - - /* Host interface */ - - reg [2:0] _delayedHostRegRead = 3'b000; - wire _hostDataInClock; - - wire [15:0] hostDataIn; - wor [15:0] hostDataOut; - - 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 < 16; i = i + 1) begin - IFDX hostDataInReg ( - .D(hostData[i]), - .C(~_hostDataInClock), - .CE(1'b1), - .Q(hostDataIn[i]) - ); - OFDTX hostDataOutReg ( - .D(hostDataOut[i]), - .C(clock29M), - .CE(~_delayedHostRegRead[2]), - .T(~hostDataOutValid), - .O(hostData[i]) - ); - end - endgenerate + always @(posedge clock29M) + _hostDataDir <= 1'b1 + & ~nHostRead + & ~nHostEnable + & hostAddress[6] + & (hostAddress[5:3] != 3'b111); /* SRAM interface (currently unused) */ @@ -191,29 +178,26 @@ module FPGA ( /* MP3 decoder interface (currently unused) */ - assign mp3Reset = 1'b1; + reg mp3SDAIn; + reg mp3SDAOut = 1'b1; + reg mp3SCLIn; + reg mp3SCLOut = 1'b1; + assign mp3ClockIn = 1'b1; + assign mp3Reset = 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; + assign mp3SDA = mp3SDAOut ? 1'bz : 1'b0; + assign mp3SCL = mp3SCLOut ? 1'bz : 1'b0; - 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; + always @(posedge clock29M) begin + mp3SDAIn <= mp3SDA; + mp3SCLIn <= mp3SCL; + end /* I2S audio output */ @@ -222,39 +206,23 @@ module FPGA ( assign dacLRCK = mp3OutLRCK; assign dacMCLK = mp3ClockOut; - /* Magic number */ - - assign hostDataOut = (hostRegister == SYS573D_FPGA_MAGIC) - ? 16'h573f - : 16'h0000; - /* Light outputs */ + reg [3:0] lightBankAHState = 4'b1111; + reg [3:0] lightBankALState = 4'b1111; + reg [3:0] lightBankBHState = 4'b1111; + reg [3:0] lightBankDState = 4'b1111; + generate 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; + // Note that XCS40XL IOBs actually have a built-in tristate flip + // flop, but ISE will not use it here as it does not have a clock + // enable input (used to gate writes to the state registers) and + // cannot be read back nor configured to be set on startup. + assign lightBankAH[i] = lightBankAHState[i] ? 1'bz : 1'b0; + assign lightBankAL[i] = lightBankALState[i] ? 1'bz : 1'b0; + assign lightBankBH[i] = lightBankBHState[i] ? 1'bz : 1'b0; + assign lightBankD[i] = lightBankDState[i] ? 1'bz : 1'b0; end endgenerate @@ -269,21 +237,81 @@ module FPGA ( /* 1-wire bus */ - assign hostDataOut = (hostRegister == SYS573D_FPGA_DS_BUS) - ? { 3'h0, ds2401, 3'h0, ds2433, 8'h00 } - : 16'h0000; - - reg ds2433State = 1'b0; - reg ds2401State = 1'b0; - - always @(posedge clock29M) - if (hostDataInPending & (hostRegister == SYS573D_FPGA_DS_BUS)) begin - ds2433State <= hostDataIn[8]; - ds2401State <= hostDataIn[12]; - end + reg ds2433In; + reg ds2433Out = 1'b0; + reg ds2401In; + reg ds2401Out = 1'b0; // 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; + assign ds2433 = ds2433Out ? 1'b0 : 1'bz; + assign ds2401 = ds2401Out ? 1'b0 : 1'bz; + + always @(posedge clock29M) begin + ds2433In <= ds2433; + ds2401In <= ds2401; + end + + /* Host registers */ + + always @(posedge clock29M) + case (hostRegAddress[5:0]) + SYS573D_FPGA_MAGIC: begin + hostReadData <= 16'h573f; + end + + SYS573D_FPGA_VERSION: begin + hostReadData <= 16'h0001; + end + + SYS573D_FPGA_MP3_I2C: begin + hostReadData <= { 2'h0, mp3SCLIn, mp3SDAIn, 12'h000 }; + + if (hostWriteReleased) begin + mp3SDAOut <= hostWriteData[12]; + mp3SCLOut <= hostWriteData[13]; + end + end + + SYS573D_FPGA_LIGHTS_AH: begin + hostReadData <= { lightBankAHState, 12'h000 }; + + if (hostWriteReleased) + lightBankAHState <= hostWriteData[15:12]; + end + + SYS573D_FPGA_LIGHTS_AL: begin + hostReadData <= { lightBankALState, 12'h000 }; + + if (hostWriteReleased) + lightBankALState <= hostWriteData[15:12]; + end + + SYS573D_FPGA_LIGHTS_BH: begin + hostReadData <= { lightBankBHState, 12'h000 }; + + if (hostWriteReleased) + lightBankBHState <= hostWriteData[15:12]; + end + + SYS573D_FPGA_LIGHTS_D: begin + hostReadData <= { lightBankDState, 12'h000 }; + + if (hostWriteReleased) + lightBankDState <= hostWriteData[15:12]; + end + + SYS573D_FPGA_DS_BUS: begin + hostReadData <= { 3'h0, ds2401In, 3'h0, ds2433In, 8'h00 }; + + if (hostWriteReleased) begin + ds2433Out <= hostWriteData[8]; + ds2401Out <= hostWriteData[12]; + end + end + + default: begin + hostReadData <= 16'hxxxx; + end + endcase endmodule diff --git a/fpga/src/spartanxl.v b/fpga/src/spartanxl.v deleted file mode 100644 index c90839c..0000000 --- a/fpga/src/spartanxl.v +++ /dev/null @@ -1,368 +0,0 @@ - -/* 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/spartanxl/map.v b/fpga/src/spartanxl/map.v new file mode 100644 index 0000000..79f7c64 --- /dev/null +++ b/fpga/src/spartanxl/map.v @@ -0,0 +1,37 @@ + +/* I/O cells */ + +module OBUFE (input I, input E, output O); + wire T; + + INV _TECHMAP_REPLACE_.inv (.I(E), .O(T)); + OBUFT _TECHMAP_REPLACE_.obuf (.I(I), .T(T), .O(O)); +endmodule + +module IOBUFE (input I, input E, output O, inout IO); + wire T; + + INV _TECHMAP_REPLACE_.inv (.I(E), .O(T)); + OBUFT _TECHMAP_REPLACE_.obuf (.I(I), .T(T), .O(IO)); + IBUF _TECHMAP_REPLACE_.ibuf (.I(IO), .O(O)); +endmodule + +/* Flip flops and latches */ + +// The dfflibmap command does not currently support mapping memory cells with an +// enable input, so these have to be declared here rather than in spartanxl.lib. +module \$_DFFE_PP0P_ (input D, input C, input R, input E, output Q); + FDCE _TECHMAP_REPLACE_ (.D(D), .C(C), .CLR(R), .CE(E), .Q(Q)); +endmodule + +module \$_DFFE_PP1P_ (input D, input C, input R, input E, output Q); + FDPE _TECHMAP_REPLACE_ (.D(D), .C(C), .PRE(R), .CE(E), .Q(Q)); +endmodule + +module \$_DLATCH_PP0_ (input E, input R, input D, output Q); + LDCE_1 _TECHMAP_REPLACE_ (.D(D), .G(E), .CLR(R), .GE(1'b1), .Q(Q)); +endmodule + +module \$_DLATCH_PP1_ (input E, input R, input D, output Q); + LDPE_1 _TECHMAP_REPLACE_ (.D(D), .G(E), .PRE(R), .GE(1'b1), .Q(Q)); +endmodule diff --git a/fpga/src/spartanxl/primitives.lib b/fpga/src/spartanxl/primitives.lib new file mode 100644 index 0000000..f8d4eaf --- /dev/null +++ b/fpga/src/spartanxl/primitives.lib @@ -0,0 +1,551 @@ + +library(spartanxl) { + /* Buffers */ + + cell(BUF) { + area: 1; + pin(I) { direction: input; } + pin(O) { direction: output; function: "I"; } + } + cell(INV) { + area: 1; + pin(I) { direction: input; } + pin(O) { direction: output; function: "!I"; } + } + + /* AND gates */ + + cell(AND2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(O) { direction: output; function: "I0*I1"; } + } + cell(AND2B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(O) { direction: output; function: "!I0*I1"; } + } + + cell(AND3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "I0*I1*I2"; } + } + cell(AND3B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "!I0*I1*I2"; } + } + cell(AND3B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "!I0*!I1*I2"; } + } + + cell(AND4) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "I0*I1*I2*I3"; } + } + cell(AND4B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!I0*I1*I2*I3"; } + } + cell(AND4B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!I0*!I1*I2*I3"; } + } + cell(AND4B3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!I0*!I1*!I2*I3"; } + } + + cell(AND5) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "I0*I1*I2*I3*I4"; } + } + cell(AND5B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!I0*I1*I2*I3*I4"; } + } + cell(AND5B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!I0*!I1*I2*I3*I4"; } + } + cell(AND5B3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!I0*!I1*!I2*I3*I4"; } + } + cell(AND5B4) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!I0*!I1*!I2*!I3*I4"; } + } + + /* NAND gates */ + + cell(NAND2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(O) { direction: output; function: "!(I0*I1)"; } + } + cell(NAND2B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(O) { direction: output; function: "!(!I0*I1)"; } + } + + cell(NAND3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "!(I0*I1*I2)"; } + } + cell(NAND3B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "!(!I0*I1*I2)"; } + } + cell(NAND3B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "!(!I0*!I1*I2)"; } + } + + cell(NAND4) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!(I0*I1*I2*I3)"; } + } + cell(NAND4B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!(!I0*I1*I2*I3)"; } + } + cell(NAND4B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!(!I0*!I1*I2*I3)"; } + } + cell(NAND4B3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!(!I0*!I1*!I2*I3)"; } + } + + cell(NAND5) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!(I0*I1*I2*I3*I4)"; } + } + cell(NAND5B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!(!I0*I1*I2*I3*I4)"; } + } + cell(NAND5B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!(!I0*!I1*I2*I3*I4)"; } + } + cell(NAND5B3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!(!I0*!I1*!I2*I3*I4)"; } + } + cell(NAND5B4) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!(!I0*!I1*!I2*!I3*I4)"; } + } + + /* OR gates */ + + cell(OR2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(O) { direction: output; function: "I0+I1"; } + } + cell(OR2B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(O) { direction: output; function: "!I0+I1"; } + } + + cell(OR3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "I0+I1+I2"; } + } + cell(OR3B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "!I0+I1+I2"; } + } + cell(OR3B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "!I0+!I1+I2"; } + } + + cell(OR4) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "I0+I1+I2+I3"; } + } + cell(OR4B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!I0+I1+I2+I3"; } + } + cell(OR4B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!I0+!I1+I2+I3"; } + } + cell(OR4B3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!I0+!I1+!I2+I3"; } + } + + cell(OR5) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "I0+I1+I2+I3+I4"; } + } + cell(OR5B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!I0+I1+I2+I3+I4"; } + } + cell(OR5B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!I0+!I1+I2+I3+I4"; } + } + cell(OR5B3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!I0+!I1+!I2+I3+I4"; } + } + cell(OR5B4) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!I0+!I1+!I2+!I3+I4"; } + } + + /* NOR gates */ + + cell(NOR2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(O) { direction: output; function: "!(I0+I1)"; } + } + cell(NOR2B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(O) { direction: output; function: "!(!I0+I1)"; } + } + + cell(NOR3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "!(I0+I1+I2)"; } + } + cell(NOR3B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "!(!I0+I1+I2)"; } + } + cell(NOR3B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "!(!I0+!I1+I2)"; } + } + + cell(NOR4) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!(I0+I1+I2+I3)"; } + } + cell(NOR4B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!(!I0+I1+I2+I3)"; } + } + cell(NOR4B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!(!I0+!I1+I2+I3)"; } + } + cell(NOR4B3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!(!I0+!I1+!I2+I3)"; } + } + + cell(NOR5) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!(I0+I1+I2+I3+I4)"; } + } + cell(NOR5B1) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!(!I0+I1+I2+I3+I4)"; } + } + cell(NOR5B2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!(!I0+!I1+I2+I3+I4)"; } + } + cell(NOR5B3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!(!I0+!I1+!I2+I3+I4)"; } + } + cell(NOR5B4) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!(!I0+!I1+!I2+!I3+I4)"; } + } + + /* XOR gates */ + + cell(XOR2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(O) { direction: output; function: "I0^I1"; } + } + + cell(XOR3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "I0^I1^I2"; } + } + + cell(XOR4) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "I0^I1^I2^I3"; } + } + + cell(XOR5) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "I0^I1^I2^I3^I4"; } + } + + /* XNOR gates */ + + cell(XNOR2) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(O) { direction: output; function: "!(I0^I1)"; } + } + + cell(XNOR3) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(O) { direction: output; function: "!(I0^I1^I2)"; } + } + + cell(XNOR4) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(O) { direction: output; function: "!(I0^I1^I2^I3)"; } + } + + cell(XNOR5) { + area: 1; + pin(I0) { direction: input; } + pin(I1) { direction: input; } + pin(I2) { direction: input; } + pin(I3) { direction: input; } + pin(I4) { direction: input; } + pin(O) { direction: output; function: "!(I0^I1^I2^I3^I4)"; } + } +} diff --git a/fpga/src/spartanxl/primitives.v b/fpga/src/spartanxl/primitives.v new file mode 100644 index 0000000..99eaffc --- /dev/null +++ b/fpga/src/spartanxl/primitives.v @@ -0,0 +1,646 @@ + +/* Constants */ + +module VCC (output P); +`ifndef SYNTHESIS + assign P = 1'b1; +`endif +endmodule + +module GND (output G); +`ifndef SYNTHESIS + assign G = 1'b0; +`endif +endmodule + +/* Buffers */ + +module BUF (input I, output O); +`ifndef SYNTHESIS + assign O = I; +`endif +endmodule + +module BUFT (input I, input T, output O); +`ifndef SYNTHESIS + assign O = T ? 1'bz : I; +`endif +endmodule + +module INV (input I, output O); +`ifndef SYNTHESIS + assign O = ~I; +`endif +endmodule + +/* AND gates */ + +module AND2 (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 AND3 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = I0 & I1 & I2; +`endif +endmodule + +module AND3B1 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = ~I0 & I1 & I2; +`endif +endmodule + +module AND3B2 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = ~I0 & ~I1 & I2; +`endif +endmodule + +module AND4 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = I0 & I1 & I2 & I3; +`endif +endmodule + +module AND4B1 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~I0 & I1 & I2 & I3; +`endif +endmodule + +module AND4B2 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~I0 & ~I1 & I2 & I3; +`endif +endmodule + +module AND4B3 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~I0 & ~I1 & ~I2 & I3; +`endif +endmodule + +module AND5 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = I0 & I1 & I2 & I3 & I4; +`endif +endmodule + +module AND5B1 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~I0 & I1 & I2 & I3 & I4; +`endif +endmodule + +module AND5B2 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~I0 & ~I1 & I2 & I3 & I4; +`endif +endmodule + +module AND5B3 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~I0 & ~I1 & ~I2 & I3 & I4; +`endif +endmodule + +module AND5B4 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~I0 & ~I1 & ~I2 & ~I3 & I4; +`endif +endmodule + +/* NAND gates */ + +module NAND2 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = ~(I0 & I1); +`endif +endmodule + +module NAND2B1 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 & I1); +`endif +endmodule + +module NAND3 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = ~(I0 & I1 & I2); +`endif +endmodule + +module NAND3B1 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 & I1 & I2); +`endif +endmodule + +module NAND3B2 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 & ~I1 & I2); +`endif +endmodule + +module NAND4 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~(I0 & I1 & I2 & I3); +`endif +endmodule + +module NAND4B1 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 & I1 & I2 & I3); +`endif +endmodule + +module NAND4B2 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 & ~I1 & I2 & I3); +`endif +endmodule + +module NAND4B3 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 & ~I1 & ~I2 & I3); +`endif +endmodule + +module NAND5 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~(I0 & I1 & I2 & I3 & I4); +`endif +endmodule + +module NAND5B1 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 & I1 & I2 & I3 & I4); +`endif +endmodule + +module NAND5B2 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 & ~I1 & I2 & I3 & I4); +`endif +endmodule + +module NAND5B3 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 & ~I1 & ~I2 & I3 & I4); +`endif +endmodule + +module NAND5B4 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 & ~I1 & ~I2 & ~I3 & I4); +`endif +endmodule + +/* OR gates */ + +module OR2 (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 OR3 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = I0 | I1 | I2; +`endif +endmodule + +module OR3B1 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = ~I0 | I1 | I2; +`endif +endmodule + +module OR3B2 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = ~I0 | ~I1 | I2; +`endif +endmodule + +module OR4 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = I0 | I1 | I2 | I3; +`endif +endmodule + +module OR4B1 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~I0 | I1 | I2 | I3; +`endif +endmodule + +module OR4B2 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~I0 | ~I1 | I2 | I3; +`endif +endmodule + +module OR4B3 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~I0 | ~I1 | ~I2 | I3; +`endif +endmodule + +module OR5 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = I0 | I1 | I2 | I3 | I4; +`endif +endmodule + +module OR5B1 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~I0 | I1 | I2 | I3 | I4; +`endif +endmodule + +module OR5B2 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~I0 | ~I1 | I2 | I3 | I4; +`endif +endmodule + +module OR5B3 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~I0 | ~I1 | ~I2 | I3 | I4; +`endif +endmodule + +module OR5B4 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~I0 | ~I1 | ~I2 | ~I3 | I4; +`endif +endmodule + +/* NOR gates */ + +module NOR2 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = ~(I0 | I1); +`endif +endmodule + +module NOR2B1 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 | I1); +`endif +endmodule + +module NOR3 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = ~(I0 | I1 | I2); +`endif +endmodule + +module NOR3B1 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 | I1 | I2); +`endif +endmodule + +module NOR3B2 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 | ~I1 | I2); +`endif +endmodule + +module NOR4 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~(I0 | I1 | I2 | I3); +`endif +endmodule + +module NOR4B1 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 | I1 | I2 | I3); +`endif +endmodule + +module NOR4B2 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 | ~I1 | I2 | I3); +`endif +endmodule + +module NOR4B3 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 | ~I1 | ~I2 | I3); +`endif +endmodule + +module NOR5 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~(I0 | I1 | I2 | I3 | I4); +`endif +endmodule + +module NOR5B1 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 | I1 | I2 | I3 | I4); +`endif +endmodule + +module NOR5B2 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 | ~I1 | I2 | I3 | I4); +`endif +endmodule + +module NOR5B3 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 | ~I1 | ~I2 | I3 | I4); +`endif +endmodule + +module NOR5B4 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~(~I0 | ~I1 | ~I2 | ~I3 | I4); +`endif +endmodule + +/* XOR gates */ + +module XOR2 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = I0 ^ I1; +`endif +endmodule + +module XOR3 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = I0 ^ I1 ^ I2; +`endif +endmodule + +module XOR4 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = I0 ^ I1 ^ I2 ^ I3; +`endif +endmodule + +module XOR5 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = I0 ^ I1 ^ I2 ^ I3 ^ I4; +`endif +endmodule + +/* XNOR gates */ + +module XNOR2 (input I0, input I1, output O); +`ifndef SYNTHESIS + assign O = ~(I0 ^ I1); +`endif +endmodule + +module XNOR3 (input I0, input I1, input I2, output O); +`ifndef SYNTHESIS + assign O = ~(I0 ^ I1 ^ I2); +`endif +endmodule + +module XNOR4 (input I0, input I1, input I2, input I3, output O); +`ifndef SYNTHESIS + assign O = ~(I0 ^ I1 ^ I2 ^ I3); +`endif +endmodule + +module XNOR5 (input I0, input I1, input I2, input I3, input I4, output O); +`ifndef SYNTHESIS + assign O = ~(I0 ^ I1 ^ I2 ^ I3 ^ I4); +`endif +endmodule + +/* Flip flops */ + +module FDCE (input D, input C, input CLR, input CE, output Q); +`ifndef SYNTHESIS + reg _Q = 1'b0; + assign Q = _Q; + + always @(posedge C, CLR) + if (CLR) + _Q <= 1'b0; + else if (CE) + _Q <= D; +`endif +endmodule + +module FDPE (input D, input C, input PRE, input CE, output Q); +`ifndef SYNTHESIS + reg _Q = 1'b1; + assign Q = _Q; + + always @(posedge C, PRE) + if (PRE) + _Q <= 1'b1; + else if (CE) + _Q <= D; +`endif +endmodule + +/* Latches */ + +module LDCE_1 (input D, input G, input CLR, input GE, output Q); +`ifndef SYNTHESIS + reg _Q = 1'b0; + assign Q = _Q; + + always @* + if (CLR) + _Q <= 1'b0; + else if (GE) + _Q <= D; +`endif +endmodule + +module LDPE_1 (input D, input G, input PRE, input GE, output Q); +`ifndef SYNTHESIS + reg _Q = 1'b1; + assign Q = _Q; + + always @* + if (PRE) + _Q <= 1'b1; + else if (GE) + _Q <= D; +`endif +endmodule + +/* CLB placement control primitives */ + +module FMAP (input I1, input I2, input I3, input I4, input O); +endmodule + +module HMAP (input I1, input I2, input I3, input O); +endmodule + +/* I/O buffers */ + +module BUFGLS (input I, output O); +`ifndef SYNTHESIS + assign O = I; +`endif +endmodule + +module IBUF (input I, output O); +`ifndef SYNTHESIS + assign O = I; +`endif +endmodule + +module OBUF (input I, output O); +`ifndef SYNTHESIS + assign O = I; +`endif +endmodule + +module OBUFT (input I, input T, output O); +`ifndef SYNTHESIS + assign O = T ? 1'bz : I; +`endif +endmodule + +/* I/O flip flops */ + +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 + +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 + +module OFDX (input D, input C, input CE, output Q); +`ifndef SYNTHESIS + IFDX ff (.D(D), .C(C), .CE(CE), .Q(Q)); +`endif +endmodule + +module OFDXI (input D, input C, input CE, output Q); +`ifndef SYNTHESIS + IFDXI ff (.D(D), .C(C), .CE(CE), .Q(Q)); +`endif +endmodule + +module OFDTX (input D, input C, input CE, input T, output O); +`ifndef SYNTHESIS + wire Q; + assign O = T ? 1'bz : Q; + + IFDX ff (.D(D), .C(C), .CE(CE), .Q(Q)); +`endif +endmodule + +module OFDTXI (input D, input C, input CE, input T, output O); +`ifndef SYNTHESIS + wire Q; + assign O = T ? 1'bz : Q; + + IFDXI ff (.D(D), .C(C), .CE(CE), .Q(Q)); +`endif +endmodule + +/* I/O pads */ + +module IPAD (output IPAD); +endmodule + +module OPAD (input OPAD); +endmodule + +module IOPAD (inout IOPAD); +endmodule + +module UPAD (inout UPAD); +endmodule + +module TDI (inout I); +endmodule + +module TDO (input O); +endmodule + +module TCK (inout I); +endmodule + +module TMS (inout I); +endmodule + +/* Fixed-function blocks */ + +module STARTUP ( + input GSR, + input GTS, + input CLK, + + output DONEIN, + output Q1Q4, + output Q2, + output Q3 +); +endmodule + +module OSC4 ( + output F8M, + output F500K, + output F16K, + output F490, + output F15 +); +endmodule + +module BSCAN( + input TDI, + input TDO1, + input TDO2, + input TCK, + input TMS, + + output TDO, + output DRCK, + output IDLE, + output SEL1, + output SEL2 +); +endmodule + +module RDBK (input TRIG, output DATA, output RIP); +endmodule + +module RDCLK (input I); +endmodule diff --git a/fpga/src/techmap.v b/fpga/src/techmap.v deleted file mode 100644 index ad4b590..0000000 --- a/fpga/src/techmap.v +++ /dev/null @@ -1,90 +0,0 @@ -/* - * This file is used by Yosys to map its internal gate representations to the - * respective primitives supported by ISE's mapping tools. Note that ISE does - * not expose LUT primitives for Spartan-XL devices, so LUT-based synthesis and - * the synth_xilinx command built into Yosys cannot be used. - */ - -(* techmap_celltype = "IOBUFT" *) -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)); -endmodule - -(* techmap_celltype = "$_NOT_" *) -module _ISE_INV (input A, output 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)); -endmodule - -(* techmap_celltype = "$_NAND_" *) -module _ISE_NAND2 (input A, input B, output 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)); -endmodule - -(* techmap_celltype = "$_OR_" *) -module _ISE_OR2 (input A, input B, output 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)); -endmodule - -(* techmap_celltype = "$_ORNOT_" *) -module _ISE_OR2B1 (input A, input B, output 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)); -endmodule - -(* techmap_celltype = "$_XNOR_" *) -module _ISE_XNOR2 (input A, input B, output Y); - XNOR2 _TECHMAP_REPLACE_ (.I0(A), .I1(B), .O(Y)); -endmodule - -(* techmap_celltype = "$_TBUF_" *) -module _ISE_BUFT (input A, input E, output 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)); -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)); -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)); -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)); -endmodule diff --git a/src/common/io.cpp b/src/common/io.cpp index 9f5083b..6d4c6ab 100644 --- a/src/common/io.cpp +++ b/src/common/io.cpp @@ -9,7 +9,8 @@ namespace io { -uint16_t _bankSwitchReg, _cartOutputReg, _miscOutputReg; +uint16_t _bankSwitchReg, _cartOutputReg, _miscOutputReg; +static uint16_t _digitalIOI2CReg, _digitalIODSBusReg; /* System initialization */ @@ -50,9 +51,9 @@ void init(void) { _bankSwitchReg = 0; _cartOutputReg = 0; _miscOutputReg = 0 - | SYS573_MISC_OUT_ADC_MOSI + | SYS573_MISC_OUT_ADC_DI | SYS573_MISC_OUT_ADC_CS - | SYS573_MISC_OUT_ADC_SCK + | SYS573_MISC_OUT_ADC_CLK | SYS573_MISC_OUT_JVS_RESET; SYS573_BANK_CTRL = _bankSwitchReg; @@ -181,7 +182,13 @@ static void _writeBitstreamMSB(const uint8_t *data, size_t length) { } } -bool loadBitstream(const uint8_t *data, size_t length) { +bool isDigitalIOPresent(void) { + const uint16_t mask = SYS573D_CPLD_STAT_ID1 | SYS573D_CPLD_STAT_ID2; + + return ((SYS573D_CPLD_STAT & mask) == SYS573D_CPLD_STAT_ID2); +} + +bool loadDigitalIOBitstream(const uint8_t *data, size_t length) { // Konami's bitstreams are always stored LSB-first and with no headers, // however Xilinx tools export .bit files which contain MSB-first bitstreams // wrapped in a TLV container. In order to upload the bitstream properly, @@ -189,7 +196,7 @@ bool loadBitstream(const uint8_t *data, size_t length) { // https://www.fpga-faq.com/FAQ_Pages/0026_Tell_me_about_bit_files.htm and // the "Data Stream Format" section in the XCS40XL datasheet for details. if (data[0] == 0xff) - return loadRawBitstream(data, length); + return loadDigitalIORawBitstream(data, length); auto dataEnd = &data[length]; uint16_t headerLength = (data[0] << 8) | data[1]; @@ -208,7 +215,7 @@ bool loadBitstream(const uint8_t *data, size_t length) { | data[4]; data += 5; - return loadRawBitstream(data, tagLength); + return loadDigitalIORawBitstream(data, tagLength); default: tagLength = (data[1] << 8) | data[2]; @@ -221,7 +228,7 @@ bool loadBitstream(const uint8_t *data, size_t length) { return false; } -bool loadRawBitstream(const uint8_t *data, size_t length) { +bool loadDigitalIORawBitstream(const uint8_t *data, size_t length) { if (data[0] != 0xff) return false; @@ -266,7 +273,7 @@ bool loadRawBitstream(const uint8_t *data, size_t length) { return false; } -void initKonamiBitstream(void) { +void initDigitalIOFPGA(void) { SYS573D_FPGA_INIT = 0xf000; SYS573D_FPGA_INIT = 0x0000; delayMicroseconds(_FPGA_INIT_REG_DELAY); @@ -282,6 +289,16 @@ void initKonamiBitstream(void) { SYS573D_CPLD_LIGHTS_CL = 0xf000; SYS573D_CPLD_LIGHTS_CH = 0xf000; SYS573D_FPGA_LIGHTS_D = 0xf000; + + _digitalIOI2CReg = 0 + | SYS573D_FPGA_MP3_I2C_SDA + | SYS573D_FPGA_MP3_I2C_SCL; + _digitalIODSBusReg = 0 + | SYS573D_FPGA_DS_BUS_DS2401 + | SYS573D_FPGA_DS_BUS_DS2433; + + SYS573D_FPGA_MP3_I2C = _digitalIOI2CReg; + SYS573D_FPGA_DS_BUS = _digitalIODSBusReg; } /* I2C driver */ @@ -289,173 +306,204 @@ void initKonamiBitstream(void) { static constexpr int _I2C_BUS_DELAY = 50; static constexpr int _I2C_RESET_DELAY = 500; -// SDA is open-drain so it is toggled by changing pin direction. -#define _SDA(value) setCartSDADir(!(value)) -#define SDA(value) _SDA(value), delayMicroseconds(_I2C_BUS_DELAY) -#define _SCL(value) setCartOutput(OUT_SCL, value) -#define SCL(value) _SCL(value), delayMicroseconds(_I2C_BUS_DELAY) -#define _CS(value) setCartOutput(OUT_CS, value) -#define CS(value) _CS(value), delayMicroseconds(_I2C_BUS_DELAY) -#define _RESET(value) setCartOutput(OUT_RESET, value) -#define RESET(value) _RESET(value), delayMicroseconds(_I2C_BUS_DELAY) +void I2CDriver::start(void) const { + _setSDA(true); + _setSCL(true, _I2C_BUS_DELAY); -void i2cStart(void) { - _SDA(true); - SCL(true); - - SDA(false); // START: SDA falling, SCL high - SCL(false); + _setSDA(false, _I2C_BUS_DELAY); // START: SDA falling, SCL high + _setSCL(false, _I2C_BUS_DELAY); } -void i2cStartWithCS(int csDelay) { - _SDA(true); - _SCL(false); - CS(true); +void I2CDriver::startWithCS(int csDelay) const { + _setSDA(true); + _setSCL(false); + _setCS(true, _I2C_BUS_DELAY); - CS(false); - delayMicroseconds(csDelay); - SCL(true); + _setCS(false, _I2C_BUS_DELAY + csDelay); + _setSCL(true, _I2C_BUS_DELAY); - SDA(false); // START: SDA falling, SCL high - SCL(false); + _setSDA(false, _I2C_BUS_DELAY); // START: SDA falling, SCL high + _setSCL(false, _I2C_BUS_DELAY); } -void i2cStop(void) { - _SDA(false); - SCL(true); +void I2CDriver::stop(void) const { + _setSDA(false); - SDA(true); // STOP: SDA rising, SCL high + _setSCL(true, _I2C_BUS_DELAY); + _setSDA(true, _I2C_BUS_DELAY); // STOP: SDA rising, SCL high } -void i2cStopWithCS(int csDelay) { - _SDA(false); - SCL(true); +void I2CDriver::stopWithCS(int csDelay) const { + _setSDA(false); - SDA(true); // STOP: SDA rising, SCL high + _setSCL(true, _I2C_BUS_DELAY); + _setSDA(true, _I2C_BUS_DELAY); // STOP: SDA rising, SCL high - SCL(false); - delayMicroseconds(csDelay); - CS(true); + _setSCL(false, _I2C_BUS_DELAY + csDelay); + _setCS(true, _I2C_BUS_DELAY); } -uint8_t i2cReadByte(void) { +bool I2CDriver::getACK(void) const { + delayMicroseconds(_I2C_BUS_DELAY); // Required for ZS01 + + _setSCL(true, _I2C_BUS_DELAY); + bool ack = _getSDA(); + _setSCL(false, _I2C_BUS_DELAY * 2); + + return ack ^ 1; +} + +void I2CDriver::sendACK(bool ack) const { + _setSDA(ack ^ 1); + _setSCL(true, _I2C_BUS_DELAY); + _setSCL(false, _I2C_BUS_DELAY); + _setSDA(true, _I2C_BUS_DELAY); +} + +uint8_t I2CDriver::readByte(void) const { uint8_t value = 0; - for (int bit = 7; bit >= 0; bit--) { // MSB first - SCL(true); - if (getCartSDA()) - value |= (1 << bit); - SCL(false); + for (int i = 7; i >= 0; i--) { // MSB first + _setSCL(true, _I2C_BUS_DELAY); + value |= _getSDA() << i; + _setSCL(false, _I2C_BUS_DELAY); } delayMicroseconds(_I2C_BUS_DELAY); return value; } -void i2cWriteByte(uint8_t value) { - for (int bit = 7; bit >= 0; bit--) { // MSB first - _SDA(value & (1 << bit)); - SCL(true); - SCL(false); +void I2CDriver::writeByte(uint8_t value) const { + for (int i = 7; i >= 0; i--) { // MSB first + _setSDA((value >> i) & 1); + _setSCL(true, _I2C_BUS_DELAY); + _setSCL(false, _I2C_BUS_DELAY); } - SDA(true); + _setSDA(true, _I2C_BUS_DELAY); } -void i2cSendACK(bool ack) { - _SDA(!ack); - SCL(true); - SCL(false); - SDA(true); -} - -bool i2cGetACK(void) { - delayMicroseconds(_I2C_BUS_DELAY); // Required for ZS01 - SCL(true); - bool ack = !getCartSDA(); - SCL(false); - - delayMicroseconds(_I2C_BUS_DELAY); - return ack; -} - -void i2cReadBytes(uint8_t *data, size_t length) { +void I2CDriver::readBytes(uint8_t *data, size_t length) const { for (; length; length--) { - *(data++) = i2cReadByte(); + *(data++) = readByte(); if (length > 1) - i2cSendACK(true); + sendACK(true); } } -bool i2cWriteBytes(const uint8_t *data, size_t length, int lastACKDelay) { +bool I2CDriver::writeBytes( + const uint8_t *data, size_t length, int lastACKDelay +) const { for (; length; length--) { - i2cWriteByte(*(data++)); + writeByte(*(data++)); if (length == 1) delayMicroseconds(lastACKDelay); - if (!i2cGetACK()) + if (!getACK()) return false; } return true; } -uint32_t i2cResetX76(void) { +uint32_t I2CDriver::resetX76(void) const { uint32_t value = 0; - _SDA(true); - _SCL(false); - _CS(false); - _RESET(false); + _setSDA(true); + _setSCL(false); + _setCS(false); + _setReset(false); - RESET(true); - SCL(true); - SCL(false); - RESET(false); - delayMicroseconds(_I2C_RESET_DELAY); + _setReset(true, _I2C_RESET_DELAY); + _setSCL(true, _I2C_BUS_DELAY); + _setSCL(false, _I2C_BUS_DELAY); + _setReset(false, _I2C_RESET_DELAY); - for (int bit = 0; bit < 32; bit++) { // LSB first - SCL(true); - if (getCartSDA()) - value |= (1 << bit); - SCL(false); + for (int i = 0; i < 32; i++) { // LSB first + _setSCL(true, _I2C_BUS_DELAY); + value |= _getSDA() << i; + _setSCL(false, _I2C_BUS_DELAY); } - CS(true); - SCL(true); + _setCS(true, _I2C_BUS_DELAY); + _setSCL(true, _I2C_BUS_DELAY); return value; } // For whatever reason the ZS01 does not implement the exact same response to // reset protocol as the X76 chips. The reset pin is also active-low rather // than active-high, and CS is ignored. -uint32_t i2cResetZS01(void) { +uint32_t I2CDriver::resetZS01(void) const { uint32_t value = 0; - _SDA(true); - _SCL(false); - _CS(false); - _RESET(true); + _setSDA(true); + _setSCL(false); + _setCS(false); + _setReset(true); - RESET(false); - RESET(true); - delayMicroseconds(_I2C_RESET_DELAY); + _setReset(false, _I2C_RESET_DELAY); + _setReset(true, _I2C_RESET_DELAY); + _setSCL(true, _I2C_BUS_DELAY); + _setSCL(false, _I2C_BUS_DELAY); - SCL(true); - SCL(false); - - for (int bit = 31; bit >= 0; bit--) { // MSB first - if (getCartSDA()) - value |= (1 << bit); - SCL(true); - SCL(false); + for (int i = 31; i >= 0; i--) { // MSB first + value |= _getSDA() << i; + _setSCL(true, _I2C_BUS_DELAY); + _setSCL(false, _I2C_BUS_DELAY); } - SCL(true); + _setSCL(true, _I2C_BUS_DELAY); return value; } +bool CartI2CDriver::_getSDA(void) const { + return (SYS573_MISC_IN / SYS573_MISC_IN_CART_SDA) & 1; +} + +void CartI2CDriver::_setSDA(bool value) const { + // SDA is open-drain so it is toggled by tristating the pin. + setCartOutput(CART_OUTPUT_SDA, false); + setCartSDADirection(value ^ 1); +} + +void CartI2CDriver::_setSCL(bool value) const { + setCartOutput(CART_OUTPUT_SCL, value); +} + +void CartI2CDriver::_setCS(bool value) const { + setCartOutput(CART_OUTPUT_CS, value); +} + +void CartI2CDriver::_setReset(bool value) const { + setCartOutput(CART_OUTPUT_RESET, value); +} + +bool DigitalIOI2CDriver::_getSDA(void) const { + return (SYS573D_FPGA_MP3_I2C / SYS573D_FPGA_MP3_I2C_SDA) & 1; +} + +void DigitalIOI2CDriver::_setSDA(bool value) const { + if (value) + _digitalIOI2CReg |= SYS573D_FPGA_MP3_I2C_SDA; + else + _digitalIOI2CReg &= ~SYS573D_FPGA_MP3_I2C_SCL; + + SYS573D_FPGA_MP3_I2C = _digitalIOI2CReg; +} + +void DigitalIOI2CDriver::_setSCL(bool value) const { + if (value) + _digitalIOI2CReg |= SYS573D_FPGA_MP3_I2C_SDA; + else + _digitalIOI2CReg &= ~SYS573D_FPGA_MP3_I2C_SCL; + + SYS573D_FPGA_MP3_I2C = _digitalIOI2CReg; +} + +const CartI2CDriver cartI2C; +const DigitalIOI2CDriver digitalIOI2C; + /* 1-wire driver */ static constexpr int _DS_RESET_LOW_TIME = 480; @@ -471,95 +519,76 @@ static constexpr int _DS_ZERO_HIGH_TIME = 5; static constexpr int _DS_ONE_LOW_TIME = 10; static constexpr int _DS_ONE_HIGH_TIME = 55; -#define _CART1WIRE(value) setCartOutput(OUT_1WIRE, !(value)) -#define _DIO1WIRE(value) setDIO1Wire(value) +bool OneWireDriver::reset(void) const { + _set(false, _DS_RESET_LOW_TIME); + _set(true, _DS_RESET_SAMPLE_DELAY); + bool present = _get(); -bool dsCartReset(void) { - _CART1WIRE(false); - delayMicroseconds(_DS_RESET_LOW_TIME); - _CART1WIRE(true); - - delayMicroseconds(_DS_RESET_SAMPLE_DELAY); - bool present = !getCartInput(IN_1WIRE); delayMicroseconds(_DS_RESET_DELAY); - - return present; + return present ^ 1; } -bool dsDIOReset(void) { - _DIO1WIRE(false); - delayMicroseconds(_DS_RESET_LOW_TIME); - _DIO1WIRE(true); - - delayMicroseconds(_DS_RESET_SAMPLE_DELAY); - bool present = !getDIO1Wire(); - delayMicroseconds(_DS_RESET_DELAY); - - return present; -} - -uint8_t dsCartReadByte(void) { +uint8_t OneWireDriver::readByte(void) const { uint8_t value = 0; - for (int bit = 0; bit < 8; bit++) { // LSB first - _CART1WIRE(false); - delayMicroseconds(_DS_READ_LOW_TIME); - _CART1WIRE(true); - delayMicroseconds(_DS_READ_SAMPLE_DELAY); - if (getCartInput(IN_1WIRE)) - value |= (1 << bit); + for (int i = 0; i < 8; i++) { // LSB first + _set(false, _DS_READ_LOW_TIME); + _set(true, _DS_READ_SAMPLE_DELAY); + value |= _get() << i; delayMicroseconds(_DS_READ_DELAY); } return value; } -uint8_t dsDIOReadByte(void) { - uint8_t value = 0; - - for (int bit = 0; bit < 8; bit++) { // LSB first - _DIO1WIRE(false); - delayMicroseconds(_DS_READ_LOW_TIME); - _DIO1WIRE(true); - delayMicroseconds(_DS_READ_SAMPLE_DELAY); - if (getDIO1Wire()) - value |= (1 << bit); - delayMicroseconds(_DS_READ_DELAY); - } - - return value; -} - -void dsCartWriteByte(uint8_t value) { - for (int bit = 0; bit < 8; bit++) { // LSB first - if (value & (1 << bit)) { - _CART1WIRE(false); - delayMicroseconds(_DS_ONE_LOW_TIME); - _CART1WIRE(true); - delayMicroseconds(_DS_ONE_HIGH_TIME); +void OneWireDriver::writeByte(uint8_t value) const { + for (int i = 8; i; i--, value >>= 1) { // LSB first + if (value & 1) { + _set(false, _DS_ONE_LOW_TIME); + _set(true, _DS_ONE_HIGH_TIME); } else { - _CART1WIRE(false); - delayMicroseconds(_DS_ZERO_LOW_TIME); - _CART1WIRE(true); - delayMicroseconds(_DS_ZERO_HIGH_TIME); + _set(false, _DS_ZERO_LOW_TIME); + _set(true, _DS_ZERO_HIGH_TIME); } } } -void dsDIOWriteByte(uint8_t value) { - for (int bit = 0; bit < 8; bit++) { // LSB first - if (value & (1 << bit)) { - _DIO1WIRE(false); - delayMicroseconds(_DS_ONE_LOW_TIME); - _DIO1WIRE(true); - delayMicroseconds(_DS_ONE_HIGH_TIME); - } else { - _DIO1WIRE(false); - delayMicroseconds(_DS_ZERO_LOW_TIME); - _DIO1WIRE(true); - delayMicroseconds(_DS_ZERO_HIGH_TIME); - } - } +bool CartDS2401Driver::_get(void) const { + return getCartInput(CART_INPUT_DS2401); } +void CartDS2401Driver::_set(bool value) const { + setCartOutput(CART_OUTPUT_DS2401, value ^ 1); +} + +bool DigitalIODS2401Driver::_get(void) const { + return (SYS573D_FPGA_DS_BUS / SYS573D_FPGA_DS_BUS_DS2401) & 1; +} + +void DigitalIODS2401Driver::_set(bool value) const { + if (value) + _digitalIODSBusReg &= ~SYS573D_FPGA_DS_BUS_DS2401; + else + _digitalIODSBusReg |= SYS573D_FPGA_DS_BUS_DS2401; + + SYS573D_FPGA_DS_BUS = _digitalIODSBusReg; +} + +bool DigitalIODS2433Driver::_get(void) const { + return (SYS573D_FPGA_DS_BUS / SYS573D_FPGA_DS_BUS_DS2433) & 1; +} + +void DigitalIODS2433Driver::_set(bool value) const { + if (value) + _digitalIODSBusReg &= ~SYS573D_FPGA_DS_BUS_DS2433; + else + _digitalIODSBusReg |= SYS573D_FPGA_DS_BUS_DS2433; + + SYS573D_FPGA_DS_BUS = _digitalIODSBusReg; +} + +const CartDS2401Driver cartDS2401; +const DigitalIODS2401Driver digitalIODS2401; +const DigitalIODS2433Driver digitalIODS2433; + } diff --git a/src/common/io.hpp b/src/common/io.hpp index 1f474b6..db6967d 100644 --- a/src/common/io.hpp +++ b/src/common/io.hpp @@ -7,6 +7,7 @@ #include "common/util.hpp" #include "ps1/registers.h" #include "ps1/registers573.h" +#include "ps1/system.h" namespace io { @@ -52,27 +53,27 @@ enum JAMMAInput : uint32_t { }; enum CartInputPin { - IN_1WIRE = 6 + CART_INPUT_DS2401 = 6 }; enum CartOutputPin { - OUT_SDA = 0, - OUT_SCL = 1, - OUT_CS = 2, - OUT_RESET = 3, - OUT_1WIRE = 4 + CART_OUTPUT_SDA = 0, + CART_OUTPUT_SCL = 1, + CART_OUTPUT_CS = 2, + CART_OUTPUT_RESET = 3, + CART_OUTPUT_DS2401 = 4 }; enum MiscOutputPin { - MISC_ADC_MOSI = 0, - MISC_ADC_CS = 1, - MISC_ADC_SCK = 2, - MISC_COIN_COUNT1 = 3, - MISC_COIN_COUNT2 = 4, - MISC_AMP_ENABLE = 5, - MISC_CDDA_ENABLE = 6, - MISC_SPU_ENABLE = 7, - MISC_JVS_RESET = 8 + MISC_OUT_ADC_DI = 0, + MISC_OUT_ADC_CS = 1, + MISC_OUT_ADC_CLK = 2, + MISC_OUT_COIN_COUNT1 = 3, + MISC_OUT_COIN_COUNT2 = 4, + MISC_OUT_AMP_ENABLE = 5, + MISC_OUT_CDDA_ENABLE = 6, + MISC_OUT_SPU_ENABLE = 7, + MISC_OUT_JVS_RESET = 8 }; /* Inputs */ @@ -106,10 +107,6 @@ static inline bool getCartInput(CartInputPin pin) { return (SYS573_DIP_CART >> (8 + pin)) & 1; } -static inline bool getCartSDA(void) { - return (SYS573_MISC_IN / SYS573_MISC_IN_CART_SDA) & 1; -} - static inline void setCartOutput(CartOutputPin pin, bool value) { if (value) _cartOutputReg |= 1 << pin; @@ -125,7 +122,7 @@ static inline void setFlashBank(int bank) { SYS573_BANK_CTRL = _bankSwitchReg; } -static inline void setCartSDADir(bool dir) { +static inline void setCartSDADirection(bool dir) { if (dir) _bankSwitchReg |= 1 << 6; else @@ -143,22 +140,112 @@ static inline void setMiscOutput(MiscOutputPin pin, bool value) { SYS573_MISC_OUT = _miscOutputReg; } -/* Digital I/O board driver */ +/* I2C driver */ -static inline bool isDigitalIOPresent(void) { - return ( - (SYS573D_CPLD_STAT & (SYS573D_CPLD_STAT_ID1 | SYS573D_CPLD_STAT_ID2)) == - SYS573D_CPLD_STAT_ID2 - ); -} +class I2CDriver { +private: + inline void _setSDA(bool value, int delay) const { + _setSDA(value); + delayMicroseconds(delay); + } + inline void _setSCL(bool value, int delay) const { + _setSCL(value); + delayMicroseconds(delay); + } + inline void _setCS(bool value, int delay) const { + _setCS(value); + delayMicroseconds(delay); + } + inline void _setReset(bool value, int delay) const { + _setReset(value); + delayMicroseconds(delay); + } -static inline bool getDIO1Wire(void) { - return (SYS573D_FPGA_DS_BUS / SYS573D_FPGA_DS_BUS_DS2401) & 1; -} + virtual bool _getSDA(void) const { return true; } + virtual void _setSDA(bool value) const {} + virtual void _setSCL(bool value) const {} + virtual void _setCS(bool value) const {} + virtual void _setReset(bool value) const {} -static inline void setDIO1Wire(bool value) { - SYS573D_FPGA_DS_BUS = (value ^ 1) * SYS573D_FPGA_DS_BUS_DS2401; -} +public: + void start(void) const; + void startWithCS(int csDelay = 0) const; + void stop(void) const; + void stopWithCS(int csDelay = 0) const; + + bool getACK(void) const; + void sendACK(bool value) const; + uint8_t readByte(void) const; + void writeByte(uint8_t value) const; + + void readBytes(uint8_t *data, size_t length) const; + bool writeBytes( + const uint8_t *data, size_t length, int lastACKDelay = 0 + ) const; + + uint32_t resetX76(void) const; + uint32_t resetZS01(void) const; +}; + +class CartI2CDriver : public I2CDriver { +private: + bool _getSDA(void) const; + void _setSDA(bool value) const; + void _setSCL(bool value) const; + void _setCS(bool value) const; + void _setReset(bool value) const; +}; + +class DigitalIOI2CDriver : public I2CDriver { +private: + bool _getSDA(void) const; + void _setSDA(bool value) const; + void _setSCL(bool value) const; +}; + +extern const CartI2CDriver cartI2C; +extern const DigitalIOI2CDriver digitalIOI2C; + +/* 1-wire driver */ + +class OneWireDriver { +private: + inline void _set(bool value, int delay) const { + _set(value); + delayMicroseconds(delay); + } + + virtual bool _get(void) const { return true; } + virtual void _set(bool value) const {} + +public: + bool reset(void) const; + + uint8_t readByte(void) const; + void writeByte(uint8_t value) const; +}; + +class CartDS2401Driver : public OneWireDriver { +private: + bool _get(void) const; + void _set(bool value) const; +}; + +class DigitalIODS2401Driver : public OneWireDriver { +private: + bool _get(void) const; + void _set(bool value) const; +}; + +class DigitalIODS2433Driver : public OneWireDriver { +private: + bool _get(void) const; + void _set(bool value) const; +}; + +extern const CartDS2401Driver cartDS2401; +extern const DigitalIODS2401Driver digitalIODS2401; +extern const DigitalIODS2433Driver digitalIODS2433; /* Other APIs */ @@ -171,30 +258,9 @@ void getRTCTime(util::Date &output); void setRTCTime(const util::Date &value, bool stop = false); bool isRTCBatteryLow(void); -bool loadBitstream(const uint8_t *data, size_t length); -bool loadRawBitstream(const uint8_t *data, size_t length); -void initKonamiBitstream(void); - -void i2cStart(void); -void i2cStartWithCS(int csDelay = 0); -void i2cStop(void); -void i2cStopWithCS(int csDelay = 0); - -uint8_t i2cReadByte(void); -void i2cWriteByte(uint8_t value); -void i2cSendACK(bool ack); -bool i2cGetACK(void); -void i2cReadBytes(uint8_t *data, size_t length); -bool i2cWriteBytes(const uint8_t *data, size_t length, int lastACKDelay = 0); - -uint32_t i2cResetX76(void); -uint32_t i2cResetZS01(void); - -bool dsCartReset(void); -bool dsDIOReset(void); -uint8_t dsCartReadByte(void); -uint8_t dsDIOReadByte(void); -void dsCartWriteByte(uint8_t value); -void dsDIOWriteByte(uint8_t value); +bool isDigitalIOPresent(void); +bool loadDigitalIOBitstream(const uint8_t *data, size_t length); +bool loadDigitalIORawBitstream(const uint8_t *data, size_t length); +void initDigitalIOFPGA(void); } diff --git a/src/common/rom.cpp b/src/common/rom.cpp index ef3df2d..e9276fb 100644 --- a/src/common/rom.cpp +++ b/src/common/rom.cpp @@ -224,8 +224,12 @@ const util::ExecutableHeader *FlashRegion::getBootExecutableHeader(void) const { for (size_t i = 1; i < length; i <<= 1) crc = (crc >> 8) ^ table[(crc ^ data[i]) & 0xff]; - if (~crc != *crcPtr) + if (~crc != *crcPtr) { + LOG_ROM("CRC32 mismatch"); + LOG_ROM("exp=0x%08x", ~crc); + LOG_ROM("got=0x%08x", *crcPtr); return nullptr; + } return header; } diff --git a/src/main/app/cartworkers.cpp b/src/main/app/cartworkers.cpp index 78b5727..0c7e7d3 100644 --- a/src/main/app/cartworkers.cpp +++ b/src/main/app/cartworkers.cpp @@ -98,7 +98,9 @@ _cartInitDone: return true; } - ready = io::loadBitstream(bitstream.as(), bitstream.length); + ready = io::loadDigitalIOBitstream( + bitstream.as(), bitstream.length + ); bitstream.destroy(); if (!ready) { @@ -107,7 +109,7 @@ _cartInitDone: } delayMicroseconds(5000); // Probably not necessary - io::initKonamiBitstream(); + io::initDigitalIOFPGA(); auto error = _cartDriver->readSystemID(); diff --git a/src/main/app/tests.cpp b/src/main/app/tests.cpp index f60970c..d5f10a1 100644 --- a/src/main/app/tests.cpp +++ b/src/main/app/tests.cpp @@ -205,19 +205,19 @@ void AudioTestScreen::playBoth(ui::Context &ctx) { } void AudioTestScreen::enableAmp(ui::Context &ctx) { - io::setMiscOutput(io::MISC_AMP_ENABLE, true); + io::setMiscOutput(io::MISC_OUT_AMP_ENABLE, true); } void AudioTestScreen::disableAmp(ui::Context &ctx) { - io::setMiscOutput(io::MISC_AMP_ENABLE, false); + io::setMiscOutput(io::MISC_OUT_AMP_ENABLE, false); } void AudioTestScreen::enableCDDA(ui::Context &ctx) { - io::setMiscOutput(io::MISC_CDDA_ENABLE, true); + io::setMiscOutput(io::MISC_OUT_CDDA_ENABLE, true); } void AudioTestScreen::disableCDDA(ui::Context &ctx) { - io::setMiscOutput(io::MISC_CDDA_ENABLE, false); + io::setMiscOutput(io::MISC_OUT_CDDA_ENABLE, false); } void AudioTestScreen::show(ui::Context &ctx, bool goBack) { @@ -236,8 +236,8 @@ void AudioTestScreen::update(ui::Context &ctx) { if (ctx.buttons.pressed(ui::BTN_START)) { if (ctx.buttons.held(ui::BTN_LEFT) || ctx.buttons.held(ui::BTN_RIGHT)) { #if 0 - io::setMiscOutput(io::MISC_AMP_ENABLE, false); - io::setMiscOutput(io::MISC_CDDA_ENABLE, false); + io::setMiscOutput(io::MISC_OUT_AMP_ENABLE, false); + io::setMiscOutput(io::MISC_OUT_CDDA_ENABLE, false); #endif ctx.show(APP->_testMenuScreen, true, true); diff --git a/src/main/cart/cartio.cpp b/src/main/cart/cartio.cpp index 4f58f87..037808f 100644 --- a/src/main/cart/cartio.cpp +++ b/src/main/cart/cartio.cpp @@ -117,6 +117,13 @@ DriverError DummyDriver::setDataKey(const uint8_t *key) { /* Functions common to all cartridge drivers */ +enum DS2401Command : uint8_t { + _DS2401_READ_ROM = 0x33, + _DS2401_MATCH_ROM = 0x55, + _DS2401_SKIP_ROM = 0xcc, + _DS2401_SEARCH_ROM = 0xf0 +}; + // TODO: _ZS01_SEND_DELAY and _ZS01_PACKET_DELAY could be tweaked to make the // tool faster, however setting both to 30000 results in bricked carts when // attempting to reflash. @@ -129,7 +136,7 @@ static constexpr int _ZS01_PACKET_DELAY = 300000; DriverError CartDriver::readSystemID(void) { auto enable = disableInterrupts(); - if (!io::dsDIOReset()) { + if (!io::digitalIODS2401.reset()) { if (enable) enableInterrupts(); @@ -139,9 +146,9 @@ DriverError CartDriver::readSystemID(void) { _dump.flags |= DUMP_HAS_SYSTEM_ID; - io::dsDIOWriteByte(0x33); + io::digitalIODS2401.writeByte(_DS2401_READ_ROM); for (int i = 0; i < 8; i++) - _dump.systemID.data[i] = io::dsDIOReadByte(); + _dump.systemID.data[i] = io::digitalIODS2401.readByte(); if (enable) enableInterrupts(); @@ -155,7 +162,7 @@ DriverError CartDriver::readSystemID(void) { DriverError X76Driver::readCartID(void) { auto enable = disableInterrupts(); - if (!io::dsCartReset()) { + if (!io::cartDS2401.reset()) { if (enable) enableInterrupts(); @@ -165,9 +172,9 @@ DriverError X76Driver::readCartID(void) { _dump.flags |= DUMP_HAS_CART_ID; - io::dsCartWriteByte(0x33); + io::cartDS2401.writeByte(_DS2401_READ_ROM); for (int i = 0; i < 8; i++) - _dump.cartID.data[i] = io::dsCartReadByte(); + _dump.cartID.data[i] = io::cartDS2401.readByte(); if (enable) enableInterrupts(); @@ -182,26 +189,26 @@ DriverError X76Driver::_x76Command( uint8_t pollByte, uint8_t cmd, int param ) const { delayMicroseconds(_X76_PACKET_DELAY); - io::i2cStartWithCS(); + io::cartI2C.startWithCS(); - io::i2cWriteByte(cmd); - if (!io::i2cGetACK()) { - io::i2cStopWithCS(); + io::cartI2C.writeByte(cmd); + if (!io::cartI2C.getACK()) { + io::cartI2C.stopWithCS(); LOG_CART_IO("NACK while sending cmd=0x%02x", cmd); return X76_NACK; } if (param >= 0) { - io::i2cWriteByte(param); - if (!io::i2cGetACK()) { - io::i2cStopWithCS(); + io::cartI2C.writeByte(param); + if (!io::cartI2C.getACK()) { + io::cartI2C.stopWithCS(); LOG_CART_IO("NACK while sending param=0x%02x", param); return X76_NACK; } } - if (!io::i2cWriteBytes(_dump.dataKey, sizeof(_dump.dataKey))) { - io::i2cStopWithCS(); + if (!io::cartI2C.writeBytes(_dump.dataKey, sizeof(_dump.dataKey))) { + io::cartI2C.stopWithCS(); LOG_CART_IO("NACK while sending data key"); return X76_NACK; } @@ -218,13 +225,13 @@ DriverError X76Driver::_x76Command( for (int i = _X76_MAX_ACK_POLLS; i; i--) { delayMicroseconds(_X76_WRITE_DELAY); - io::i2cStart(); - io::i2cWriteByte(pollByte); - if (io::i2cGetACK()) + io::cartI2C.start(); + io::cartI2C.writeByte(pollByte); + if (io::cartI2C.getACK()) return NO_ERROR; } - io::i2cStopWithCS(); + io::cartI2C.stopWithCS(); LOG_CART_IO("ACK polling timeout (wrong key?)"); return X76_POLL_FAIL; } @@ -255,18 +262,18 @@ DriverError X76F041Driver::readPrivateData(void) { if (error) return error; - io::i2cReadByte(); // Ignore "secure read setup" byte - io::i2cStart(); + io::cartI2C.readByte(); // Ignore "secure read setup" byte + io::cartI2C.start(); - io::i2cWriteByte(i & 0xff); - if (!io::i2cGetACK()) { - io::i2cStopWithCS(); + io::cartI2C.writeByte(i & 0xff); + if (!io::cartI2C.getACK()) { + io::cartI2C.stopWithCS(); LOG_CART_IO("NACK after resending addr=0x%02x", i & 0xff); return X76_NACK; } - io::i2cReadBytes(&_dump.data[i], 128); - io::i2cStopWithCS(); + io::cartI2C.readBytes(&_dump.data[i], 128); + io::cartI2C.stopWithCS(); } _dump.flags |= DUMP_PRIVATE_DATA_OK; @@ -278,8 +285,8 @@ DriverError X76F041Driver::readPrivateData(void) { return error; util::clear(_dump.config); - io::i2cReadBytes(_dump.config, 5); - io::i2cStopWithCS(); + io::cartI2C.readBytes(_dump.config, 5); + io::cartI2C.stopWithCS(); _dump.flags |= DUMP_CONFIG_OK; return NO_ERROR; @@ -294,8 +301,8 @@ DriverError X76F041Driver::writeData(void) { if (error) return error; - auto ok = io::i2cWriteBytes(&_dump.data[i], 8); - io::i2cStopWithCS(_X76_WRITE_DELAY); + auto ok = io::cartI2C.writeBytes(&_dump.data[i], 8); + io::cartI2C.stopWithCS(_X76_WRITE_DELAY); if (!ok) { LOG_CART_IO("NACK while sending data bytes"); @@ -309,8 +316,8 @@ DriverError X76F041Driver::writeData(void) { if (error) return error; - auto ok = io::i2cWriteBytes(_dump.config, 5); - io::i2cStopWithCS(_X76_WRITE_DELAY); + auto ok = io::cartI2C.writeBytes(_dump.config, 5); + io::cartI2C.stopWithCS(_X76_WRITE_DELAY); if (!ok) { LOG_CART_IO("NACK while sending config registers"); @@ -327,7 +334,7 @@ DriverError X76F041Driver::erase(void) { if (error) return error; - io::i2cStopWithCS(_X76_WRITE_DELAY); + io::cartI2C.stopWithCS(_X76_WRITE_DELAY); util::clear(_dump.dataKey); return NO_ERROR; @@ -343,14 +350,14 @@ DriverError X76F041Driver::setDataKey(const uint8_t *key) { // The X76F041 requires the key to be sent twice as a way of ensuring it // gets received correctly. for (int i = 2; i; i--) { - if (!io::i2cWriteBytes(key, sizeof(_dump.dataKey))) { - io::i2cStopWithCS(_X76_WRITE_DELAY); + if (!io::cartI2C.writeBytes(key, sizeof(_dump.dataKey))) { + io::cartI2C.stopWithCS(_X76_WRITE_DELAY); LOG_CART_IO("NACK while setting new data key"); return X76_NACK; } } - io::i2cStopWithCS(_X76_WRITE_DELAY); + io::cartI2C.stopWithCS(_X76_WRITE_DELAY); _dump.copyKeyFrom(key); return NO_ERROR; @@ -370,9 +377,9 @@ DriverError X76F100Driver::readPrivateData(void) { if (error) return error; - //io::i2cStart(); - io::i2cReadBytes(_dump.data, 112); - io::i2cStopWithCS(); + //io::cartI2C.Start(); + io::cartI2C.readBytes(_dump.data, 112); + io::cartI2C.stopWithCS(); _dump.flags |= DUMP_PRIVATE_DATA_OK; return NO_ERROR; @@ -387,8 +394,8 @@ DriverError X76F100Driver::writeData(void) { if (error) return error; - auto ok = io::i2cWriteBytes(&_dump.data[i], 8); - io::i2cStopWithCS(_X76_WRITE_DELAY); + auto ok = io::cartI2C.writeBytes(&_dump.data[i], 8); + io::cartI2C.stopWithCS(_X76_WRITE_DELAY); if (!ok) { LOG_CART_IO("NACK while sending data bytes"); @@ -411,8 +418,8 @@ DriverError X76F100Driver::erase(void) { if (error) return error; - auto ok = io::i2cWriteBytes(dummy, 8); - io::i2cStopWithCS(_X76_WRITE_DELAY); + auto ok = io::cartI2C.writeBytes(dummy, 8); + io::cartI2C.stopWithCS(_X76_WRITE_DELAY); if (!ok) { LOG_CART_IO("NACK while sending data bytes"); @@ -433,8 +440,8 @@ DriverError X76F100Driver::setDataKey(const uint8_t *key) { if (error) return error; - auto ok = io::i2cWriteBytes(key, sizeof(_dump.dataKey)); - io::i2cStopWithCS(_X76_WRITE_DELAY); + auto ok = io::cartI2C.writeBytes(key, sizeof(_dump.dataKey)); + io::cartI2C.stopWithCS(_X76_WRITE_DELAY); if (!ok) { LOG_CART_IO("NACK while setting new data key"); @@ -450,7 +457,7 @@ DriverError X76F100Driver::setDataKey(const uint8_t *key) { DriverError ZS01Driver::_transact(ZS01Packet &request, ZS01Packet &response) { delayMicroseconds(_ZS01_PACKET_DELAY); - io::i2cStart(); + io::cartI2C.start(); #if 0 char buffer[48]; @@ -459,16 +466,16 @@ DriverError ZS01Driver::_transact(ZS01Packet &request, ZS01Packet &response) { LOG_CART_IO("S: %s", buffer); #endif - if (!io::i2cWriteBytes( + if (!io::cartI2C.writeBytes( &request.command, sizeof(ZS01Packet), _ZS01_SEND_DELAY )) { - io::i2cStop(); + io::cartI2C.stop(); LOG_CART_IO("NACK while sending request packet"); return ZS01_NACK; } - io::i2cReadBytes(&response.command, sizeof(ZS01Packet)); - io::i2cStop(); + io::cartI2C.readBytes(&response.command, sizeof(ZS01Packet)); + io::cartI2C.stop(); #if 0 util::hexToString(buffer, &response.command, sizeof(ZS01Packet), ' '); @@ -651,14 +658,14 @@ CartDriver *newCartDriver(CartDump &dump) { } #ifdef ENABLE_ZS01_CART_DRIVER - uint32_t id1 = io::i2cResetZS01(); + auto id1 = io::cartI2C.resetZS01(); LOG_CART_IO("detecting ZS01: 0x%08x", id1); if (id1 == _ID_ZS01) return new ZS01Driver(dump); #endif - uint32_t id2 = io::i2cResetX76(); + auto id2 = io::cartI2C.resetX76(); LOG_CART_IO("detecting X76: 0x%08x", id2); switch (id2) { diff --git a/src/main/main.cpp b/src/main/main.cpp index 95b032e..764852e 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -41,7 +41,7 @@ int main(int argc, const char **argv) { gpu::enableDisplay(true); spu::setMasterVolume(spu::MAX_VOLUME / 2); - io::setMiscOutput(io::MISC_SPU_ENABLE, true); + io::setMiscOutput(io::MISC_OUT_SPU_ENABLE, true); app->run(args.resourcePtr, args.resourceLength); diff --git a/src/ps1/registers573.h b/src/ps1/registers573.h index 651f0e2..0aa19d1 100644 --- a/src/ps1/registers573.h +++ b/src/ps1/registers573.h @@ -21,9 +21,9 @@ /* System 573 base hardware */ typedef enum { - SYS573_MISC_OUT_ADC_MOSI = 1 << 0, + SYS573_MISC_OUT_ADC_DI = 1 << 0, SYS573_MISC_OUT_ADC_CS = 1 << 1, - SYS573_MISC_OUT_ADC_SCK = 1 << 2, + SYS573_MISC_OUT_ADC_CLK = 1 << 2, SYS573_MISC_OUT_COIN_COUNT1 = 1 << 3, SYS573_MISC_OUT_COIN_COUNT2 = 1 << 4, SYS573_MISC_OUT_AMP_ENABLE = 1 << 5, @@ -33,7 +33,7 @@ typedef enum { } Sys573MiscOutputFlag; typedef enum { - SYS573_MISC_IN_ADC_MISO = 1 << 0, + SYS573_MISC_IN_ADC_DO = 1 << 0, SYS573_MISC_IN_ADC_SARS = 1 << 1, SYS573_MISC_IN_CART_SDA = 1 << 2, SYS573_MISC_IN_JVS_SENSE = 1 << 3, @@ -137,6 +137,11 @@ typedef enum { SYS573D_CPLD_CTRL_UNKNOWN = 1 << 15 } Sys573DCPLDControlFlag; +typedef enum { + SYS573D_FPGA_MP3_I2C_SDA = 1 << 12, + SYS573D_FPGA_MP3_I2C_SCL = 1 << 13 +} Sys573DFPGAMP3I2CFlag; + typedef enum { SYS573D_FPGA_DS_BUS_DS2433 = 1 << 8, SYS573D_FPGA_DS_BUS_DS2401 = 1 << 12 @@ -144,6 +149,8 @@ typedef enum { #define SYS573D_FPGA_MAGIC _MMIO16(DEV0_BASE | 0x640080) +#define SYS573D_FPGA_NET_ID _MMIO16(DEV0_BASE | 0x640090) + #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)