Difference between revisions of "ATC"
Tom Golubev (Talk | contribs) |
Tom Golubev (Talk | contribs) (→TODO in WIKI) |
||
(27 intermediate revisions by the same user not shown) | |||
Line 4: | Line 4: | ||
By processing the DUT, the ATC creates an object with inputs and outputs which are exactly the same as the DUT.<br> | By processing the DUT, the ATC creates an object with inputs and outputs which are exactly the same as the DUT.<br> | ||
− | + | alu.v | |
− | module | + | module alu |
+ | (input int data1, | ||
input int data2, | input int data2, | ||
output int out); | output int out); | ||
Line 15: | Line 16: | ||
− | The ATC created testbench will give access to data1, data2 and out, which is the complete interface of | + | The ATC created testbench will give access to data1, data2 and out, which is the complete interface of alu.v |
==Implementation:==<br> | ==Implementation:==<br> | ||
Line 23: | Line 24: | ||
− | * | + | * alu.xml (Excerpt taken)<br> |
<code> | <code> | ||
− | <testbench base=" | + | <testbench base="alu_tb" suite="vcs" ttb="alu.v"> |
<verilog> | <verilog> | ||
− | tests/ | + | tests/alu_tb.v |
</verilog> | </verilog> | ||
<source> | <source> | ||
− | tests/ | + | tests/alu_tb.cpp |
+ | tests/alu_ttb.cpp | ||
</source> | </source> | ||
− | <tab>tests/ | + | <tab>tests/alu_ttb.tab</tab> |
</testbench> | </testbench> | ||
</code> | </code> | ||
*This will create the complete interface for your testbench int the tests/ directory | *This will create the complete interface for your testbench int the tests/ directory | ||
− | + | *Note that both tb.cpp and ttb.cpp files have to be in the xml file for VCS to compile them. Order does not matter. | |
<p> | <p> | ||
#dut_tb.v - The verilog testbench, VCS will run this (Autogenerated every time your run rake)<br> | #dut_tb.v - The verilog testbench, VCS will run this (Autogenerated every time your run rake)<br> | ||
Line 45: | Line 47: | ||
#dut_ttb.h - VPI definitions, defines object that you use to communicate to ports of DUT (Autogenerated every time your run rake)<br> | #dut_ttb.h - VPI definitions, defines object that you use to communicate to ports of DUT (Autogenerated every time your run rake)<br> | ||
#dut_ttb.cpp - VPI Testbench backend, communication with VCS... (Autogenerated every time your run rake)<br> | #dut_ttb.cpp - VPI Testbench backend, communication with VCS... (Autogenerated every time your run rake)<br> | ||
− | #dut_ttb.tab - VCS file that correlates verilog functions with C++ VPI functions (Autogenerated every time your run rake, deprecated)<br></p> | + | #dut_ttb.tab - VCS file that correlates verilog functions with C++ VPI functions (Autogenerated every time your run rake, deprecated(1))<br></p> |
− | < | + | <br> |
+ | (1) The .tab file is still being auto-generated by the ATC. VCS, our primary simulator, is deprecating tab files and seems to be switching to the Modelsim way. Modelsim uses a struct, located in the ttb.cpp file, to map between the verilog functions and the C++ functions. The tab file does exactly the same thing, but is unnecessary (easier to put into the cpp file). So in effect, ignore the deprecated issue as this does not affect the end user at all. | ||
+ | <br><br><br> | ||
+ | |||
+ | ==Imports / Using Packages== | ||
+ | |||
+ | External packages are automatically parsed by the ATC. The top verilog file is parsed for imports::, and each import is processed.<br> | ||
+ | The ATC requires very strict lexical standards in the following areas:<br> | ||
+ | <br> | ||
+ | * module input / output declarations<br> | ||
+ | * All struct, const and typedefs.<br> | ||
+ | <br> | ||
+ | # Module inputs / outputs | ||
+ | Example:<br> | ||
+ | |||
+ | import scoore::*; // Automatically include package scoore, ATC will find and parse all imported packages | ||
+ | module alu | ||
+ | (input BoolType clk // Notice where the ( is, and the no space between it and the first port | ||
+ | ,input int data1 // Notice the comma is before the input / output keyword | ||
+ | ,input int data2 // Every port member requires a type, 1 bit members can be BoolType (package scoore::*) | ||
+ | ,output int out | ||
+ | ); // After ending port definitions for the top verilog file, the ATC does no further parsing of this file | ||
+ | always_comb begin | ||
+ | out = data1 + data2; | ||
+ | end<br> | ||
+ | end module<br> | ||
+ | <br> | ||
+ | <br> | ||
+ | # Packages: structs, consts, and typedefs<br> | ||
+ | <br> | ||
+ | package scoore; | ||
+ | |||
+ | const int SCOORE_ADDR_BITS = 32; // Example const: make sure a space is present between the = and both name and value | ||
+ | |||
+ | const L1MemReqType L1MEMREQ_READLINE = 3'b000; // bit sizes are fine, the ATC ignores the size, and converts hex or binary value to integer | ||
+ | |||
+ | typedef logic [3-1:0] ALUSelectType; // Example typedef: make sure a space is present between logic keyword and size | ||
+ | |||
+ | typedef struct packed{ // Example struct definition | ||
+ | ALUSelectType alu_type; | ||
+ | }ALUStateType; // Notice the end struct bracket and struct name have no space | ||
+ | |||
+ | endpackage | ||
<br><br><br> | <br><br><br> | ||
− | <H2> | + | |
+ | <H2>Running the initially created tb</H2><br> | ||
<br> | <br> | ||
− | [agolubev@mascd2 atcexample]$rake test:atcexample_tb<br> | + | [agolubev@mascd2 atcexample]$<b>rake test:atcexample_tb</b><br> |
(in /mada/users/agolubev/scoore)<br> | (in /mada/users/agolubev/scoore)<br> | ||
cd /mada/users/agolubev/scoore/projects/scoore/atcexample<br> | cd /mada/users/agolubev/scoore/projects/scoore/atcexample<br> | ||
Line 89: | Line 134: | ||
− | + | When the tb is first run, the check() fn prints out a variable, (num_total_ops) which corresponds to the clock cycle count. | |
− | + | ||
− | + | <b>Note:</b> clock cycle count starts at 0 | |
+ | The tb also has a verilog variable tb_cycle, that one may add to the wave viewer. This is to aid debugging. <br> | ||
+ | In the example above, the check() fn prints out the tb_cycle variable, which is set in the set() fn.<br> | ||
+ | <h2>Troubleshooting:</h2><br> | ||
+ | <br> | ||
+ | Q: Error-[ITSFM] Illegal `timescale for module <br> | ||
+ | /mada/users/agolubev/scoore/projects/scoore/l0d/rtl/SRAM_1W_1R_3x64test.v, 25 <br> | ||
+ | Module "SRAM_1W_1R_3x64test_v" has `timescale but previous module(s) do not.v <br> | ||
+ | Please refer LRM 1364-2001 section 19.8. <br> | ||
+ | A: As of verilog 2001, we do not use the `timescale directive. <br> | ||
+ | This is set in the _ttb.v file, so that we can parametrize it and test for power. <br> | ||
+ | <br> | ||
+ | The following command inline removes all `timescale directives. Use with caution, but is tested. <br> | ||
+ | sed -i 's/`timescale.*//' rtl/*.v | ||
+ | WORK IN PROGRESS | ||
+ | ==TODO in WIKI== | ||
+ | Explain overwriting ttb files | ||
+ | * vpi_printf vs printf - Use vpi_printf instead of printf, due to VCS compatibility issues. | ||
+ | * Please use the following nomenclature for printing messages. | ||
+ | This was borrowed from synplify. Its convenience stems from the fact that one can grep for warnings / errors easily. | ||
+ | Print nomenclature: Please start all printf lines with the following | ||
+ | @D - Debug | ||
+ | @E - Errors | ||
+ | @W - Warnings | ||
+ | * Cycle Count - Since these testbenches are cycle accurate, a C++ variable, num_total_ops, has the absolute cycle count. Its scope is available in all .cpp files | ||
+ | It is incremented every positive edge. Please use this variable for timing purposes. | ||
− | + | * tb_cycle: A verilog variable tb_cycle, takes on the value of num_total_ops every clock cycle, add this signal to help with debugging when using the wave window. | |
− | + | * VCS GUI: To launch the gui, envoke rake with the gui=1 option (e.g. rake test:salu_tb gui=1). This will fork the vcs gui, and give you back the terminal. | |
− | + | Explain tb_cycle | |
− | + | tb_cycle is a 32 bit entitity that lives in the _tb.v file, and added automatically | |
− | + | It is used to help with debugging using the waveform window | |
− | + | Each clock cycle, num_total_ops is incremented in the _ttb file. Your _tb.cpp file has access to this int, which keeps track of the clock cycle number. | |
+ | It is available both in the waveform viewer and the cpp testbench itself to view it, use dut->tb_cycle.to_i(). | ||
− | |||
− | |||
− | |||
− | + | vpi_printf("@D wcb_read_fsm_tb check(): tb_cycle[%d]\n", dut->tb_cycle.to_i()); | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | @D | + | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
+ | ==Writing / Reading Data Members== - Explains how members are read / written | ||
+ | Let's assume we're using the struct ByteType below. It contains 8 bits total. | ||
+ | ==Bits / Bytes / Endianess.== | ||
+ | typedef struct packed { | ||
+ | BoolType msb; | ||
+ | logic [6-1:0] mid; | ||
+ | BoolType lsb; | ||
+ | }ByteType; | ||
+ | This is stored as a char array of bits. | ||
+ | char array ByteType [sizeof(ByteType)] = [msb, 6 mid bits, lsb] | ||
+ | When setting a member of type ByteType to an int (32 Bits), only the 8 lsb bits of the int will be set to the ByteType | ||
+ | ByteType = (256 + 254);// is also = 0`b1_1111_1110 | ||
+ | Setting this will make ByteType 254, since it can only store 8 bits. | ||
+ | ==Dealing With Reset== | ||
+ | For most simulations, a power on reset needs to be asserted for at least one clock cycle. Depending on your module, SCOORE's specs require anywhere from 4 - 100 cycles of reset. | ||
+ | The simulator will show red waves, meaning they are unknown, since the memory had not been reset of initialized. There are several ways to assert the reset signal; the Verilog and the VPI way. | ||
+ | For the sake of flexibility and standardization, we will only assert reset from the C++ testbench itself. | ||
+ | In the _tb.cpp file, the reset code should resemble the following, and live in the tb_set function. | ||
+ | * if (num_total_ops <= 4) dut->reset = 1; else dut->reset = 0; | ||
+ | This will render the first 4 cycles of the testbench useless, but flops do have to be reset for the simulation to be correct. | ||
+ | unsigned int NUM_EXECUTE_CYCLES = 10 | ||
+ | rake only needs to be run if the .rv files have been change and are pertinent to the design. or if you change your logic. | ||
− | + | *Fix rake issue about compiling and error* | |
− | + | ||
− | + | ||
− | + |
Latest revision as of 00:11, 16 August 2009
Contents
Automatic Testbench Creator (ATC)
The ATC is a VPI testbench creator, it processes a verilog topfile, which is the device under test (DUT).
By processing the DUT, the ATC creates an object with inputs and outputs which are exactly the same as the DUT.
alu.v
module alu (input int data1, input int data2, output int out); always_comb begin out = data1 + data2; end end module
The ATC created testbench will give access to data1, data2 and out, which is the complete interface of alu.v
==Implementation:==
The ATC is integrated into rake. To use it, edit the xml file in your top directory of the module.
- In the testbench xml tag, add the ttb attribute, and set it to the name of your DUT.
This assumes that the dut.v file is relative to rtl/dut.v, and the output of the ATC will be to tests/
- alu.xml (Excerpt taken)
<testbench base="alu_tb" suite="vcs" ttb="alu.v"> <verilog> tests/alu_tb.v </verilog> <source> tests/alu_tb.cpp tests/alu_ttb.cpp </source> <tab>tests/alu_ttb.tab</tab> </testbench>
- This will create the complete interface for your testbench int the tests/ directory
- Note that both tb.cpp and ttb.cpp files have to be in the xml file for VCS to compile them. Order does not matter.
- dut_tb.v - The verilog testbench, VCS will run this (Autogenerated every time your run rake)
- dut_tb.cpp - Your VPI testbench, C++ (Autogenerated only if file doesn't exist)
- dut_tb.h - Any vars / stuff you need for your tb (Autogenerated only if file doesn't exist)
- dut_ttb.h - VPI definitions, defines object that you use to communicate to ports of DUT (Autogenerated every time your run rake)
- dut_ttb.cpp - VPI Testbench backend, communication with VCS... (Autogenerated every time your run rake)
- dut_ttb.tab - VCS file that correlates verilog functions with C++ VPI functions (Autogenerated every time your run rake, deprecated(1))
(1) The .tab file is still being auto-generated by the ATC. VCS, our primary simulator, is deprecating tab files and seems to be switching to the Modelsim way. Modelsim uses a struct, located in the ttb.cpp file, to map between the verilog functions and the C++ functions. The tab file does exactly the same thing, but is unnecessary (easier to put into the cpp file). So in effect, ignore the deprecated issue as this does not affect the end user at all.
Imports / Using Packages
External packages are automatically parsed by the ATC. The top verilog file is parsed for imports::, and each import is processed.
The ATC requires very strict lexical standards in the following areas:
- module input / output declarations
- All struct, const and typedefs.
- Module inputs / outputs
Example:
import scoore::*; // Automatically include package scoore, ATC will find and parse all imported packages module alu (input BoolType clk // Notice where the ( is, and the no space between it and the first port ,input int data1 // Notice the comma is before the input / output keyword ,input int data2 // Every port member requires a type, 1 bit members can be BoolType (package scoore::*) ,output int out ); // After ending port definitions for the top verilog file, the ATC does no further parsing of this file always_comb begin out = data1 + data2; end
end module
- Packages: structs, consts, and typedefs
package scoore;
const int SCOORE_ADDR_BITS = 32; // Example const: make sure a space is present between the = and both name and value
const L1MemReqType L1MEMREQ_READLINE = 3'b000; // bit sizes are fine, the ATC ignores the size, and converts hex or binary value to integer
typedef logic [3-1:0] ALUSelectType; // Example typedef: make sure a space is present between logic keyword and size
typedef struct packed{ // Example struct definition ALUSelectType alu_type; }ALUStateType; // Notice the end struct bracket and struct name have no space
endpackage
Running the initially created tb
[agolubev@mascd2 atcexample]$rake test:atcexample_tb
(in /mada/users/agolubev/scoore)
cd /mada/users/agolubev/scoore/projects/scoore/atcexample
Warning-[ACC_CLI_ON] ACC/CLI capabilities enabled
ACC/CLI capabilities have been enabled for the entire design. For faster
performance enable module specific capability in pli.tab file
50 modules and 0 UDP read.
However, due to incremental compilation, no re-compilation is necessary.
g++ -pipe -Wno-write-strings -I/mada/software/synopsys/vcs//include -I/mada/users/agolubev/scoore/projects/scoore/synthesis/rtl
-I/mada/users/agolubev/scoore/storage/rtl -I/mada/users/agolubev/scoore/memcell/rtl -I/mada/users/agolubev/scoore/projects/scoore/common/rtl
-I/mada/users/agolubev/scoore/projects/scoore/atcexample/rtl -O -I/mada/software/synopsys/vcs/include -c ../tests/atcexample_tb.cpp
g++ -pipe -Wno-write-strings -I/mada/software/synopsys/vcs//include -I/mada/users/agolubev/scoore/projects/scoore/synthesis/rtl
-I/mada/users/agolubev/scoore/storage/rtl -I/mada/users/agolubev/scoore/memcell/rtl -I/mada/users/agolubev/scoore/projects/scoore/common/rtl
-I/mada/users/agolubev/scoore/projects/scoore/atcexample/rtl -O -I/mada/software/synopsys/vcs/include -c ../tests/atcexample_ttb.cpp
../simv up to date
full clock set to 10ns
Testbench Seeded with 1247602844
@D atcexample_tb check(): tb_cycle[0]
@D atcexample_tb check(): tb_cycle[1]
@D atcexample_tb check(): tb_cycle[2]
@D atcexample_tb check(): tb_cycle[3]
@D atcexample_tb check(): tb_cycle[4]
@D atcexample_tb check(): tb_cycle[5]
@D atcexample_tb check(): tb_cycle[6]
@D atcexample_tb check(): tb_cycle[7]
@D atcexample_tb check(): tb_cycle[8]
@D atcexample_tb check(): tb_cycle[9]
10 Clock Cycles Total atcexample_tb FINISHED
When the tb is first run, the check() fn prints out a variable, (num_total_ops) which corresponds to the clock cycle count.
Note: clock cycle count starts at 0
The tb also has a verilog variable tb_cycle, that one may add to the wave viewer. This is to aid debugging.
In the example above, the check() fn prints out the tb_cycle variable, which is set in the set() fn.
Troubleshooting:
Q: Error-[ITSFM] Illegal `timescale for module
/mada/users/agolubev/scoore/projects/scoore/l0d/rtl/SRAM_1W_1R_3x64test.v, 25
Module "SRAM_1W_1R_3x64test_v" has `timescale but previous module(s) do not.v
Please refer LRM 1364-2001 section 19.8.
A: As of verilog 2001, we do not use the `timescale directive.
This is set in the _ttb.v file, so that we can parametrize it and test for power.
The following command inline removes all `timescale directives. Use with caution, but is tested.
sed -i 's/`timescale.*//' rtl/*.v
WORK IN PROGRESS
TODO in WIKI
Explain overwriting ttb files
- vpi_printf vs printf - Use vpi_printf instead of printf, due to VCS compatibility issues.
* Please use the following nomenclature for printing messages. This was borrowed from synplify. Its convenience stems from the fact that one can grep for warnings / errors easily. Print nomenclature: Please start all printf lines with the following @D - Debug @E - Errors @W - Warnings
* Cycle Count - Since these testbenches are cycle accurate, a C++ variable, num_total_ops, has the absolute cycle count. Its scope is available in all .cpp files It is incremented every positive edge. Please use this variable for timing purposes.
- tb_cycle: A verilog variable tb_cycle, takes on the value of num_total_ops every clock cycle, add this signal to help with debugging when using the wave window.
- VCS GUI: To launch the gui, envoke rake with the gui=1 option (e.g. rake test:salu_tb gui=1). This will fork the vcs gui, and give you back the terminal.
Explain tb_cycle
tb_cycle is a 32 bit entitity that lives in the _tb.v file, and added automatically
It is used to help with debugging using the waveform window
Each clock cycle, num_total_ops is incremented in the _ttb file. Your _tb.cpp file has access to this int, which keeps track of the clock cycle number.
It is available both in the waveform viewer and the cpp testbench itself to view it, use dut->tb_cycle.to_i().
vpi_printf("@D wcb_read_fsm_tb check(): tb_cycle[%d]\n", dut->tb_cycle.to_i());
==Writing / Reading Data Members== - Explains how members are read / written
Let's assume we're using the struct ByteType below. It contains 8 bits total.
==Bits / Bytes / Endianess.== typedef struct packed { BoolType msb; logic [6-1:0] mid; BoolType lsb; }ByteType;
This is stored as a char array of bits. char array ByteType [sizeof(ByteType)] = [msb, 6 mid bits, lsb]
When setting a member of type ByteType to an int (32 Bits), only the 8 lsb bits of the int will be set to the ByteType ByteType = (256 + 254);// is also = 0`b1_1111_1110 Setting this will make ByteType 254, since it can only store 8 bits.
Dealing With Reset
For most simulations, a power on reset needs to be asserted for at least one clock cycle. Depending on your module, SCOORE's specs require anywhere from 4 - 100 cycles of reset. The simulator will show red waves, meaning they are unknown, since the memory had not been reset of initialized. There are several ways to assert the reset signal; the Verilog and the VPI way. For the sake of flexibility and standardization, we will only assert reset from the C++ testbench itself.
In the _tb.cpp file, the reset code should resemble the following, and live in the tb_set function. * if (num_total_ops <= 4) dut->reset = 1; else dut->reset = 0; This will render the first 4 cycles of the testbench useless, but flops do have to be reset for the simulation to be correct.
unsigned int NUM_EXECUTE_CYCLES = 10
rake only needs to be run if the .rv files have been change and are pertinent to the design. or if you change your logic.
- Fix rake issue about compiling and error*