mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 11:42:30 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			158 lines
		
	
	
	
		
			5.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
	
		
			5.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  *  yosys -- Yosys Open SYnthesis Suite
 | |
|  *
 | |
|  *  Copyright (C) 2024  Emily Schmidt <emily@yosyshq.com>
 | |
|  *  Copyright (C) 2024 National Technology and Engineering Solutions of Sandia, LLC
 | |
|  *
 | |
|  *  Permission to use, copy, modify, and/or distribute this software for any
 | |
|  *  purpose with or without fee is hereby granted, provided that the above
 | |
|  *  copyright notice and this permission notice appear in all copies.
 | |
|  *
 | |
|  *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | |
|  *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | |
|  *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | |
|  *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | |
|  *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | |
|  *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | |
|  *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include "kernel/yosys.h"
 | |
| #include "kernel/functional.h"
 | |
| #include <random>
 | |
| 
 | |
| USING_YOSYS_NAMESPACE
 | |
| PRIVATE_NAMESPACE_BEGIN
 | |
| 
 | |
| struct MemContentsTest {
 | |
| 	int addr_width, data_width;
 | |
| 	MemContents state;
 | |
| 	using addr_t = MemContents::addr_t;
 | |
| 	std::map<addr_t, RTLIL::Const> reference;
 | |
| 	MemContentsTest(int addr_width, int data_width) : addr_width(addr_width), data_width(data_width), state(addr_width, data_width, RTLIL::Const(State::S0, data_width))  {}
 | |
| 	void check() {
 | |
| 		state.check();
 | |
| 		for(auto addr = 0; addr < (1<<addr_width); addr++) {
 | |
| 			auto it = reference.find(addr);
 | |
| 			if(it != reference.end()) {
 | |
| 				if(state.count_range(addr, addr + 1) != 1) goto error;
 | |
| 				if(it->second != state[addr]) goto error;
 | |
| 			} else {
 | |
| 				if(state.count_range(addr, addr + 1) != 0) goto error;
 | |
| 			}
 | |
| 		}
 | |
| 		return;
 | |
| 		error:
 | |
| 		printf("FAIL\n");
 | |
| 		int digits = (data_width + 3) / 4;
 | |
| 		
 | |
| 		for(auto addr = 0; addr < (1<<addr_width); addr++) {
 | |
| 			if(addr % 8 == 0) printf("%.8x   ", addr);
 | |
| 			auto it = reference.find(addr);
 | |
| 			bool ref_def = it != reference.end();
 | |
| 			RTLIL::Const ref_value = ref_def ? it->second : state.default_value();
 | |
| 			std::string ref_string = stringf("%.*x", digits, ref_value.as_int());
 | |
| 			bool sta_def = state.count_range(addr, addr + 1) == 1;
 | |
| 			RTLIL::Const sta_value = state[addr];
 | |
| 			std::string sta_string = stringf("%.*x", digits, sta_value.as_int());
 | |
| 			if(ref_def && sta_def) {
 | |
| 				if(ref_value == sta_value) printf("%s%s", ref_string.c_str(), string(digits, ' ').c_str());
 | |
| 				else printf("%s%s", ref_string.c_str(), sta_string.c_str());
 | |
| 			} else if(ref_def) {
 | |
| 				printf("%s%s", ref_string.c_str(), string(digits, 'M').c_str());
 | |
| 			} else if(sta_def) {
 | |
| 				printf("%s%s", sta_string.c_str(), string(digits, 'X').c_str());
 | |
| 			} else {
 | |
| 				printf("%s", string(2*digits, ' ').c_str());
 | |
| 			}
 | |
| 			printf(" ");
 | |
| 			if(addr % 8 == 7) printf("\n");
 | |
| 		}
 | |
| 		printf("\n");
 | |
| 		//log_abort();
 | |
| 	}
 | |
| 	void clear_range(addr_t begin_addr, addr_t end_addr) {
 | |
| 		for(auto addr = begin_addr; addr != end_addr; addr++)
 | |
| 			reference.erase(addr);
 | |
| 		state.clear_range(begin_addr, end_addr);
 | |
| 		check();
 | |
| 	}
 | |
| 	void insert_concatenated(addr_t addr, RTLIL::Const const &values) {
 | |
| 		addr_t words = ((addr_t) values.size() + data_width - 1) / data_width;
 | |
| 		for(addr_t i = 0; i < words; i++) {
 | |
| 			reference.erase(addr + i);
 | |
| 			reference.emplace(addr + i, values.extract(i * data_width, data_width));
 | |
| 		}
 | |
| 		state.insert_concatenated(addr, values);
 | |
| 		check();
 | |
| 	}
 | |
| 	template<typename Rnd> void run(Rnd &rnd, int n) {
 | |
| 		std::uniform_int_distribution<addr_t> addr_dist(0, (1<<addr_width) - 1);
 | |
| 		std::poisson_distribution<addr_t> length_dist(10);
 | |
| 		std::uniform_int_distribution<uint64_t> data_dist(0, ((uint64_t)1<<data_width) - 1);
 | |
| 		while(n-- > 0) {
 | |
| 			addr_t low = addr_dist(rnd);
 | |
| 			//addr_t length = std::min((1<<addr_width) - low, length_dist(rnd));
 | |
| 			//addr_t high = low + length - 1;
 | |
| 			addr_t high = addr_dist(rnd);
 | |
| 			if(low > high) std::swap(low, high);
 | |
| 			if((rnd() & 7) == 0) {
 | |
| 				log_debug("clear %.2x to %.2x\n", (int)low, (int)high);
 | |
| 				clear_range(low, high + 1);
 | |
| 			} else {
 | |
| 				log_debug("insert %.2x to %.2x\n", (int)low, (int)high);
 | |
| 				RTLIL::Const values;
 | |
| 				for(addr_t addr = low; addr <= high; addr++) {
 | |
| 					RTLIL::Const word(data_dist(rnd), data_width);
 | |
| 					values.append(word);
 | |
| 				}
 | |
| 				insert_concatenated(low, values);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| };
 | |
| 
 | |
| struct FunctionalTestGeneric : public Pass
 | |
| {
 | |
| 	FunctionalTestGeneric() : Pass("test_generic", "test the generic compute graph") {
 | |
| 		internal();
 | |
| 	}
 | |
| 
 | |
|     void help() override
 | |
| 	{
 | |
| 		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
 | |
| 		log("\n");
 | |
| 		log("TODO: add help message\n");
 | |
| 		log("\n");
 | |
|     }
 | |
| 
 | |
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) override
 | |
| 	{
 | |
|         log_header(design, "Executing Test Generic.\n");
 | |
| 
 | |
| 		size_t argidx = 1;
 | |
| 		extra_args(args, argidx, design);
 | |
| /*
 | |
| 		MemContentsTest test(8, 16);
 | |
| 
 | |
| 		std::random_device seed_dev;
 | |
| 		std::mt19937 rnd(23); //seed_dev());
 | |
| 		test.run(rnd, 1000);
 | |
| */
 | |
| 
 | |
| 		for (auto module : design->selected_modules()) {
 | |
|             log("Dumping module `%s'.\n", module->name);
 | |
| 			auto fir = Functional::IR::from_module(module);
 | |
| 			for(auto node : fir)
 | |
| 				std::cout << RTLIL::unescape_id(node.name()) << " = " << node.to_string([](auto n) { return RTLIL::unescape_id(n.name()); }) << "\n";
 | |
| 			for(auto output : fir.all_outputs())
 | |
| 				std::cout << RTLIL::unescape_id(output->kind) << " " << RTLIL::unescape_id(output->name) << " = " << RTLIL::unescape_id(output->value().name()) << "\n";
 | |
| 			for(auto state : fir.all_states())
 | |
| 				std::cout << RTLIL::unescape_id(state->kind) << " " << RTLIL::unescape_id(state->name) << " = " << RTLIL::unescape_id(state->next_value().name()) << "\n";
 | |
| 		}
 | |
| 	}
 | |
| } FunctionalCxxBackend;
 | |
| 
 | |
| PRIVATE_NAMESPACE_END
 |