Difference between revisions of "Memory elements of a RamNet"
From Verific Design Automation FAQ
(Created page with "In Verific Netlist Database, a RamNet is created for every identifier in the parsetree that is inferred as multi-port memory. This example checks what memory elements are con...") |
|||
| Line 1: | Line 1: | ||
| − | In Verific | + | In Verific statically-elaborated netlist, there are identifiers marked as possible RamNet. |
| − | This example checks what | + | In Verific netlist database, a RamNet is created for every identifier in the parsetree that is inferred as multi-port memory. |
| + | |||
| + | This example checks what identifiers in the elaborated parsetree can become RamNet, and checks for RamNets in the netlist database. | ||
C++: | C++: | ||
<nowiki> | <nowiki> | ||
| − | #include "veri_file.h" | + | #include "veri_file.h" // Make Verilog reader available |
| − | #include " | + | #include "VeriModule.h" // Definition of a VeriModule and VeriPrimitive |
| − | #include " | + | #include "VeriId.h" // Definitions of all identifier definition tree nodes |
| − | #include " | + | #include "VeriScope.h" // Symbol table of locally declared identifiers |
| − | #include " | + | #include "DataBase.h" |
| − | #include | + | #include <iostream> |
#ifdef VERIFIC_NAMESPACE | #ifdef VERIFIC_NAMESPACE | ||
using namespace Verific ; | using namespace Verific ; | ||
#endif | #endif | ||
| + | using namespace std; | ||
| − | void | + | void checkMemory(VeriModule *mod) |
{ | { | ||
| + | cout << " in module: " << mod->Name() << "\n" ; | ||
| + | VeriScope *scope = mod->GetScope() ; | ||
| + | Set local_ids ; | ||
| + | scope->GetDeclaredLocalIds(local_ids) ; | ||
| + | SetIter si ; | ||
| + | VeriIdDef *id ; | ||
| + | FOREACH_SET_ITEM(&local_ids, si, &id) { | ||
| + | if (!id) continue ; | ||
| + | if (id->CanBeMultiPortRam()) { | ||
| + | cout << " " << id->Name() <<" can be RamNet\n"; | ||
| + | if (id->IsUsed()) { | ||
| + | cout << " can have read port\n"; | ||
| + | } | ||
| + | if (id->IsAssigned()) { | ||
| + | cout << " can have write port\n"; | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | void checkMemory(Netlist* netlist) | ||
| + | { | ||
| + | cout << " in netlist: " << netlist->Owner()->Name() << "\n" ; | ||
// Traverse all the multiport memory nets of the netlist to check the portrefs. | // Traverse all the multiport memory nets of the netlist to check the portrefs. | ||
Net *net ; | Net *net ; | ||
MapIter mi ; | MapIter mi ; | ||
| − | FOREACH_NET_OF_NETLIST( | + | FOREACH_NET_OF_NETLIST(netlist, mi, net) { |
// Only interested in RamNet | // Only interested in RamNet | ||
if (!net || !net->IsRamNet()) continue ; | if (!net || !net->IsRamNet()) continue ; | ||
| + | cout << " " << net->Name() <<" is RamNet\n"; | ||
unsigned hasReadPort = 0 ; | unsigned hasReadPort = 0 ; | ||
unsigned hasWritePort = 0 ; | unsigned hasWritePort = 0 ; | ||
| Line 49: | Line 76: | ||
} | } | ||
} | } | ||
| + | if (hasReadPort) cout << " has read port\n"; | ||
| + | if (hasWritePort) cout << " has write port\n"; | ||
| + | if (hasClockedWritePort) cout << " has clockedwrite port\n"; | ||
| + | } | ||
| + | } | ||
| − | + | // Netlist database - collect netlists in the design hiearchy | |
| − | + | void Accumulate(Netlist *netlist, Set &done) | |
| − | + | { | |
| + | if (!netlist) return ; // Ignore NULL netlists | ||
| + | |||
| + | SetItem *item = done.GetItem(netlist) ; | ||
| + | if (item) { | ||
| + | return ; // We've already been here | ||
| + | } | ||
| + | |||
| + | Instance *inst ; | ||
| + | MapIter mi ; | ||
| + | FOREACH_INSTANCE_OF_NETLIST(netlist, mi, inst) { | ||
| + | // Now go into the netlist associated with the instance | ||
| + | Accumulate(inst->View(), done) ; | ||
| + | } | ||
| + | |||
| + | // Insert the traversed netlist | ||
| + | done.Insert(netlist) ; | ||
| + | } | ||
| + | |||
| + | // Parsetree - collects module in the design hiearchy | ||
| + | void Accumulate(VeriModule *module, Set &done) | ||
| + | { | ||
| + | if (!module) return ; // Ignore NULL netlists | ||
| + | SetItem *item = done.GetItem(module) ; | ||
| + | if (item) { | ||
| + | return ; // We've already been here | ||
} | } | ||
| + | |||
| + | // Get the scope of the module: | ||
| + | VeriScope *scope = module->GetScope() ; | ||
| + | // Find all the declared ids in this scope: | ||
| + | Map *ids = scope ? scope->DeclArea() : 0 ; | ||
| + | MapIter mi ; | ||
| + | VeriIdDef *id ; | ||
| + | FOREACH_MAP_ITEM(ids, mi, 0, &id) { // Traverse declared ids | ||
| + | if (!id || !id->IsInst()) continue ; // Consider only the instance ids | ||
| + | VeriModuleInstantiation *mod_inst = id->GetModuleInstance() ; // Take the module instance | ||
| + | VeriModule *mod = mod_inst ? mod_inst->GetInstantiatedModule() : 0 ; // The module instance is a module | ||
| + | if (mod) { // This is verilog module instantiation: need to go into that module | ||
| + | Accumulate(mod, done) ; // Traverse the instantiated module | ||
| + | } | ||
| + | } | ||
| + | |||
| + | // Insert the traversed module | ||
| + | done.Insert(module) ; | ||
} | } | ||
int main (int argc, char **argv) | int main (int argc, char **argv) | ||
{ | { | ||
| − | + | const char *file_name = "test.sv" ; // defaulf input filename | |
| + | if (argc > 1) file_name = argv[1] ; // Set the file name as specified by the user | ||
| + | |||
| + | // Make sure memory inference is enabled | ||
RuntimeFlags::SetVar("veri_extract_multiport_rams", 1) ; | RuntimeFlags::SetVar("veri_extract_multiport_rams", 1) ; | ||
| + | // Runtime options related to memory inference - enable them as needed | ||
| + | RuntimeFlags::SetVar("veri_allow_asynchronous_ram", 1) ; | ||
| + | // RuntimeFlags::SetVar("veri_allow_ram_with_constant_index", 1) ; | ||
| + | // RuntimeFlags::SetVar("veri_allow_any_ram_in_loop", 1) ; | ||
| + | // RuntimeFlags::SetVar("veri_allow_ram_reset", 1) ; | ||
| + | RuntimeFlags::SetVar("veri_minimum_ram_size", 16) ; | ||
| − | + | if (!veri_file::Analyze(file_name, veri_file::SYSTEM_VERILOG)) return 1 ; | |
| − | if (!veri_file::Analyze( | + | if (!veri_file::ElaborateAllStatic()) return 1 ; |
| − | + | Array *all_top_modules = veri_file::GetTopModules("work") ; | |
| − | + | VeriModule *top_module = (all_top_modules && all_top_modules->Size()) ? (VeriModule *)all_top_modules->GetFirst() : 0 ; | |
| − | + | cout << "* From elaborated parsetree *\n" ; | |
| − | + | ||
| − | + | Set modules(POINTER_HASH); | |
| − | + | Accumulate(top_module, modules); | |
| − | + | ||
| + | VeriModule *module ; | ||
| + | SetIter si ; | ||
| + | // FOREACH_SET_ITEM(&modules, si, &module) { // if you want to print top module last | ||
| + | FOREACH_SET_ITEM_BACK(&modules, si, &module) { // if you want to print top module first | ||
| + | if (module) { | ||
| + | checkMemory(module); | ||
| + | } | ||
} | } | ||
| − | + | // if (!veri_file::ElaborateAll()) return 1; | |
| + | if (!veri_file::Elaborate(top_module->Name())) return 1; | ||
| + | |||
| + | Netlist *top = Netlist::PresentDesign() ; | ||
| − | return 0 ; | + | // Lets accumulate all netlist |
| + | Set netlists(POINTER_HASH) ; | ||
| + | Accumulate(top, netlists) ; | ||
| + | |||
| + | cout << "* From netlist database *\n" ; | ||
| + | Netlist *netlist ; | ||
| + | // FOREACH_SET_ITEM (&netlists, si, &netlist) { // if you want to print top netlist last | ||
| + | FOREACH_SET_ITEM_BACK (&netlists, si, &netlist) { // if you want to print top netlist first | ||
| + | // Skip primitives and operators | ||
| + | if (netlist->IsPrimitive() || netlist->IsOperator()) continue ; | ||
| + | checkMemory(netlist) ; | ||
| + | } | ||
| + | |||
| + | return 0 ; | ||
} | } | ||
</nowiki> | </nowiki> | ||
| Line 83: | Line 189: | ||
test.sv: | test.sv: | ||
<nowiki> | <nowiki> | ||
| + | module top (input clk, input [6:0]addr, input [7:0]in, output reg [7:0]out, output reg [7:0]out1); | ||
| + | |||
| + | test inst(.clk(clk), .write(1'b0), .addr(addr), .in(in), .out(out), .out1(out1)); | ||
| + | |||
| + | endmodule | ||
| + | |||
| + | |||
module test (input clk, write, input [6:0]addr, input [7:0]in, output reg [7:0]out, output reg [7:0]out1) ; | module test (input clk, write, input [6:0]addr, input [7:0]in, output reg [7:0]out, output reg [7:0]out1) ; | ||
reg [7:0]RAM[127:0] ; | reg [7:0]RAM[127:0] ; | ||
| Line 103: | Line 216: | ||
$ test-linux | $ test-linux | ||
-- Analyzing Verilog file 'test.sv' (VERI-1482) | -- Analyzing Verilog file 'test.sv' (VERI-1482) | ||
| − | test.sv(1): INFO: compiling module 'test' (VERI-1018) | + | test.sv(1): INFO: compiling module 'top' (VERI-1018) |
| − | test.sv( | + | * From elaborated parsetree * |
| − | + | in module: top | |
| − | + | in module: test | |
| − | + | RAM can be RamNet | |
| − | + | can have read port | |
| + | can have write port | ||
| + | RAM1 can be RamNet | ||
| + | can have write port | ||
| + | RAM2 can be RamNet | ||
| + | can have read port | ||
| + | test.sv(1): INFO: compiling module 'top' (VERI-1018) | ||
| + | test.sv(8): INFO: compiling module 'test' (VERI-1018) | ||
| + | test.sv(11): WARNING: net 'RAM2' does not have a driver (VDB-1002) | ||
| + | * From netlist database * | ||
| + | in netlist: top | ||
| + | in netlist: test | ||
| + | RAM is RamNet | ||
| + | has read port | ||
| + | has clockedwrite port | ||
| + | RAM1 is RamNet | ||
| + | has clockedwrite port | ||
| + | RAM2 is RamNet | ||
| + | has read port | ||
$ | $ | ||
</nowiki> | </nowiki> | ||
Latest revision as of 16:53, 31 January 2020
In Verific statically-elaborated netlist, there are identifiers marked as possible RamNet.
In Verific netlist database, a RamNet is created for every identifier in the parsetree that is inferred as multi-port memory.
This example checks what identifiers in the elaborated parsetree can become RamNet, and checks for RamNets in the netlist database.
C++:
#include "veri_file.h" // Make Verilog reader available
#include "VeriModule.h" // Definition of a VeriModule and VeriPrimitive
#include "VeriId.h" // Definitions of all identifier definition tree nodes
#include "VeriScope.h" // Symbol table of locally declared identifiers
#include "DataBase.h"
#include <iostream>
#ifdef VERIFIC_NAMESPACE
using namespace Verific ;
#endif
using namespace std;
void checkMemory(VeriModule *mod)
{
cout << " in module: " << mod->Name() << "\n" ;
VeriScope *scope = mod->GetScope() ;
Set local_ids ;
scope->GetDeclaredLocalIds(local_ids) ;
SetIter si ;
VeriIdDef *id ;
FOREACH_SET_ITEM(&local_ids, si, &id) {
if (!id) continue ;
if (id->CanBeMultiPortRam()) {
cout << " " << id->Name() <<" can be RamNet\n";
if (id->IsUsed()) {
cout << " can have read port\n";
}
if (id->IsAssigned()) {
cout << " can have write port\n";
}
}
}
}
void checkMemory(Netlist* netlist)
{
cout << " in netlist: " << netlist->Owner()->Name() << "\n" ;
// Traverse all the multiport memory nets of the netlist to check the portrefs.
Net *net ;
MapIter mi ;
FOREACH_NET_OF_NETLIST(netlist, mi, net) {
// Only interested in RamNet
if (!net || !net->IsRamNet()) continue ;
cout << " " << net->Name() <<" is RamNet\n";
unsigned hasReadPort = 0 ;
unsigned hasWritePort = 0 ;
unsigned hasClockedWritePort = 0;
// Traverse all the portrefs of the net to check if the portref is connected to any ram ports.
SetIter si ;
PortRef *pr ;
FOREACH_PORTREF_OF_NET(net,si, pr) {
Instance *inst = pr ? pr->GetInst() : 0 ;
if (!inst) continue ;
if (inst->Type() == OPER_READ_PORT) {
// This net is connected to a memory read port
hasReadPort = 1 ;
}
if (inst->Type() == OPER_WRITE_PORT) {
// This net is connected to a memory write port
hasWritePort = 1;
}
if (inst->Type() == OPER_CLOCKED_WRITE_PORT) {
// This net is connected to a memory clocked write port
hasClockedWritePort = 1;
}
}
if (hasReadPort) cout << " has read port\n";
if (hasWritePort) cout << " has write port\n";
if (hasClockedWritePort) cout << " has clockedwrite port\n";
}
}
// Netlist database - collect netlists in the design hiearchy
void Accumulate(Netlist *netlist, Set &done)
{
if (!netlist) return ; // Ignore NULL netlists
SetItem *item = done.GetItem(netlist) ;
if (item) {
return ; // We've already been here
}
Instance *inst ;
MapIter mi ;
FOREACH_INSTANCE_OF_NETLIST(netlist, mi, inst) {
// Now go into the netlist associated with the instance
Accumulate(inst->View(), done) ;
}
// Insert the traversed netlist
done.Insert(netlist) ;
}
// Parsetree - collects module in the design hiearchy
void Accumulate(VeriModule *module, Set &done)
{
if (!module) return ; // Ignore NULL netlists
SetItem *item = done.GetItem(module) ;
if (item) {
return ; // We've already been here
}
// Get the scope of the module:
VeriScope *scope = module->GetScope() ;
// Find all the declared ids in this scope:
Map *ids = scope ? scope->DeclArea() : 0 ;
MapIter mi ;
VeriIdDef *id ;
FOREACH_MAP_ITEM(ids, mi, 0, &id) { // Traverse declared ids
if (!id || !id->IsInst()) continue ; // Consider only the instance ids
VeriModuleInstantiation *mod_inst = id->GetModuleInstance() ; // Take the module instance
VeriModule *mod = mod_inst ? mod_inst->GetInstantiatedModule() : 0 ; // The module instance is a module
if (mod) { // This is verilog module instantiation: need to go into that module
Accumulate(mod, done) ; // Traverse the instantiated module
}
}
// Insert the traversed module
done.Insert(module) ;
}
int main (int argc, char **argv)
{
const char *file_name = "test.sv" ; // defaulf input filename
if (argc > 1) file_name = argv[1] ; // Set the file name as specified by the user
// Make sure memory inference is enabled
RuntimeFlags::SetVar("veri_extract_multiport_rams", 1) ;
// Runtime options related to memory inference - enable them as needed
RuntimeFlags::SetVar("veri_allow_asynchronous_ram", 1) ;
// RuntimeFlags::SetVar("veri_allow_ram_with_constant_index", 1) ;
// RuntimeFlags::SetVar("veri_allow_any_ram_in_loop", 1) ;
// RuntimeFlags::SetVar("veri_allow_ram_reset", 1) ;
RuntimeFlags::SetVar("veri_minimum_ram_size", 16) ;
if (!veri_file::Analyze(file_name, veri_file::SYSTEM_VERILOG)) return 1 ;
if (!veri_file::ElaborateAllStatic()) return 1 ;
Array *all_top_modules = veri_file::GetTopModules("work") ;
VeriModule *top_module = (all_top_modules && all_top_modules->Size()) ? (VeriModule *)all_top_modules->GetFirst() : 0 ;
cout << "* From elaborated parsetree *\n" ;
Set modules(POINTER_HASH);
Accumulate(top_module, modules);
VeriModule *module ;
SetIter si ;
// FOREACH_SET_ITEM(&modules, si, &module) { // if you want to print top module last
FOREACH_SET_ITEM_BACK(&modules, si, &module) { // if you want to print top module first
if (module) {
checkMemory(module);
}
}
// if (!veri_file::ElaborateAll()) return 1;
if (!veri_file::Elaborate(top_module->Name())) return 1;
Netlist *top = Netlist::PresentDesign() ;
// Lets accumulate all netlist
Set netlists(POINTER_HASH) ;
Accumulate(top, netlists) ;
cout << "* From netlist database *\n" ;
Netlist *netlist ;
// FOREACH_SET_ITEM (&netlists, si, &netlist) { // if you want to print top netlist last
FOREACH_SET_ITEM_BACK (&netlists, si, &netlist) { // if you want to print top netlist first
// Skip primitives and operators
if (netlist->IsPrimitive() || netlist->IsOperator()) continue ;
checkMemory(netlist) ;
}
return 0 ;
}
test.sv:
module top (input clk, input [6:0]addr, input [7:0]in, output reg [7:0]out, output reg [7:0]out1);
test inst(.clk(clk), .write(1'b0), .addr(addr), .in(in), .out(out), .out1(out1));
endmodule
module test (input clk, write, input [6:0]addr, input [7:0]in, output reg [7:0]out, output reg [7:0]out1) ;
reg [7:0]RAM[127:0] ;
reg [7:0]RAM1[127:0] ;
reg [7:0]RAM2[127:0] ;
always @(posedge clk) begin
if (write) begin
RAM[addr] = in ;
RAM1[addr] = in ;
end
out = RAM[addr] ;
out1 = RAM2[addr] ;
end
endmodule
Run:
$ test-linux
-- Analyzing Verilog file 'test.sv' (VERI-1482)
test.sv(1): INFO: compiling module 'top' (VERI-1018)
* From elaborated parsetree *
in module: top
in module: test
RAM can be RamNet
can have read port
can have write port
RAM1 can be RamNet
can have write port
RAM2 can be RamNet
can have read port
test.sv(1): INFO: compiling module 'top' (VERI-1018)
test.sv(8): INFO: compiling module 'test' (VERI-1018)
test.sv(11): WARNING: net 'RAM2' does not have a driver (VDB-1002)
* From netlist database *
in netlist: top
in netlist: test
RAM is RamNet
has read port
has clockedwrite port
RAM1 is RamNet
has clockedwrite port
RAM2 is RamNet
has read port
$