First FPGA project.  Looking for advice - Page 1
Forum section: electronics / general

author: hermitengineer
author_rank: Regular Contributor
timestamp: May 14, 2021, 03:50:10 am
content: This is my first time designing for an FPGA, and learning Verilog from zero. So I'd appreciate any constructive criticism on coding, style, etc. I developed the code in Vivado and simulated and synthesized it for an XC7S6 series chip to verify that it acts as it is supposed to. It works (virtually) but uses maybe 5% of the chip's resources.Second, this is a project to duplicate the functionality of a 40-pin DIP designed in the late 70's by General Instruments for an ancient game system. As such, the board should also be about 40-pin DIP sized. So, I'd also appreciate suggestions for an FPGA to use, along with the level shifters, voltage regulator(s), and flash memory. Obviously, size would be the biggest issue.Thanks

author: asmi
author_rank: Super Contributor
timestamp: May 14, 2021, 04:50:36 am
content: You might want to take a look at Digilent's CMOD boards:CMOD A7orCMOD S7. They have DIP-48 size, so not sure if it's going to be OK.If you want to design your own, making it so small is going to be a challenge. The smallest package for S7 is 8x8 mm, but it's 0.5 mm ball pitch, so you will need to use advanced PCB tech. If you prefer to use more conventional tech, you can take a look at A7's CPG236/238 package (it's 0.5 mm pitch too, but the pinout is such that it's possible to route it using conventional PCB process) - it's 10x10 mm. The smallest "conventional PCB-friendly" S7 package is CSGA225, but at 13x13 mm it's probably a tad too close to the your size limits (assuming 0.7 inch or 17.8 mm for the PCB width). It could be doable though.I think the XC7A12T-1CPG238 or XC7A15T-1CPG236 would be the best choice because they are the smallest accessible with conventional PCB tech. I've attached pinout diagrams and package drawing for A15T option for your convenience (taken from UG475), A12T has the same physical dimensions and footprint, but different pinout (see aforementioned user guide UG475 for all these details).

author: up8051
author_rank: Frequent Contributor
timestamp: May 14, 2021, 09:02:40 am
content: It looks that your project is simple, maybe CPLD circuits will be enough.For example: ATF150x 5V supply, PLCC44

author: woofy
author_rank: Frequent Contributor
timestamp: May 14, 2021, 10:06:49 am
content: I did something similar for the Intel 4004 CPU, except I never needed the level shifting as it was a 3.3v replica from the start. But it did fit on a 16 pin DIP footprint. I used the Lattice ice40LP1k and GD25Q20C flash for that.TheCP16xx (A PDP11 inspired device) is more complex so I would choose the ice40HX8k. The CB132 package will fit the 40 pin DIP footprint. A suitable flash could be the AT25SF081. Bidirectional 3.3v-5v level shifting could be done with TXS0108E devices. This will not take much power so linear regulators will be fine. You can ignore the 12v and -3v and just power from the 5v supply.

author: emece67
author_rank: Frequent Contributor
timestamp: May 14, 2021, 03:36:20 pm
content: .

author: Bassman59
author_rank: Super Contributor
timestamp: May 14, 2021, 06:19:45 pm
content: Quote from: hermitengineer on May 14, 2021, 03:50:10 amHow much experience do you have doing synchronous digital logic design?

author: hermitengineer
author_rank: Regular Contributor
timestamp: May 14, 2021, 08:06:57 pm
content: Quote from: emece67 on May 14, 2021, 03:36:20 pmYeah I was working with the timing diagrams of the CP1600 CPU which is used by the system, an internal document detailing the behavior of the original chip, and the results of actual observation of its behavior. It's an ... interesting setup. As I think I mentioned in the code, the CPU is a 4-state machine where P2 rise is TS1, P2 fall is TS2, second rise is TS3, and second fall is TS4. The fun part is that this is the processor's state machine, and outside of the processor we would need some fuzzy logic to figure out which state it is in, if that is even necessary. In the case of this chip, it does not seem to be, as long as you are okay with the fact that P2 has 2 positive edges for the same bus operation.So, for instance, the write to memory does not have valid data on the first pulse but does on the second. With the current code, the memory is written on both positive edges, but the correct value wins.Anyway, what I do know is that the 3 control lines should be valid on the rising edge of P2 and throughout the high level.This chip is a split-brained one, where the first half is mainly clocked by P2 and the other half is mainly clocked by SR3. SR3 is a level trigger for the purpose of enabling the SD outputs, but its edges also trigger a couple of internal changes. Rationale for the count: The graphics chip will ask the CPU for control of the bus (BUSRQ) early in an attempt to ensure that the CPU has time to honor the request before the graphics chip needs it. But that means it might still be in the middle of displaying that last line when the CPU relents. At that time, BUSAK will be active but loading of values should not begin yet. So there is the activation counter which is reset by SR3's pulses, ensuring that the next set of values do not begin to load until that line is finished. So the count should be reset by the edge of SR3, at least. But holding reset asynchronously is also an option. Maybe even the preference because the edges are about 8 clocks apart.Similarly, the DTB condition is pretty much a level trigger for enabling DB as an output. The bus expects to see the value through both P2 pulses (in other words, 3 phase changes) while DTB is active, so once we are sure there is a DTB that we are supposed to respond to, we have to hold it until the condition changes.Quote from: emece67 on May 14, 2021, 03:36:20 pmYeah this chip will be running constantly because it's part of the video display system. The 20-position shift register represents the background tiles for every 16 lines (8 lines per tile, but doubled because of the TV's interlace). The graphics chip that works along with this chip initiates the load sequence of the background tiles from its internal memory, 20 at a time, then repeats those 20 for the next 7 lines, then makes it load the next 20, and so on, until it has filled the screen. Then the graphics chip sends an interrupt request to the CPU which responds with an INTAK. We see the INTAK and reset the address while entering CPU mode.Anyway, because of that, it should only take 1 cycle to get everything into a known state, so it would likely not be noticeable. That is probably why the original designer didn't add a reset pin, even though the other chips have one.The next is a matter of taste, but a little of indentation can help to ascertain what is the asynchronous part of a block from the syncronous one:Code:always@(negedge SR3 or posedge INTAK)beginif(INTAK) beginADDR <= 0;end else if(LD) beginADDR <= ADDR + 1;endendvs.Code:always@(posedge INTAK, negedge SR3) beginif (INTAK) beginADDR <= 0;end elseif (LD) beginADDR <= ADDR + 1;endendI can see either argument. My personal preference (both in general programming and in this) is that if it's a sequence of conditions rather than a hierarchy, I prefer to keep the indenting the same. One could argue that it IS a hierarchy, and you are technically correct. But logically, it's just a list of conditions where the first one that's true wins. It's logically closer to a case statement. This is probably why some languages added the syntatic sugar of "elseif".Quote from: emece67 on May 14, 2021, 03:36:20 pmI'll have to review my rationale for this block, and consider whether or not it's still valid (may be a leftover from my crash course in Verilog).Quote from: Bassman59 on May 14, 2021, 06:19:45 pmI guess this is your way of saying "What a mess of spaghetti code"Some experience, but definitely not up to modern standards. I understand edge and level triggering, at least, and I am conscious of propagation delay.But the device that I'm duplicating was designed before modern design disciplines were established, so some of the odd triggering you might be noticing is unfortunately necessary.

author: hermitengineer
author_rank: Regular Contributor
timestamp: May 14, 2021, 10:05:41 pm
content: When I started thinking about this project, I did buy an Alchitry AU kit from Sparkfun. That's why I used Vivado for development--it's aSpartanArtix-7 based board. Of course learning Vivado was about as much effort as learning Verilog was, and I still can't claim to be an expert in either yet.But the kit comes with a USB port for programming, which you apparently have to do with their Alchitry software rather than the Xilinx programmer. It does seem to have a breakout board for the GPIO pins, though I'll have to solder on their provided header plugs. It also comes with a 3rd board with 4 7-segment displays, 5 buttons, and a large bank of DIP switches. So at least I have a supposedly working board for experimentation.I'll look into the other suggestions on this thread though.

author: emece67
author_rank: Frequent Contributor
timestamp: May 14, 2021, 11:04:23 pm
content: .

author: james_s
author_rank: Super Contributor
timestamp: May 14, 2021, 11:17:29 pm
content: Before you reinvent the wheel, look at existing hardware solutions for FPGA or CPLD replacements of vintage ASICs used in arcade games. It's possible there will be an existing design you can use as-is or with modifications to the pinout. Then you just have to focus on the code. For development purposes you can use just about any dev board. In practice I find that simple resistors on the input lines is adequate for level shifting, and the 3.3V outputs will drive 5V TTL stuff just fine. If it were life safety hardware I'd say definitely go with proper level shifters but for a game? Probably not really necessary.

author: hermitengineer
author_rank: Regular Contributor
timestamp: May 15, 2021, 04:02:46 am
content: Quote from: emece67 on May 14, 2021, 11:04:23 pmOh, I see. It's expected that every comparison at the top level reference a named event? So the code ought to look something like:Code:always@(negedge SR3 or posedge INTAK)beginif(INTAK) beginADDR <= 0;end else if(!SR3) beginif(LD)ADDR <= ADDR + 1;endendendSo that means the reference to !LD in the previous always block should also be within a sub-block since it is not an event?

author: hermitengineer
author_rank: Regular Contributor
timestamp: May 15, 2021, 04:50:38 am
content: Quote from: james_s on May 14, 2021, 11:17:29 pmAwwww come on, let me have my fun.Well, I did do a search for an FPGA implementation of this chip, at least. There's a core of the entire system for the MiSTer written in VHDL (with a much larger SytemVerilog/VHDL/TCL glue that I guess interfaces it with the core of the platform), but it combines all 4 of the chips that do graphics into a single entity and integrates them too tightly to be separated without basically reimplementing the one I want.

author: james_s
author_rank: Super Contributor
timestamp: May 15, 2021, 06:11:30 am
content: Quote from: hermitengineer on May 15, 2021, 04:50:38 amI'm not trying to stop you from having fun, I'm just pointing out that there are existing devices that have a CPLD or FPGA on a carrier board meant to plug into a DIP socket, and given the highly flexible nature of CPLD and FPGA pins, you might not have to make many if any changes to an existing hardware design to make it work. Either way the main challenge is in writing and debugging the HDL to make it do what you want it to do. If the design is small enough to fit into a CPLD that's going to be easier in most cases than an FPGA. FPGAs offer cool features like clock PLLs and hardware multipliers but they typically require external configuration memory and multiple power supply rails.

author: hermitengineer
author_rank: Regular Contributor
timestamp: May 15, 2021, 09:05:01 am
content: Quote from: james_s on May 15, 2021, 06:11:30 amOh you mean other 40-pin FPGA/CPLD projects. I understood you to mean repeating someone else's RA-3-9600. Yeah you're right. That would also be worth looking into.Are there CPLDs that have RAM? I do have a simple CPLD dev kit, but of course it only has a few dozen combinatorial logic gates with various choices of output. This particular chip has 352 16-bit words of RAM, as well as 20 14-bit registers arranged as a circular shift register. I suppose it may also be possible to add an external RAM chip or two, if they can fit on a DIP-sized board with the CPLD.Edit: Just looked around and found a 128Kx16 SRAM for about $1.5, and it can come in a BGA or TSSOP44 package, both of which could fit on a DIP40. That would likely allow the logic to fit within a CPLD (though it needs another 16+9+xx pins for the memory interface). But that is a workable alternative.

author: emece67
author_rank: Frequent Contributor
timestamp: May 15, 2021, 09:43:16 am
content: .

author: emece67
author_rank: Frequent Contributor
timestamp: May 15, 2021, 10:39:27 am
content: .

author: NorthGuy
author_rank: Super Contributor
timestamp: May 15, 2021, 03:40:34 pm
content: Quote from: emece67 on May 15, 2021, 10:39:27 amYou still can directly instantiate LUTs, add routing delays perhaps, and thereby make combinatorial logic glitch-free. The only problem is that the tools will not do this for you, so you're on your own. Your idea with fast clock is much easier to implement.

author: hermitengineer
author_rank: Regular Contributor
timestamp: May 15, 2021, 06:23:07 pm
content: Quote from: emece67 on May 15, 2021, 10:39:27 amI see. Yeah I made every effort to design the circuit so that the combinatorial changes were finalized before the triggers that used their values. For instance, in "DMA mode", the internal memory always has the data at the current address output-enabled. On positive edge of SR3, this data is latched into the shift register, and on negative edge of SR3, the address is incremented. Therefore the data is always valid when latched. As far as presenting this data to the SD side, there is a timing window for how long SD is allowed to be in flux after SR3 goes positive. The FPGA, at least, ought to make that window easily. The data output may initially be the previous contents of the shift register, but the memory load should happen and propagate well before the other chips on that bus begin to examine it.The one asynchronous signal that I am most concerned about, false "DTB" signal, is somewhat mitigated by the fact that between bus operations, the CPU always drops all control lines to 0 for a CPU cycle before initiating the next state. DTB is both BC1 and BC2 high, so the only way to reach this state by accident is from the situation where BDIR is also high (INTAK) and BDIR drops first. However, the CPU had control of the bus for the INTAK but had already high-z'd the bus by the time the false DTB would cause this chip to burp data to the DB bus for those brief nanoseconds, and only if it had been addressed by the INTAK.

author: james_s
author_rank: Super Contributor
timestamp: May 15, 2021, 10:24:16 pm
content: Quote from: hermitengineer on May 15, 2021, 09:05:01 amTo my knowledge, no, if you need RAM that either means FPGA or external RAM chip. Which of these options makes sense depends, it could be a tossup between them.Either way I would focus on getting the HDL working first and then figure out what hardware you want to build for the final device. I have a DE2 dev board that I use for this sort of thing, it has lots of IO, SRAM and DRAM onboard, a bunch of switches, some buttons and LEDs and 7 segment displays that are handy for monitoring things during development.

author: hermitengineer
author_rank: Regular Contributor
timestamp: May 16, 2021, 05:59:36 am
content: Okay, I've attempted to implement some of the criticism about coding. In the process, I also discovered a value that was being sampled at the same time it was being changedBut in taking a close look at the synthesized and implemented schematics, I was drawn to the fact that it optimized out DB output to always be ground. WTF? The sim code depends on all 16 bits working correctly. Then I looked around some more and realized that the internal memory is only storing the 15th bit. Again, WTF? I guess I should make sure: How do you assign to an entire 16 bits at a time?The current code:always@(negedge P2) beginif(db_to_ram)beginmemory <= DB;endendwhere memory is defined as:reg [15:0] memory [351:0];and DB is defined as:inout wire [15:0] DBThe assignment at least worked for the RTL elaboration and for the simulation, but the synthesis only assigned the 15th bit, and the implementation step agreed.

author: miken
author_rank: Regular Contributor
timestamp: May 16, 2021, 07:10:02 am
content: Ah, the joys of bringing up a new designTake a look at the synthesis warnings and I think you'll understand eventually what is happening. Remember that the tools prune whatever isn't actually being used.

author: hermitengineer
author_rank: Regular Contributor
timestamp: May 16, 2021, 08:27:13 am
content: Quote from: miken on May 16, 2021, 07:10:02 amThis may be a Vivado question, but where do I find these warnings? I have a "Messages" tab with 2 warnings listed, both in the "General" subtree. One is that the IP directory cannot be found (so what? I'm not using any IP) and the other is that the GeneratedRun file is not found (?)In the synthesis message tree, no warnings or errors. In the synthesized design message tree, no warnings or errors.

author: asmi
author_rank: Super Contributor
timestamp: May 16, 2021, 01:58:53 pm
content: Quote from: hermitengineer on May 16, 2021, 08:27:13 amLook in synthesis and implementation logs. They are in the "Log" tab on the bottom of the Vivado window.Also remember that the goal of FPGA is to OUTPUT stuff. So if synthesis or implementation can mathematically prove something does not affect output, it's going to be pruned. For example, if you only write to the memory but never read, this whole part is going to be removed. If you do read back memory, but only certain bits affect output, all other bits will be optimized away.You can prevent stuff from being optimized away by using attributes (like "KEEP"), but I strongly advise against it unless you know what are you doing.

author: rstofer
author_rank: Super Contributor
timestamp: May 16, 2021, 04:29:10 pm
content: Look in the Message folder (tab) on the Console pane after running Synthesis. It is unlikely that your code isn't generating a bunch of warnings.Under RTL Analysis, Open Elaborated Design, open the Schematic and see what logic has been generated. This will require successful synthesis.Sampling and signal change do not occur simultaneously on the clock edge. The signal is sampled no closer than tsetupbefore the clock and the output is stable no sooner than tholdafter the clock. That's why asynchronous logic is so hard to create. All of the potential transitions have to be covered in the Karnaugh Map and these small undefined regions generate glitches. We get around this problem by designing synchronous logic.https://www.nandland.com/articles/setup-and-hold-time-in-an-fpga.html

author: hermitengineer
author_rank: Regular Contributor
timestamp: May 16, 2021, 07:53:45 pm
content: Here's the log. It seems to be the same thing as the messages, just in pure text format. But it explicitly says "0 warnings, 0 errors". Maybe the warnings I need are disabled by default and there's a setting to turn them on?Code:*** Running vivadowith args -log RA_3_9600.vds -m64 -product Vivado -mode batch -messageDb vivado.pb -notrace -source RA_3_9600.tcl****** Vivado v2020.2 (64-bit)**** SW Build 3064766 on Wed Nov 18 09:12:45 MST 2020**** IP Build 3064653 on Wed Nov 18 14:17:31 MST 2020** Copyright 1986-2020 Xilinx, Inc. All Rights Reserved.source RA_3_9600.tcl -notraceCommand: synth_design -top RA_3_9600 -part xc7s6cpga196-2Starting synth_designAttempting to get a license for feature 'Synthesis' and/or device 'xc7s6'INFO: [Common 17-349] Got license for feature 'Synthesis' and/or device 'xc7s6'INFO: [Device 21-403] Loading part xc7s6cpga196-2INFO: [Synth 8-7079] Multithreading enabled for synth_design using a maximum of 2 processes.INFO: [Synth 8-7078] Launching helper process for spawning children vivado processesINFO: [Synth 8-7075] Helper process launched with PID 8220---------------------------------------------------------------------------------Starting RTL Elaboration : Time (s): cpu = 00:00:04 ; elapsed = 00:00:04 . Memory (MB): peak = 1017.004 ; gain = 0.000---------------------------------------------------------------------------------INFO: [Synth 8-6157] synthesizing module 'RA_3_9600' [C:/Users/Documents/RA_3_9600/RA_3_9600.srcs/sources_1/imports/new/RA-3-9600.sv:21]INFO: [Synth 8-6157] synthesizing module 'RINGBUFFER' [C:/Users/Documents/RA_3_9600/RA_3_9600.srcs/sources_1/imports/new/RINGBUFFER.sv:30]INFO: [Synth 8-6155] done synthesizing module 'RINGBUFFER' (1#1) [C:/Users/Documents/RA_3_9600/RA_3_9600.srcs/sources_1/imports/new/RINGBUFFER.sv:30]INFO: [Synth 8-6157] synthesizing module 'CPUADDRDECODER' [C:/Users/Documents/RA_3_9600/RA_3_9600.srcs/sources_1/imports/new/CPUADDRDECODER.sv:26]INFO: [Synth 8-6155] done synthesizing module 'CPUADDRDECODER' (2#1) [C:/Users/Documents/RA_3_9600/RA_3_9600.srcs/sources_1/imports/new/CPUADDRDECODER.sv:26]INFO: [Synth 8-6157] synthesizing module 'CPUBUSDECODER' [C:/Users/Documents/RA_3_9600/RA_3_9600.srcs/sources_1/imports/new/CPUBUSDECODER.sv:23]INFO: [Synth 8-6155] done synthesizing module 'CPUBUSDECODER' (3#1) [C:/Users/Documents/RA_3_9600/RA_3_9600.srcs/sources_1/imports/new/CPUBUSDECODER.sv:23]INFO: [Synth 8-6157] synthesizing module 'CARDADDR' [C:/Users/Documents/RA_3_9600/RA_3_9600.srcs/sources_1/imports/new/CARDADDR.sv:23]INFO: [Synth 8-6155] done synthesizing module 'CARDADDR' (4#1) [C:/Users/Documents/RA_3_9600/RA_3_9600.srcs/sources_1/imports/new/CARDADDR.sv:23]INFO: [Synth 8-6155] done synthesizing module 'RA_3_9600' (5#1) [C:/Users/Documents/RA_3_9600/RA_3_9600.srcs/sources_1/imports/new/RA-3-9600.sv:21]---------------------------------------------------------------------------------Finished RTL Elaboration : Time (s): cpu = 00:00:04 ; elapsed = 00:00:05 . Memory (MB): peak = 1017.004 ; gain = 0.000------------------------------------------------------------------------------------------------------------------------------------------------------------------Start Handling Custom Attributes------------------------------------------------------------------------------------------------------------------------------------------------------------------Finished Handling Custom Attributes : Time (s): cpu = 00:00:05 ; elapsed = 00:00:05 . Memory (MB): peak = 1017.004 ; gain = 0.000------------------------------------------------------------------------------------------------------------------------------------------------------------------Finished RTL Optimization Phase 1 : Time (s): cpu = 00:00:05 ; elapsed = 00:00:05 . Memory (MB): peak = 1017.004 ; gain = 0.000---------------------------------------------------------------------------------Netlist sorting complete. Time (s): cpu = 00:00:00 ; elapsed = 00:00:00.005 . Memory (MB): peak = 1017.004 ; gain = 0.000INFO: [Project 1-570] Preparing netlist for logic optimizationProcessing XDC ConstraintsInitializing timing engineParsing XDC File [C:/Users/Documents/RA_3_9600/RA_3_9600.srcs/constrs_1/imports/new/RA_Pins.xdc]Finished Parsing XDC File [C:/Users/Documents/RA_3_9600/RA_3_9600.srcs/constrs_1/imports/new/RA_Pins.xdc]INFO: [Project 1-236] Implementation specific constraints were found while reading constraint file [C:/Users/Documents/RA_3_9600/RA_3_9600.srcs/constrs_1/imports/new/RA_Pins.xdc]. These constraints will be ignored for synthesis but will be used in implementation. Impacted constraints are listed in the file [.Xil/RA_3_9600_propImpl.xdc].Resolution: To avoid this warning, move constraints listed in [.Xil/RA_3_9600_propImpl.xdc] to another XDC file and exclude this new file from synthesis with the used_in_synthesis property (File Properties dialog in GUI) and re-run elaboration/synthesis.Completed Processing XDC ConstraintsNetlist sorting complete. Time (s): cpu = 00:00:00 ; elapsed = 00:00:00 . Memory (MB): peak = 1037.844 ; gain = 0.000INFO: [Project 1-111] Unisim Transformation Summary:No Unisim elements were transformed.Constraint Validation Runtime : Time (s): cpu = 00:00:00 ; elapsed = 00:00:00.003 . Memory (MB): peak = 1037.844 ; gain = 0.000---------------------------------------------------------------------------------Finished Constraint Validation : Time (s): cpu = 00:00:10 ; elapsed = 00:00:11 . Memory (MB): peak = 1037.844 ; gain = 20.840------------------------------------------------------------------------------------------------------------------------------------------------------------------Start Loading Part and Timing Information---------------------------------------------------------------------------------Loading part: xc7s6cpga196-2---------------------------------------------------------------------------------Finished Loading Part and Timing Information : Time (s): cpu = 00:00:10 ; elapsed = 00:00:11 . Memory (MB): peak = 1037.844 ; gain = 20.840------------------------------------------------------------------------------------------------------------------------------------------------------------------Start Applying 'set_property' XDC Constraints------------------------------------------------------------------------------------------------------------------------------------------------------------------Finished applying 'set_property' XDC Constraints : Time (s): cpu = 00:00:10 ; elapsed = 00:00:11 . Memory (MB): peak = 1037.844 ; gain = 20.840------------------------------------------------------------------------------------------------------------------------------------------------------------------Finished RTL Optimization Phase 2 : Time (s): cpu = 00:00:11 ; elapsed = 00:00:11 . Memory (MB): peak = 1037.844 ; gain = 20.840------------------------------------------------------------------------------------------------------------------------------------------------------------------Start RTL Component Statistics---------------------------------------------------------------------------------Detailed RTL Component Info :+---Adders :2 Input 8 Bit Adders := 12 Input 4 Bit Adders := 1+---Registers :16 Bit Registers := 114 Bit Registers := 208 Bit Registers := 13 Bit Registers := 11 Bit Registers := 3+---Muxes :2 Input 16 Bit Muxes := 22 Input 14 Bit Muxes := 22 Input 9 Bit Muxes := 1---------------------------------------------------------------------------------Finished RTL Component Statistics------------------------------------------------------------------------------------------------------------------------------------------------------------------Start Part Resource Summary---------------------------------------------------------------------------------Part Resources:DSPs: 10 (col length:20)BRAMs: 10 (col length: RAMB18 20 RAMB36 10)---------------------------------------------------------------------------------Finished Part Resource Summary------------------------------------------------------------------------------------------------------------------------------------------------------------------Start Cross Boundary and Area Optimization------------------------------------------------------------------------------------------------------------------------------------------------------------------Finished Cross Boundary and Area Optimization : Time (s): cpu = 00:00:12 ; elapsed = 00:00:13 . Memory (MB): peak = 1037.844 ; gain = 20.840------------------------------------------------------------------------------------------------------------------------------------------------------------------Start ROM, RAM, DSP, Shift Register and Retiming Reporting---------------------------------------------------------------------------------Distributed RAM: Preliminary MappingReport (see note below)+------------+------------+-----------+----------------------+---------------------------+|Module Name | RTL Object | Inference | Size (Depth x Width) | Primitives |+------------+------------+-----------+----------------------+---------------------------+|RA_3_9600 | memory_reg | Implied | 512 x 16 | RAM64X1D x 6RAM64M x 30|+------------+------------+-----------+----------------------+---------------------------+Note: The table above is a preliminary report that shows the Distributed RAMs at the current stage of the synthesis flow. Some Distributed RAMs may be reimplemented as non Distributed RAM primitives later in the synthesis flow. Multiple instantiated RAMs are reported only once.---------------------------------------------------------------------------------Finished ROM, RAM, DSP, Shift Register and Retiming Reporting------------------------------------------------------------------------------------------------------------------------------------------------------------------Start Applying XDC Timing Constraints------------------------------------------------------------------------------------------------------------------------------------------------------------------Finished Applying XDC Timing Constraints : Time (s): cpu = 00:00:17 ; elapsed = 00:00:18 . Memory (MB): peak = 1037.844 ; gain = 20.840------------------------------------------------------------------------------------------------------------------------------------------------------------------Start Timing Optimization---------------------------------------------------------------------------------Inferred a: "set_disable_timing -from a -to z i_12(tricell)"Inferred a: "set_disable_timing -from a -to z i_13(tricell)"Inferred a: "set_disable_timing -from a -to z i_9(tricell)"Inferred a: "set_disable_timing -from a -to z i_10(tricell)"Inferred a: "set_disable_timing -from a -to z i_11(tricell)"Inferred a: "set_disable_timing -from a -to z i_6(tricell)"Inferred a: "set_disable_timing -from a -to z i_7(tricell)"Inferred a: "set_disable_timing -from a -to z i_8(tricell)"Inferred a: "set_disable_timing -from a -to z i_3(tricell)"Inferred a: "set_disable_timing -from a -to z i_4(tricell)"Inferred a: "set_disable_timing -from a -to z i_5(tricell)"Inferred a: "set_disable_timing -from a -to z i_0(tricell)"Inferred a: "set_disable_timing -from a -to z i_1(tricell)"Inferred a: "set_disable_timing -from a -to z i_2(tricell)"---------------------------------------------------------------------------------Finished Timing Optimization : Time (s): cpu = 00:00:18 ; elapsed = 00:00:18 . Memory (MB): peak = 1037.844 ; gain = 20.840------------------------------------------------------------------------------------------------------------------------------------------------------------------Start ROM, RAM, DSP, Shift Register and Retiming Reporting---------------------------------------------------------------------------------Distributed RAM: Final MappingReport+------------+------------+-----------+----------------------+---------------------------+|Module Name | RTL Object | Inference | Size (Depth x Width) | Primitives |+------------+------------+-----------+----------------------+---------------------------+|RA_3_9600 | memory_reg | Implied | 512 x 16 | RAM64X1D x 6RAM64M x 30|+------------+------------+-----------+----------------------+---------------------------+---------------------------------------------------------------------------------Finished ROM, RAM, DSP, Shift Register and Retiming Reporting------------------------------------------------------------------------------------------------------------------------------------------------------------------Start Technology Mapping------------------------------------------------------------------------------------------------------------------------------------------------------------------Finished Technology Mapping : Time (s): cpu = 00:00:18 ; elapsed = 00:00:18 . Memory (MB): peak = 1037.844 ; gain = 20.840------------------------------------------------------------------------------------------------------------------------------------------------------------------Start IO Insertion------------------------------------------------------------------------------------------------------------------------------------------------------------------Start Flattening Before IO Insertion------------------------------------------------------------------------------------------------------------------------------------------------------------------Finished Flattening Before IO Insertion------------------------------------------------------------------------------------------------------------------------------------------------------------------Start Final Netlist Cleanup------------------------------------------------------------------------------------------------------------------------------------------------------------------Finished Final Netlist Cleanup------------------------------------------------------------------------------------------------------------------------------------------------------------------Finished IO Insertion : Time (s): cpu = 00:00:21 ; elapsed = 00:00:22 . Memory (MB): peak = 1037.844 ; gain = 20.840------------------------------------------------------------------------------------------------------------------------------------------------------------------Start Renaming Generated Instances------------------------------------------------------------------------------------------------------------------------------------------------------------------Finished Renaming Generated Instances : Time (s): cpu = 00:00:21 ; elapsed = 00:00:22 . Memory (MB): peak = 1037.844 ; gain = 20.840------------------------------------------------------------------------------------------------------------------------------------------------------------------Start Rebuilding User Hierarchy------------------------------------------------------------------------------------------------------------------------------------------------------------------Finished Rebuilding User Hierarchy : Time (s): cpu = 00:00:21 ; elapsed = 00:00:22 . Memory (MB): peak = 1037.844 ; gain = 20.840------------------------------------------------------------------------------------------------------------------------------------------------------------------Start Renaming Generated Ports------------------------------------------------------------------------------------------------------------------------------------------------------------------Finished Renaming Generated Ports : Time (s): cpu = 00:00:21 ; elapsed = 00:00:22 . Memory (MB): peak = 1037.844 ; gain = 20.840------------------------------------------------------------------------------------------------------------------------------------------------------------------Start Handling Custom Attributes------------------------------------------------------------------------------------------------------------------------------------------------------------------Finished Handling Custom Attributes : Time (s): cpu = 00:00:21 ; elapsed = 00:00:22 . Memory (MB): peak = 1037.844 ; gain = 20.840------------------------------------------------------------------------------------------------------------------------------------------------------------------Start Renaming Generated Nets------------------------------------------------------------------------------------------------------------------------------------------------------------------Finished Renaming Generated Nets : Time (s): cpu = 00:00:21 ; elapsed = 00:00:22 . Memory (MB): peak = 1037.844 ; gain = 20.840------------------------------------------------------------------------------------------------------------------------------------------------------------------Start ROM, RAM, DSP, Shift Register and Retiming Reporting---------------------------------------------------------------------------------Static Shift Register Report:+------------+--------------------+--------+-------+--------------+--------------------+-------------------+--------+---------+|Module Name | RTL Name | Length | Width | Reset Signal | Pull out first Reg | Pull out last Reg | SRL16E | SRLC32E |+------------+--------------------+--------+-------+--------------+--------------------+-------------------+--------+---------+|RA_3_9600 | rb/RING_reg | 19 | 14 | NO | NO | YES | 0 | 14 |+------------+--------------------+--------+-------+--------------+--------------------+-------------------+--------+---------+---------------------------------------------------------------------------------Finished ROM, RAM, DSP, Shift Register and Retiming Reporting------------------------------------------------------------------------------------------------------------------------------------------------------------------Start Writing Synthesis Report---------------------------------------------------------------------------------Report BlackBoxes:+-+--------------+----------+| |BlackBox name |Instances |+-+--------------+----------++-+--------------+----------+Report Cell Usage:+------+---------+------+| |Cell |Count |+------+---------+------+|1 |BUFG | 2||2 |LUT1 | 6||3 |LUT2 | 32||4 |LUT3 | 26||5 |LUT4 | 11||6 |LUT5 | 5||7 |LUT6 | 6||8 |RAM64X1D | 6||9 |SRLC32E | 14||10 |FDCE | 12||11 |FDPE | 2||12 |FDRE | 44||13 |IBUF | 6||14 |IOBUF | 30|+------+---------+------+---------------------------------------------------------------------------------Finished Writing Synthesis Report : Time (s): cpu = 00:00:21 ; elapsed = 00:00:22 . Memory (MB): peak = 1037.844 ; gain = 20.840---------------------------------------------------------------------------------Synthesis finished with 0 errors, 0 critical warnings and 0 warnings.Synthesis Optimization Runtime : Time (s): cpu = 00:00:14 ; elapsed = 00:00:20 . Memory (MB): peak = 1037.844 ; gain = 0.000Synthesis Optimization Complete : Time (s): cpu = 00:00:21 ; elapsed = 00:00:22 . Memory (MB): peak = 1037.844 ; gain = 20.840INFO: [Project 1-571] Translating synthesized netlistNetlist sorting complete. Time (s): cpu = 00:00:00 ; elapsed = 00:00:00.002 . Memory (MB): peak = 1037.844 ; gain = 0.000INFO: [Netlist 29-17] Analyzing 36 Unisim elements for replacementINFO: [Netlist 29-28] Unisim Transformation completed in 0 CPU secondsINFO: [Project 1-570] Preparing netlist for logic optimizationINFO: [Opt 31-138] Pushed 0 inverter(s) to 0 load pin(s).Netlist sorting complete. Time (s): cpu = 00:00:00 ; elapsed = 00:00:00 . Memory (MB): peak = 1044.445 ; gain = 0.000INFO: [Project 1-111] Unisim Transformation Summary:A total of 36 instances were transformed.IOBUF => IOBUF (IBUF, OBUFT): 30 instancesRAM64X1D => RAM64X1D (RAMD64E(x2)): 6 instancesINFO: [Common 17-83] Releasing license: Synthesis25 Infos, 0 Warnings, 0 Critical Warnings and 0 Errors encountered.synth_design completed successfullysynth_design: Time (s): cpu = 00:00:26 ; elapsed = 00:00:27 . Memory (MB): peak = 1044.445 ; gain = 27.441INFO: [Common 17-1381] The checkpoint 'C:/Users/Documents/RA_3_9600/RA_3_9600.runs/synth_1/RA_3_9600.dcp' has been generated.INFO: [runtcl-4] Executing : report_utilization -file RA_3_9600_utilization_synth.rpt -pb RA_3_9600_utilization_synth.pbINFO: [Common 17-206] Exiting Vivado at Sun May 16 13:41:20 2021...

author: hermitengineer
author_rank: Regular Contributor
timestamp: May 16, 2021, 08:16:41 pm
content: Quote from: rstofer on May 16, 2021, 04:29:10 pmThe RTL elaboration is definitely correct, the simulation test code passes, and it uses all of the bits of all of the memory in the testing. Both synthesis and implementation are "successful". 0 warnings, 0 critical warnings, 0 errors, but the synthesized schematic has hacked out most of the logic.What is most baffling, though, is that it only strips out 15 of the 16 memory bits. It generates lookup tables to replace the parts that read RAM and replaces the data with constant values. Then after deciding that nobody is reading 15 of the bits, apparently, it culls them. But #15, apparently IS used.

author: miken
author_rank: Regular Contributor
timestamp: May 16, 2021, 10:12:44 pm
content: Hmm, maybe you fixed it after your initial post? This is what I get in 2019.2.

author: hermitengineer
author_rank: Regular Contributor
timestamp: May 16, 2021, 11:16:29 pm
content: Well, I haven't fixed anything and it's still going wrong. Is there a way to force a complete re-synthesis from nothing? Maybe it's skipping some steps because it thinks some of the files are unchanged?Anyway, DB is one of the chip's inout port vectors. The RINGBUFFER's 'unconnected port' is connected to the memory output. But maybe I specified it wrong?DB (as an output) is also connected to memory output under the ram_to_db condition.

author: hermitengineer
author_rank: Regular Contributor
timestamp: May 17, 2021, 12:18:47 am
content: Even more curious, I tried to run the post-synthesis functional simulation. It came up with errors that make no sense.Code:ERROR: [VRFC 10-3180] cannot find port 'SD_OBUF' on this module [C:/Users/Documents/RA_3_9600/RA_3_9600.sim/sim_1/synth/func/xsim/ra3_9600_tb_func_synth.v:1344]ERROR: [VRFC 10-3180] cannot find port 'Q' on this module [C:/Users/Documents/RA_3_9600/RA_3_9600.sim/sim_1/synth/func/xsim/ra3_9600_tb_func_synth.v:1343]ERROR: [VRFC 10-3180] cannot find port 'DB_IBUF' on this module [C:/Users/Documents/RA_3_9600/RA_3_9600.sim/sim_1/synth/func/xsim/ra3_9600_tb_func_synth.v:1342]ERROR: [VRFC 10-3180] cannot find port 'CLK' on this module [C:/Users/Documents/RA_3_9600/RA_3_9600.sim/sim_1/synth/func/xsim/ra3_9600_tb_func_synth.v:1341]ERROR: [VRFC 10-3180] cannot find port 'BUSAK_IBUF' on this module [C:/Users/Documents/RA_3_9600/RA_3_9600.sim/sim_1/synth/func/xsim/ra3_9600_tb_func_synth.v:1340]ERROR: [XSIM 43-3322] Static elaboration of top level Verilog design unit(s) in library work failed.The file in question, where the errors are:Code:CPUBUSDECODER decoder(.BUSAK_IBUF(BUSAK_IBUF),.CLK(intak),.DB_IBUF(DB_IBUF[13:0]),.Q(\RING_reg ),.SD_OBUF(SD_OBUF));The module that it had just defined:Code:module CPUBUSDECODER(SD_OBUF,DB_IBUF,Q,CLK,BUSAK_IBUF);output [13:0]SD_OBUF;input [13:0]DB_IBUF;input [13:0]Q;input CLK;input BUSAK_IBUF;wire BUSAK_IBUF;wire CLK;wire [13:0]DB_IBUF;wire [13:0]Q;wire [13:0]SD_OBUF;wire mode;wire mode_i_2_n_0;

author: rstofer
author_rank: Super Contributor
timestamp: May 17, 2021, 01:00:50 am
content: Quote from: hermitengineer on May 16, 2021, 11:16:29 pmJust click on Run Synthesis and click on OK in the popup dialog.Follow this with Generate Bitstream to get all the errors and warnings.

author: rstofer
author_rank: Super Contributor
timestamp: May 17, 2021, 01:06:32 am
content: You do have a Constraints file to define the pinout of your project, right?

author: hermitengineer
author_rank: Regular Contributor
timestamp: May 17, 2021, 01:56:09 am
content: Quote from: rstofer on May 17, 2021, 01:00:50 amThat might be the missing link. I never generated the bitstream since I wasn't ready to try to upload it.Edit: Well, the bitstream added a couple more warnings, but none of the scale that deletes entire sections of your circuitry. Two about the same LUT driving a clock, one that I haven't configured the voltage for the chip yet.Quote from: rstofer on May 17, 2021, 01:06:32 amYeah, I just used the auto-place pins tool for the moment.

author: hermitengineer
author_rank: Regular Contributor
timestamp: May 18, 2021, 04:20:50 am
content: I've made some progress by splitting each module into its own project and compiling it separately. It actually reports warnings and errors! Most of the modules compiled cleanly. But I note that it complains about a lack of input delay constraints in some cases. But, what timing constraint would you place on an asynchronous input?Secondly, I now see in one module that it warns of a non-clock source driving clock inputs. The non-clock source is, of course, SR3. It is definitely a trigger for the case of advancing an address counter, but it's also an asynchronous level trigger for the purpose of making SD an output, and an asynchronous clear for another counter. It is NOT a clock. If I specify it as one, then the timing constraints cry about cross-domain interaction. It seems that Vivado hates asynchronous triggers. Are there any tricks for telling it that you definitely want an input to be asynchronous and you'll take your lumps from any race conditions?

author: Bassman59
author_rank: Super Contributor
timestamp: May 18, 2021, 05:27:32 am
content: Quote from: hermitengineer on May 18, 2021, 04:20:50 amIt's not that Vivado hates asynchronous triggers. It's that that FPGA fabric hates having flip-flop clock inputs driven regular logic signals not on a global clock net.Remember any signal on the sensitivity list with a negedge or posedge decoration is considered to be either an async reset or a clock, and the discussion above tells how the two are distinguished. So you wrote your code to infer an edge-triggered flip-flop.Try putting a BUFG macro on the signal which you are using as that clock. That will put the signal on the global clock net and satisfy the tools. Note that you might incur a routing delay penalty for doing so.

author: hermitengineer
author_rank: Regular Contributor
timestamp: May 18, 2021, 06:45:43 am
content: Quote from: Bassman59 on May 18, 2021, 05:27:32 amWell, I tried that. The schematic shows it appearing on a BUFG buffer, but it still gives me the same message: "The clock pin card_addr_reg.C is not reached by a timing clock" and in the timing report it says "Register/Latch pins with no clock driven by root clock pin: SR3" and lists card_addr_reg[0..7]/C. In "no_input_delay" it complains with high severity about a lack of timing constraints on my asynchronous inputs (yeah, that's part of being asynchronous).Well, here's what I have currently:Code:module CARDADDR((* CLOCK_BUFFER_TYPE = "BUFG" *) input SR3,input P2,input BUSAK,input mode,output reg [7:0] card_addr,output reg loading_values);...always@(posedge P2, posedge SR3) beginif(SR3) begincard_load_count <= 0;LD_EN <= 0;end else if(P2) beginif(!LD_EN) begin{LD_EN, card_load_count} <= { 1'b0, card_load_count } + 1;endendendI should note that if this is the only code, all clears are asynchronous. But with the follow-on code, it apparently freaks out about the possibility of loading a transitional value from LD_EN and converts it to a synchronous clear.Code:always@(posedge P2, posedge BUSAK) beginif(BUSAK) beginloading_values <= 0;end else if(P2) beginloading_values <= 1;endendIt generates a little more circuitry for this part than I'd deem necessary, but whatever.Finally, the section that it panics about clocking without a timed clock (and also freaks out about all the other inputs to its generated FFs being possibly unconstrained):Code:always@(negedge SR3, negedge mode)beginif(!mode) begincard_addr <= 0;end else beginif(loading_values) begincard_addr <= card_addr + 1;endendendAnd here's a basic circuit diagram of what I'm trying to synthesize

author: Bassman59
author_rank: Super Contributor
timestamp: May 18, 2021, 03:44:01 pm
content: Quote from: hermitengineer on May 18, 2021, 06:45:43 amWell, you described a synchronous clear.Actually, it's more confusing than that. In the above block, which is the "clock" and which is the "asynchronous reset?" Looks to me like SR3 is the reset and P2 is the clock. What might be confusing the tools (and you, and me) is that you check the state of P2 for your clock edge detector. Now, I'm a VHDL guy, and this is one of the "features" of Verilog that still makes me wonder what they were thinking. (VHDL is absolutely clear on this: you'd userising_edge(P2)to clearly indicate "I want to infer a rising-edge-triggered flip-flop with the clock as P2." But I digress.)So what you described above -- and this is, I think the root of your problem -- will asynchronously clear LD_EN when SR3 is high. Here is where Verilog gets REALLY confusing. FPGA flip-flops have only one clock. The normal idiom for inferring a flip-flop with an async clear is:Code:always @(posedge clk, negedge rst) beginif (!rst)q <= 1'b0;elseq <=d;endThe synthesizer does pattern-matching. The above idiom is the pattern for a flip-flop and the synthesizer "knows" that rst is the async reset and clk is the rising-edge-triggered clock. It's strange how the sensitivity list looks suggests the reset is edge triggered. As we know, an async reset overrides a clock. Imagine we've brought rst low -- we've triggered a reset. Now, when there's a positive edge on the clock, the process is triggered again. But since we first check the state of rst and we see that it's low, that condition wins and the reset assignment continues. (I honestly don't know why the idiom isn't @(posedge clk, rst), and I've been musing over this since first doing Verilog in 1996.)But what you wrote above? That's confusing! It really does look like you want two clocks, and I'm not surprised that the synthesizer is giving you fits.You might wish to simulate that block and see what it's actually doing. Because it looks to me like LD_EN is permanently low. Look at the assignment:Code:if(!LD_EN) begin{LD_EN, card_load_count} <= { 1'b0, card_load_count } + 1;endLD_EN is always assigned 1'b0, so it's always low and on every rising edge of P2 card_load_count increments. What happens when that incremented overloads? I have no idea. I don't know what you intend with this code.QuoteHere you're doing a simpler flop with async clear. Get rid of the check if (P2). It is implied that if BUSAK has not seen a rising edge, then the only thing that triggers the block is the rising edge of P2. And that should infer a proper edge-triggered flip-flop with P2 as the clock and BUSAK as the async clear.QuoteFrom what I understand, you're trying to model exactly how the original design, implemented in basically async logic, in an inherently-synchronous device (the FPGA). The reason for doing it the "old way" in the old days was because that's what was available to the design engineers. Thankfully, we don't have to design like that any more. And you're learning the reasons why -- for one, the tools don't like async design.QuoteFor clarity: the complaints you get come from the timing analyzer or the synthesizer?In any case, you've used SR3 as a reset way up above and now you're using it as a clock, so there's no surprise that the tools can't make heads or tail of what you want to do.

author: hermitengineer
author_rank: Regular Contributor
timestamp: May 18, 2021, 06:34:20 pm
content: Quote from: Bassman59 on May 18, 2021, 03:44:01 pmYes, both card_load_count and LD_EN should be asynchronous clears based on SR3. It's not the above code that converts LD_EN to a synchronous one though. As I say, the above code alone leaves everything as intended. It's the use of LD_EN in the next block that forces conversion to a synchronous clear.Quote from: Bassman59 on May 18, 2021, 03:44:01 pmActually, Verilog handles this like a champ. The {} construct tells it to treat the list of bit vectors as one large value concatenating the bits in the order presented. So the 3-bit count is extended to a 4-bit count with a 0 for its high bit. Then the arithmetic operation adds 1 and, on a count of 7, the count resets to 0 with a 1 in the high bit as expected. This 4-bit value is then split back into count and LD_EN, with the 1 being assigned to LD_EN. The auto-generated schematic bears this out, that LD_EN is treated exactly as if it were the 4th bit.I did experiment earlier with making the count 4 bits and connecting LD_EN as a wire to the 4th bit. This did not change the generated schematic at all, nor did it change the fact that the lower 3 bits are asynchronous clear but the 4th is converted to synchronous.Quote from: Bassman59 on May 18, 2021, 03:44:01 pmUggh... this is wrong though. It needs to depend on LD_EN, as noted in my provided schematic. This must be from backing out an experimental change stupidly, since not using the first block's output causes it to be optimized out. Let's correct the block:Code:always@(posedge P2, posedge BUSAK) beginif(BUSAK) beginloading_values <= 0;end else beginif(LD_EN) beginloading_values <= 1;endendendQuote from: Bassman59 on May 18, 2021, 03:44:01 pmTiming analyzer. These complaints come from the "Check Timing" section.Quote from: Bassman59 on May 18, 2021, 03:44:01 pmYeah and that's the problem: It is both. Is there a way to "clone" the signal in a way that fools Verilog into thinking one is a clock and the other is a reset signal?

author: emece67
author_rank: Frequent Contributor
timestamp: May 18, 2021, 11:39:17 pm
content: .

author: hermitengineer
author_rank: Regular Contributor
timestamp: May 19, 2021, 06:03:15 am
content: Well, it turns out I'm an idiot. (pauses for gasps to fade away)Quote from: emece67 on May 18, 2021, 11:39:17 pmUnfortunately, my circuit is wrong. The flip-flop is only supposed to be set by the count, never reset. Then the flip-flop can actually drive the address counter correctly rather than keeping it always on.Anyway, I finally figured out that it's NOT doing a synchronous clear of the high bit. It's inverting the sense. FDCE vs FDPE, both are asynchronous. But the latter turns on instead of off. Vivado decided that was a more efficient implementation.Now, one thing I've come up with as a kludge: Provide SR3 on 2 separate pins to the chip. This allows me to interpret one as a clock input and the other as an asynchronous input, even though they are both the same. With that, my code shows:Code:always@(posedge P2, posedge SR3_RST) beginif(SR3_RST) begincard_load_count <= 0;LD_EN <= 0;end else if(P2) beginif(!LD_EN) begin{LD_EN, card_load_count} <= { 1'b0, card_load_count } + 1;endendendalways@(posedge P2, posedge BUSAK) beginif(BUSAK) beginloading_values <= 0;end else beginif(LD_EN) beginloading_values <= 1;endendend// Advance the address if LD is activealways@(negedge SR3_CLK, negedge mode)beginif(!mode) begincard_addr <= 0;end else beginif(loading_values) begincard_addr <= card_addr + 1;endendendI still have to make Vivado think that SR3_CLK is a timed clock, but at least that eliminates all of the gripes. Adding a few other constraints has tamed the rest of the timing analysis, though I am not completely certain I specified sane values.A final note is that I had to make 'mode' a false path to the clear pins, or it cries about that timing constraint. Apparently, it attempts to implement the 8-bit counter using 2 lookahead carry units, and it gets paranoid about hold times with regards to SR3_CLK. With the false path, it goes back to implementing the 8-bit counter with LUTs again, which apparently doesn't have hold time paranoia.Code:set_property IOSTANDARD LVTTL [get_ports {card_addr}]set_property IOSTANDARD LVTTL [get_ports {card_addr}]set_property IOSTANDARD LVTTL [get_ports {card_addr}]set_property IOSTANDARD LVTTL [get_ports {card_addr}]set_property IOSTANDARD LVTTL [get_ports {card_addr}]set_property IOSTANDARD LVTTL [get_ports {card_addr}]set_property IOSTANDARD LVTTL [get_ports {card_addr}]set_property IOSTANDARD LVTTL [get_ports {card_addr}]set_property IOSTANDARD LVTTL [get_ports BUSAK]set_property IOSTANDARD LVTTL [get_ports loading_values]set_property IOSTANDARD LVTTL [get_ports mode]set_property IOSTANDARD LVTTL [get_ports P2]create_clock -period 500.000 -name P2 -waveform {0.000 250.000} [get_ports P2]# set_false_path -from [get_clocks SR3] -to [get_clocks P2]create_clock -period 2000.000 -name SR3 -waveform {0.000 1000.000} [get_ports SR3_CLK]set_input_delay 0.000 [get_ports {BUSAK mode SR3_RST}]set_false_path -from [get_ports mode] -to [get_pins -hierarchical *card_addr_reg*/CLR*]set_output_delay -clock [get_clocks SR3] -min 300.000 [get_ports {{card_addr} {card_addr} {card_addr} {card_addr} {card_addr} {card_addr} {card_addr} {card_addr}}]set_output_delay -clock [get_clocks P2] -min 300.000 [get_ports loading_values]set_output_delay -clock [get_clocks SR3] -max 400.000 [get_ports {{card_addr} {card_addr} {card_addr} {card_addr} {card_addr} {card_addr} {card_addr} {card_addr}}]set_output_delay -clock [get_clocks P2] -max 400.000 [get_ports loading_values]

author: Bassman59
author_rank: Super Contributor
timestamp: May 19, 2021, 10:07:13 pm
content: Quote from: Bassman59 on May 18, 2021, 03:44:01 pmTiming analyzer. These complaints come from the "Check Timing" section.I think where the tools are not sufficient for dealing with this comes in the basic period constraint. They expect that when a signal is used as a clock, it will toggle at a given periodandthat your logic starts and ends with registers on that same clock. So the period constraint is really saying, "the prop delay between the start register and the end register must be no more than XX ns." The timing analyzer takes into account the start flop's clock-to-out, the end flop's setup requirements, and both the logic and the routing in between.If there's no "start" and "end" registers, as such, the tools get ... confused. And this is really where the notion of doing asynchronous design in an FPGA kinda goes to hell. It's not that the design idiom itself is good, bad or indifferent. It's just that the FPGA fabric and the tools are not intended to deal with it. And, really, what you are doing is async design.QuotePut a BUFG on SR3, call its output SR3_Clk or something, and then use SR3 for the reset and SR3_Clk as the clock.NB: I haven't tried this so I don't know whether this will actually work.

author: hermitengineer
author_rank: Regular Contributor
timestamp: May 19, 2021, 10:22:48 pm
content: Yeah I guess it also has such a thing as a "virtual clock" which is supposed to be the dumping ground for the combinational logic. I guess even with that, it expects the results to be available before the next virtual cycle though.I also discovered the "disable timing check" constraint. This may be necessary for the asynchronous clears, since the analyzer wants to put some kind of limits on them even though they are async. I sorta get the rationale, that if you, say, don't provide a large enough pulse width you might only catch 1 or 2 of them, or that if you drop the signal at just the wrong time you might see a FF do something stupid. But since this is a simple design and the engineers who designed it way back then seem to have taken great care to keep the signal timing where everything behaves, I'd rather Vivado not concern itself with those details.On the good side, it has been quite educational, to see how even the timing constraints will affect the implementation circuit design.

author: hermitengineer
author_rank: Regular Contributor
timestamp: May 20, 2021, 09:48:17 am
content: So, it's beginning to look like I at least have adequate grasp of Verilog. But Vivado's timing constraints are still confusing.If I use the constraints wizard to set an input delay, for instance, it asks which clock (makes sense) and which edge (also makes sense) but then asks for the delay value plus the trace delay. Okay, I understand trace delay in principal: signals don't make it instantly from one location on the PCB to the other. This was even becoming an issue in the days of 386. I get it, but I can only guess at what the trace delay might be for this board (and at its paltry clock speed, it really won't matter). So I just throw 1ns in there and call it good.Then it wants to know about signal delay for each input. This is where I get confused. The signal paradigm is that the signal arrives long before the clock pulse. But the timing diagram suggests that it wants to know how long AFTER the clock pulse to look for the signal. Am I correct in this interpretation? And if so, does that mean I should use negative numbers to say that the signal is already there?Even with this, though, I get timing errors even on the simplest of circuits. For instance:Code:module test(input a,input b,input c,input d,input e,output y,output reg z);always@(posedge c) beginz <= a | b;endassign y = z & (c | d) ^ (c & e);endThe combinational part is handled well. In fact, if I don't trigger on any edges, it creates nothing but a combinational circuit. Curiously, this is true even for the constructCode:always@ (c) beginz <= a | b;endIt does not create a circuit that clocks on either change of c. It just creates a combinational circuit a|b and wires it to z.Anyway, if the circuit is purely combinational, then no timing analysis seems to be done. Makes sense. But with the trigger I added, and with a constraint file I added, it complains about the hold time for a in relation to c.Code:create_clock -period 100.000 -waveform {0.000 50.000} [get_ports c]set_input_delay -clock [get_clocks c] -min -add_delay -25.000 [get_ports a]set_input_delay -clock [get_clocks c] -max -add_delay 50.000 [get_ports a]set_input_delay -clock [get_clocks c] -min -add_delay -25.000 [get_ports b]set_input_delay -clock [get_clocks c] -max -add_delay 50.000 [get_ports b]This results in a hold violation. It seems mad that the data arrived before it was needed. Why? Furthermore, it only complained about input "a" and not "b". Why? They are both placed on adjacent pads and are both sent on a whirlwind winding route throughout the entire chip before finally making it to the LUT. So if there are skewed arrival times, it's the router's fault. But either way, it appears that the timing check has decided that "a" arrived -11ns before the required time of 0. Why is that a problem?

author: emece67
author_rank: Frequent Contributor
timestamp: May 20, 2021, 11:14:42 am
content: .

author: emece67
author_rank: Frequent Contributor
timestamp: May 20, 2021, 11:55:03 am
content: .

author: rstofer
author_rank: Super Contributor
timestamp: May 20, 2021, 03:50:37 pm
content: An FPGA will easily run at 100 MHz and 10ns is a lot faster than the old LSTTL could run (14 ns clock to Q output, 32 MHz max, asynchronous inputs to output change 38 ns and 20-25 ns of setup time for clocked inputs). So, this project will eventually come down to "what does the circuit do" instead of "how did the circuit do it".Asynchronous design with FPGAs just isn't done. The tools don't want to do it and they will be an impediment throughout the process. A process destined to fail, IMO.It would seem to me that it would be better to define how the inputs affected the outputs and then just design a simple synchronous circuit that would emulate the original.Think of the new circuit as a 'black box'. It has inputs and outputs and only one clock. What should the outputs look like when the inputs change. Maybe make up a timing diagram like the one on page 10 here but for the entire project.https://www.ti.com/lit/ds/symlink/sn74ls163a.pdfBTW, only synthesis matters.

author: hermitengineer
author_rank: Regular Contributor
timestamp: May 20, 2021, 05:54:05 pm
content: Quote from: emece67 on May 20, 2021, 11:14:42 amYeah I saw that afterwards. It was left over from the initial test where everything WAS combinational. I removed the references to 'c' in the combinational part. But it did not affect any of the timing-related gripes.If there are no timing constraints given on the inputs, the router will make nice neat connections from the pads to the LUTs. If the timing is specified as negative setup time, meaning the signal is already good, then the router will spaghetti the route all over the chip like a doodling child, give up, and say that it can't get the hold time within the required 0ns time. The best I can figure is that it freaks out, thinking that the data is no longer valid after the rising edge, even if you specify a positive value for the max. It seems that the only satisfactory answer would be "0" after the rising edge for the non-clock inputs.

author: miken
author_rank: Regular Contributor
timestamp: May 21, 2021, 07:10:04 am
content: The most understandable presentation of the timing constraints I've seen is in Vivado under Tools -> Language Templates. Maybe that will help.

author: hermitengineer
author_rank: Regular Contributor
timestamp: May 22, 2021, 11:54:53 am
content: On the original project, I fixed the memory problems. First, Vivado doesn't seem to synthesize the dual-port memory well. I always chose the latched address for a write, but read from either the latched one or the internal counter, depending on conditions. This seems to be what broke Vivado's brain, even though they have memory primitives constructed for that purpose.Oh well, if I switch to CPLD with external memory, I'll need to migrate to a single address port anyway.The other issue was not using a power of 2 for memory size. This caused problems with memory address sizes as it lost the high bit. Specifying 512 instead of 352 words solved that issue.But even still, the simulations of synthesis or implementation continue to fail for unknown reasons. It has many ports that it claims don't exist, even though they definitely do exist in the code. For instance, mode_reg_0 is defined for the module on line 9xx, but when it tries to instantiate the module it claims the port cannot be found. Same for the IBUFs on a number of pins. What's this about?