mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 19:52:31 +00:00 
			
		
		
		
	cxxrtl: add a representation of simulation timestamps.
While the VCD format separates the timescale and the timestep (likely to allow representing the timestep with a small integer type), time in CXXRTL is represented using a uniform 96-bit number, which allows for a ±100 year range at femtosecond resolution. The implementation uses `value<96>`, which provides fast arithmetic and comparison operations, as well as conversion to/from a more common representation of integer seconds plus femtoseconds.
This commit is contained in:
		
							parent
							
								
									c72dc15f02
								
							
						
					
					
						commit
						a94fafa8fe
					
				
					 1 changed files with 229 additions and 0 deletions
				
			
		
							
								
								
									
										229
									
								
								backends/cxxrtl/runtime/cxxrtl/cxxrtl_time.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										229
									
								
								backends/cxxrtl/runtime/cxxrtl/cxxrtl_time.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,229 @@ | ||||||
|  | /*
 | ||||||
|  |  *  yosys -- Yosys Open SYnthesis Suite | ||||||
|  |  * | ||||||
|  |  *  Copyright (C) 2023  Catherine <whitequark@whitequark.org> | ||||||
|  |  * | ||||||
|  |  *  Permission to use, copy, modify, and/or distribute this software for any | ||||||
|  |  *  purpose with or without fee is hereby granted. | ||||||
|  |  * | ||||||
|  |  *  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. | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef CXXRTL_TIME_H | ||||||
|  | #define CXXRTL_TIME_H | ||||||
|  | 
 | ||||||
|  | #include <cinttypes> | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
|  | #include <cxxrtl/cxxrtl.h> | ||||||
|  | 
 | ||||||
|  | namespace cxxrtl { | ||||||
|  | 
 | ||||||
|  | // A timestamp or a difference in time, stored as a 96-bit number of femtoseconds (10e-15 s). The dynamic range and
 | ||||||
|  | // resolution of this format can represent any VCD timestamp within 136 years, without the need for a timescale.
 | ||||||
|  | class time { | ||||||
|  | public: | ||||||
|  | 	static constexpr size_t bits = 96; // 3 chunks
 | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  | 	static constexpr value<bits> resolution = value<bits> { | ||||||
|  | 		chunk_t(1000000000000000ull & 0xffffffffull), chunk_t(1000000000000000ull >> 32), 0u | ||||||
|  | 	}; | ||||||
|  | 	static constexpr size_t resolution_digits = 15; | ||||||
|  | 
 | ||||||
|  | 	// Signed number of femtoseconds from the beginning of time.
 | ||||||
|  | 	value<bits> raw; | ||||||
|  | 
 | ||||||
|  | public: | ||||||
|  | 	constexpr time() {} | ||||||
|  | 
 | ||||||
|  | 	explicit constexpr time(const value<bits> &raw) : raw(raw) {} | ||||||
|  | 	explicit operator const value<bits> &() const { return raw; } | ||||||
|  | 
 | ||||||
|  | 	static constexpr time maximum() { | ||||||
|  | 		return time(value<bits> { 0xffffffffu, 0xffffffffu, 0x7fffffffu }); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	time(int32_t secs, int64_t femtos) { | ||||||
|  | 		value<32> secs_val; | ||||||
|  | 		secs_val.set((uint32_t)secs); | ||||||
|  | 		value<64> femtos_val; | ||||||
|  | 		femtos_val.set((uint64_t)femtos); | ||||||
|  | 		raw = secs_val.sext<bits>().mul<bits>(resolution).add(femtos_val.sext<bits>()); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	bool is_zero() const { | ||||||
|  | 		return raw.is_zero(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Extracts the sign of the value.
 | ||||||
|  | 	bool is_negative() const { | ||||||
|  | 		return raw.is_neg(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Extracts the absolute number of whole seconds. Negative if the value is negative.
 | ||||||
|  | 	int32_t secs() const { | ||||||
|  | 		return raw.sdivmod(resolution).first.trunc<32>().get<uint32_t>(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Extracts the absolute number of femtoseconds in the fractional second. Negative if the value is negative.
 | ||||||
|  | 	int64_t femtos() const { | ||||||
|  | 		return raw.sdivmod(resolution).second.trunc<64>().get<uint64_t>(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	bool operator==(const time &other) const { | ||||||
|  | 		return raw == other.raw; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	bool operator!=(const time &other) const { | ||||||
|  | 		return raw != other.raw; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	bool operator>(const time &other) const { | ||||||
|  | 		return other.raw.scmp(raw); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	bool operator>=(const time &other) const { | ||||||
|  | 		return !raw.scmp(other.raw); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	bool operator<(const time &other) const { | ||||||
|  | 		return raw.scmp(other.raw); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	bool operator<=(const time &other) const { | ||||||
|  | 		return !other.raw.scmp(raw); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	time operator+(const time &other) const { | ||||||
|  | 		return time(raw.add(other.raw)); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	time &operator+=(const time &other) { | ||||||
|  | 		*this = *this + other; | ||||||
|  | 		return *this; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	time operator-() const { | ||||||
|  | 		return time(raw.neg()); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	time operator-(const time &other) const { | ||||||
|  | 		return *this + (-other); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	time &operator-=(const time &other) { | ||||||
|  | 		*this = *this - other; | ||||||
|  | 		return *this; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	operator std::string() const { | ||||||
|  | 		char buf[38]; // len(f"-{2**64}.{10**15-1}") + 1 == 38
 | ||||||
|  | 		int32_t secs = this->secs(); | ||||||
|  | 		int64_t femtos = this->femtos(); | ||||||
|  | 		snprintf(buf, sizeof(buf), "%s%" PRIi32 ".%015" PRIi64, | ||||||
|  | 			is_negative() ? "-" : "", secs >= 0 ? secs : -secs, femtos >= 0 ? femtos : -femtos); | ||||||
|  | 		return buf; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | #if __cplusplus >= 201603L | ||||||
|  | 	[[nodiscard("ignoring parse errors")]] | ||||||
|  | #endif | ||||||
|  | 	bool parse(const std::string &str) { | ||||||
|  | 		enum { | ||||||
|  | 			parse_sign_opt, | ||||||
|  | 			parse_integral, | ||||||
|  | 			parse_fractional, | ||||||
|  | 		} state = parse_sign_opt; | ||||||
|  | 		bool negative = false; | ||||||
|  | 		int32_t integral = 0; | ||||||
|  | 		int64_t fractional = 0; | ||||||
|  | 		size_t frac_digits = 0; | ||||||
|  | 		for (auto chr : str) { | ||||||
|  | 			switch (state) { | ||||||
|  | 				case parse_sign_opt: | ||||||
|  | 					state = parse_integral; | ||||||
|  | 					if (chr == '+' || chr == '-') { | ||||||
|  | 						negative = (chr == '-'); | ||||||
|  | 						break; | ||||||
|  | 					} | ||||||
|  | 					/* fallthrough */ | ||||||
|  | 				case parse_integral: | ||||||
|  | 					if (chr >= '0' && chr <= '9') { | ||||||
|  | 						integral *= 10; | ||||||
|  | 						integral += chr - '0'; | ||||||
|  | 					} else if (chr == '.') { | ||||||
|  | 						state = parse_fractional; | ||||||
|  | 					} else { | ||||||
|  | 						return false; | ||||||
|  | 					} | ||||||
|  | 					break; | ||||||
|  | 				case parse_fractional: | ||||||
|  | 					if (chr >= '0' && chr <= '9' && frac_digits < resolution_digits) { | ||||||
|  | 						fractional *= 10; | ||||||
|  | 						fractional += chr - '0'; | ||||||
|  | 						frac_digits++; | ||||||
|  | 					} else { | ||||||
|  | 						return false; | ||||||
|  | 					} | ||||||
|  | 					break; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		if (frac_digits == 0) | ||||||
|  | 			return false; | ||||||
|  | 		while (frac_digits++ < resolution_digits) | ||||||
|  | 			fractional *= 10; | ||||||
|  | 		*this = negative ? -time { integral, fractional} : time { integral, fractional }; | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Out-of-line definition required until C++17.
 | ||||||
|  | constexpr value<time::bits> time::resolution; | ||||||
|  | 
 | ||||||
|  | std::ostream &operator<<(std::ostream &os, const time &val) { | ||||||
|  | 	os << (std::string)val; | ||||||
|  | 	return os; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // These literals are (confusingly) compatible with the ones from `std::chrono`: the `std::chrono` literals do not
 | ||||||
|  | // have an underscore (e.g. 1ms) and the `cxxrtl::time` literals do (e.g. 1_ms). This syntactic difference is
 | ||||||
|  | // a requirement of the C++ standard. Despite being compatible the literals should not be mixed in the same namespace.
 | ||||||
|  | namespace time_literals { | ||||||
|  | 
 | ||||||
|  | time operator""_s(unsigned long long seconds) { | ||||||
|  | 	return time { (int32_t)seconds, 0 }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | time operator""_ms(unsigned long long milliseconds) { | ||||||
|  | 	return time { 0, (int64_t)milliseconds * 1000000000000 }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | time operator""_us(unsigned long long microseconds) { | ||||||
|  | 	return time { 0, (int64_t)microseconds * 1000000000 }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | time operator""_ns(unsigned long long nanoseconds) { | ||||||
|  | 	return time { 0, (int64_t)nanoseconds * 1000000 }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | time operator""_ps(unsigned long long picoseconds) { | ||||||
|  | 	return time { 0, (int64_t)picoseconds * 1000 }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | time operator""_fs(unsigned long long femtoseconds) { | ||||||
|  | 	return time { 0, (int64_t)femtoseconds }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue