From ac419477e7032c353a2b56ae711c375e5d5563b9 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Tue, 23 Apr 2024 20:40:58 +0100 Subject: [PATCH] Verilog unary negation --- lib/nvc/verilog-body.vhd | 92 ++++++++++++++++++++++----------------- lib/nvc/verilog.vhd | 2 + src/vlog/vlog-lower.c | 17 ++++++-- src/vlog/vlog-node.h | 1 + src/vlog/vlog-number.c | 35 ++++++++++----- src/vlog/vlog-parse.y | 7 +++ test/regress/ivtest3.v | 45 +++++++++++++++++++ test/regress/testlist.txt | 1 + test/test_vlog.c | 1 + 9 files changed, 148 insertions(+), 53 deletions(-) create mode 100644 test/regress/ivtest3.v diff --git a/lib/nvc/verilog-body.vhd b/lib/nvc/verilog-body.vhd index dc17993d..e7fe3694 100644 --- a/lib/nvc/verilog-body.vhd +++ b/lib/nvc/verilog-body.vhd @@ -70,10 +70,10 @@ package body verilog is function to_logic (value : t_net_array) return t_packed_logic is constant length : natural := value'length; - alias a_value : t_net_array(1 to length) is value; - variable result : t_packed_logic(1 to length); + alias a_value : t_net_array(length - 1 downto 0) is value; + variable result : t_packed_logic(length - 1 downto 0); begin - for i in 1 to length loop + for i in result'range loop result(i) := to_logic(a_value(i)); end loop; return result; @@ -81,10 +81,10 @@ package body verilog is function to_logic (value : t_resolved_net_array) return t_packed_logic is constant length : natural := value'length; - alias a_value : t_resolved_net_array(1 to length) is value; - variable result : t_packed_logic(1 to length); + alias a_value : t_resolved_net_array(length - 1 downto 0) is value; + variable result : t_packed_logic(length - 1 downto 0); begin - for i in 1 to length loop + for i in result'range loop result(i) := to_logic(a_value(i)); end loop; return result; @@ -124,10 +124,10 @@ package body verilog is function to_net_value (value : t_packed_logic) return t_net_array is constant length : natural := value'length; - alias a_value : t_packed_logic(1 to length) is value; - variable result : t_net_array(1 to length); + alias a_value : t_packed_logic(length - 1 downto 0) is value; + variable result : t_net_array(length - 1 downto 0); begin - for i in 1 to length loop + for i in result'range loop result(i) := to_net_value(a_value(i)); end loop; return result; @@ -135,10 +135,10 @@ package body verilog is function to_net_value (value : t_packed_logic) return t_resolved_net_array is constant length : natural := value'length; - alias a_value : t_packed_logic(1 to length) is value; - variable result : t_resolved_net_array(1 to length); + alias a_value : t_packed_logic(length - 1 downto 0) is value; + variable result : t_resolved_net_array(length - 1 downto 0); begin - for i in 1 to length loop + for i in result'range loop result(i) := to_net_value(a_value(i)); end loop; return result; @@ -146,29 +146,27 @@ package body verilog is function to_integer (value : t_packed_logic) return t_int64 is - alias v : t_packed_logic(0 to value'length - 1) is value; - variable r : t_int64 := 0; - variable add : t_int64 := 1; + alias v : t_packed_logic(value'length - 1 downto 0) is value; + variable r : t_int64 := 0; begin for i in v'range loop + r := r * 2; if v(i) = '1' then - r := r + add; + r := r + 1; end if; - add := add * 2; end loop; return r; end function; function to_time (value : t_packed_logic) return delay_length is - alias v : t_packed_logic(0 to value'length - 1) is value; - variable r : delay_length := 0 fs; - variable add : delay_length := 1 fs; + alias v : t_packed_logic(value'length - 1 downto 0) is value; + variable r : delay_length := 0 fs; begin for i in v'range loop + r := r * 2; if v(i) = '1' then - r := r + add; + r := r + 1 fs; end if; - add := add * 2; end loop; return r; end function; @@ -227,7 +225,7 @@ package body verilog is constant length : natural := value'length; constant lookup : string(1 to 4) := "XZ01"; variable result : string(1 to length); - alias a_value : t_packed_logic(1 to length) is value; + alias a_value : t_packed_logic(length downto 1) is value; begin for i in 1 to length loop result(i) := lookup(t_logic'pos(a_value(i)) + 1); @@ -237,21 +235,21 @@ package body verilog is function resize (value : t_packed_logic; length : natural) return t_packed_logic is constant orig : natural := value'length; - alias a_value : t_packed_logic(1 to orig) is value; + alias a_value : t_packed_logic(orig - 1 downto 0) is value; begin if length = orig then return value; elsif length < orig then - return a_value(1 to length); + return a_value(length - 1 downto 0); else return (1 to length - orig => '0') & value; end if; end function; function resize (value : t_logic; length : natural) return t_packed_logic is - subtype rtype is t_packed_logic(1 to length); + subtype rtype is t_packed_logic(length - 1 downto 0); begin - return rtype'(1 => value, others => '0'); + return rtype'(0 => value, others => '0'); end function; function "and" (l, r : t_logic) return t_logic is @@ -291,9 +289,9 @@ package body verilog is constant llen : natural := l'length; constant rlen : natural := r'length; constant len : natural := maximum(llen, rlen); - alias la : t_packed_logic(0 to llen - 1) is l; - alias ra : t_packed_logic(0 to rlen - 1) is r; - variable result : t_packed_logic(0 to len - 1); + alias la : t_packed_logic(llen - 1 downto 0) is l; + alias ra : t_packed_logic(rlen - 1 downto 0) is r; + variable result : t_packed_logic(len - 1 downto 0); begin for i in result'range loop if i < llen and i < rlen then @@ -316,8 +314,8 @@ package body verilog is function "not" (x : t_packed_logic) return t_packed_logic is constant len : natural := x'length; - alias xa : t_packed_logic(0 to len - 1) is x; - variable result : t_packed_logic(0 to len - 1); + alias xa : t_packed_logic(len - 1 downto 0) is x; + variable result : t_packed_logic(len - 1 downto 0); begin for i in result'range loop result(i) := not xa(i); @@ -340,9 +338,9 @@ package body verilog is function add_unsigned (l, r : t_packed_logic; c : t_logic) return t_packed_logic is constant l_left : integer := l'length - 1; - alias xl : t_packed_logic(0 to l_left) is l; - alias xr : t_packed_logic(0 to l_left) is r; - variable result : t_packed_logic(0 to l_left); + alias xl : t_packed_logic(l_left downto 0) is l; + alias xr : t_packed_logic(l_left downto 0) is r; + variable result : t_packed_logic(l_left downto 0); variable cbit : t_logic := c; begin for i in 0 to l_left loop @@ -360,26 +358,40 @@ package body verilog is return add_unsigned(lext, rext, '0'); end function; + function "-" (arg : t_packed_logic) return t_packed_logic is + constant arg_left : integer := arg'length - 1; + alias xarg : t_packed_logic(arg_left downto 0) is arg; + variable result : t_packed_logic(arg_left downto 0); + variable cbit : t_logic := '1'; + begin + for i in 0 to arg_left loop + report t_logic'image(xarg(i)); + result(i) := not xarg(i) xor cbit; + cbit := cbit and not xarg(i); + end loop; + return result; + end function; + function "=" (l, r : t_packed_logic) return boolean is constant lsize : natural := l'length; constant rsize : natural := r'length; constant minsize : natural := minimum(lsize, rsize); - alias la : t_packed_logic(1 to lsize) is l; - alias ra : t_packed_logic(1 to rsize) is r; + alias la : t_packed_logic(lsize - 1 downto 0) is l; + alias ra : t_packed_logic(rsize - 1 downto 0) is r; begin - for i in 1 to minsize loop + for i in 0 to minsize - 1 loop if la(i) /= ra(i) then return false; end if; end loop; if lsize > rsize then - for i in minsize + 1 to lsize loop + for i in minsize to lsize - 1 loop if la(i) /= '0' then return false; end if; end loop; elsif rsize > lsize then - for i in minsize + 1 to rsize loop + for i in minsize to rsize - 1 loop if ra(i) /= '0' then return false; end if; diff --git a/lib/nvc/verilog.vhd b/lib/nvc/verilog.vhd index 11062a31..0f65dbde 100644 --- a/lib/nvc/verilog.vhd +++ b/lib/nvc/verilog.vhd @@ -78,6 +78,8 @@ package verilog is function "+" (l, r : t_packed_logic) return t_packed_logic; + function "-" (arg : t_packed_logic) return t_packed_logic; + function "=" (l, r : t_packed_logic) return boolean; function "/=" (l, r : t_packed_logic) return boolean; diff --git a/src/vlog/vlog-lower.c b/src/vlog/vlog-lower.c index e4fa7d74..f390817c 100644 --- a/src/vlog/vlog-lower.c +++ b/src/vlog/vlog-lower.c @@ -309,6 +309,9 @@ static vcode_reg_t vlog_lower_unary(lower_unit_t *lu, vlog_unary_t op, case V_UNARY_NOT: tb_cat(tb, "\"not\"("); break; + case V_UNARY_NEG: + tb_cat(tb, "\"-\"("); + break; } vcode_type_t vlogic = vlog_logic_type(); @@ -524,7 +527,7 @@ static vcode_reg_t vlog_lower_rvalue(lower_unit_t *lu, vlog_node_t v) else { vcode_reg_t *bits LOCAL = xmalloc_array(width, sizeof(vcode_reg_t)); for (int i = 0; i < width; i++) - bits[i] = emit_const(vlogic, number_bit(num, i)); + bits[width - i - 1] = emit_const(vlogic, number_bit(num, i)); vcode_type_t varray = vtype_carray(width, vlogic, vlogic); return emit_const_array(varray, bits, width); @@ -562,8 +565,16 @@ static void vlog_lower_sensitivity(lower_unit_t *lu, vlog_node_t v) switch (vlog_kind(v)) { case V_REF: { - vcode_reg_t nets_reg = vlog_lower_lvalue(lu, v); - vcode_reg_t count_reg = emit_const(vtype_offset(), 1); + vcode_reg_t value_reg = vlog_lower_lvalue(lu, v), count_reg, nets_reg; + if (vcode_reg_kind(value_reg) == VCODE_TYPE_UARRAY) { + nets_reg = emit_unwrap(value_reg); + count_reg = emit_uarray_len(value_reg, 0); + } + else { + nets_reg = value_reg; + count_reg = emit_const(vtype_offset(), 1); + } + emit_sched_event(nets_reg, count_reg); } break; diff --git a/src/vlog/vlog-node.h b/src/vlog/vlog-node.h index 5717597d..683f2005 100644 --- a/src/vlog/vlog-node.h +++ b/src/vlog/vlog-node.h @@ -105,6 +105,7 @@ typedef enum { typedef enum { V_UNARY_BITNEG, V_UNARY_NOT, + V_UNARY_NEG, } vlog_unary_t; typedef enum { diff --git a/src/vlog/vlog-number.c b/src/vlog/vlog-number.c index d91d1965..4ab5c3e5 100644 --- a/src/vlog/vlog-number.c +++ b/src/vlog/vlog-number.c @@ -47,7 +47,7 @@ static void number_shift_left(number_t *n, unsigned count, uint64_t carry_in) case TAG_BIGNUM: { assert(count < 32); - for (int i = 0; i < BIGNUM_WORDS(n->big->width); i++) { + for (int i = BIGNUM_WORDS(n->big->width) - 1; i >= 0; i--) { const uint64_t carry_out = n->big->packed[i] >> (64 - count * 2); n->big->packed[i] <<= count * 2; n->big->packed[i] |= carry_in; @@ -64,6 +64,15 @@ static void number_shift_left(number_t *n, unsigned count, uint64_t carry_in) } } +static void strip_underscores(char *s) +{ + char *p; + for (p = s; *s; s++) { + if (*s != '_') *p++ = *s; + } + *p = '\0'; +} + number_t number_new(const char *str) { int width = 32; @@ -92,8 +101,13 @@ number_t number_new(const char *str) has_xz |= (*pp == 'x' || *pp == 'z'); if (!has_xz && width <= INTEGER_WIDTH_MAX) { - char *eptr; - const int64_t bits = strtoll(p, &eptr, radix); + char *eptr, *copy LOCAL = NULL; + int64_t bits = strtoll(p, &eptr, radix); + if (*eptr == '_') { + copy = xstrdup(p); + strip_underscores(copy); + bits = strtoll(copy, &eptr, radix); + } if (*eptr != '\0') errorf("invalid character '%c' in number %s", *eptr, str); @@ -316,7 +330,8 @@ vlog_logic_t number_bit(number_t val, unsigned n) return ((val.intg.packed >> n) & 1) | LOGIC_0; case TAG_BIGNUM: assert(n < val.big->width); - return (val.big->packed[n / 32] >> ((n % 32) * 2)) & 3; + return (val.big->packed[(val.big->width - n - 1) / 32] + >> ((n % 32) * 2)) & 3; default: DEBUG_ONLY(fatal_trace("invalid number tag %x", val.common.tag)); return 0; @@ -331,7 +346,7 @@ number_t number_pack(const uint8_t *bits, unsigned width) if (!has_xz && width <= INTEGER_WIDTH_MAX) { uint64_t packed = 0; - for (int i = width - 1; i >= 0; i--) { + for (int i = 0; i < width; i++) { assert(bits[i] <= 0b11); packed <<= 1; packed |= (bits[i] & 1); @@ -348,7 +363,7 @@ number_t number_pack(const uint8_t *bits, unsigned width) } else if (width <= SMALLNUM_WIDTH_MAX) { uint64_t packed = SMALL_PACKED_ZERO; - for (int i = width - 1; i >= 0; i--) { + for (int i = 0; i < width; i++) { assert(bits[i] <= 0b11); packed <<= 2; packed |= bits[i]; @@ -369,13 +384,13 @@ number_t number_pack(const uint8_t *bits, unsigned width) bn->width = width; bn->issigned = 0; - for (int i = nwords - 1, b = 0; i >= 0; i--) { + for (int i = 0; i < nwords; i++) { bn->packed[i] = BIG_PACKED_ZERO; - for (int j = 0; j < 32 && b < width; j++, b++) { - assert(bits[b] <= 0b11); + for (int j = 0; j < 32 && i*32 + j < width; j++) { + assert(bits[i*32 + j] <= 0b11); bn->packed[i] <<= 2; - bn->packed[i] |= bits[b]; + bn->packed[i] |= bits[i*32 + j]; } } diff --git a/src/vlog/vlog-parse.y b/src/vlog/vlog-parse.y index 4454029c..162a8547 100644 --- a/src/vlog/vlog-parse.y +++ b/src/vlog/vlog-parse.y @@ -876,6 +876,13 @@ expression: primary vlog_set_subkind($$, V_UNARY_NOT); vlog_set_value($$, $2); } + | '-' expression + { + $$ = vlog_new(V_UNARY); + vlog_set_loc($$, &@$); + vlog_set_subkind($$, V_UNARY_NEG); + vlog_set_value($$, $2); + } ; list_of_expressions: diff --git a/test/regress/ivtest3.v b/test/regress/ivtest3.v new file mode 100644 index 00000000..70f5732b --- /dev/null +++ b/test/regress/ivtest3.v @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +module ivtest3; + + wire [31:0] A; + wire [24:0] B; + reg [15:0] C; + + assign A = B; + assign B = C; + + initial begin + C = 0; + #1 if (A !== 32'h0) begin + $display("FAILED -- A === %h", A); + $finish; + end + + C = -1; + #1 if (A !== 32'h00_00_ff_ff) begin + $display("FAILED -- A == %h instead of 0000ffff", A); + $finish; + end + + $display("PASSED"); + end + +endmodule diff --git a/test/regress/testlist.txt b/test/regress/testlist.txt index 0820d75a..73a56525 100644 --- a/test/regress/testlist.txt +++ b/test/regress/testlist.txt @@ -966,3 +966,4 @@ vhpi14 normal,vhpi issue877 normal,2008 issue878 wave,2008,dump-arrays ivtest2 verilog,gold +ivtest3 verilog diff --git a/test/test_vlog.c b/test/test_vlog.c index ee4cfd99..b52f74a1 100644 --- a/test/test_vlog.c +++ b/test/test_vlog.c @@ -299,6 +299,7 @@ START_TEST(test_number2) { "'hffffffff", 32, INTEGER_ENCODE_MAX, "4294967295" }, { "64'b0", 64, 0, "64'b0" }, { "64'b101", 64, 5, "64'b101" }, + { "8'b00_01", 8, 1, "8'd1" }, }; LOCAL_TEXT_BUF tb = tb_new(); -- 2.39.2