Skip to content

Commit d3d4a71

Browse files
committed
[Yosys+Odin]: Add a Verilog entity to generate DSPs' declaration as blackboxes
Signed-off-by: Seyed Alireza Damghani <[email protected]>
1 parent 8c524bd commit d3d4a71

File tree

13 files changed

+375
-25
lines changed

13 files changed

+375
-25
lines changed

ODIN_II/SRC/BLIFWriter.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,15 @@ inline void BLIF::Writer::_write(const netlist_t* netlist) {
7474
output_blif(this->output_file, netlist);
7575
}
7676

77-
inline void BLIF::Writer::_create_file(const file_type_e /* file_type */) {
78-
this->output_file = create_blif(global_args.output_file.value().c_str());
77+
inline void BLIF::Writer::_create_file(const char* file_name, const file_type_e file_type) {
78+
// validate the file_name pionter
79+
oassert(file_name);
80+
// validate the file type
81+
if (file_type != _BLIF)
82+
error_message(UTIL, unknown_location,
83+
"BLIF back-end entity cannot create file types(%d) other than BLIF", file_type);
84+
// create the BLIF file and set it as the output file
85+
this->output_file = create_blif(file_name);
7986
}
8087
/**
8188
* ---------------------------------------------------------------------------------------------

ODIN_II/SRC/GenericIO.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ void GenericIO::_write(const netlist_t* /* netlist */) {
4444
"Function \"%s\" is called for reading the input file without definition provided!\n", __PRETTY_FUNCTION__);
4545
}
4646

47-
void GenericIO::_create_file(const file_type_e /* file_type */) {
47+
void GenericIO::_create_file(const char* /* file_name */, const file_type_e /* file_type */) {
4848
error_message(UTIL, unknown_location,
4949
"Function \"%s\" is called for reading the input file without definition provided!\n", __PRETTY_FUNCTION__);
5050
}

ODIN_II/SRC/GenericWriter.cpp

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,16 @@ GenericWriter::GenericWriter()
3737
: GenericIO() {
3838
this->output_file = NULL;
3939
this->blif_writer = NULL;
40+
this->verilog_writer = NULL;
4041
}
4142

4243
GenericWriter::~GenericWriter() {
4344
if (this->output_file)
4445
fclose(this->output_file);
4546
if (this->blif_writer)
4647
delete this->blif_writer;
48+
if (this->verilog_writer)
49+
delete this->verilog_writer;
4750
}
4851

4952
inline void GenericWriter::_write(const netlist_t* netlist) {
@@ -52,12 +55,12 @@ inline void GenericWriter::_write(const netlist_t* netlist) {
5255
this->write_blif(netlist);
5356
break;
5457
}
58+
case (file_type_e::_VERILOG): {
59+
this->write_verilog(netlist);
60+
break;
61+
}
5562
/**
5663
* [TODO]
57-
* case (file_type_e::_VERILOG): {
58-
* netlist = this->write_verilog();
59-
* break;
60-
* }
6164
* case (file_type_e::_EBLIF): {
6265
* netlist = this->write_verilog();
6366
* break;
@@ -79,22 +82,30 @@ inline void GenericWriter::write_blif(const netlist_t* netlist) {
7982
this->blif_writer->_write(netlist);
8083
}
8184

82-
inline void GenericWriter::_create_file(const file_type_e file_type) {
85+
inline void GenericWriter::write_verilog(const netlist_t* netlist) {
86+
oassert(this->verilog_writer);
87+
this->verilog_writer->_write(netlist);
88+
}
89+
90+
inline void GenericWriter::_create_file(const char* file_name, const file_type_e file_type) {
91+
// validate the file_name pointer
92+
oassert(file_name);
93+
8394
switch (file_type) {
8495
case (file_type_e::_BLIF): {
8596
if (!this->blif_writer) {
8697
this->blif_writer = new BLIF::Writer();
87-
this->blif_writer->_create_file(file_type);
98+
this->blif_writer->_create_file(file_name, file_type);
8899
}
89100
break;
90101
}
102+
case (file_type_e::_VERILOG): {
103+
this->verilog_writer = new Verilog::Writer();
104+
this->verilog_writer->_create_file(file_name, file_type);
105+
break;
106+
}
91107
/**
92108
* [TODO]
93-
* case (file_type_e::_VERILOG): {
94-
* this->verilog_writer = new VERILOG::Writer();
95-
* this->verilog_writer->_create_file();
96-
* break;
97-
* }
98109
* case (file_type_e::_EBLIF): {
99110
* this->eblif_writer = new EBLIF::Writer();
100111
* this->eblif_writer->_create_file();

ODIN_II/SRC/VerilogWriter.cpp

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
/**
2+
* Copyright (c) 2021 Seyed Alireza Damghani ([email protected])
3+
*
4+
* Permission is hereby granted, free of charge, to any person
5+
* obtaining a copy of this software and associated documentation
6+
* files (the "Software"), to deal in the Software without
7+
* restriction, including without limitation the rights to use,
8+
* copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the
10+
* Software is furnished to do so, subject to the following
11+
* conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be
14+
* included in all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18+
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21+
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23+
* OTHER DEALINGS IN THE SOFTWARE.
24+
*
25+
* @file: includes the definition of VERILOG Writer class to write a
26+
* given netlist in a Verilog file. In addition to the netlist, the
27+
* target architecture hardblocks(DSPs) can be outputed as a blackbox.
28+
* With that said, only the DSPs' declaration are printed.
29+
*/
30+
31+
#include <sstream> //std::stringstream
32+
33+
#include "Verilog.hpp"
34+
#include "odin_globals.h"
35+
#include "hard_blocks.h"
36+
#include "vtr_util.cpp"
37+
38+
Verilog::Writer::Writer()
39+
: GenericWriter() {
40+
this->models_declaration = sc_new_string_cache();
41+
}
42+
43+
Verilog::Writer::~Writer() = default;
44+
45+
inline void Verilog::Writer::_create_file(const char* file_name, const file_type_e file_type) {
46+
// validate the file_name pointer
47+
oassert(file_name);
48+
// validate the file type
49+
if (file_type != _VERILOG)
50+
error_message(UTIL, unknown_location,
51+
"Verilog back-end entity cannot create file types(%d) other than Verilog", file_type);
52+
// create the Verilog file and set it as the output file
53+
this->output_file = create_verilog(file_name);
54+
}
55+
56+
57+
void Verilog::Writer::_write(const netlist_t* netlist) {
58+
59+
// to write the top module and netlist components
60+
if (netlist) {
61+
/* [TODO] */
62+
}
63+
64+
// print out the rest od models, including DSPs in the target architecture
65+
t_model* model = Arch.models;
66+
67+
while(model) {
68+
int sc_spot;
69+
if ((sc_spot = sc_lookup_string(this->models_declaration, model->name)) != -1){
70+
fprintf(this->output_file, "%s", (char*)this->models_declaration->data[sc_spot]);
71+
fflush(this->output_file);
72+
}
73+
model = model->next;
74+
}
75+
}
76+
77+
/**
78+
*-------------------------------------------------------------------------------------------
79+
* (function: create_verilog)
80+
*
81+
* @brief initiate a new output file stream
82+
*
83+
* @param file_name the path to the verilog file
84+
*
85+
* @return an output stream to the verilog file
86+
*-------------------------------------------------------------------------------------------
87+
*/
88+
FILE* Verilog::Writer::create_verilog(const char* file_name) {
89+
FILE* out = NULL;
90+
91+
/* open the file for output */
92+
out = fopen(file_name, "w");
93+
94+
if (out == NULL) {
95+
error_message(UTIL, unknown_location, "Could not open output file %s\n", file_name);
96+
}
97+
return (out);
98+
}
99+
100+
101+
/**
102+
*-------------------------------------------------------------------------------------------
103+
* (function: declare_blackbox)
104+
*
105+
* @brief find the corresponding blackbox with the given
106+
* name in the given target arhitecture, then add its
107+
* Verilog declartion to this->models_declaration string cache.
108+
*
109+
* @param bb_name the blackbox(DSP) name
110+
*
111+
* @return a long value, which is representing the index of
112+
* the declartion in models string cache. Will return -1 if
113+
* a DSP with the given name does not exist in the architecture.
114+
*-------------------------------------------------------------------------------------------
115+
*/
116+
long Verilog::Writer::declare_blackbox(const char* bb_name) {
117+
/* to validate the blackbox name */
118+
oassert(bb_name);
119+
120+
t_model* bb = find_hard_block(bb_name);
121+
if (bb == NULL) {
122+
error_message(UTIL, unknown_location,
123+
"Odin-II failed to find DSP module \"%s\" in the target device.", bb_name);
124+
}
125+
126+
std::stringstream bb_declaration;
127+
128+
// need to specify "(* blackbox *)" tag if Yosys
129+
// is going to elaborate the Verilog file
130+
if (elaborator_e::_YOSYS) {
131+
bb_declaration << BLACKBOX_ATTR << NEWLINE;
132+
}
133+
134+
bb_declaration << MODULE << TAB << bb_name << OPEN_PARENTHESIS << std::endl;
135+
bb_declaration << declare_ports(bb) << std::endl;
136+
bb_declaration << CLOSE_PARENTHESIS << SEMICOLON << std::endl;
137+
bb_declaration << HARD_BLOCK_COMMENT << std::endl;
138+
bb_declaration << END_MODULE << NEWLINE << std::endl;
139+
140+
int sc_spot;
141+
if ((sc_spot = sc_add_string(this->models_declaration, bb->name)) != -1 ) {
142+
this->models_declaration->data[sc_spot] = (void*) vtr::strdup(bb_declaration.str().c_str());
143+
return (sc_spot);
144+
}
145+
146+
return (-1);
147+
}
148+
149+
/**
150+
*-------------------------------------------------------------------------------------------
151+
* (function: declare_ports)
152+
*
153+
* @brief generate a string that includes the declaration
154+
* of input/output ports of a given t_model
155+
*
156+
* @param model the DSP t_model pointer
157+
*
158+
* @return a string value including the declaration of all
159+
* input/output ports related to the given DSP model
160+
*-------------------------------------------------------------------------------------------
161+
*/
162+
std::string Verilog::Writer::declare_ports(t_model* model) {
163+
/* to validate the model pointer */
164+
oassert(model);
165+
166+
std::stringstream input_stream;
167+
t_model_ports* input_port = model->inputs;
168+
while(input_port) {
169+
input_stream << TAB
170+
<< INPUT_PORT << TAB
171+
<< OPEN_SQUARE_BRACKET
172+
<< input_port->size << COLON << "0"
173+
<< CLOSE_SQUARE_BRACKET
174+
<< TAB << input_port->name
175+
<< COMMA << std::endl;
176+
177+
// move forward until the end of input ports' list
178+
input_port = input_port->next;
179+
}
180+
181+
std::stringstream output_stream;
182+
t_model_ports* output_port = model->outputs;
183+
while(output_port) {
184+
output_stream << TAB
185+
<< OUTPUT_PORT << TAB
186+
<< OPEN_SQUARE_BRACKET
187+
<< output_port->size << COLON << "0"
188+
<< CLOSE_SQUARE_BRACKET
189+
<< TAB << output_port->name
190+
<< COMMA << std::endl;
191+
192+
// move forward until the end of output ports' list
193+
output_port = output_port->next;
194+
}
195+
196+
std::string input_str = input_stream.str();
197+
std::string output_str = output_stream.str();
198+
199+
// check the value of input/output ports declaration
200+
// to trim extra last semicolon if required
201+
std::stringstream ports_declaration;
202+
if (!input_stream.str().empty() && output_stream.str().empty()) {
203+
input_str[input_str.find_last_not_of(COMMA)-1] = '\0';
204+
ports_declaration << input_str;
205+
} else if (!output_stream.str().empty()) {
206+
if (!input_stream.str().empty())
207+
ports_declaration << input_str;
208+
209+
ports_declaration << output_str.substr(0, output_str.find_last_not_of(COMMA)-1);
210+
}
211+
212+
// return the string value
213+
return (ports_declaration.str());
214+
}

ODIN_II/SRC/YYosys.cpp

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,11 @@
4242
#include <sys/wait.h> // wait
4343

4444
#include "YYosys.hpp"
45-
#include "config_t.h" // configuration
46-
#include "odin_util.h" // get_directory
47-
#include "odin_error.h" // error_message
45+
#include "Verilog.hpp"
46+
#include "config_t.h" // configuration
47+
#include "odin_util.h" // get_directory
48+
#include "odin_error.h" // error_message
49+
#include "hard_blocks.h" // hard_block_names
4850

4951
#ifdef ODIN_USE_YOSYS
5052
# include "kernel/yosys.h" // Yosys
@@ -122,6 +124,8 @@ void YYosys::perform_elaboration() {
122124
if (this->yosys_pid == 0) {
123125
/* initalize Yosys */
124126
this->init_yosys();
127+
/* generate and load DSP declarations */
128+
this->load_target_dsp_blocks();
125129
/* perform elaboration using Yosys API */
126130
this->elaborate();
127131

@@ -144,6 +148,38 @@ void YYosys::perform_elaboration() {
144148
#endif
145149
}
146150

151+
/**
152+
* ---------------------------------------------------------------------------------------------
153+
* (function: load_target_dsp_blocks)
154+
*
155+
* @brief this routine generates a Verilog file, including the
156+
* declaration of all DSP blocks available in the targer architecture.
157+
* Then, the Verilog fle is read by Yosys to make it aware of them
158+
* -------------------------------------------------------------------------------------------*/
159+
void YYosys::load_target_dsp_blocks() {
160+
#ifndef ODIN_USE_YOSYS
161+
error_message(PARSE_ARGS, unknown_location, "%s", YOSYS_INSTALLATION_ERROR);
162+
#else
163+
Verilog::Writer vw = Verilog::Writer();
164+
vw._create_file(configuration.dsp_verilog.c_str());
165+
166+
t_model* hb = Arch.models;
167+
while(hb) {
168+
// declare hardblocks in a verilog file
169+
if (strcmp(hb->name, SINGLE_PORT_RAM_string) &&
170+
strcmp(hb->name, DUAL_PORT_RAM_string) &&
171+
strcmp(hb->name, "multiply") &&
172+
strcmp(hb->name, "adder"))
173+
vw.declare_blackbox(hb->name);
174+
175+
hb = hb->next;
176+
}
177+
178+
vw._write(NULL);
179+
run_pass(std::string("read_verilog -nomem2reg " + configuration.dsp_verilog));
180+
#endif
181+
}
182+
147183
/**
148184
* ---------------------------------------------------------------------------------------------
149185
* (function: init_yosys)

ODIN_II/SRC/hard_blocks.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ void cache_hard_block_names() {
5959
hard_blocks = Arch.models;
6060
hard_block_names = sc_new_string_cache();
6161
while (hard_blocks) {
62-
sc_add_string(hard_block_names, hard_blocks->name);
62+
int sc_spot = sc_add_string(hard_block_names, hard_blocks->name);
63+
hard_block_names->data[sc_spot] = (void*)hard_blocks;
6364
hard_blocks = hard_blocks->next;
6465
}
6566
}

ODIN_II/SRC/include/BLIF.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ class BLIF {
608608
}
609609

610610
void _write(const netlist_t* netlist);
611-
void _create_file(const file_type_e file_type);
611+
void _create_file(const char* file_name, const file_type_e file_type = _BLIF);
612612

613613
protected:
614614
/**

0 commit comments

Comments
 (0)