diff options
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | backends/btor/btor.cc | 4 | ||||
| -rw-r--r-- | passes/sat/sim.cc | 204 | ||||
| -rw-r--r-- | techlibs/intel_alm/Makefile.inc | 1 | ||||
| -rw-r--r-- | techlibs/intel_alm/common/bram_m10k.txt | 4 | ||||
| -rw-r--r-- | techlibs/intel_alm/common/bram_m10k_map.v | 16 | ||||
| -rw-r--r-- | techlibs/intel_alm/common/mem_sim.v | 2 | ||||
| -rw-r--r-- | techlibs/intel_alm/common/quartus_rename.v | 9 | ||||
| -rw-r--r-- | techlibs/intel_alm/synth_intel_alm.cc | 3 | ||||
| -rw-r--r-- | tests/arch/intel_alm/blockram.ys | 3 | 
10 files changed, 221 insertions, 27 deletions
@@ -129,7 +129,7 @@ LDFLAGS += -rdynamic  LDLIBS += -lrt  endif -YOSYS_VER := 0.15+7 +YOSYS_VER := 0.15+11  GIT_REV := $(shell git -C $(YOSYS_SRC) rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)  OBJS = kernel/version_$(GIT_REV).o diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index d62cc4c3d..73e88c049 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -678,7 +678,7 @@ struct BtorWorker  			int sid = get_bv_sid(GetSize(sig_y));  			int nid = next_nid++; -			btorf("%d state %d\n", nid, sid); +			btorf("%d state %d%s\n", nid, sid, getinfo(cell).c_str());  			if (cell->type == ID($anyconst)) {  				int nid2 = next_nid++; @@ -699,7 +699,7 @@ struct BtorWorker  				int one_nid = get_sig_nid(State::S1);  				int zero_nid = get_sig_nid(State::S0);  				initstate_nid = next_nid++; -				btorf("%d state %d\n", initstate_nid, sid); +				btorf("%d state %d%s\n", initstate_nid, sid, getinfo(cell).c_str());  				btorf("%d init %d %d %d\n", next_nid++, sid, initstate_nid, one_nid);  				btorf("%d next %d %d %d\n", next_nid++, sid, initstate_nid, zero_nid);  			} diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index d15ae9b57..9d32cc9b3 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -77,6 +77,7 @@ struct OutputWriter  struct SimShared  {  	bool debug = false; +	bool verbose = true;  	bool hide_internal = true;  	bool writeback = false;  	bool zinit = false; @@ -181,7 +182,7 @@ struct SimInstance  			if ((shared->fst) && !(shared->hide_internal && wire->name[0] == '$')) {  				fstHandle id = shared->fst->getHandle(scope + "." + RTLIL::unescape_id(wire->name));  				if (id==0 && wire->name.isPublic()) -					log_warning("Unable to found wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(wire->name)).c_str()); +					log_warning("Unable to find wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(wire->name)).c_str());  				fst_handles[wire] = id;  			} @@ -326,6 +327,16 @@ struct SimInstance  		return did_something;  	} +	void set_memory_state(IdString memid, Const addr, Const data) +	{ +		auto &state = mem_database[memid]; + +		int offset = (addr.as_int() - state.mem->start_offset) * state.mem->width; +		for (int i = 0; i < GetSize(data); i++) +			if (0 <= i+offset && i+offset < GetSize(data)) +				state.data.bits[i+offset] = data.bits[i]; +	} +  	void update_cell(Cell *cell)  	{  		if (ff_database.count(cell)) @@ -754,7 +765,7 @@ struct SimInstance  				IdString name = qsig.as_wire()->name;  				fstHandle id = shared->fst->getHandle(scope + "." + RTLIL::unescape_id(name));  				if (id==0 && name.isPublic()) -					log_warning("Unable to found wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(name)).c_str()); +					log_warning("Unable to find wire %s in input file.\n", (scope + "." + RTLIL::unescape_id(name)).c_str());  				if (id!=0) {  					Const fst_val = Const::from_string(shared->fst->valueOf(id));  					set_state(qsig, fst_val); @@ -909,7 +920,7 @@ struct SimWorker : SimShared  		if (debug)  			log("\n===== 0 =====\n"); -		else +		else if (verbose)  			log("Simulating cycle 0.\n");  		set_inports(reset, State::S1); @@ -926,7 +937,7 @@ struct SimWorker : SimShared  		{  			if (debug)  				log("\n===== %d =====\n", 10*cycle + 5); -			else +			else if (verbose)  				log("Simulating cycle %d.\n", (cycle*2)+1);  			set_inports(clock, State::S0);  			set_inports(clockn, State::S1); @@ -936,7 +947,7 @@ struct SimWorker : SimShared  			if (debug)  				log("\n===== %d =====\n", 10*cycle + 10); -			else +			else if (verbose)  				log("Simulating cycle %d.\n", (cycle*2)+2);  			set_inports(clock, State::S1); @@ -961,7 +972,7 @@ struct SimWorker : SimShared  		}  	} -	void run_cosim(Module *topmod, int numcycles) +	void run_cosim_fst(Module *topmod, int numcycles)  	{  		log_assert(top == nullptr);  		fst = new FstData(sim_filename); @@ -1053,7 +1064,8 @@ struct SimWorker : SimShared  		try {  			fst->reconstructAllAtTimes(fst_clock, startCount, stopCount, [&](uint64_t time) { -				log("Co-simulating %s %d [%lu%s].\n", (all_samples ? "sample" : "cycle"), cycle, (unsigned long)time, fst->getTimescaleString()); +				if (verbose) +					log("Co-simulating %s %d [%lu%s].\n", (all_samples ? "sample" : "cycle"), cycle, (unsigned long)time, fst->getTimescaleString());  				bool did_something = false;  				for(auto &item : inputs) {  					std::string v = fst->valueOf(item.second); @@ -1092,13 +1104,17 @@ struct SimWorker : SimShared  		delete fst;  	} -	void run_cosim_witness(Module *topmod) +	void run_cosim_aiger_witness(Module *topmod)  	{  		log_assert(top == nullptr); +		if ((clock.size()+clockn.size())==0) +			log_error("Clock signal must be specified.\n");  		std::ifstream mf(map_filename);  		std::string type, symbol;  		int variable, index;  		dict<int, std::pair<SigBit,bool>> inputs, inits, latches; +		if (mf.fail()) +			log_cmd_error("Not able to read AIGER witness map file.\n");  		while (mf >> type >> variable >> index >> symbol) {  			RTLIL::IdString escaped_s = RTLIL::escape_id(symbol);  			Wire *w = topmod->wire(escaped_s); @@ -1158,7 +1174,8 @@ struct SimWorker : SimShared  					state = 3;  					break;  				default: -					log("Simulating cycle %d.\n", cycle); +					if (verbose) +						log("Simulating cycle %d.\n", cycle);  					top->setState(inputs, line);  					if (cycle) {  						set_inports(clock, State::S1); @@ -1183,6 +1200,132 @@ struct SimWorker : SimShared  		register_output_step(10*cycle);  		write_output_files();  	} + +	std::vector<std::string> split(std::string text, const char *delim) +	{ +		std::vector<std::string> list; +		char *p = strdup(text.c_str()); +		char *t = strtok(p, delim); +		while (t != NULL) { +			list.push_back(t); +			t = strtok(NULL, delim); +		} +		free(p); +		return list; +	} + +	std::string signal_name(std::string const & name) +	{ +		size_t pos = name.find_first_of("@"); +		if (pos==std::string::npos) { +			pos = name.find_first_of("#"); +			if (pos==std::string::npos) +				log_error("Line does not contain proper signal name `%s`\n", name.c_str()); +		} +		return name.substr(0, pos); +	} + +	void run_cosim_btor2_witness(Module *topmod) +	{ +		log_assert(top == nullptr); +		if ((clock.size()+clockn.size())==0) +			log_error("Clock signal must be specified.\n"); +		std::ifstream f; +		f.open(sim_filename.c_str()); +		if (f.fail() || GetSize(sim_filename) == 0) +			log_error("Can not open file `%s`\n", sim_filename.c_str()); + +		int state = 0; +		int cycle = 0; +		top = new SimInstance(this, scope, topmod); +		register_signals(); +		int prev_cycle = 0; +		int curr_cycle = 0; +		std::vector<std::string> parts; +		size_t len = 0; +		while (!f.eof()) +		{ +			std::string line; +			std::getline(f, line); +			if (line.size()==0) continue; + +			if (line[0]=='#' || line[0]=='@' || line[0]=='.') {  +				if (line[0]!='.') +					curr_cycle = atoi(line.c_str()+1);  +				else +					curr_cycle = -1; // force detect change + +				if (curr_cycle != prev_cycle) { +					if (verbose) +						log("Simulating cycle %d.\n", cycle); +					set_inports(clock, State::S1); +					set_inports(clockn, State::S0); +					update(); +					register_output_step(10*cycle+0); +					set_inports(clock, State::S0); +					set_inports(clockn, State::S1); +					update(); +					register_output_step(10*cycle+5); +					cycle++; +					prev_cycle = curr_cycle; +				} +				if (line[0]=='.') break; +				continue; +			} + +			switch(state) +			{ +				case 0: +					if (line=="sat") +						state = 1; +					break; +				case 1: +					if (line[0]=='b' || line[0]=='j') +						state = 2; +					else +						log_error("Line does not contain property.\n"); +					break; +				default: // set state or inputs +					parts = split(line, " "); +					len = parts.size(); +					if (len<3 || len>4) +						log_error("Invalid set state line content.\n"); + +					RTLIL::IdString escaped_s = RTLIL::escape_id(signal_name(parts[len-1])); +					if (len==3) { +						Wire *w = topmod->wire(escaped_s); +						if (!w) { +							Cell *c = topmod->cell(escaped_s); +							if (!c) +								log_warning("Wire/cell %s not present in module %s\n",log_id(escaped_s),log_id(topmod)); +							else if (c->type.in(ID($anyconst), ID($anyseq))) { +								SigSpec sig_y= c->getPort(ID::Y); +								if ((int)parts[1].size() != GetSize(sig_y)) +									log_error("Size of wire %s is different than provided data.\n", log_signal(sig_y)); +								top->set_state(sig_y, Const::from_string(parts[1])); +							} +						} else { +							if ((int)parts[1].size() != w->width) +								log_error("Size of wire %s is different than provided data.\n", log_signal(w)); +							top->set_state(w, Const::from_string(parts[1])); +						} +					} else { +						Cell *c = topmod->cell(escaped_s); +						if (!c) +							log_error("Cell %s not present in module %s\n",log_id(escaped_s),log_id(topmod)); +						if (!c->is_mem_cell()) +							log_error("Cell %s is not memory cell in module %s\n",log_id(escaped_s),log_id(topmod)); +						 +						Const addr = Const::from_string(parts[1].substr(1,parts[1].size()-2)); +						Const data = Const::from_string(parts[2]); +						top->set_memory_state(c->parameters.at(ID::MEMID).decode_string(), addr, data); +					} +					break; +			} +		} +		register_output_step(10*cycle); +		write_output_files(); +	}  };  struct VCDWriter : public OutputWriter @@ -1311,14 +1454,19 @@ struct AIWWriter : public OutputWriter  	void write(std::map<int, bool> &) override  	{  		if (!aiwfile.is_open()) return; +		if (worker->map_filename.empty()) +			log_cmd_error("For AIGER witness file map parameter is mandatory.\n"); +  		std::ifstream mf(worker->map_filename);  		std::string type, symbol;  		int variable, index; +		if (mf.fail()) +			log_cmd_error("Not able to read AIGER witness map file.\n");  		while (mf >> type >> variable >> index >> symbol) {  			RTLIL::IdString escaped_s = RTLIL::escape_id(symbol);  			Wire *w = worker->top->module->wire(escaped_s);  			if (!w) -				log_error("Wire %s not present in module %s\n",log_signal(w),log_id(worker->top->module)); +				log_error("Wire %s not present in module %s\n",log_id(escaped_s),log_id(worker->top->module));  			if (index < w->start_offset || index > w->start_offset + w->width)  				log_error("Index %d for wire %s is out of range\n", index, log_signal(w));  			if (type == "input") { @@ -1455,7 +1603,7 @@ struct SimPass : public Pass {  		log("    -map <filename>\n");  		log("        read file with port and latch symbols, needed for AIGER witness input\n");  		log("\n"); -		log("    -scope\n"); +		log("    -scope <name>\n");  		log("        scope of simulation top model\n");  		log("\n");  		log("    -at <time>\n"); @@ -1479,10 +1627,20 @@ struct SimPass : public Pass {  		log("    -sim-gate\n");  		log("        co-simulation, x in FST can match any value in simulation\n");  		log("\n"); +		log("    -q\n"); +		log("        disable per-cycle/sample log message\n"); +		log("\n");  		log("    -d\n");  		log("        enable debug output\n");  		log("\n");  	} + + +	static std::string file_base_name(std::string const & path) +	{ +		return path.substr(path.find_last_of("/\\") + 1); +	} +  	void execute(std::vector<std::string> args, RTLIL::Design *design) override  	{  		SimWorker worker; @@ -1544,6 +1702,10 @@ struct SimPass : public Pass {  				worker.hide_internal = false;  				continue;  			} +			if (args[argidx] == "-q") { +				worker.verbose = false; +				continue; +			}  			if (args[argidx] == "-d") {  				worker.debug = true;  				continue; @@ -1632,11 +1794,21 @@ struct SimPass : public Pass {  		if (worker.sim_filename.empty())  			worker.run(top_mod, numcycles); -		else -			if (worker.map_filename.empty()) -				worker.run_cosim(top_mod, numcycles); -			else -				worker.run_cosim_witness(top_mod); +		else { +			std::string filename_trim = file_base_name(worker.sim_filename); +			if (filename_trim.size() > 4 && ((filename_trim.compare(filename_trim.size()-4, std::string::npos, ".fst") == 0) || +				filename_trim.compare(filename_trim.size()-4, std::string::npos, ".vcd") == 0)) { +				worker.run_cosim_fst(top_mod, numcycles); +			} else if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".aiw") == 0) { +				if (worker.map_filename.empty()) +					log_cmd_error("For AIGER witness file map parameter is mandatory.\n"); +				worker.run_cosim_aiger_witness(top_mod); +			} else if (filename_trim.size() > 4 && filename_trim.compare(filename_trim.size()-4, std::string::npos, ".wit") == 0) { +				worker.run_cosim_btor2_witness(top_mod); +			} else { +				log_cmd_error("Unhandled extension for simulation input file `%s`.\n", worker.sim_filename.c_str()); +			} +		}  	}  } SimPass; diff --git a/techlibs/intel_alm/Makefile.inc b/techlibs/intel_alm/Makefile.inc index 614d5802c..b5f279a92 100644 --- a/techlibs/intel_alm/Makefile.inc +++ b/techlibs/intel_alm/Makefile.inc @@ -19,6 +19,7 @@ $(eval $(call add_share_file,share/intel_alm/cyclonev,techlibs/intel_alm/cyclone  # RAM  $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_m10k.txt)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_m10k_map.v))  $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_m20k.txt))  $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_m20k_map.v))  $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/lutram_mlab.txt)) diff --git a/techlibs/intel_alm/common/bram_m10k.txt b/techlibs/intel_alm/common/bram_m10k.txt index 0d9a49b7d..560711b65 100644 --- a/techlibs/intel_alm/common/bram_m10k.txt +++ b/techlibs/intel_alm/common/bram_m10k.txt @@ -1,4 +1,4 @@ -bram MISTRAL_M10K +bram $__MISTRAL_M10K      init   0   # TODO: Re-enable when I figure out how BRAM init works      abits 13   @D8192x1      dbits  1   @D8192x1 @@ -21,7 +21,7 @@ bram MISTRAL_M10K  endbram -match MISTRAL_M10K +match $__MISTRAL_M10K      min efficiency 5      make_transp  endmatch diff --git a/techlibs/intel_alm/common/bram_m10k_map.v b/techlibs/intel_alm/common/bram_m10k_map.v new file mode 100644 index 000000000..8f9d4a3b3 --- /dev/null +++ b/techlibs/intel_alm/common/bram_m10k_map.v @@ -0,0 +1,16 @@ +// Stub to invert M10K write-enable. + +module \$__MISTRAL_M10K (CLK1, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); + +parameter CFG_ABITS = 10; +parameter CFG_DBITS = 10; + +input CLK1; +input [CFG_ABITS-1:0] A1ADDR, B1ADDR; +input [CFG_DBITS-1:0] A1DATA; +input A1EN, B1EN; +output reg [CFG_DBITS-1:0] B1DATA; + +MISTRAL_M10K #(.CFG_ABITS(CFG_ABITS), .CFG_DBITS(CFG_DBITS)) _TECHMAP_REPLACE_ (.CLK1(CLK1), .A1ADDR(A1ADDR), .A1DATA(A1DATA), .A1EN(!A1EN), .B1ADDR(B1ADDR), .B1DATA(B1DATA), .B1EN(B1EN)); + +endmodule
\ No newline at end of file diff --git a/techlibs/intel_alm/common/mem_sim.v b/techlibs/intel_alm/common/mem_sim.v index 370e17f27..c9ba8c7f1 100644 --- a/techlibs/intel_alm/common/mem_sim.v +++ b/techlibs/intel_alm/common/mem_sim.v @@ -145,7 +145,7 @@ endspecify  `endif  always @(posedge CLK1) begin -    if (A1EN) +    if (!A1EN)          mem[(A1ADDR + 1) * CFG_DBITS - 1 : A1ADDR * CFG_DBITS] <= A1DATA;      if (B1EN) diff --git a/techlibs/intel_alm/common/quartus_rename.v b/techlibs/intel_alm/common/quartus_rename.v index 5850f6907..217dc5de9 100644 --- a/techlibs/intel_alm/common/quartus_rename.v +++ b/techlibs/intel_alm/common/quartus_rename.v @@ -157,6 +157,11 @@ output [CFG_DBITS-1:0] B1DATA;  // Much like the MLAB, the M10K has mem_init[01234] parameters which would let  // you initialise the RAM cell via hex literals. If they were implemented. +// Since the MISTRAL_M10K block has an inverted write-enable (like the real hardware) +// but the Quartus primitive expects a normal write-enable, we add an inverter. +wire A1EN_N; +NOT wren_inv (.IN(A1EN), .OUT(A1EN_N)); +  `RAM_BLOCK #(      .operation_mode("dual_port"),      .logical_ram_name(_TECHMAP_CELLNAME_), @@ -176,10 +181,10 @@ output [CFG_DBITS-1:0] B1DATA;      .port_b_first_bit_number(0),      .port_b_address_clock("clock0"),      .port_b_read_enable_clock("clock0") -) _TECHMAP_REPLACE_ ( +) ram_block (      .portaaddr(A1ADDR),      .portadatain(A1DATA), -    .portawe(A1EN), +    .portawe(A1EN_N),      .portbaddr(B1ADDR),      .portbdataout(B1DATA),      .portbre(B1EN), diff --git a/techlibs/intel_alm/synth_intel_alm.cc b/techlibs/intel_alm/synth_intel_alm.cc index 34a5ffa5d..43d3592d5 100644 --- a/techlibs/intel_alm/synth_intel_alm.cc +++ b/techlibs/intel_alm/synth_intel_alm.cc @@ -262,8 +262,7 @@ struct SynthIntelALMPass : public ScriptPass {  		if (!nobram && check_label("map_bram", "(skip if -nobram)")) {  			run(stringf("memory_bram -rules +/intel_alm/common/bram_%s.txt", bram_type.c_str())); -			if (help_mode || bram_type != "m10k") -				run(stringf("techmap -map +/intel_alm/common/bram_%s_map.v", bram_type.c_str())); +			run(stringf("techmap -map +/intel_alm/common/bram_%s_map.v", bram_type.c_str()));  		}  		if (!nolutram && check_label("map_lutram", "(skip if -nolutram)")) { diff --git a/tests/arch/intel_alm/blockram.ys b/tests/arch/intel_alm/blockram.ys index c157c3165..3b61b9339 100644 --- a/tests/arch/intel_alm/blockram.ys +++ b/tests/arch/intel_alm/blockram.ys @@ -2,5 +2,6 @@ read_verilog ../common/blockram.v  chparam -set ADDRESS_WIDTH 10 -set DATA_WIDTH 10 sync_ram_sdp  synth_intel_alm -family cyclonev -noiopad -noclkbuf  cd sync_ram_sdp +select -assert-count 1 t:MISTRAL_NOT  select -assert-count 1 t:MISTRAL_M10K -select -assert-none t:MISTRAL_M10K %% t:* %D +select -assert-none t:MISTRAL_NOT t:MISTRAL_M10K %% t:* %D  | 
