1- /* *
2- * Copyright (c) 2021 Seyed Alireza Damghani ([email protected] ) 1+ /*
2+ * Copyright 2023 CAS—Atlantic (University of New Brunswick, CASA )
33 *
44 * Permission is hereby granted, free of charge, to any person
55 * obtaining a copy of this software and associated documentation
2121 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2222 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2323 * OTHER DEALINGS IN THE SOFTWARE.
24- *
25- * @file: This file includes the definitions of the routines to map
26- * block memories to VTR compatible memory types, i.e., Single Port RAM
27- * and Dual Port RAM. The definition of block memory and read-only memory
28- * is provided in techlib directory in the Odin-II root directory.
29- * Basically, a memory block with both read and write accesses that has a
30- * separate port for each operation is called BRAM. While following the
31- * same definition, a read-only memory block is referred to as a BRAM that
32- * has only read access (even multiple accesses). This function also
33- * includes ymem block support which somehow represents the Yosys internal
34- * memory cell.
3524 */
3625
3726#include < string.h>
@@ -68,6 +57,7 @@ static void create_r2w_dual_port_ram(block_memory_t* bram, netlist_t* netlist);
6857static void create_2rw_dual_port_ram (block_memory_t * bram, netlist_t * netlist);
6958static void create_2r2w_dual_port_ram (block_memory_t * bram, netlist_t * netlist);
7059static void create_nrmw_dual_port_ram (block_memory_t * bram, netlist_t * netlist);
60+ static void create_2rw_multiplexed_dual_port_ram (block_memory_t * bram, netlist_t * netlist);
7161
7262static nnode_t * ymem_to_rom (nnode_t * node, uintptr_t traverse_mark_number);
7363static nnode_t * ymem2_to_rom (nnode_t * node, uintptr_t traverse_mark_number);
@@ -850,11 +840,6 @@ static void create_2rw_dual_port_ram(block_memory_t* bram, netlist_t* netlist) {
850840 add_pin_to_signal_list (rd_data2, bram->read_data ->pins [i + offset]);
851841 }
852842
853- /* delete rd pins since we use corresponding wr_en and zero*/
854- for (i = 0 ; i < bram->read_en ->count ; ++i) {
855- delete_npin (bram->read_en ->pins [i]);
856- }
857-
858843 /* *
859844 * [NOTE]:
860845 * Odin-II handle memory block with more than two distint
@@ -874,11 +859,16 @@ static void create_2rw_dual_port_ram(block_memory_t* bram, netlist_t* netlist) {
874859 free_signal_list (rd_data2);
875860
876861 /* all ports have different address */
877- create_nrmw_dual_port_ram (bram, netlist);
862+ create_2rw_multiplexed_dual_port_ram (bram, netlist);
878863 return ;
879864 }
880865 }
881866
867+ /* delete rd pins since we use corresponding wr_en and zero*/
868+ for (i = 0 ; i < bram->read_en ->count ; ++i) {
869+ delete_npin (bram->read_en ->pins [i]);
870+ }
871+
882872 /* map matched read data to the out1 */
883873 signals->out1 = (first_match) ? rd_data1 : rd_data2;
884874
@@ -979,11 +969,6 @@ static void create_2r2w_dual_port_ram(block_memory_t* bram, netlist_t* netlist)
979969 add_pin_to_signal_list (rd_data2, bram->read_data ->pins [i + offset]);
980970 }
981971
982- /* delete rd pins since we use corresponding wr_en and zero*/
983- for (i = 0 ; i < bram->read_en ->count ; ++i) {
984- delete_npin (bram->read_en ->pins [i]);
985- }
986-
987972 /* *
988973 * [NOTE]:
989974 * Odin-II handle memory block with more than two distint
@@ -1012,6 +997,11 @@ static void create_2r2w_dual_port_ram(block_memory_t* bram, netlist_t* netlist)
1012997 return ;
1013998 }
1014999
1000+ /* delete rd pins since we use corresponding wr_en and zero*/
1001+ for (i = 0 ; i < bram->read_en ->count ; ++i) {
1002+ delete_npin (bram->read_en ->pins [i]);
1003+ }
1004+
10151005 /* create a list of dpram ram signals */
10161006 dp_ram_signals* signals = (dp_ram_signals*)vtr::malloc (sizeof (dp_ram_signals));
10171007
@@ -1163,6 +1153,88 @@ static void create_nrmw_dual_port_ram(block_memory_t* bram, netlist_t* netlist)
11631153 free_dp_ram_signals (signals);
11641154}
11651155
1156+ /* *
1157+ * (function: create_2rw_multiplexed_dual_port_ram)
1158+ *
1159+ * @brief read ports are multiplexed using read enable.
1160+ * multiple write ports are multiplexed using write enable.
1161+ * Then, the BRAM will be mapped to a DPRAM
1162+ *
1163+ * @param bram pointing to a bram node node
1164+ * @param netlist pointer to the current netlist file
1165+ */
1166+ static void create_2rw_multiplexed_dual_port_ram (block_memory_t * bram, netlist_t * netlist) {
1167+ int i;
1168+ nnode_t * old_node = bram->node ;
1169+ int data_width = bram->node ->attributes ->DBITS ;
1170+ int addr_width = bram->node ->attributes ->ABITS ;
1171+ int num_rd_ports = old_node->attributes ->RD_PORTS ;
1172+ int num_wr_ports = old_node->attributes ->WR_PORTS ;
1173+
1174+ /* should have been resovled before this function */
1175+ oassert (num_rd_ports == 2 );
1176+ oassert (num_wr_ports == 1 );
1177+
1178+ /* dual port ram signals */
1179+ dp_ram_signals* signals = (dp_ram_signals*)vtr::calloc (1 , sizeof (dp_ram_signals));
1180+ signal_list_t * selectors = NULL ;
1181+
1182+ /* INPUTS */
1183+ selectors = copy_input_signals (bram->read_en );
1184+ /* adding the read addr input port as address1 */
1185+ signals->addr1 = split_cascade_port (bram->read_addr ,
1186+ selectors,
1187+ addr_width,
1188+ old_node,
1189+ netlist);
1190+ free_signal_list (selectors);
1191+
1192+ signals->addr2 = init_signal_list ();
1193+ for (i = 0 ; i < bram->write_addr ->count ; ++i) {
1194+ add_pin_to_signal_list (signals->addr2 , bram->write_addr ->pins [i]);
1195+ }
1196+
1197+ /* handling clock signals */
1198+ signals->clk = bram->clk ->pins [0 ];
1199+
1200+ /* we pad the first data port using pad pins */
1201+ signals->data1 = init_signal_list ();
1202+ for (i = 0 ; i < data_width; ++i) {
1203+ add_pin_to_signal_list (signals->data1 , get_pad_pin (netlist));
1204+ }
1205+
1206+ signals->data2 = init_signal_list ();
1207+ for (i = 0 ; i < data_width; ++i) {
1208+ add_pin_to_signal_list (signals->data2 , bram->write_data ->pins [i]);
1209+ }
1210+
1211+ /* first port does not have data, so the enable is GND */
1212+ signals->we1 = get_zero_pin (netlist);
1213+
1214+ signals->we2 = bram->write_en ->pins [0 ];
1215+
1216+ /* OUTPUT */
1217+ /* leaving out1 of dpram null, so it will create a new pins */
1218+ signals->out1 = NULL ;
1219+ signals->out2 = NULL ;
1220+
1221+ /* create a DPRAM node */
1222+ nnode_t * dpram = create_dual_port_ram (signals, old_node);
1223+
1224+ signal_list_t * dpram_outputs = init_signal_list ();
1225+ for (i = 0 ; i < data_width; ++i) {
1226+ add_pin_to_signal_list (dpram_outputs, dpram->output_pins [i]);
1227+ }
1228+
1229+ /* decode the spram outputs to the n bram output ports */
1230+ decode_out_port (dpram_outputs, bram->read_data , bram->read_en , old_node, netlist);
1231+
1232+ // CLEAN UP
1233+ cleanup_block_memory_old_node (old_node);
1234+ free_signal_list (dpram_outputs);
1235+ free_dp_ram_signals (signals);
1236+ }
1237+
11661238/* *
11671239 * (function: map_rom_to_mem_hardblocks)
11681240 *
@@ -2234,4 +2306,4 @@ static void free_block_memory(block_memory_t* to_free) {
22342306 vtr::free (to_free->memory_id );
22352307
22362308 vtr::free (to_free);
2237- }
2309+ }
0 commit comments