mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 11:42:30 +00:00 
			
		
		
		
	Added TRANSPARENT parameter to $memrd (and RD_TRANSPARENT to $mem)
This commit is contained in:
		
							parent
							
								
									de9226a64f
								
							
						
					
					
						commit
						a6750b3753
					
				
					 11 changed files with 186 additions and 78 deletions
				
			
		|  | @ -716,6 +716,8 @@ struct BtorDumper | |||
| 			else if(cell->type == "$memrd") | ||||
| 			{ | ||||
| 				log("writing memrd cell\n"); | ||||
| 				if (cell->parameters.at("\\CLK_ENABLE").as_bool() == true) | ||||
| 					log_error("The btor backen does not support $memrd cells with built-in registers. Run memory_dff with -wr_only.\n"); | ||||
| 				str = cell->parameters.at(RTLIL::IdString("\\MEMID")).decode_string(); | ||||
| 				int mem = dump_memory(module->memories.at(RTLIL::IdString(str.c_str()))); | ||||
| 				int address_width = cell->parameters.at(RTLIL::IdString("\\ABITS")).as_int(); | ||||
|  | @ -729,6 +731,8 @@ struct BtorDumper | |||
| 			else if(cell->type == "$memwr") | ||||
| 			{ | ||||
| 				log("writing memwr cell\n"); | ||||
| 				if (cell->parameters.at("\\CLK_ENABLE").as_bool() == false) | ||||
| 					log_error("The btor backen does not support $memwr cells without built-in registers. Run memory_dff (but with -wr_only).\n"); | ||||
| 				int clk = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\CLK")), 1); | ||||
| 				bool polarity = cell->parameters.at(RTLIL::IdString("\\CLK_POLARITY")).as_bool(); | ||||
| 				int enable = dump_sigspec(&cell->connections.at(RTLIL::IdString("\\EN")), 1); | ||||
|  |  | |||
|  | @ -25,7 +25,8 @@ proc; | |||
| opt; opt_const -mux_undef; opt; | ||||
| rename -hide;;; | ||||
| techmap -share_map pmux2mux.v;; | ||||
| memory -nomap;; | ||||
| memory_dff -wr_only | ||||
| memory_collect;; | ||||
| flatten;; | ||||
| memory_unpack;  | ||||
| splitnets -driver; | ||||
|  |  | |||
|  | @ -1245,6 +1245,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) | |||
| 
 | ||||
| 			cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(0); | ||||
| 			cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(0); | ||||
| 			cell->parameters["\\TRANSPARENT"] = RTLIL::Const(0); | ||||
| 
 | ||||
| 			return RTLIL::SigSpec(wire); | ||||
| 		} | ||||
|  |  | |||
|  | @ -556,6 +556,7 @@ namespace { | |||
| 				param("\\MEMID"); | ||||
| 				param("\\CLK_ENABLE"); | ||||
| 				param("\\CLK_POLARITY"); | ||||
| 				param("\\TRANSPARENT"); | ||||
| 				port("\\CLK", 1); | ||||
| 				port("\\ADDR", param("\\ABITS")); | ||||
| 				port("\\DATA", param("\\WIDTH")); | ||||
|  | @ -582,6 +583,7 @@ namespace { | |||
| 				param("\\OFFSET"); | ||||
| 				param("\\RD_CLK_ENABLE"); | ||||
| 				param("\\RD_CLK_POLARITY"); | ||||
| 				param("\\RD_TRANSPARENT"); | ||||
| 				param("\\WR_CLK_ENABLE"); | ||||
| 				param("\\WR_CLK_POLARITY"); | ||||
| 				port("\\RD_CLK", param("\\RD_PORTS")); | ||||
|  |  | |||
|  | @ -250,6 +250,10 @@ the \B{CLK} input is not used. | |||
| \item \B{CLK\_POLARITY} \\ | ||||
| Clock is active on the positive edge if this parameter has the value {\tt 1'b1} and on the negative | ||||
| edge if this parameter is {\tt 1'b0}. | ||||
| 
 | ||||
| \item \B{TRANSPARENT} \\ | ||||
| If this parameter is set to {\tt 1'b1}, a read and write to the same address in the same cycle will | ||||
| return the new value. Otherwise the old value is returned. | ||||
| \end{itemize} | ||||
| 
 | ||||
| The {\tt \$memwr} cells have a clock input \B{CLK}, an enable input \B{EN}, an address input \B{ADDR} | ||||
|  | @ -308,6 +312,9 @@ This parameter is \B{RD\_PORTS} bits wide, containing a clock enable bit for eac | |||
| \item \B{RD\_CLK\_POLARITY} \\ | ||||
| This parameter is \B{RD\_PORTS} bits wide, containing a clock polarity bit for each read port. | ||||
| 
 | ||||
| \item \B{RD\_TRANSPARENT} \\ | ||||
| This parameter is \B{RD\_PORTS} bits wide, containing a transparent bit for each read port. | ||||
| 
 | ||||
| \item \B{WR\_PORTS} \\ | ||||
| The number of write ports on this memory cell. | ||||
| 
 | ||||
|  |  | |||
|  | @ -54,6 +54,7 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) | |||
| 	RTLIL::SigSpec sig_rd_clk; | ||||
| 	RTLIL::SigSpec sig_rd_clk_enable; | ||||
| 	RTLIL::SigSpec sig_rd_clk_polarity; | ||||
| 	RTLIL::SigSpec sig_rd_transparent; | ||||
| 	RTLIL::SigSpec sig_rd_addr; | ||||
| 	RTLIL::SigSpec sig_rd_data; | ||||
| 
 | ||||
|  | @ -105,18 +106,21 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) | |||
| 			RTLIL::SigSpec clk = cell->connections["\\CLK"]; | ||||
| 			RTLIL::SigSpec clk_enable = RTLIL::SigSpec(cell->parameters["\\CLK_ENABLE"]); | ||||
| 			RTLIL::SigSpec clk_polarity = RTLIL::SigSpec(cell->parameters["\\CLK_POLARITY"]); | ||||
| 			RTLIL::SigSpec transparent = RTLIL::SigSpec(cell->parameters["\\TRANSPARENT"]); | ||||
| 			RTLIL::SigSpec addr = cell->connections["\\ADDR"]; | ||||
| 			RTLIL::SigSpec data = cell->connections["\\DATA"]; | ||||
| 
 | ||||
| 			clk.extend(1, false); | ||||
| 			clk_enable.extend(1, false); | ||||
| 			clk_polarity.extend(1, false); | ||||
| 			transparent.extend(1, false); | ||||
| 			addr.extend(addr_bits, false); | ||||
| 			data.extend(memory->width, false); | ||||
| 
 | ||||
| 			sig_rd_clk.append(clk); | ||||
| 			sig_rd_clk_enable.append(clk_enable); | ||||
| 			sig_rd_clk_polarity.append(clk_polarity); | ||||
| 			sig_rd_transparent.append(transparent); | ||||
| 			sig_rd_addr.append(addr); | ||||
| 			sig_rd_data.append(data); | ||||
| 		} | ||||
|  | @ -147,7 +151,7 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) | |||
| 
 | ||||
| 	mem->parameters["\\WR_PORTS"] = RTLIL::Const(wr_ports); | ||||
| 	mem->parameters["\\WR_CLK_ENABLE"] = wr_ports ? sig_wr_clk_enable.chunks[0].data : RTLIL::Const(0, 0); | ||||
| 	mem->parameters["\\WR_CLK_POLARITY"] = wr_ports ? sig_wr_clk_enable.chunks[0].data : RTLIL::Const(0, 0); | ||||
| 	mem->parameters["\\WR_CLK_POLARITY"] = wr_ports ? sig_wr_clk_polarity.chunks[0].data : RTLIL::Const(0, 0); | ||||
| 
 | ||||
| 	mem->connections["\\WR_CLK"] = sig_wr_clk; | ||||
| 	mem->connections["\\WR_ADDR"] = sig_wr_addr; | ||||
|  | @ -165,7 +169,8 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Memory *memory) | |||
| 
 | ||||
| 	mem->parameters["\\RD_PORTS"] = RTLIL::Const(rd_ports); | ||||
| 	mem->parameters["\\RD_CLK_ENABLE"] = rd_ports ? sig_rd_clk_enable.chunks[0].data : RTLIL::Const(0, 0); | ||||
| 	mem->parameters["\\RD_CLK_POLARITY"] = rd_ports ? sig_rd_clk_enable.chunks[0].data : RTLIL::Const(0, 0); | ||||
| 	mem->parameters["\\RD_CLK_POLARITY"] = rd_ports ? sig_rd_clk_polarity.chunks[0].data : RTLIL::Const(0, 0); | ||||
| 	mem->parameters["\\RD_TRANSPARENT"] = rd_ports ? sig_rd_transparent.chunks[0].data : RTLIL::Const(0, 0); | ||||
| 
 | ||||
| 	mem->connections["\\RD_CLK"] = sig_rd_clk; | ||||
| 	mem->connections["\\RD_ADDR"] = sig_rd_addr; | ||||
|  |  | |||
|  | @ -113,14 +113,6 @@ static void handle_wr_cell(RTLIL::Module *module, RTLIL::Cell *cell) | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| #if 1 | ||||
| static void handle_rd_cell(RTLIL::Module*, RTLIL::Cell*) | ||||
| { | ||||
| 	// merging dffs into read ports isn't neccessary for memory_map.
 | ||||
| 	// we'd loose the information if the register is on the address or
 | ||||
| 	// data port and wouldn't get any benefits.
 | ||||
| } | ||||
| #else | ||||
| static void disconnect_dff(RTLIL::Module *module, RTLIL::SigSpec sig) | ||||
| { | ||||
| 	normalize_sig(module, sig); | ||||
|  | @ -149,43 +141,46 @@ static void handle_rd_cell(RTLIL::Module *module, RTLIL::Cell *cell) | |||
| 
 | ||||
| 	bool clk_polarity = 0; | ||||
| 
 | ||||
| 	RTLIL::SigSpec clk_addr = RTLIL::SigSpec(RTLIL::State::Sx); | ||||
| 	RTLIL::SigSpec sig_addr = cell->connections["\\ADDR"]; | ||||
| 	if (find_sig_before_dff(module, sig_addr, clk_addr, clk_polarity)) | ||||
| 	{ | ||||
| 		cell->connections["\\CLK"] = clk_addr; | ||||
| 		cell->connections["\\ADDR"] = sig_addr; | ||||
| 		cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1); | ||||
| 		cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity); | ||||
| 		log("merged address $dff to cell.\n"); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	RTLIL::SigSpec clk_data = RTLIL::SigSpec(RTLIL::State::Sx); | ||||
| 	RTLIL::SigSpec sig_data = cell->connections["\\DATA"]; | ||||
| 	if (find_sig_before_dff(module, sig_data, clk_data, clk_polarity, true)) | ||||
| 	if (find_sig_before_dff(module, sig_data, clk_data, clk_polarity, true) && | ||||
| 			clk_data != RTLIL::SigSpec(RTLIL::State::Sx)) | ||||
| 	{ | ||||
| 		disconnect_dff(module, sig_data); | ||||
| 		cell->connections["\\CLK"] = clk_data; | ||||
| 		cell->connections["\\DATA"] = sig_data; | ||||
| 		cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1); | ||||
| 		cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity); | ||||
| 		cell->parameters["\\TRANSPARENT"] = RTLIL::Const(0); | ||||
| 		log("merged data $dff to cell.\n"); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	RTLIL::SigSpec clk_addr = RTLIL::SigSpec(RTLIL::State::Sx); | ||||
| 	RTLIL::SigSpec sig_addr = cell->connections["\\ADDR"]; | ||||
| 	if (find_sig_before_dff(module, sig_addr, clk_addr, clk_polarity) && | ||||
| 			clk_addr != RTLIL::SigSpec(RTLIL::State::Sx)) | ||||
| 	{ | ||||
| 		cell->connections["\\CLK"] = clk_addr; | ||||
| 		cell->connections["\\ADDR"] = sig_addr; | ||||
| 		cell->parameters["\\CLK_ENABLE"] = RTLIL::Const(1); | ||||
| 		cell->parameters["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity); | ||||
| 		cell->parameters["\\TRANSPARENT"] = RTLIL::Const(1); | ||||
| 		log("merged address $dff to cell.\n"); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	log("no (compatible) $dff found.\n"); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| static void handle_module(RTLIL::Design *design, RTLIL::Module *module) | ||||
| static void handle_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_wr_only) | ||||
| { | ||||
| 	for (auto &cell_it : module->cells) { | ||||
| 		if (!design->selected(module, cell_it.second)) | ||||
| 			continue; | ||||
| 		if (cell_it.second->type == "$memwr" && !cell_it.second->parameters["\\CLK_ENABLE"].as_bool()) | ||||
| 				handle_wr_cell(module, cell_it.second); | ||||
| 		if (cell_it.second->type == "$memrd" && !cell_it.second->parameters["\\CLK_ENABLE"].as_bool()) | ||||
| 		if (!flag_wr_only && cell_it.second->type == "$memrd" && !cell_it.second->parameters["\\CLK_ENABLE"].as_bool()) | ||||
| 				handle_rd_cell(module, cell_it.second); | ||||
| 	} | ||||
| } | ||||
|  | @ -196,19 +191,35 @@ struct MemoryDffPass : public Pass { | |||
| 	{ | ||||
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | ||||
| 		log("\n"); | ||||
| 		log("    memory_dff [selection]\n"); | ||||
| 		log("    memory_dff [options] [selection]\n"); | ||||
| 		log("\n"); | ||||
| 		log("This pass detects DFFs at memory ports and merges them into the memory port.\n"); | ||||
| 		log("I.e. it consumes an asynchronous memory port and the flip-flops at its\n"); | ||||
| 		log("interface and yields a synchronous memory port.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -wr_only\n"); | ||||
| 		log("        do not merge registers on read ports\n"); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 	virtual void execute(std::vector<std::string> args, RTLIL::Design *design) { | ||||
| 	virtual void execute(std::vector<std::string> args, RTLIL::Design *design) | ||||
| 	{ | ||||
| 		bool flag_wr_only = false; | ||||
| 
 | ||||
| 		log_header("Executing MEMORY_DFF pass (merging $dff cells to $memrd and $memwr).\n"); | ||||
| 		extra_args(args, 1, design); | ||||
| 
 | ||||
| 		size_t argidx; | ||||
| 		for (argidx = 1; argidx < args.size(); argidx++) { | ||||
| 			if (args[argidx] == "-wr_only") { | ||||
| 				flag_wr_only = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
| 
 | ||||
| 		for (auto &mod_it : design->modules) | ||||
| 			if (design->selected(mod_it.second)) | ||||
| 				handle_module(design, mod_it.second); | ||||
| 				handle_module(design, mod_it.second, flag_wr_only); | ||||
| 	} | ||||
| } MemoryDffPass; | ||||
|   | ||||
|  |  | |||
|  | @ -162,44 +162,47 @@ static void handle_cell(RTLIL::Module *module, RTLIL::Cell *cell) | |||
| 
 | ||||
| 		if (cell->parameters["\\RD_CLK_ENABLE"].bits[i] == RTLIL::State::S1) | ||||
| 		{ | ||||
| #if 1 | ||||
| 			RTLIL::Cell *c = new RTLIL::Cell; | ||||
| 			c->name = genid(cell->name, "$rdreg", i); | ||||
| 			c->type = "$dff"; | ||||
| 			c->parameters["\\WIDTH"] = RTLIL::Const(mem_abits); | ||||
| 			c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]); | ||||
| 			c->connections["\\CLK"] = cell->connections["\\RD_CLK"].extract(i, 1); | ||||
| 			c->connections["\\D"] = rd_addr; | ||||
| 			module->cells[c->name] = c; | ||||
| 			count_dff++; | ||||
| 			if (cell->parameters["\\RD_TRANSPARENT"].bits[i] == RTLIL::State::S1) | ||||
| 			{ | ||||
| 				RTLIL::Cell *c = new RTLIL::Cell; | ||||
| 				c->name = genid(cell->name, "$rdreg", i); | ||||
| 				c->type = "$dff"; | ||||
| 				c->parameters["\\WIDTH"] = RTLIL::Const(mem_abits); | ||||
| 				c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]); | ||||
| 				c->connections["\\CLK"] = cell->connections["\\RD_CLK"].extract(i, 1); | ||||
| 				c->connections["\\D"] = rd_addr; | ||||
| 				module->cells[c->name] = c; | ||||
| 				count_dff++; | ||||
| 
 | ||||
| 			RTLIL::Wire *w = new RTLIL::Wire; | ||||
| 			w->name = genid(cell->name, "$rdreg", i, "$q"); | ||||
| 			w->width = mem_abits; | ||||
| 			module->wires[w->name] = w; | ||||
| 				RTLIL::Wire *w = new RTLIL::Wire; | ||||
| 				w->name = genid(cell->name, "$rdreg", i, "$q"); | ||||
| 				w->width = mem_abits; | ||||
| 				module->wires[w->name] = w; | ||||
| 
 | ||||
| 			c->connections["\\Q"] = RTLIL::SigSpec(w); | ||||
| 			rd_addr = RTLIL::SigSpec(w); | ||||
| #else | ||||
| 			RTLIL::Cell *c = new RTLIL::Cell; | ||||
| 			c->name = genid(cell->name, "$rdreg", i); | ||||
| 			c->type = "$dff"; | ||||
| 			c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"]; | ||||
| 			c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]); | ||||
| 			c->connections["\\CLK"] = cell->connections["\\RD_CLK"].extract(i, 1); | ||||
| 			c->connections["\\Q"] = rd_signals.back(); | ||||
| 			module->cells[c->name] = c; | ||||
| 			count_dff++; | ||||
| 				c->connections["\\Q"] = RTLIL::SigSpec(w); | ||||
| 				rd_addr = RTLIL::SigSpec(w); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				RTLIL::Cell *c = new RTLIL::Cell; | ||||
| 				c->name = genid(cell->name, "$rdreg", i); | ||||
| 				c->type = "$dff"; | ||||
| 				c->parameters["\\WIDTH"] = cell->parameters["\\WIDTH"]; | ||||
| 				c->parameters["\\CLK_POLARITY"] = RTLIL::Const(cell->parameters["\\RD_CLK_POLARITY"].bits[i]); | ||||
| 				c->connections["\\CLK"] = cell->connections["\\RD_CLK"].extract(i, 1); | ||||
| 				c->connections["\\Q"] = rd_signals.back(); | ||||
| 				module->cells[c->name] = c; | ||||
| 				count_dff++; | ||||
| 
 | ||||
| 			RTLIL::Wire *w = new RTLIL::Wire; | ||||
| 			w->name = genid(cell->name, "$rdreg", i, "$d"); | ||||
| 			w->width = mem_width; | ||||
| 			module->wires[w->name] = w; | ||||
| 				RTLIL::Wire *w = new RTLIL::Wire; | ||||
| 				w->name = genid(cell->name, "$rdreg", i, "$d"); | ||||
| 				w->width = mem_width; | ||||
| 				module->wires[w->name] = w; | ||||
| 
 | ||||
| 			rd_signals.clear(); | ||||
| 			rd_signals.push_back(RTLIL::SigSpec(w)); | ||||
| 			c->connections["\\D"] = rd_signals.back(); | ||||
| #endif | ||||
| 				rd_signals.clear(); | ||||
| 				rd_signals.push_back(RTLIL::SigSpec(w)); | ||||
| 				c->connections["\\D"] = rd_signals.back(); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		for (int j = 0; j < mem_abits; j++) | ||||
|  |  | |||
|  | @ -55,6 +55,7 @@ static void handle_memory(RTLIL::Module *module, RTLIL::Cell *memory) | |||
| 		cell->parameters["\\WIDTH"] = memory->parameters.at("\\WIDTH"); | ||||
| 		cell->parameters["\\CLK_ENABLE"] = RTLIL::SigSpec(memory->parameters.at("\\RD_CLK_ENABLE")).extract(i, 1).as_const(); | ||||
| 		cell->parameters["\\CLK_POLARITY"] = RTLIL::SigSpec(memory->parameters.at("\\RD_CLK_POLARITY")).extract(i, 1).as_const(); | ||||
| 		cell->parameters["\\TRANSPARENT"] = RTLIL::SigSpec(memory->parameters.at("\\RD_TRANSPARENT")).extract(i, 1).as_const(); | ||||
| 		cell->connections["\\CLK"] = memory->connections.at("\\RD_CLK").extract(i, 1); | ||||
| 		cell->connections["\\ADDR"] = memory->connections.at("\\RD_ADDR").extract(i*abits, abits); | ||||
| 		cell->connections["\\DATA"] = memory->connections.at("\\RD_DATA").extract(i*mem->width, mem->width); | ||||
|  |  | |||
|  | @ -1220,6 +1220,7 @@ parameter WIDTH = 8; | |||
| parameter RD_PORTS = 1; | ||||
| parameter RD_CLK_ENABLE = 1'b1; | ||||
| parameter RD_CLK_POLARITY = 1'b1; | ||||
| parameter RD_TRANSPARENT = 1'b1; | ||||
| 
 | ||||
| parameter WR_PORTS = 1; | ||||
| parameter WR_CLK_ENABLE = 1'b1; | ||||
|  | @ -1242,37 +1243,70 @@ generate | |||
| 	for (i = 0; i < RD_PORTS; i = i+1) begin:rd | ||||
| 		if (RD_CLK_ENABLE[i] == 0) begin:rd_noclk | ||||
| 			always @(RD_ADDR or update_async_rd) | ||||
| 				RD_DATA[ (i+1)*WIDTH-1 : i*WIDTH ] <= data[ RD_ADDR[ (i+1)*ABITS-1 : i*ABITS ] - OFFSET ]; | ||||
| 				RD_DATA[ i*WIDTH +: WIDTH ] <= data[ RD_ADDR[ i*ABITS +: ABITS ] - OFFSET ]; | ||||
| 		end else | ||||
| 		if (RD_CLK_POLARITY[i] == 1) begin:rd_posclk | ||||
| 			always @(posedge RD_CLK[i]) | ||||
| 				RD_DATA[ (i+1)*WIDTH-1 : i*WIDTH ] <= data[ RD_ADDR[ (i+1)*ABITS-1 : i*ABITS ] - OFFSET ]; | ||||
| 		end else begin:rd_negclk | ||||
| 			always @(negedge RD_CLK[i]) | ||||
| 				RD_DATA[ (i+1)*WIDTH-1 : i*WIDTH ] <= data[ RD_ADDR[ (i+1)*ABITS-1 : i*ABITS ] - OFFSET ]; | ||||
| 		if (RD_TRANSPARENT[i] == 1) begin:rd_transparent | ||||
| 			reg [ABITS-1:0] addr_buf; | ||||
| 			if (RD_CLK_POLARITY[i] == 1) begin:rd_trans_posclk | ||||
| 				always @(posedge RD_CLK[i]) | ||||
| 					addr_buf <= RD_ADDR[ i*ABITS +: ABITS ]; | ||||
| 			end else begin:rd_trans_negclk | ||||
| 				always @(negedge RD_CLK[i]) | ||||
| 					addr_buf <= RD_ADDR[ i*ABITS +: ABITS ]; | ||||
| 			end | ||||
| 			always @(addr_buf or update_async_rd) | ||||
| 				RD_DATA[ i*WIDTH +: WIDTH ] <= data[ addr_buf - OFFSET ]; | ||||
| 		end else begin:rd_notransparent | ||||
| 			if (RD_CLK_POLARITY[i] == 1) begin:rd_notrans_posclk | ||||
| 				always @(posedge RD_CLK[i]) | ||||
| 					RD_DATA[ i*WIDTH +: WIDTH ] <= data[ RD_ADDR[ i*ABITS +: ABITS ] - OFFSET ]; | ||||
| 			end else begin:rd_notrans_negclk | ||||
| 				always @(negedge RD_CLK[i]) | ||||
| 					RD_DATA[ i*WIDTH +: WIDTH ] <= data[ RD_ADDR[ i*ABITS +: ABITS ] - OFFSET ]; | ||||
| 			end | ||||
| 		end | ||||
| 	end | ||||
| 
 | ||||
| 	for (i = 0; i < WR_PORTS; i = i+1) begin:wr | ||||
| 		integer k; | ||||
| 		reg found_collision; | ||||
| 		if (WR_CLK_ENABLE[i] == 0) begin:wr_noclk | ||||
| 			always @(WR_ADDR or WR_DATA or WR_EN) begin | ||||
| 				if (WR_EN[i]) begin | ||||
| 					data[ WR_ADDR[ (i+1)*ABITS-1 : i*ABITS ] - OFFSET ] <= WR_DATA[ (i+1)*WIDTH-1 : i*WIDTH ]; | ||||
| 					update_async_rd <= 1; update_async_rd <= 0; | ||||
| 					found_collision = 0; | ||||
| 					for (k = i+1; k < WR_PORTS; k = k+1) | ||||
| 						if (WR_EN[k] && WR_ADDR[ i*ABITS +: ABITS ] == WR_ADDR[ k*ABITS +: ABITS ]) | ||||
| 							found_collision = 1; | ||||
| 					if (!found_collision) begin | ||||
| 						data[ WR_ADDR[ i*ABITS +: ABITS ] - OFFSET ] <= WR_DATA[ i*WIDTH +: WIDTH ]; | ||||
| 						update_async_rd <= 1; update_async_rd <= 0; | ||||
| 					end | ||||
| 				end | ||||
| 			end | ||||
| 		end else | ||||
| 		if (WR_CLK_POLARITY[i] == 1) begin:rd_posclk | ||||
| 			always @(posedge WR_CLK[i]) | ||||
| 				if (WR_EN[i]) begin | ||||
| 					data[ WR_ADDR[ (i+1)*ABITS-1 : i*ABITS ] - OFFSET ] <= WR_DATA[ (i+1)*WIDTH-1 : i*WIDTH ]; | ||||
| 					update_async_rd <= 1; update_async_rd <= 0; | ||||
| 					found_collision = 0; | ||||
| 					for (k = i+1; k < WR_PORTS; k = k+1) | ||||
| 						if (WR_EN[k] && WR_ADDR[ i*ABITS +: ABITS ] == WR_ADDR[ k*ABITS +: ABITS ]) | ||||
| 							found_collision = 1; | ||||
| 					if (!found_collision) begin | ||||
| 						data[ WR_ADDR[ i*ABITS +: ABITS ] - OFFSET ] <= WR_DATA[ i*WIDTH +: WIDTH ]; | ||||
| 						update_async_rd <= 1; update_async_rd <= 0; | ||||
| 					end | ||||
| 				end | ||||
| 		end else begin:rd_negclk | ||||
| 			always @(negedge WR_CLK[i]) | ||||
| 				if (WR_EN[i]) begin | ||||
| 					data[ WR_ADDR[ (i+1)*ABITS-1 : i*ABITS ] - OFFSET ] <= WR_DATA[ (i+1)*WIDTH-1 : i*WIDTH ]; | ||||
| 					update_async_rd <= 1; update_async_rd <= 0; | ||||
| 					found_collision = 0; | ||||
| 					for (k = i+1; k < WR_PORTS; k = k+1) | ||||
| 						if (WR_EN[k] && WR_ADDR[ i*ABITS +: ABITS ] == WR_ADDR[ k*ABITS +: ABITS ]) | ||||
| 							found_collision = 1; | ||||
| 					if (!found_collision) begin | ||||
| 						data[ WR_ADDR[ i*ABITS +: ABITS ] - OFFSET ] <= WR_DATA[ i*WIDTH +: WIDTH ]; | ||||
| 						update_async_rd <= 1; update_async_rd <= 0; | ||||
| 					end | ||||
| 				end | ||||
| 		end | ||||
| 	end | ||||
|  |  | |||
|  | @ -75,3 +75,42 @@ assign y4 = mem2[addr][bit]; | |||
| 
 | ||||
| endmodule | ||||
| 
 | ||||
| // ---------------------------------------------------------- | ||||
| 
 | ||||
| module test03(clk, wr_addr, wr_data, wr_enable, rd_addr, rd_data); | ||||
| 
 | ||||
| input clk, wr_enable; | ||||
| input [3:0] wr_addr, wr_data, rd_addr; | ||||
| output reg [3:0] rd_data; | ||||
| 
 | ||||
| reg [3:0] memory [0:15]; | ||||
| 
 | ||||
| always @(posedge clk) begin | ||||
| 	if (wr_enable) | ||||
| 		memory[wr_addr] <= wr_data; | ||||
| 	rd_data <= memory[rd_addr]; | ||||
| end | ||||
| 
 | ||||
| endmodule | ||||
| 
 | ||||
| // ---------------------------------------------------------- | ||||
| 
 | ||||
| module test04(clk, wr_addr, wr_data, wr_enable, rd_addr, rd_data); | ||||
| 
 | ||||
| input clk, wr_enable; | ||||
| input [3:0] wr_addr, wr_data, rd_addr; | ||||
| output [3:0] rd_data; | ||||
| 
 | ||||
| reg rd_addr_buf; | ||||
| reg [3:0] memory [0:15]; | ||||
| 
 | ||||
| always @(posedge clk) begin | ||||
| 	if (wr_enable) | ||||
| 		memory[wr_addr] <= wr_data; | ||||
| 	rd_addr_buf <= rd_addr; | ||||
| end | ||||
| 
 | ||||
| assign rd_data = memory[rd_addr_buf]; | ||||
| 
 | ||||
| endmodule | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue