Awesome
KiCad to Verilog Generator
Introduction
This is a KiCad plugin for generating Verilog code from a KiCad 6.0 (or later) schematic.
This is useful if you are designing a retro circuit board, e.g. a CPU made out of discrete TTL chips, and want to simulate it. You would design your circuit in KiCad's schematic editor, convert it to Verilog, and use any one of the several free [Verilog simulators](List of HDL simulators - Wikipedia) available.
You would most certainly not use KiCadVerilog (KV) to write Verilog for an FPGA. In that case, you would just write the Verilog directly. As such, KV is, admittedly, a niche application.
It's important to understand exactly what KV will and will not do for you. It will help you immensely, but you will still need to write some Verilog code yourself.
KV takes the netlist generated by KiCad's schematic editor and converts it to Verilog. There are more details below, but essentially it generates Verilog wires for the KiCad nets, generates Verilog modules for the KiCad symbols (the components in your schematic) with appropriate port lists, and generates instantiations of the modules that pass the appropriate signals to the module. So all the wiring of your design is correctly converted to Verilog.
But KV doesn't know the functionality of the components in your design. So you still need to write the Verilog code that goes into the modules that KV generates (or find it on the web).
KV helps you integrate your Verilog code with the KV-generated Verilog code. In the KiCad schematic, each symbol has Properties, and those properties include a list of Fields. KV looks for custom fields, which you'll create, and uses them to insert the code you write into the generated Verilog. So you can simulate your design, modify the schematic, re-generate the Verilog, and have all your work automatically incorporated into the re-generated code.
(If your first thought is that you don't want to put a large chunk of Verilog code in the KiCad fields, don't worry: that's addressed later.)
KV does more, like detecting pull-up and pull-down resistors, and bypass capacitors. But this gives you the general idea and helps you decide whether KV will meet your needs. Let's get into the details.
Installing KiCadVerilog
If you are running under Windows: go to the Windows Start menu and select
KiCad 6.0 Command Prompt
(in the KiCad 6.0 folder). In the command prompt window that appears, give the commandpip install pyparsing
. If KiCad was running during this, exit and re-run it.
Next, install the plugin itself. Download the plugin's zip file. From the KiCad Project Manager, select Tools->Plugin and Content Manager
. In the displayed window, click the Install from File...
button at the bottom and select the zip file.
If Pcbnew was running while you did that, you'll need to select its Tools->External Plugins->Refresh Plugins
menu. The KiCadVerilog icon should then appear on Pcbnew's toolbar.
Running KiCadVerilog
The following section, Understanding KiCadVerilog, explains exactly what KV does, and what you need to do to create a complete Verilog program. But let's do the easy stuff first: running KiCadVerilog.
First, generate a netlist for your schematic. To do this, run the Schematic Editor, select File->Export->Netlist...
, click the Export Netlist
button, and choose a file name.
Next, run the PCB Editor (even if you haven't created a PCB for this project yet). Click the KiCadVerilog button on the toolbar () or select Tools->External Plugins->KiCadVerilog
. You'll see the following dialog box:
Enter the path of the netlist file you just exported. Give the path and name of the file where you would like the Verilog file generated, and click Generate Verilog.
Complex schematics might take a minute to process. Be patient. Errors, warnings, and messages will appear in the Results box when the Verilog generation is done.
Understanding KiCadVerilog
Overview
There are more details in the following sections. But the general approach to converting your schematic to Verilog is this:
-
Write (or find on the web) a Verilog module implementing the behavior of each component in your schematic. So, for example, if you have a 7402 quad NOR gate in your circuit, you need to write or find Verilog code that implements a quad NOR gate. Put these modules in one or more include files.
-
Export a netlist of your schematic from KiCad's Schematic Editor, run KiCadVerilog on it, and open the generated Verilog in a text editor.
-
For each module in the generated code, write an instantiation of the module from step 1 that implements that component's behavior. Usually, the instantiation will just be a single line of code that takes the arguments passed into the module, and re-arranges them to call the Verilog modules you wrote in step 1.
These one line instantiations you're writing will not stay in the generated Verilog file. You're only writing them here because it's a convenient text editor, where you can see all the arguments to the module. But in step 4, you're going to copy the instantiations you write here, and paste them into fields in the KiCad schematic.
Notice that if you use the same component multiple times, e.g. if you have multiple 7402 quad NOR gates in your design, the instantiations of them will all be the same. So you only have to write the instantiation once (but in the next step, you will copy that instantiation into a field for each 7402 in your schematic).
-
Go back to KiCad's Schematic Editor and bring up the symbol properties for each component. Create a VerilogInclude field and enter the name of the include file that has the implementation for that component. Create a VerilogCode field, and copy and paste the instantiation you wrote for that component.
Since the Verilog you write is incorporated into the KiCad schematic, it will always be incorporated into the generated Verilog, without any additional effort on your part.
Note that if you have multiple identical components, like multipe 7402s, you don't really need to create VerilogInclude fields for each of them. If just one of them includes the Verilog file you need, the generated Verilog code will have the necessary
include
statement. -
Re-export the netlist and run KiCadVerilog on it. You should now have a file ready for Verilog simulation.
The Generated Verilog Code
A KiCad netlist contains nets and parts (i.e. the symbols or components in your schematic). The parts have pins (i.e. the pins on an integrated circuit, or the leads of components like resistors and capacitors). The netlist also contains information about which nets are connected to which pins.
Legal Names
Each net, part, and pin in the netlist has a name. The names are legal according to KiCad's rules, but Verilog has different rules. And so, in the Verilog code KV generates, the KiCad names are converted to legal Verilog names. Most illegal Verilog characters are converted to underscores. Characters that typically indicate inverse logic (*, ~, /) are converted to the letter n. Plus signs are converted to the word "plus" (so that a net named "+5V" becomes "plus5V"), and non-ASCII characters are converted to their hexadecimal codes.
Includes
The first code KV generates is a list of include
directives. You specify which files to `include in the generated Verilog by adding VerilogInclude fields to symbols in your KiCad schematic (see below).
Top-Level Module
The generated top-level Verilog module is given a name based on the output file name specified in the dialog, above.
The top-level module's ports are determined by VerilogModulePort fields that you can specify in the symbol properties in the KiCad schematic (see below).
Wires
Within the top-level module, KV generates a Verilog wire for every net in the netlist. However, KV detects a small number of special-case wires.
KiCad has power port symbols, such as "+5V", "+3V3", etc. A net connected to one of these symbols gets its name from the symbol. KV looks for nets whose names start with a plus sign, or whose names are "Vdd" or "Vcc" (KV uses a case-insensitive comparison).
Those nets are assumed to be a logical 1 value. And so when KV generates a Verilog wire for them, it assigns that wire the value of 1. As a result, any pin tied to a positive voltage will be connected to a logical 1 in the Verilog code.
Similarly, if a net is named "GND" or "Vss" (case-insensitive), the generated Verilog wire is assigned a value of 0. Any pin tied to ground will be connected to a logical 0 in the Verilog code.
KV also recognizes nets that are being pulled up or pulled down. If a net is connected to a resistor, and the other end of that resistor is connected to net that was recognized as a positive voltage, then the first net is being pulled up, and a tri1 wire is generated in Verilog.
If a net is connected to a resistor that is connected to ground, the net is being pulled down and KV generates it as a tri0 wire.
KV recognizes a resistor as a part with two pins and whose KiCad description field contains the word "resistor" (case insensitive).
Module Invocations
After generating the wires, KV generates module invocations for each part (symbol) in your schematic, with the following exceptions:
-
It does not generate module invocations (or modules) for pull-up and pull-down resistors.
-
It does not generate module invocations or modules for bypass capacitors. Bypass capacitors are identified as parts with two pins, the word "capacitor" (case-insensitive) in their KiCad description, with one pin connected to a net with a positive voltage, and the other pin connected to a ground net.
All other parts, be they ICs, LEDs, transistors, motors, etc. have module invocations generated for them. The port list in the invocation is a list of (almost) all the wires connected to the component's pins, in order of the pin number. I say "almost" because pins that, in KiCad, have the type "power input" or "power output" are not included in the port list.
Modules
Finally, KV generates a module for each part that it generated an invocation for. The module's port list is the name of each pin on the part (except for pins that, in KiCad, have the type "power input" or "power output"). Note that some parts don't have named pins. In those cases, the name of the port will be the pin number preceded by an underscore (e.g. "_1").
KV attempts to identify buses among the pins. For example, a memory chip may have pins named A0 through A12, and D0 through D7. KV recognizes buses when there are pins with the same base name, with a number at the end.
For each bus found, KV generates a macro definition within the module. For example:
`define A {A12, A11, A10, A9, A8, A7, A6, A5, A4, A3, A2, A1, A0}
When you write Verilog code to be included in the module, you can make use of those bus macros. Remember: they're macros, not Verilog buses. To reference them, you must precede the name with a backtick.
Next, KV inserts the Verilog code that you specified in the part's VerilogCode field in the KiCad schematic editor (see below).
At the end of the module, KV generates `undef statements to undefine the bus macros. That way, multiple modules can have buses with the same name.
KiCadVerilog Fields
KV helps you integrate your Verilog code with the generated code. KV doesn't know the behavior of the parts in your schematic, so you must provide Verilog code to implement their behavior. Then, you must [add fields to the symbols](Schematic Editor | 6.0 | English | Documentation | KiCad) in your schematic to tell KV how to integrate your code.
KV recognizes three fields: VerilogInclude, VerilogCode, and VerilogModulePort. The names are case-insensitive.
As an example:
Note that while this example has all three Verilog fields for one symbol, that's certainly not necessary. A symbol can have all, some, or none of the Verilog fields. Typically, however, if a symbol has a VerilogCode field, it should have a VerilogInclude field, since the code is usually instantiating a module that's in an include file.
VerilogInclude
A symbol may have a VerilogInclude field with the path and name of one file in it. KV gathers up all the VerilogInclude fields from all the symbols, eliminates duplicate requests for the same file name, and generates `include directives.
In the example above, no path is specified for the include file, but of course you can specify the path along with the file name. Think carefully about the correct path to specify. You're creating the VerilogInclude field in KiCad, but the `include directive will be processed by the Verilog simulator, and it will search for the file based on what directory the simulator is running in, using the simulator's rules for finding include files.
VerilogCode
The contents of the VerilogCode field are copied into the Verilog module that is generated for the symbol.
KiCad fields are a single line of text. You can embed escape codes such as \n to put multiple lines in the generated file. But in general, it's best to limit the VerilogCode field to a single line of Verilog.
And so in most cases, the Verilog code in the VerilogCode field should instantiate another module, and you should write that module in the include file specified in VerilogInclude.
In the above example, KV generates a module for U1 and inserts the code from the VerilogCode field, producing:
module U1(
output _1,
input _2,
input _3,
output _4,
input _5,
input _6,
input _8,
input _9,
output _10,
input _11,
input _12,
output _13);
ttl_7402 U1(_2, _3, _5, _6, _8, _9, _11, _12, _1, _4, _10, _13);
endmodule
In the file specified by the VerilogInclude field, 7402.v, we write:
// Quad 2-input NOR gate
module ttl_7402
(
input a1, b1, a2, b2, a3, b3, a4, b4,
output o1, o2, o3, o4
);
assign o1 = ~(a1 | b1);
assign o2 = ~(a2 | b2);
assign o3 = ~(a3 | b3);
assign o4 = ~(a4 | b4);
endmodule
VerilogModulePort
The VerilogModulePort field lets you specify what ports should be listed in the top-level module that KV generates.
This is, admittedly, kludgy. The ports in the top-level module are names of wires. Ideally, we should be specifying which KiCad nets, or Verilog wires, should be ports for the top-level module. But KiCad does not provide user-definable fields for nets.
So instead, KV looks for VerilogModulePort fields in the symbols. The field contains a comma-separated list of pin numbers. The wires connected to those pins will be used as ports in the top-level module.
Multiple symbols may have VerilogModulePort fields, and the port list will contain all the wires from all the fields. There is no way to control the order those ports are defined.
In KiCad, each pin has a type, e.g. input, output, passive, unspecified, etc. KV uses this when generating the port type. KiCad input, output, and bidirectional pin types result in Verilog input, output, and inout port types, respectively. All other KiCad pin types result in a Verilog inout port type.
Errors and Warnings
Error: Unable to open <Verilog file> for output.: File error.
Error: Unable to open <netlist file> for reading.: File error.
Error: Unable to parse <netlist file> as a KiCad 6+ netlist.: Either the specified file is not a netlist, or there's a bug in the code. If you suspect the latter, please open an issue.
Warning: No relevant nets connected to <ref>.: The specified component in your schematic is not wired up to anything.
Warning: Pin <n> on part <ref> is not connected to a net, and is not marked as 'no-connect': Self-explanatory.
Warning: Module <module name> has no Verilog code.: You did not create a VerilogCode field for the specified component. If you do not require any code for it, and you want to get rid of the warning, add a VerilogCode field to the component and put a Verilog comment in it, e.g. // No implementation
Info: No module generated for <ref> because it has no relevant pins.: "Relevant pins" includes signal pins, but excludes power pins. If a component has only power pins, KV will not generate a Verilog module for it.
About
KiCadVerilog is released under the MIT license.
I welcome bug reports, bug fixes, new feature requests, new feature implementations, questions, comments, and anecdotes about how you've used KiCadVerilog, at GitHub - galacticstudios/KiCadVerilog: Generate Verilog code from a KiCad netlist.