Skip to content

Commit 1f39b90

Browse files
committed
Add support for Stratix 10 quad port ram to vqm2blif
1 parent 9c6afc4 commit 1f39b90

File tree

3 files changed

+84
-4
lines changed

3 files changed

+84
-4
lines changed

libs/libvqm/vqm_parser.l

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
^[ \t]*\/\/[^\n\r]*(\n|\r\n) /* skip one-line comments */
4141
^[ \t]*\(\*[^\n\r]*\*\) /* skip synthesis attributes and directives */
4242
[ \t]+ /* skip white spaces */
43-
! /* skip the logical operator ! applied on the input ports of the lut - this results in lut mask not being valid anoymore */
43+
(!|~) /* skip the logical operator ! applied on the input ports of the lut - this results in lut mask not being valid anoymore */
4444
(\n|\r\n) /* skip empty lines */
4545
module return TOKEN_MODULE;
4646
endmodule return TOKEN_ENDMODULE;

utils/vqm2blif/src/base/vqm2blif_util.cpp

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ void generate_opname_ram (t_node* vqm_node, const LogicalModels& arch_models, st
552552
reg_outputs = true;
553553
}
554554
} else {
555-
VTR_ASSERT(ram_info.mode == "dual_port" || ram_info.mode == "bidir_dual_port");
555+
VTR_ASSERT(ram_info.mode == "dual_port" || ram_info.mode == "bidir_dual_port" || ram_info.mode == "quad_port");
556556
VTR_ASSERT_MSG(ram_info.port_b_input_clock, "RAM inputs always assumed sequential");
557557

558558
if (ram_info.mode == "dual_port" && ram_info.port_b_output_clock) {
@@ -568,6 +568,16 @@ void generate_opname_ram (t_node* vqm_node, const LogicalModels& arch_models, st
568568
cout << " port A output sequential: " << bool(ram_info.port_a_output_clock) << "\n";
569569
cout << " port B output sequential: " << bool(ram_info.port_b_output_clock) << "\n";
570570
}
571+
} else {
572+
if (ram_info.port_a_output_clock && ram_info.port_b_output_clock) {
573+
reg_outputs = true; //Sequential output
574+
} else if (!ram_info.port_a_output_clock && !ram_info.port_b_output_clock) {
575+
reg_outputs = false; //Comb output
576+
} else {
577+
cout << "Unable to resolve whether quad port RAM " << vqm_node->name << " outputs are sequential or combinational:\n";
578+
cout << " port A output sequential: " << bool(ram_info.port_a_output_clock) << "\n";
579+
cout << " port B output sequential: " << bool(ram_info.port_b_output_clock) << "\n";
580+
}
571581
}
572582
}
573583

@@ -602,6 +612,8 @@ void generate_opname_ram (t_node* vqm_node, const LogicalModels& arch_models, st
602612
//&& (port_b_data_width == NULL) && (port_b_addr_width == NULL)) {
603613
if(ram_info.mode == "single_port" || ram_info.mode == "rom") {
604614
VTR_ASSERT(ram_info.port_b_addr_width == 0);
615+
VTR_ASSERT(ram_info.port_b_addr2_width == 0);
616+
VTR_ASSERT(ram_info.port_a_addr2_width == 0);
605617

606618
//Only print the address width, the data widths are handled by the VPR memory class
607619
mode_hash.append(".port_a_address_width{" + std::to_string(ram_info.port_a_addr_width) + "}");
@@ -613,8 +625,9 @@ void generate_opname_ram (t_node* vqm_node, const LogicalModels& arch_models, st
613625
}
614626

615627
//A dual port memory, both port A and B params have been found
616-
} else {
617-
VTR_ASSERT(ram_info.mode == "dual_port" || ram_info.mode == "bidir_dual_port");
628+
} else if (ram_info.mode == "dual_port" || ram_info.mode == "bidir_dual_port"){
629+
VTR_ASSERT(ram_info.port_b_addr2_width == 0);
630+
VTR_ASSERT(ram_info.port_a_addr2_width == 0);
618631

619632
//2) Both ports are the same size, so only append the address widths, the data widths are handled by the VPR memory class
620633
if ( (ram_info.port_a_data_width == ram_info.port_b_data_width)
@@ -645,6 +658,53 @@ void generate_opname_ram (t_node* vqm_node, const LogicalModels& arch_models, st
645658
tmp_mode_hash.append(".port_a_data_width{" + std::to_string(ram_info.port_a_data_width) + "}");
646659
tmp_mode_hash.append(".port_b_data_width{" + std::to_string(ram_info.port_b_data_width) + "}");
647660

661+
LogicalModelId arch_model_id = arch_models.get_model_by_name(tmp_mode_hash);
662+
if (!arch_model_id.is_valid()) {
663+
//3a) Not found, use the default name (no specific address/data widths)
664+
; // do nothing
665+
} else {
666+
//3b) Use the more detailed name, since it was found in the architecture
667+
mode_hash = tmp_mode_hash;
668+
}
669+
}
670+
} else {
671+
VTR_ASSERT(ram_info.mode == "quad_port");
672+
673+
//2) Both ports are the same size, so only append the address widths, the data widths are handled by the VPR memory class
674+
if ( (ram_info.port_a_data_width == ram_info.port_b_data_width)
675+
&& (ram_info.port_a_addr_width == ram_info.port_b_addr_width)
676+
&& (ram_info.port_a_addr_width == ram_info.port_b_addr2_width)
677+
&& (ram_info.port_a_addr2_width == ram_info.port_b_addr2_width)) {
678+
679+
mode_hash.append(".port_a_address_width{" + std::to_string(ram_info.port_a_addr_width) + "}");
680+
mode_hash.append(".port_a_address2_width{" + std::to_string(ram_info.port_a_addr2_width) + "}");
681+
mode_hash.append(".port_b_address_width{" + std::to_string(ram_info.port_b_addr_width) + "}");
682+
mode_hash.append(".port_b_address2_width{" + std::to_string(ram_info.port_b_addr2_width) + "}");
683+
684+
LogicalModelId arch_model_id = arch_models.get_model_by_name(mode_hash);
685+
if (!arch_model_id.is_valid()) {
686+
cout << "Error: could not find dual port (non-mixed_width) memory primitive '" << mode_hash << "' in architecture file";
687+
exit(1);
688+
}
689+
//3) Mixed width dual port ram
690+
} else {
691+
//Make a temporary copy of the mode hash
692+
string tmp_mode_hash = mode_hash;
693+
694+
/*
695+
* Try to see if the detailed version exists in the architecture,
696+
* if it does, use it. Otherwise use the operation mode only.
697+
*/
698+
699+
tmp_mode_hash.append(".port_a_address_width{" + std::to_string(ram_info.port_a_addr_width) + "}");
700+
tmp_mode_hash.append(".port_a_address2_width{" + std::to_string(ram_info.port_a_addr2_width) + "}");
701+
tmp_mode_hash.append(".port_b_address_width{" + std::to_string(ram_info.port_b_addr_width) + "}");
702+
tmp_mode_hash.append(".port_b_address2_width{" + std::to_string(ram_info.port_b_addr2_width) + "}");
703+
704+
//Each port has a different size, so print both the address and data widths. Mixed widths are not handled by the VPR memory class
705+
tmp_mode_hash.append(".port_a_data_width{" + std::to_string(ram_info.port_a_data_width) + "}");
706+
tmp_mode_hash.append(".port_b_data_width{" + std::to_string(ram_info.port_b_data_width) + "}");
707+
648708
LogicalModelId arch_model_id = arch_models.get_model_by_name(tmp_mode_hash);
649709
if (!arch_model_id.is_valid()) {
650710
//3a) Not found, use the default name (no specific address/data widths)
@@ -997,8 +1057,10 @@ RamInfo get_ram_info(const t_node* vqm_node, string device) {
9971057
//We need to save the ram data and address widths, to identfy the RAM type (singel port, rom, simple dual port, true dual port)
9981058
t_node_parameter* port_a_data_width = NULL;
9991059
t_node_parameter* port_a_addr_width = NULL;
1060+
t_node_parameter* port_a_addr2_width = NULL;
10001061
t_node_parameter* port_b_data_width = NULL;
10011062
t_node_parameter* port_b_addr_width = NULL;
1063+
t_node_parameter* port_b_addr2_width = NULL;
10021064

10031065
for (int i = 0; i < vqm_node->number_of_params; i++){
10041066
//Each parameter specifies a configuration of the node in the circuit.
@@ -1020,6 +1082,11 @@ RamInfo get_ram_info(const t_node* vqm_node, string device) {
10201082
port_a_addr_width = temp_param;
10211083
continue;
10221084
}
1085+
if (strcmp (temp_param->name, "port_a_address2_width") == 0){
1086+
VTR_ASSERT( temp_param->type == NODE_PARAMETER_INTEGER );
1087+
port_a_addr2_width = temp_param;
1088+
continue;
1089+
}
10231090
if (strcmp (temp_param->name, "port_b_data_width") == 0){
10241091
VTR_ASSERT( temp_param->type == NODE_PARAMETER_INTEGER );
10251092
port_b_data_width = temp_param;
@@ -1030,6 +1097,11 @@ RamInfo get_ram_info(const t_node* vqm_node, string device) {
10301097
port_b_addr_width = temp_param;
10311098
continue;
10321099
}
1100+
if (strcmp (temp_param->name, "port_b_address2_width") == 0){
1101+
VTR_ASSERT( temp_param->type == NODE_PARAMETER_INTEGER );
1102+
port_b_addr2_width = temp_param;
1103+
continue;
1104+
}
10331105
if (strcmp (temp_param->name, "port_a_address_clock") == 0){ // This parameter doesn't exist for Stratix 10 - clock0 is always used for port address_a
10341106
VTR_ASSERT( temp_param->type == NODE_PARAMETER_STRING );
10351107
port_a_address_clock = temp_param;
@@ -1096,6 +1168,12 @@ RamInfo get_ram_info(const t_node* vqm_node, string device) {
10961168
VTR_ASSERT(port_a_data_width);
10971169
ram_info.port_a_data_width = port_a_data_width->value.integer_value;
10981170

1171+
if (port_a_addr2_width) {
1172+
ram_info.port_a_addr2_width = port_a_addr2_width->value.integer_value;
1173+
}
1174+
if (port_b_addr2_width) {
1175+
ram_info.port_b_addr2_width = port_b_addr2_width->value.integer_value;
1176+
}
10991177
if (port_b_addr_width) {
11001178
ram_info.port_b_addr_width = port_b_addr_width->value.integer_value;
11011179
}

utils/vqm2blif/src/base/vqm2blif_util.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ typedef pair <const char*, v_OptionBaseToken> tokpair;
9999
struct RamInfo {
100100
std::string mode = "";
101101
int port_a_addr_width = 0;
102+
int port_a_addr2_width = 0;
102103
int port_a_data_width = 0;
103104
t_node_port_association* port_a_input_clock = nullptr;
104105
t_node_port_association* port_a_input_ena = nullptr;
@@ -108,6 +109,7 @@ struct RamInfo {
108109
t_node_port_association* port_a_dataout_sclr = nullptr;
109110

110111
int port_b_addr_width = 0;
112+
int port_b_addr2_width = 0;
111113
int port_b_data_width = 0;
112114
t_node_port_association* port_b_input_clock = nullptr;
113115
t_node_port_association* port_b_input_ena = nullptr;

0 commit comments

Comments
 (0)