mirror of
https://github.com/rdolbeau/NuBusFPGA.git
synced 2024-06-16 07:29:28 +00:00
Compare commits
5 Commits
824806768a
...
0a4e49f2b2
Author | SHA1 | Date | |
---|---|---|---|
|
0a4e49f2b2 | ||
|
e5b036d044 | ||
|
24f570d9ee | ||
|
96bf6d55e7 | ||
|
4baf007f31 |
15
README.md
15
README.md
|
@ -22,9 +22,9 @@ Directory 'nubus-to-ztex'
|
||||||
|
|
||||||
The (now obsolete) V1.0 custom board is a NuBus-compliant (I hope...) board, designed to receive a [ZTex USB-FPGA Module 2.13](https://www.ztex.de/usb-fpga-2/usb-fpga-2.13.e.html) as a daughterboard. The ZTex module contains the actual FPGA (Artix-7), some RAM, programming hardware, etc. The NuBus board contains level-shifters & drivers ICs to interface between the NuBus signals and the FPGA, a CPLD handling some level-shifting & the bus mastering arbitration, a serial header, two user Leds, 14 debug Leds tied to specific NuBus or CPLD/FPGA signals, a JTAG header, a USB micro-B connector, a VGA chip & connector, and a HDMI chip & connector. It supports every NuBus feature except the optional parity (i.e. it can do both slave and master modes). The V1.0 board is in commit 3f3371a. The CPLD solution works but is annoying as it requires older Xilinx software (ISE 14.7) and dedicated JTAG programmer to use.
|
The (now obsolete) V1.0 custom board is a NuBus-compliant (I hope...) board, designed to receive a [ZTex USB-FPGA Module 2.13](https://www.ztex.de/usb-fpga-2/usb-fpga-2.13.e.html) as a daughterboard. The ZTex module contains the actual FPGA (Artix-7), some RAM, programming hardware, etc. The NuBus board contains level-shifters & drivers ICs to interface between the NuBus signals and the FPGA, a CPLD handling some level-shifting & the bus mastering arbitration, a serial header, two user Leds, 14 debug Leds tied to specific NuBus or CPLD/FPGA signals, a JTAG header, a USB micro-B connector, a VGA chip & connector, and a HDMI chip & connector. It supports every NuBus feature except the optional parity (i.e. it can do both slave and master modes). The V1.0 board is in commit 3f3371a. The CPLD solution works but is annoying as it requires older Xilinx software (ISE 14.7) and dedicated JTAG programmer to use.
|
||||||
|
|
||||||
The current board is V1.2. It drops the CPLD and VGA port. Bus arbitration is now done inside the FPGA. It gains a micro-sd slot, and a custom expansion connector that is based (and compatible with, with more signals) PMod. It supports the same accelerated HDMI framebuffer and RAM Disk. Optionally, The Declaration Rom can be stored in a Flash NOR chip connected ot the PMOd expansion connector (easier for working on embedded driver in the DeclRom). The ROM can alternately be stored in a sector of the config flash from the ZTex board.
|
The current board is V1.2. It drops the CPLD and VGA port. Bus arbitration is now done inside the FPGA. It gains a micro-sd slot, and a custom expansion connector that is based (and compatible with, with more signals) PMod. It supports the same accelerated HDMI framebuffer and RAM Disk. Optionally, The Declaration Rom can be stored in a Flash NOR chip connected ot the PMOd expansion connector (easier for working on embedded driver in the DeclRom). The ROM can alternately be stored in a sector of the config flash from the ZTex board on any *FPGA.
|
||||||
|
|
||||||
The new (July 2023) [ZTex USB-FPGA Module 2.12](https://www.ztex.de/usb-fpga-2/usb-fpga-2.12.e.html) should be compatible with all *FPGA, but has not yet been tested.
|
The new (July 2023) [ZTex USB-FPGA Module 2.12](https://www.ztex.de/usb-fpga-2/usb-fpga-2.12.e.html) is theoretically compatible with all *FPGA, but at this stage there is some issue when using the 2.12b I own. Some further tests are planned.
|
||||||
|
|
||||||
The PCBs were designed with Kicad 5.1
|
The PCBs were designed with Kicad 5.1
|
||||||
|
|
||||||
|
@ -46,13 +46,15 @@ The Declaration ROM is in the subdirectory VintageBusFPGA_Common/DeclROM and inc
|
||||||
|
|
||||||
The code for the NuBusFPGAInit (which should be renamed and enables acceleration) is in NuBusFPGAInit/, and will need a CodeWarrior INIT project to build, on a real Macintosh or an emulated one using e.g. Qemu. It enables graphic acceleration.
|
The code for the NuBusFPGAInit (which should be renamed and enables acceleration) is in NuBusFPGAInit/, and will need a CodeWarrior INIT project to build, on a real Macintosh or an emulated one using e.g. Qemu. It enables graphic acceleration.
|
||||||
|
|
||||||
The code for the Audio component (which enables audio support over HDMI) is in NuBusFPGAHDMIAudio/.
|
The code for the Audio component (which enables audio support over HDMI when using the alternate PHY) is in NuBusFPGAHDMIAudio/.
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
* Can the framebuffer change resolution ?
|
* Can the framebuffer change resolution ?
|
||||||
No and yes. No, it cannot change the resolution outputed through the HDMI connector by software. That is currently 'gatewired' into the FPGA configuration, so the board needs a new bitstream to change resolution. Yes, you can change the resolution in System 7 / MacOS 8 by software, but the new resolution is 'windowbowed' in the middle of the screen (e.g. it can display 640x480 surrounded by lots of black pixels in the middle of a Full HD LCD).
|
Yes and no. The gateware has a default resolution baked into it that the device will use by default, and can use one of two different physical interface (PHY): the Litex-derived one (which uses DVI signalling) or a more HDMI-like one in verilog. "windowboxed" mode is always availeble, where a smaller esolution is displayed in the middle of the larger screen, which you can select in System 7/MacOS 8 with the Monitor control panel. When using the Litex PHY, some resolution are also available as "hardware" resolution, outputing the appropriate signalling - but the Litex PHY doesn't support audio. The alternate PHY does support audio, but doesn't allow to use a different output resolution, only Full HD (1920x1080) and does support audio output.
|
||||||
This is a 'gateware' (configuration of the FPGA) limitation. Changing the output resolution requires changing the pixel clock, which is possible but not easy to do. There is currently no plan to remove that limitation, but the gateware is open-source and contributions are welcome :-)
|
|
||||||
|
* Is Audio supported ?
|
||||||
|
Yes and no. a 8 or 16-bits, audio or stereo, 44.1 KHz audio device is available but nly when using the alternate HDMI PHY (see previous question)
|
||||||
|
|
||||||
* Is USB supported ?
|
* Is USB supported ?
|
||||||
No. There is a USB connector, but it is currently useless. The gateware could include a USB OHCI host device, and that is supported in the SBusFPGA under NetBSD. However, no Apple OS running on a 68k Mac has any support for USB, so it would require an entire USB stack to be ported, which is a huge undertaking. Also, NuBus is quite a slow bus even by early 2000s standard, and USB OHCI does a lot of DMA all the time, which would use up most if not all (or maybe more than all!) the available bandwidth. There might be some support in NetBSD/mac68k eventually just to test feasibility, but it even there it's unlikely to be useful.
|
No. There is a USB connector, but it is currently useless. The gateware could include a USB OHCI host device, and that is supported in the SBusFPGA under NetBSD. However, no Apple OS running on a 68k Mac has any support for USB, so it would require an entire USB stack to be ported, which is a huge undertaking. Also, NuBus is quite a slow bus even by early 2000s standard, and USB OHCI does a lot of DMA all the time, which would use up most if not all (or maybe more than all!) the available bandwidth. There might be some support in NetBSD/mac68k eventually just to test feasibility, but it even there it's unlikely to be useful.
|
||||||
|
@ -68,8 +70,9 @@ The code for the Audio component (which enables audio support over HDMI) is in N
|
||||||
|
|
||||||
* How about adding Ethernet ?
|
* How about adding Ethernet ?
|
||||||
Software is the issue. Ethernet is supported by the gateware infrastructure, and a prototype design to add Fast Ethernet via RMII through the expansion connector is available. However, there is currently no software support for it. There's some documentation from Apple, and there's [an example driver available](http://www.mactcp.org.nz/ethernet.html), but the System 7/MacOS 8 driver for LiteEth is still to be written.
|
Software is the issue. Ethernet is supported by the gateware infrastructure, and a prototype design to add Fast Ethernet via RMII through the expansion connector is available. However, there is currently no software support for it. There's some documentation from Apple, and there's [an example driver available](http://www.mactcp.org.nz/ethernet.html), but the System 7/MacOS 8 driver for LiteEth is still to be written.
|
||||||
|
The [SEthernet](https://github.com/rhalkyard/SEthernet) project is a much more likely source of Ethernet for '030-based system.
|
||||||
|
|
||||||
* Why slow NuBus, when PDS is so much faster ?
|
* Why slow NuBus, when PDS is so much faster ?
|
||||||
NuBus is well documented, and electrically quite isolated from the rest of the machine. Safer to play with than PDS which is directly connected to the CPU. And the connector for it it still in general use and easy to get. And NuBus is available on multiple generations of machines.
|
NuBus is well documented, and electrically quite isolated from the rest of the machine. Safer to play with than PDS which is directly connected to the CPU. And the connector for it it still in general use and easy to get. And NuBus is available on multiple generations of machines.
|
||||||
My primary machine for this is a Quadra 650, with a 68040 and the associated PDS. Unfortunately, the connector for that PDS is near impossible to get nowadadays ([specifications are there](https://tinkerdifferent.com/resources/specifications-for-the-quadra-pds-connector.124/)). '030 PDS uses 120-pins DIN 41612, similar to bur larger than NuBus' 96-pins. They are also available, but less common. But there is a catch - although sharing a connector board-side, the IIsi, SE/30 and IIfx pinouts are slightly different. And the LCIII is completely different.
|
My primary machine for this is a Quadra 650, with a 68040 and the associated PDS. Unfortunately, the connector for that PDS is near impossible to get nowadadays ([specifications are there](https://tinkerdifferent.com/resources/specifications-for-the-quadra-pds-connector.124/)). '030 PDS uses 120-pins DIN 41612, similar to bur larger than NuBus' 96-pins. They are also available, but less common. But there is a catch - although sharing a connector board-side, the IIsi, SE/30 and IIfx pinouts are slightly different. And the LCIII is completely different.
|
||||||
Also - [IIsiFPGA](https://github.com/rdolbeau/IIsiFPGA) :-)
|
Also - see [IIsiFPGA](https://github.com/rdolbeau/IIsiFPGA) and [QuadraFPGA](https://github.com/rdolbeau/QuadraFPGA) :-)
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
nubus-to-ztex-gateware/REF_20240223/2.12b/LitexPHY/rom_V1_2.bin
Normal file
BIN
nubus-to-ztex-gateware/REF_20240223/2.12b/LitexPHY/rom_V1_2.bin
Normal file
Binary file not shown.
Binary file not shown.
1
nubus-to-ztex-gateware/REF_20240223/2.13a
Symbolic link
1
nubus-to-ztex-gateware/REF_20240223/2.13a
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
2.12b
|
|
@ -1 +1 @@
|
||||||
Subproject commit 06c4327335c34b0adaac18f9a3dc9c1badc19953
|
Subproject commit 56129b4ddc3313e1566007024e0eb9505577ae10
|
|
@ -4,9 +4,9 @@
|
||||||
source /opt/Xilinx/Vivado/2023.2/settings64.sh
|
source /opt/Xilinx/Vivado/2023.2/settings64.sh
|
||||||
export LD_LIBRARY_PATH=/opt/Xilinx/Vivado/2023.2/lib/lnx64.o/SuSE
|
export LD_LIBRARY_PATH=/opt/Xilinx/Vivado/2023.2/lib/lnx64.o/SuSE
|
||||||
|
|
||||||
python3 nubus_to_fpga_soc.py --build --csr-csv csr.csv --csr-json csr.json --variant=ztex2.13a --version=V1.2 --sys-clk-freq 100e6 --goblin --goblin-res 1920x1080@60Hz --hdmi --config-flash # --ethernet # --sdcard # --flash
|
python3 nubus_to_fpga_soc.py --build --csr-csv csr.csv --csr-json csr.json --variant=ztex2.12b --version=V1.2 --sys-clk-freq 100e6 --goblin --goblin-res 1920x1080@60Hz --hdmi --config-flash --goblin-alt # --ethernet # --sdcard # --flash
|
||||||
|
|
||||||
#python3 nubus_to_fpga_soc.py --csr-csv csr.csv --csr-json csr.json --variant=ztex2.13a --version=V1.2 --sys-clk-freq 100e6
|
#python3 nubus_to_fpga_soc.py --build --csr-csv csr.csv --csr-json csr.json --variant=ztex2.13a --version=V1.2 --sys-clk-freq 100e6 --goblin --goblin-res 1280x1024@60Hz --hdmi --config-flash # --ethernet # --sdcard # --flash
|
||||||
|
|
||||||
) 2>&1 | tee build_V1_2.log
|
) 2>&1 | tee build_V1_2.log
|
||||||
# --goblin --goblin-res 1280x1024@60Hz
|
# --goblin --goblin-res 1280x1024@60Hz
|
||||||
|
|
|
@ -12,6 +12,8 @@ class MDIOCtrl(Module, AutoCSR):
|
||||||
div_clk_begin = 39
|
div_clk_begin = 39
|
||||||
div_clk_half = 20
|
div_clk_half = 20
|
||||||
|
|
||||||
|
div_clk_state_change = 2
|
||||||
|
|
||||||
sig_mdc = platform.request("sep_mdc");
|
sig_mdc = platform.request("sep_mdc");
|
||||||
sig_mdio = platform.request("sep_mdio");
|
sig_mdio = platform.request("sep_mdio");
|
||||||
mdio_o = Signal()
|
mdio_o = Signal()
|
||||||
|
@ -100,7 +102,7 @@ class MDIOCtrl(Module, AutoCSR):
|
||||||
in_preamble.eq(0),
|
in_preamble.eq(0),
|
||||||
mdio_oe.eq(0), # don't drive
|
mdio_oe.eq(0), # don't drive
|
||||||
#mdio_oe.eq(1), # drive 0 at idle ?
|
#mdio_oe.eq(1), # drive 0 at idle ?
|
||||||
If(cmd_recv & (clk_div == 2), # CHECKME
|
If(cmd_recv & (clk_div == div_clk_state_change), # CHECKME
|
||||||
NextValue(cmd_recv, 0),
|
NextValue(cmd_recv, 0),
|
||||||
NextValue(write, mdio_command.fields.write),
|
NextValue(write, mdio_command.fields.write),
|
||||||
|
|
||||||
|
@ -125,7 +127,7 @@ class MDIOCtrl(Module, AutoCSR):
|
||||||
mdio_fsm.act("Preamble",
|
mdio_fsm.act("Preamble",
|
||||||
in_preamble.eq(1),
|
in_preamble.eq(1),
|
||||||
mdio_oe.eq(1),
|
mdio_oe.eq(1),
|
||||||
If(clk_div == 2, # CHECKME
|
If(clk_div == div_clk_state_change, # CHECKME
|
||||||
If(int_cnt == 0,
|
If(int_cnt == 0,
|
||||||
NextValue(int_cnt, 31),
|
NextValue(int_cnt, 31),
|
||||||
in_preamble.eq(0), # switch mdio_o to MSb of output_data
|
in_preamble.eq(0), # switch mdio_o to MSb of output_data
|
||||||
|
@ -144,12 +146,12 @@ class MDIOCtrl(Module, AutoCSR):
|
||||||
mdio_fsm.act("WData",
|
mdio_fsm.act("WData",
|
||||||
in_preamble.eq(0),
|
in_preamble.eq(0),
|
||||||
mdio_oe.eq(1),
|
mdio_oe.eq(1),
|
||||||
If(clk_div == 2,
|
If(clk_div == div_clk_state_change,
|
||||||
shift_od.eq(1), # so during clk_div == 1, output will move to the next bit
|
shift_od.eq(1), # so during clk_div == 1, output will move to the next bit
|
||||||
NextValue(int_cnt, int_cnt - 1),
|
NextValue(int_cnt, int_cnt - 1),
|
||||||
If(int_cnt == 0,
|
If(int_cnt == 0,
|
||||||
mdio_o.eq(1), # help pull-ups
|
mdio_o.eq(1), # help pull-ups
|
||||||
mdio_oe.eq(0), # stop driving
|
# mdio_oe.eq(0), # stop driving
|
||||||
NextValue(output_data, 0), # make sure it's zero
|
NextValue(output_data, 0), # make sure it's zero
|
||||||
NextState("Idle"), ## fixme: delay to idle by one MDC clok cycle?
|
NextState("Idle"), ## fixme: delay to idle by one MDC clok cycle?
|
||||||
)
|
)
|
||||||
|
@ -159,11 +161,11 @@ class MDIOCtrl(Module, AutoCSR):
|
||||||
mdio_fsm.act("RData",
|
mdio_fsm.act("RData",
|
||||||
in_preamble.eq(0),
|
in_preamble.eq(0),
|
||||||
mdio_oe.eq(1),
|
mdio_oe.eq(1),
|
||||||
If(clk_div == 2,
|
If(clk_div == div_clk_state_change,
|
||||||
shift_od.eq(1), # so during clk_div == 2, output will move to the next bit
|
shift_od.eq(1), # so during clk_div == div_clk_state_change, output will move to the next bit
|
||||||
NextValue(int_cnt, int_cnt - 1),
|
NextValue(int_cnt, int_cnt - 1),
|
||||||
If(int_cnt == 18,
|
If(int_cnt == 18,
|
||||||
#mdio_o.eq(1), # help pull-ups
|
mdio_o.eq(1), # help pull-ups
|
||||||
#mdio_oe.eq(0), # stop driving during TA
|
#mdio_oe.eq(0), # stop driving during TA
|
||||||
NextState("TA"),
|
NextState("TA"),
|
||||||
)
|
)
|
||||||
|
@ -172,7 +174,8 @@ class MDIOCtrl(Module, AutoCSR):
|
||||||
|
|
||||||
mdio_fsm.act("TA",
|
mdio_fsm.act("TA",
|
||||||
mdio_oe.eq(0),
|
mdio_oe.eq(0),
|
||||||
If(clk_div == 2,
|
If(clk_div == div_clk_state_change,
|
||||||
|
# mdio_oe.eq(0), # stop driving
|
||||||
NextValue(rdata[15], mdio_i), # DEBUG, will capture on 17 and 16, will be flushed by shifting
|
NextValue(rdata[15], mdio_i), # DEBUG, will capture on 17 and 16, will be flushed by shifting
|
||||||
shift_rd.eq(1), # DEBUG, shift in 2 cycles to make room
|
shift_rd.eq(1), # DEBUG, shift in 2 cycles to make room
|
||||||
NextValue(int_cnt, int_cnt - 1),
|
NextValue(int_cnt, int_cnt - 1),
|
||||||
|
@ -185,10 +188,12 @@ class MDIOCtrl(Module, AutoCSR):
|
||||||
|
|
||||||
mdio_fsm.act("Capture",
|
mdio_fsm.act("Capture",
|
||||||
mdio_oe.eq(0),
|
mdio_oe.eq(0),
|
||||||
If(clk_div == 2,
|
If(clk_div == div_clk_state_change,
|
||||||
NextValue(rdata[15], mdio_i),
|
NextValue(rdata[15], mdio_i),
|
||||||
NextValue(int_cnt, int_cnt - 1),
|
NextValue(int_cnt, int_cnt - 1),
|
||||||
If(int_cnt == 0,
|
If(int_cnt == 0,
|
||||||
|
mdio_oe.eq(0),
|
||||||
|
mdio_o.eq(1), # help pull-ups
|
||||||
NextState("Idle"),
|
NextState("Idle"),
|
||||||
).Else(
|
).Else(
|
||||||
shift_rd.eq(1), # shift in 2 cycles to make room
|
shift_rd.eq(1), # shift in 2 cycles to make room
|
||||||
|
@ -196,10 +201,10 @@ class MDIOCtrl(Module, AutoCSR):
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
led0 = platform.request("user_led", 0)
|
#led0 = platform.request("user_led", 0)
|
||||||
led1 = platform.request("user_led", 1)
|
#led1 = platform.request("user_led", 1)
|
||||||
|
#
|
||||||
self.comb += [
|
#self.comb += [
|
||||||
led0.eq(~mdio_fsm.ongoing("Idle")),
|
# led0.eq(~mdio_fsm.ongoing("Idle")),
|
||||||
#led1.eq(clk_div != 0),
|
# #led1.eq(clk_div != 0),
|
||||||
]
|
#]
|
||||||
|
|
|
@ -37,7 +37,7 @@ from nubus_memfifo_wb import NuBus2WishboneFIFO
|
||||||
from nubus_cpu_wb import Wishbone2NuBus
|
from nubus_cpu_wb import Wishbone2NuBus
|
||||||
|
|
||||||
# CRG ----------------------------------------------------------------------------------------------
|
# CRG ----------------------------------------------------------------------------------------------
|
||||||
class _CRG(Module):
|
class _CRG(Module, AutoCSR): # AutoCSR for DRP
|
||||||
def __init__(self, platform, version, sys_clk_freq,
|
def __init__(self, platform, version, sys_clk_freq,
|
||||||
goblin=False,
|
goblin=False,
|
||||||
hdmi=False,
|
hdmi=False,
|
||||||
|
@ -101,7 +101,7 @@ class _CRG(Module):
|
||||||
assert(false)
|
assert(false)
|
||||||
self.cd_nubus90.clk = clk2x_nubus
|
self.cd_nubus90.clk = clk2x_nubus
|
||||||
self.comb += self.cd_nubus90.rst.eq(~rst_nubus_n)
|
self.comb += self.cd_nubus90.rst.eq(~rst_nubus_n)
|
||||||
platform.add_platform_command("create_clock -name nubus90_clk -period 50.0 -waveform {{0.0 37.5}} [get_ports clk2x_3v3_n]")
|
platform.add_platform_command("create_clock -name nubus90_clk -period 50.0 -waveform {{0.0 25}} [get_ports clk2x_3v3_n]")
|
||||||
|
|
||||||
num_adv = 0
|
num_adv = 0
|
||||||
num_clk = 0
|
num_clk = 0
|
||||||
|
@ -119,7 +119,7 @@ class _CRG(Module):
|
||||||
platform.add_platform_command("create_generated_clock -name sys4x90clk [get_pins {{{{MMCME2_ADV/CLKOUT{}}}}}]".format(num_clk))
|
platform.add_platform_command("create_generated_clock -name sys4x90clk [get_pins {{{{MMCME2_ADV/CLKOUT{}}}}}]".format(num_clk))
|
||||||
num_clk = num_clk + 1
|
num_clk = num_clk + 1
|
||||||
if (ethernet):
|
if (ethernet):
|
||||||
pll.create_clkout(self.cd_eth, 50e6, phase=90) # fixme: what if sys_clk_feq != 100e6?
|
pll.create_clkout(self.cd_eth, 50e6, phase=90) # fixme: what if sys_clk_feq != 100e6? # why phase ???
|
||||||
platform.add_platform_command("create_generated_clock -name ethclk [get_pins {{{{MMCME2_ADV/CLKOUT{}}}}}]".format(num_clk))
|
platform.add_platform_command("create_generated_clock -name ethclk [get_pins {{{{MMCME2_ADV/CLKOUT{}}}}}]".format(num_clk))
|
||||||
num_clk = num_clk + 1
|
num_clk = num_clk + 1
|
||||||
|
|
||||||
|
@ -166,6 +166,8 @@ class _CRG(Module):
|
||||||
num_clk = num_clk + 1
|
num_clk = num_clk + 1
|
||||||
platform.add_platform_command("create_generated_clock -name hdmi5x_clk [get_pins {{{{MMCME2_ADV_{}/CLKOUT{}}}}}]".format(num_adv, num_clk))
|
platform.add_platform_command("create_generated_clock -name hdmi5x_clk [get_pins {{{{MMCME2_ADV_{}/CLKOUT{}}}}}]".format(num_adv, num_clk))
|
||||||
num_clk = num_clk + 1
|
num_clk = num_clk + 1
|
||||||
|
video_pll.expose_drp()
|
||||||
|
|
||||||
|
|
||||||
self.comb += video_pll.reset.eq(~rst_nubus_n)
|
self.comb += video_pll.reset.eq(~rst_nubus_n)
|
||||||
#platform.add_false_path_constraints(self.cd_sys.clk, self.cd_vga.clk)
|
#platform.add_false_path_constraints(self.cd_sys.clk, self.cd_vga.clk)
|
||||||
|
@ -176,7 +178,7 @@ class _CRG(Module):
|
||||||
|
|
||||||
|
|
||||||
class NuBusFPGA(MacPeriphSoC):
|
class NuBusFPGA(MacPeriphSoC):
|
||||||
def __init__(self, variant, version, sys_clk_freq, goblin, hdmi, goblin_res, sdcard, flash, config_flash, ethernet, **kwargs):
|
def __init__(self, variant, version, sys_clk_freq, goblin, hdmi, goblin_res, use_goblin_alt, sdcard, flash, config_flash, ethernet, **kwargs):
|
||||||
print(f"Building NuBusFPGA for board version {version}")
|
print(f"Building NuBusFPGA for board version {version}")
|
||||||
|
|
||||||
self.platform = platform = ztex213_nubus.Platform(variant = variant, version = version)
|
self.platform = platform = ztex213_nubus.Platform(variant = variant, version = version)
|
||||||
|
@ -187,8 +189,6 @@ class NuBusFPGA(MacPeriphSoC):
|
||||||
if (ethernet and (version == "V1.2")):
|
if (ethernet and (version == "V1.2")):
|
||||||
platform.add_extension(ztex213_nubus._rmii_eth_extpmod_io_v1_2)
|
platform.add_extension(ztex213_nubus._rmii_eth_extpmod_io_v1_2)
|
||||||
|
|
||||||
use_goblin_alt = True
|
|
||||||
|
|
||||||
MacPeriphSoC.__init__(self,
|
MacPeriphSoC.__init__(self,
|
||||||
platform=platform,
|
platform=platform,
|
||||||
sys_clk_freq=sys_clk_freq,
|
sys_clk_freq=sys_clk_freq,
|
||||||
|
@ -380,7 +380,7 @@ class NuBusFPGA(MacPeriphSoC):
|
||||||
if (goblin):
|
if (goblin):
|
||||||
MacPeriphSoC.mac_add_goblin(self, use_goblin_alt = use_goblin_alt, hdmi = hdmi, goblin_res = goblin_res, goblin_irq = fb_irq, audio_irq = audio_irq)
|
MacPeriphSoC.mac_add_goblin(self, use_goblin_alt = use_goblin_alt, hdmi = hdmi, goblin_res = goblin_res, goblin_irq = fb_irq, audio_irq = audio_irq)
|
||||||
|
|
||||||
if (sdcard):
|
if (sdcard): ### WIP WIP WIP WIP
|
||||||
self.add_sdcard()
|
self.add_sdcard()
|
||||||
# irq?
|
# irq?
|
||||||
|
|
||||||
|
@ -388,14 +388,13 @@ class NuBusFPGA(MacPeriphSoC):
|
||||||
# we need the CRG to provide the cd_eth clock: "use refclk_cd as RMII reference clock (provided by user design) (no external clock).
|
# we need the CRG to provide the cd_eth clock: "use refclk_cd as RMII reference clock (provided by user design) (no external clock).
|
||||||
self.ethphy = LiteEthPHYRMII(
|
self.ethphy = LiteEthPHYRMII(
|
||||||
clock_pads = self.platform.request("eth_clocks"),
|
clock_pads = self.platform.request("eth_clocks"),
|
||||||
|
#clock_pads = None,
|
||||||
pads = self.platform.request("eth"))
|
pads = self.platform.request("eth"))
|
||||||
self.add_ethernet(phy=self.ethphy, data_width = 32)
|
self.add_ethernet(phy=self.ethphy, data_width = 32)
|
||||||
print(f"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% {self.ethmac.interface.sram.ev.irq}") # FIXME HANDLEME
|
print(f"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% {self.ethmac.interface.sram.ev.irq}") # FIXME HANDLEME
|
||||||
|
|
||||||
from mdio import MDIOCtrl
|
from mdio import MDIOCtrl
|
||||||
self.submodules.mdio_ctrl = MDIOCtrl(platform=platform)
|
self.submodules.mdio_ctrl = MDIOCtrl(platform=platform)
|
||||||
|
|
||||||
|
|
||||||
# for testing
|
# for testing
|
||||||
if (False):
|
if (False):
|
||||||
from nubus_master_tst import PingMaster
|
from nubus_master_tst import PingMaster
|
||||||
|
@ -411,7 +410,8 @@ def main():
|
||||||
parser.add_argument("--sys-clk-freq", default=100e6, help="NuBusFPGA system clock (default 100e6 = 100 MHz)")
|
parser.add_argument("--sys-clk-freq", default=100e6, help="NuBusFPGA system clock (default 100e6 = 100 MHz)")
|
||||||
parser.add_argument("--goblin", action="store_true", help="add a goblin framebuffer")
|
parser.add_argument("--goblin", action="store_true", help="add a goblin framebuffer")
|
||||||
parser.add_argument("--hdmi", action="store_true", help="The framebuffer uses HDMI (default to VGA, required for V1.2)")
|
parser.add_argument("--hdmi", action="store_true", help="The framebuffer uses HDMI (default to VGA, required for V1.2)")
|
||||||
parser.add_argument("--goblin-res", default="640x480@60Hz", help="Specify the goblin resolution")
|
parser.add_argument("--goblin-res", default="1920x1080@60Hz", help="Specify the goblin resolution")
|
||||||
|
parser.add_argument("--goblin-alt", action="store_true", help="Use alternate HDMI Phy with Audio support (requires Full HD resolution)")
|
||||||
parser.add_argument("--sdcard", action="store_true", help="add a sdcard controller (V1.2 only)")
|
parser.add_argument("--sdcard", action="store_true", help="add a sdcard controller (V1.2 only)")
|
||||||
parser.add_argument("--flash", action="store_true", help="add a Flash device [V1.2+FLASHTEMP PMod] and configure the ROM to it")
|
parser.add_argument("--flash", action="store_true", help="add a Flash device [V1.2+FLASHTEMP PMod] and configure the ROM to it")
|
||||||
parser.add_argument("--config-flash", action="store_true", help="Configure the ROM to the internal Flash used for FPGA config")
|
parser.add_argument("--config-flash", action="store_true", help="Configure the ROM to the internal Flash used for FPGA config")
|
||||||
|
@ -440,10 +440,39 @@ def main():
|
||||||
print(" ***** ERROR ***** : VGA not supported on V1.2\n");
|
print(" ***** ERROR ***** : VGA not supported on V1.2\n");
|
||||||
assert(False)
|
assert(False)
|
||||||
|
|
||||||
|
if ((not args.hdmi) and args.goblin_alt):
|
||||||
|
print(" ***** ERROR ***** : VGA and Goblin Alt PHY don't make sense\n");
|
||||||
|
assert(False)
|
||||||
|
|
||||||
if (args.config_flash and args.flash):
|
if (args.config_flash and args.flash):
|
||||||
print(" ***** ERROR ***** : ROM-in-Flash can only use config OR PMod, not both\n");
|
print(" ***** ERROR ***** : ROM-in-Flash can only use config OR PMod, not both\n");
|
||||||
assert(False)
|
assert(False)
|
||||||
|
|
||||||
|
if (args.goblin_alt and (args.goblin_res != "1920x1080@60Hz")):
|
||||||
|
print(" ***** ERROR ***** : Goblin Alt PHY currently only supports Full HD\n");
|
||||||
|
assert(False)
|
||||||
|
|
||||||
|
if (True):
|
||||||
|
f = open("decl_rom_config.mak","w+")
|
||||||
|
hres = int(args.goblin_res.split("@")[0].split("x")[0])
|
||||||
|
vres = int(args.goblin_res.split("@")[0].split("x")[1])
|
||||||
|
f.write("TARGET=NUBUSFPGA\n")
|
||||||
|
f.write("FEATURES+= -DNUBUSFPGA")
|
||||||
|
f.write(" -DENABLE_RAMDSK") # only NuBusFPGA for now
|
||||||
|
if (args.goblin_alt):
|
||||||
|
f.write(" -DENABLE_HDMIAUDIO") # no audio in litex-style not-hdmi phy
|
||||||
|
else:
|
||||||
|
f.write(" -DENABLE_HDMI_ALT_CHANGE");
|
||||||
|
if (args.version == "V1.0"):
|
||||||
|
f.write(" -DENABLE_HDMI_ALT_CHANGE_48MHZ");
|
||||||
|
elif (args.version == "V1.2"):
|
||||||
|
f.write(" -DENABLE_HDMI_ALT_CHANGE_54MHZ");
|
||||||
|
|
||||||
|
f.write("\n");
|
||||||
|
f.write(f"HRES={hres}\n");
|
||||||
|
f.write(f"VRES={vres}\n");
|
||||||
|
f.close()
|
||||||
|
|
||||||
soc = NuBusFPGA(**soc_core_argdict(args),
|
soc = NuBusFPGA(**soc_core_argdict(args),
|
||||||
variant=args.variant,
|
variant=args.variant,
|
||||||
version=args.version,
|
version=args.version,
|
||||||
|
@ -451,6 +480,7 @@ def main():
|
||||||
goblin=args.goblin,
|
goblin=args.goblin,
|
||||||
hdmi=args.hdmi,
|
hdmi=args.hdmi,
|
||||||
goblin_res=args.goblin_res,
|
goblin_res=args.goblin_res,
|
||||||
|
use_goblin_alt=args.goblin_alt,
|
||||||
sdcard=args.sdcard,
|
sdcard=args.sdcard,
|
||||||
flash=args.flash,
|
flash=args.flash,
|
||||||
config_flash=args.config_flash,
|
config_flash=args.config_flash,
|
||||||
|
|
|
@ -1,139 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
from migen import *
|
|
||||||
|
|
||||||
from VintageBusFPGA_Common.wb_master import *
|
|
||||||
from VintageBusFPGA_Common.wb_master import _WRITE_CMD, _WAIT_CMD, _DONE_CMD
|
|
||||||
|
|
||||||
|
|
||||||
dfii_control_sel = 0x01
|
|
||||||
dfii_control_cke = 0x02
|
|
||||||
dfii_control_odt = 0x04
|
|
||||||
dfii_control_reset_n = 0x08
|
|
||||||
|
|
||||||
dfii_command_cs = 0x01
|
|
||||||
dfii_command_we = 0x02
|
|
||||||
dfii_command_cas = 0x04
|
|
||||||
dfii_command_ras = 0x08
|
|
||||||
dfii_command_wrdata = 0x10
|
|
||||||
dfii_command_rddata = 0x20
|
|
||||||
|
|
||||||
# /!\ keep up to date with csr /!\
|
|
||||||
sdram_dfii_base = 0xf0a01800
|
|
||||||
sdram_dfii_control = sdram_dfii_base + 0x000
|
|
||||||
sdram_dfii_pi0_command = sdram_dfii_base + 0x004
|
|
||||||
sdram_dfii_pi0_command_issue = sdram_dfii_base + 0x008
|
|
||||||
sdram_dfii_pi0_address = sdram_dfii_base + 0x00c
|
|
||||||
sdram_dfii_pi0_baddress = sdram_dfii_base + 0x010
|
|
||||||
|
|
||||||
# /!\ keep up to date with csr /!\
|
|
||||||
ddrphy_base = 0xf0a00000
|
|
||||||
ddrphy_rst = ddrphy_base + 0x000
|
|
||||||
ddrphy_dly_sel = ddrphy_base + 0x004
|
|
||||||
ddrphy_rdly_dq_rst = ddrphy_base + 0x014
|
|
||||||
ddrphy_rdly_dq_inc = ddrphy_base + 0x018
|
|
||||||
ddrphy_rdly_dq_bitslip_rst = ddrphy_base + 0x01c
|
|
||||||
ddrphy_rdly_dq_bitslip = ddrphy_base + 0x020
|
|
||||||
ddrphy_wdly_dq_bitslip_rst = ddrphy_base + 0x024
|
|
||||||
ddrphy_wdly_dq_bitslip = ddrphy_base + 0x028
|
|
||||||
ddrphy_rdphase = ddrphy_base + 0x02c
|
|
||||||
ddrphy_wdphase = ddrphy_base + 0x030
|
|
||||||
|
|
||||||
|
|
||||||
def period_to_cycles(sys_clk_freq, period):
|
|
||||||
return int(period*sys_clk_freq)
|
|
||||||
|
|
||||||
def ddr3_init_instructions(sys_clk_freq):
|
|
||||||
return [
|
|
||||||
_WAIT_CMD | period_to_cycles(sys_clk_freq, 0.001),
|
|
||||||
# phase
|
|
||||||
_WRITE_CMD, ddrphy_rdphase, 2,
|
|
||||||
_WRITE_CMD, ddrphy_wdphase, 3,
|
|
||||||
|
|
||||||
# software control
|
|
||||||
_WRITE_CMD, sdram_dfii_control, dfii_control_reset_n | dfii_control_odt | dfii_control_cke,
|
|
||||||
|
|
||||||
# reset
|
|
||||||
_WRITE_CMD, ddrphy_rst, 1,
|
|
||||||
_WAIT_CMD | period_to_cycles(sys_clk_freq, 0.001),
|
|
||||||
_WRITE_CMD, ddrphy_rst, 0,
|
|
||||||
_WAIT_CMD | period_to_cycles(sys_clk_freq, 0.001),
|
|
||||||
|
|
||||||
# release reset
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_address, 0x0,
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_baddress, 0,
|
|
||||||
_WRITE_CMD, sdram_dfii_control, dfii_control_odt|dfii_control_reset_n,
|
|
||||||
_WAIT_CMD | period_to_cycles(sys_clk_freq, 0.005),
|
|
||||||
|
|
||||||
# bring cke high
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_address, 0x0,
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_baddress, 0,
|
|
||||||
_WRITE_CMD, sdram_dfii_control, dfii_control_cke|dfii_control_odt|dfii_control_reset_n,
|
|
||||||
_WAIT_CMD | period_to_cycles(sys_clk_freq, 0.001),
|
|
||||||
|
|
||||||
# load mode register 2, CWL = 5
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_address, 0x200,
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_baddress, 2,
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_command, dfii_command_ras|dfii_command_cas|dfii_command_we|dfii_command_cs,
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_command_issue, 1,
|
|
||||||
|
|
||||||
# load mode register 3
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_address, 0x0,
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_baddress, 3,
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_command, dfii_command_ras|dfii_command_cas|dfii_command_we|dfii_command_cs,
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_command_issue, 1,
|
|
||||||
|
|
||||||
# load mode register 1
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_address, 0x6,
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_baddress, 1,
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_command, dfii_command_ras|dfii_command_cas|dfii_command_we|dfii_command_cs,
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_command_issue, 1,
|
|
||||||
|
|
||||||
# load mode register 0, CL=6, BL=8
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_address, 0x920,
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_baddress, 0,
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_command, dfii_command_ras|dfii_command_cas|dfii_command_we|dfii_command_cs,
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_command_issue, 1,
|
|
||||||
_WAIT_CMD | period_to_cycles(sys_clk_freq, 0.0002),
|
|
||||||
|
|
||||||
# zq calibration
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_address, 0x400,
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_baddress, 0,
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_command, dfii_command_we|dfii_command_cs,
|
|
||||||
_WRITE_CMD, sdram_dfii_pi0_command_issue, 1,
|
|
||||||
_WAIT_CMD | period_to_cycles(sys_clk_freq, 0.0002),
|
|
||||||
|
|
||||||
# hardware control
|
|
||||||
_WRITE_CMD, sdram_dfii_control, dfii_control_sel,
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def ddr3_config_instructions(bitslip, delay):
|
|
||||||
r = []
|
|
||||||
for module in range(2):
|
|
||||||
r += [_WRITE_CMD, ddrphy_dly_sel, 1<<module ]
|
|
||||||
r += [_WRITE_CMD, ddrphy_wdly_dq_bitslip_rst, 1<<module ] # checkme ? should be ?
|
|
||||||
r += [_WRITE_CMD, ddrphy_dly_sel, 0 ]
|
|
||||||
for module in range(2):
|
|
||||||
r += [_WRITE_CMD, ddrphy_dly_sel, 1<<module ]
|
|
||||||
r += [_WRITE_CMD, ddrphy_rdly_dq_bitslip_rst, 1]
|
|
||||||
for i in range(bitslip):
|
|
||||||
r += [_WRITE_CMD, ddrphy_rdly_dq_bitslip, 1]
|
|
||||||
r += [_WRITE_CMD, ddrphy_rdly_dq_rst, 1]
|
|
||||||
for i in range(delay):
|
|
||||||
r += [_WRITE_CMD, ddrphy_rdly_dq_inc, 1]
|
|
||||||
r += [_WRITE_CMD, ddrphy_dly_sel, 0 ]
|
|
||||||
return r
|
|
||||||
|
|
||||||
class DDR3Init(WishboneMaster):
|
|
||||||
def __init__(self, sys_clk_freq, bitslip, delay):
|
|
||||||
WishboneMaster.__init__(self,
|
|
||||||
ddr3_init_instructions(sys_clk_freq) +
|
|
||||||
ddr3_config_instructions(bitslip, delay) +
|
|
||||||
[_DONE_CMD])
|
|
||||||
|
|
||||||
class DDR3FBInit(WishboneMaster):
|
|
||||||
def __init__(self, sys_clk_freq, bitslip, delay):
|
|
||||||
WishboneMaster.__init__(self,
|
|
||||||
ddr3_init_instructions(sys_clk_freq) +
|
|
||||||
ddr3_config_instructions(bitslip, delay) +
|
|
||||||
[_DONE_CMD])
|
|
Loading…
Reference in New Issue
Block a user