Merge branch 'YosysHQ:main' into main

This commit is contained in:
Akash Levy 2025-04-03 10:48:42 -07:00 committed by GitHub
commit 439d859bba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 255 additions and 27 deletions

View File

@ -1117,7 +1117,7 @@ define DOC_USAGE_STDERR
docs/source/generated/$(1): $(TARGETS) docs/source/generated FORCE docs/source/generated/$(1): $(TARGETS) docs/source/generated FORCE
-$(Q) ./$(PROGRAM_PREFIX)$(1) --help 2> $$@ -$(Q) ./$(PROGRAM_PREFIX)$(1) --help 2> $$@
endef endef
DOCS_USAGE_STDERR := yosys-config yosys-filterlib DOCS_USAGE_STDERR := yosys-filterlib
# The in-tree ABC (yosys-abc) is only built when ABCEXTERNAL is not set. # The in-tree ABC (yosys-abc) is only built when ABCEXTERNAL is not set.
ifeq ($(ABCEXTERNAL),) ifeq ($(ABCEXTERNAL),)
@ -1131,7 +1131,7 @@ define DOC_USAGE_STDOUT
docs/source/generated/$(1): $(TARGETS) docs/source/generated docs/source/generated/$(1): $(TARGETS) docs/source/generated
$(Q) ./$(PROGRAM_PREFIX)$(1) --help > $$@ || rm $$@ $(Q) ./$(PROGRAM_PREFIX)$(1) --help > $$@ || rm $$@
endef endef
DOCS_USAGE_STDOUT := yosys yosys-smtbmc yosys-witness DOCS_USAGE_STDOUT := yosys yosys-smtbmc yosys-witness yosys-config
$(foreach usage,$(DOCS_USAGE_STDOUT),$(eval $(call DOC_USAGE_STDOUT,$(usage)))) $(foreach usage,$(DOCS_USAGE_STDOUT),$(eval $(call DOC_USAGE_STDOUT,$(usage))))
docs/usage: $(addprefix docs/source/generated/,$(DOCS_USAGE_STDOUT) $(DOCS_USAGE_STDERR)) docs/usage: $(addprefix docs/source/generated/,$(DOCS_USAGE_STDOUT) $(DOCS_USAGE_STDERR))

View File

@ -128,6 +128,12 @@
# error "C++17 or later compatible compiler is required" # error "C++17 or later compatible compiler is required"
#endif #endif
#if defined(__has_cpp_attribute) && __has_cpp_attribute(gnu::cold)
# define YS_COLD [[gnu::cold]]
#else
# define YS_COLD
#endif
#include "kernel/io.h" #include "kernel/io.h"
YOSYS_NAMESPACE_BEGIN YOSYS_NAMESPACE_BEGIN

View File

@ -36,12 +36,12 @@ help() {
echo "" echo ""
echo " $0 --datdir/simlib.v" echo " $0 --datdir/simlib.v"
echo "" echo ""
} >&2 } >&$(( $1 + 1))
exit 1 exit $1
} }
if [ $# -eq 0 ]; then if [ $# -eq 0 ]; then
help help 1
fi fi
if [ "$1" = "--build" ]; then if [ "$1" = "--build" ]; then
@ -83,7 +83,7 @@ for opt; do
tokens=( "${tokens[@]}" '@DATDIR@'"${opt#${prefix}datdir}" ) ;; tokens=( "${tokens[@]}" '@DATDIR@'"${opt#${prefix}datdir}" ) ;;
--help|-\?|-h) --help|-\?|-h)
if [ ${#tokens[@]} -eq 0 ]; then if [ ${#tokens[@]} -eq 0 ]; then
help help 0
else else
tokens=( "${tokens[@]}" "$opt" ) tokens=( "${tokens[@]}" "$opt" )
fi ;; fi ;;

View File

@ -1750,7 +1750,38 @@ skip_identity:
else if (inA == inB) else if (inA == inB)
ACTION_DO(ID::Y, cell->getPort(ID::A)); ACTION_DO(ID::Y, cell->getPort(ID::A));
} }
if (cell->type == ID($pow) && cell->getPort(ID::A).is_fully_const() && !cell->parameters[ID::B_SIGNED].as_bool()) {
SigSpec sig_a = assign_map(cell->getPort(ID::A));
SigSpec sig_y = assign_map(cell->getPort(ID::Y));
int y_size = GetSize(sig_y);
int bit_idx;
const auto onehot = sig_a.is_onehot(&bit_idx);
if (onehot) {
if (bit_idx == 1) {
log_debug("Replacing pow cell `%s' in module `%s' with left-shift\n",
cell->name.c_str(), module->name.c_str());
cell->type = ID($shl);
cell->parameters[ID::A_WIDTH] = 1;
cell->setPort(ID::A, Const(State::S1, 1));
}
else {
log_debug("Replacing pow cell `%s' in module `%s' with multiply and left-shift\n",
cell->name.c_str(), module->name.c_str());
cell->type = ID($mul);
cell->parameters[ID::A_SIGNED] = 0;
cell->setPort(ID::A, Const(bit_idx, cell->parameters[ID::A_WIDTH].as_int()));
SigSpec y_wire = module->addWire(NEW_ID, y_size);
cell->setPort(ID::Y, y_wire);
module->addShl(NEW_ID, Const(State::S1, 1), y_wire, sig_y);
}
did_something = true;
goto next_cell;
}
}
if (!keepdc && cell->type == ID($mul)) if (!keepdc && cell->type == ID($mul))
{ {
bool a_signed = cell->parameters[ID::A_SIGNED].as_bool(); bool a_signed = cell->parameters[ID::A_SIGNED].as_bool();

View File

@ -32,6 +32,61 @@
using namespace Yosys; using namespace Yosys;
bool LibertyInputStream::extend_buffer_once()
{
if (eof)
return false;
// To support unget we leave the last already read character in the buffer
if (buf_pos > 1) {
size_t move_pos = buf_pos - 1;
memmove(buffer.data(), buffer.data() + move_pos, buf_end - move_pos);
buf_pos -= move_pos;
buf_end -= move_pos;
}
const size_t chunk_size = 4096;
if (buffer.size() < buf_end + chunk_size) {
buffer.resize(buf_end + chunk_size);
}
size_t read_size = f.rdbuf()->sgetn(buffer.data() + buf_end, chunk_size);
buf_end += read_size;
if (read_size < chunk_size)
eof = true;
return read_size != 0;
}
bool LibertyInputStream::extend_buffer_at_least(size_t size) {
while (buffered_size() < size) {
if (!extend_buffer_once())
return false;
}
return true;
}
int LibertyInputStream::get_cold()
{
if (buf_pos == buf_end) {
if (!extend_buffer_at_least())
return EOF;
}
int c = buffer[buf_pos];
buf_pos += 1;
return c;
}
int LibertyInputStream::peek_cold(size_t offset)
{
if (buf_pos + offset >= buf_end) {
if (!extend_buffer_at_least(offset + 1))
return EOF;
}
return buffer[buf_pos + offset];
}
LibertyAst::~LibertyAst() LibertyAst::~LibertyAst()
{ {
for (auto child : children) for (auto child : children)
@ -237,15 +292,19 @@ int LibertyParser::lexer(std::string &str)
// search for identifiers, numbers, plus or minus. // search for identifiers, numbers, plus or minus.
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') { if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') {
str = static_cast<char>(c); f.unget();
while (1) { size_t i = 1;
c = f.get(); while (true) {
c = f.peek(i);
if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.')
str += c; i += 1;
else else
break; break;
} }
f.unget(); str.clear();
str.append(f.buffered_data(), f.buffered_data() + i);
f.consume(i);
if (str == "+" || str == "-") { if (str == "+" || str == "-") {
/* Single operator is not an identifier */ /* Single operator is not an identifier */
// fprintf(stderr, "LEX: char >>%s<<\n", str.c_str()); // fprintf(stderr, "LEX: char >>%s<<\n", str.c_str());
@ -260,23 +319,24 @@ int LibertyParser::lexer(std::string &str)
// if it wasn't an identifer, number of array range, // if it wasn't an identifer, number of array range,
// maybe it's a string? // maybe it's a string?
if (c == '"') { if (c == '"') {
str = ""; size_t i = 0;
#ifdef FILTERLIB while (true) {
str += c; c = f.peek(i);
#endif line += (c == '\n');
while (1) { if (c != '"')
c = f.get(); i += 1;
if (c == '\n') else
line++;
if (c == '"') {
#ifdef FILTERLIB
str += c;
#endif
break; break;
}
str += c;
} }
// fprintf(stderr, "LEX: string >>%s<<\n", str.c_str()); str.clear();
#ifdef FILTERLIB
f.unget();
str.append(f.buffered_data(), f.buffered_data() + i + 2);
f.consume(i + 2);
#else
str.append(f.buffered_data(), f.buffered_data() + i);
f.consume(i + 1);
#endif
return 'v'; return 'v';
} }

View File

@ -90,12 +90,54 @@ namespace Yosys
bool eval(dict<std::string, bool>& values); bool eval(dict<std::string, bool>& values);
}; };
class LibertyInputStream {
std::istream &f;
std::vector<char> buffer;
size_t buf_pos = 0;
size_t buf_end = 0;
bool eof = false;
bool extend_buffer_once();
bool extend_buffer_at_least(size_t size = 1);
YS_COLD int get_cold();
YS_COLD int peek_cold(size_t offset);
public:
LibertyInputStream(std::istream &f) : f(f) {}
size_t buffered_size() { return buf_end - buf_pos; }
const char *buffered_data() { return buffer.data() + buf_pos; }
int get() {
if (buf_pos == buf_end)
return get_cold();
int c = buffer[buf_pos];
buf_pos += 1;
return c;
}
int peek(size_t offset = 0) {
if (buf_pos + offset >= buf_end)
return peek_cold(offset);
return buffer[buf_pos + offset];
}
void consume(size_t n = 1) {
buf_pos += n;
}
void unget() {
buf_pos -= 1;
}
};
class LibertyMergedCells; class LibertyMergedCells;
class LibertyParser class LibertyParser
{ {
friend class LibertyMergedCells; friend class LibertyMergedCells;
private: private:
std::istream &f; LibertyInputStream f;
int line; int line;
/* lexer return values: /* lexer return values:

89
tests/opt/opt_pow.ys Normal file
View File

@ -0,0 +1,89 @@
# Default power of two
design -reset
read_rtlil << EOT
autoidx 3
attribute \cells_not_processed 1
attribute \src "<stdin>:1.1-3.10"
module \top
attribute \src "<stdin>:2.17-2.20"
wire width 32 $add$<stdin>:2$1_Y
attribute \src "<stdin>:2.12-2.21"
wire width 32 signed $pow$<stdin>:2$2_Y
attribute \src "<stdin>:1.29-1.30"
wire width 15 input 1 \a
attribute \src "<stdin>:1.51-1.52"
wire width 32 output 2 \b
attribute \src "<stdin>:2.17-2.20"
cell $add $add$<stdin>:2$1
parameter \A_SIGNED 0
parameter \A_WIDTH 15
parameter \B_SIGNED 0
parameter \B_WIDTH 32
parameter \Y_WIDTH 32
connect \A \a
connect \B 2
connect \Y $add$<stdin>:2$1_Y
end
attribute \src "<stdin>:2.12-2.21"
cell $pow $pow$<stdin>:2$2
parameter \A_SIGNED 0
parameter \A_WIDTH 32
parameter \B_SIGNED 0
parameter \B_WIDTH 32
parameter \Y_WIDTH 32
connect \A 2
connect \B $add$<stdin>:2$1_Y
connect \Y $pow$<stdin>:2$2_Y
end
connect \b $pow$<stdin>:2$2_Y
end
EOT
select -assert-count 1 t:$pow
select -assert-none t:$shl
opt_expr
select -assert-none t:$pow
select -assert-count 1 t:$shl
read_verilog << EOT
module ref(input wire [14:0] a, output wire [31:0] b);
assign b = 1 << (a+2);
endmodule
EOT
equiv_make top ref equiv
select -assert-any -module equiv t:$equiv
equiv_induct
equiv_status -assert
# Other power of 2 value
design -reset
read_verilog <<EOT
module top(input wire [14:0] a, output wire [31:0] b);
assign b = 128**(a+2);
endmodule
EOT
# Check the cell counts have changed correctly
select -assert-count 1 t:$pow
select -assert-none t:$shl
select -assert-none t:$mul
opt_expr
select -assert-none t:$pow
select -assert-count 1 t:$shl
select -assert-count 1 t:$mul
read_verilog <<EOT
module ref(input wire [14:0] a, output wire [31:0] b);
assign b = 1 << (7 * (a+2));
endmodule
EOT
equiv_make top ref equiv
select -assert-any -module equiv t:$equiv
equiv_induct
equiv_status -assert