Yosys error out of bound expression

1 vote and 2 comments so far on Reddit

I wonder what is happening in this example. Seems like computed ranges in generate blocks are problematic. Is this an issue of the code or some Yosis limitation?

Example follows:

`timescale 1ns / 1ps

module constant_value(out1); parameter BITSIZE_out1=1, value=0; // OUT output [BITSIZE_out1-1:0] out1; assign out1 = value; endmodule

module register_SE(clock, reset, in1, wenable, out1); parameter BITSIZE_in1=1, BITSIZE_out1=1; // IN input clock; input reset; input [BITSIZE_in1-1:0] in1; input wenable; // OUT output [BITSIZE_out1-1:0] out1; reg [BITSIZE_out1-1:0] reg_out1; assign out1 = reg_out1; always @(posedge clock) if (wenable) reg_out1 <= in1; endmodule

module top(clock, reset, in1, in2, in3, sel_LOAD, sel_STORE, S_oe_ram, S_we_ram, S_addr_ram, S_Wdata_ram, Sin_Rdata_ram, S_data_ram_size, Sin_DataRdy, out1, Sout_Rdata_ram, Sout_DataRdy, proxy_in1, proxy_in2, proxy_in3, proxy_sel_LOAD, proxy_sel_STORE, proxy_out1, dout_a, dout_b, memory_addr_a, memory_addr_b, din_value_aggregated, be, bram_write); parameter BITSIZE_in1=1, BITSIZE_in2=1, BITSIZE_in3=1, BITSIZE_out1=1, BITSIZE_S_addr_ram=1, BITSIZE_S_Wdata_ram=8, BITSIZE_Sin_Rdata_ram=8, BITSIZE_Sout_Rdata_ram=8, BITSIZE_S_data_ram_size=1, address_space_begin=0, address_space_rangesize=4, BUS_PIPELINED=1, BRAM_BITSIZE=32, PRIVATE_MEMORY=0, USE_SPARSE_MEMORY=1, BITSIZE_proxy_in1=1, BITSIZE_proxy_in2=1, BITSIZE_proxy_in3=1, BITSIZE_proxy_out1=1, BITSIZE_dout_a=1, BITSIZE_dout_b=1, BITSIZE_memory_addr_a=1, BITSIZE_memory_addr_b=1, BITSIZE_din_value_aggregated=1, BITSIZE_be=1, nbit_read_addr=32, n_byte_on_databus=4, n_mem_elements=4, n_bytes=4; // IN input clock; input reset; input [BITSIZE_in1-1:0] in1; input [BITSIZE_in2-1:0] in2; input [BITSIZE_in3-1:0] in3; input sel_LOAD; input sel_STORE; input S_oe_ram; input S_we_ram; input [BITSIZE_S_addr_ram-1:0] S_addr_ram; input [BITSIZE_S_Wdata_ram-1:0] S_Wdata_ram; input [BITSIZE_Sin_Rdata_ram-1:0] Sin_Rdata_ram; input [BITSIZE_S_data_ram_size-1:0] S_data_ram_size; input Sin_DataRdy; input [BITSIZE_proxy_in1-1:0] proxy_in1; input [BITSIZE_proxy_in2-1:0] proxy_in2; input [BITSIZE_proxy_in3-1:0] proxy_in3; input proxy_sel_LOAD; input proxy_sel_STORE; input [BITSIZE_dout_a-1:0] dout_a; input [BITSIZE_dout_b-1:0] dout_b; // OUT output [BITSIZE_out1-1:0] out1; output [BITSIZE_Sout_Rdata_ram-1:0] Sout_Rdata_ram; output Sout_DataRdy; output [BITSIZE_proxy_out1-1:0] proxy_out1; output [BITSIZE_memory_addr_a-1:0] memory_addr_a; output [BITSIZE_memory_addr_b-1:0] memory_addr_b; output [BITSIZE_din_value_aggregated-1:0] din_value_aggregated; output [BITSIZE_be-1:0] be; output bram_write; ifndef __ICARUS__ function integer log2; input integer value; integer temp_value; begin temp_value = value-1; for (log2=0; temp_value>0; log2=log2+1) temp_value = temp_value>>1; end endfunctionendif ifdef __ICARUS__ parameter nbit_addr = BITSIZE_S_addr_ram/*n_bytes == 1 ? 1 : $clog2(n_bytes)*/; parameter nbits_address_space_rangesize = $clog2(address_space_rangesize); parameter nbits_byte_offset = n_byte_on_databus==1 ? 1 : $clog2(n_byte_on_databus);else parameter nbit_addr = BITSIZE_S_addr_ram/n_bytes == 1 ? 1 : log2(n_bytes)/; parameter nbits_address_space_rangesize = log2(address_space_rangesize); parameter nbits_byte_offset = n_byte_on_databus==1 ? 1 : log2(n_byte_on_databus); `endif

function [n_byte_on_databus2-1:0] CONV; input [n_byte_on_databus2-1:0] po2; begin case (po2) 1:CONV=(1<<1)-1; 2:CONV=(1<<2)-1; 4:CONV=(1<<4)-1; 8:CONV=(1<<8)-1; 16:CONV=(1<<16)-1; 32:CONV=(1<<32)-1; default:CONV=-1; endcase end endfunction wire [2BRAM_BITSIZE-1:0] dout; wire [2BRAM_BITSIZE-1:0] out1_shifted; wire [2BRAM_BITSIZE-1:0] S_Wdata_ram_int; wire cs, oe_ram_cs, we_ram_cs; wire [n_byte_on_databus2-1:0] conv_in; wire [n_byte_on_databus*2-1:0] conv_out; wire [nbits_byte_offset-1:0] byte_offset; wire [BITSIZE_in2-1:0] tmp_addr; wire [nbit_addr-1:0] relative_addr;

reg we_ram_cs_delayed; reg oe_ram_cs_delayed; reg [nbits_byte_offset-1:0] delayed_byte_offset;

assign tmp_addr = (proxy_sel_LOAD||proxy_sel_STORE) ? proxy_in2 : in2;

generate genvar j0_a; for (j0_a=0; j0_a<n_byte_on_databus; j0_a=j0_a+1) begin : dout_a_computation assign dout[(j0_a+18-1):j0_a8] = dout_a[j0_a+18-1:j0_a8]; end endgenerate

endmodule

This is the error output:

ERROR: Range select out of bounds on signal `dout_a’ at main_minimal_interface.v:149!

@zachjs

Steps to reproduce the issue

module top;
	function automatic [31:0] operation;
		input reg [3:0] rounds;
		input integer x;
		integer i;
		begin
			for (i = 0; i < rounds[3:0]; i = i + 1)
				x = x * 2;
			operation = x;
		end
	endfunction

	wire a;
	assign a = 2;

	parameter A = 3;

	wire [31:0] x;
	assign x = operation(A, a);

// `define VERIFY
`ifdef VERIFY
    assert property (a == 2);
    assert property (A == 3);
    assert property (x == 16);
`endif
endmodule

Expected behavior

The loop in operation should be successfully elaborated given that is invoked with rounds as a constant.

Actual behavior

test.v:7: ERROR: 2nd expression of generate for-loop is not constant!

@Ravenslofty

As I read the Verilog-2005 standard, Yosys is correct.

The operands of a constant
expression consist of constant numbers, strings, parameters, constant bit-selects and part-selects of parameters, constant function calls (see 10.4.5), and constant system function calls only

and

The data types reg, integer, time, real, and realtime are all variable data types.

rounds[3:0] is not a constant expression because rounds is reg, which is a variable and not a parameter.

@zachjs



Copy link


Collaborator

Author

The invocation of operation() in this example is not a constant_function_call, as the right hand side of a continuous assignment is not required to be a constant expression.

Yosys should be able to unroll the loop in this function given that rounds is given a constant expression, and is itself never procedurally assigned within the function. I’ve poked around a bit further and I think I can add this functionality in a PR soon.

@clairexen

According to IEEE Std. 1364.1 a constant_expression is an expression of constant_primary, which in trurn is a genvar_identifier, number, parameter_identifier or specparam_identifier. The rounds identifier above however is an hierarchical_identifier that is not a genvar_identifier, parameter_identifier or specparam_identifier. Thus this is a primary and the whole thing an expression, not a constant_primary and a constant_expression.

@Ravenslofty

Okay, so Yosys is in the wrong because rounds is not required to be a constant_expression in this context?

@clairexen

Okay, so Yosys is in the wrong because rounds is not required to be a constant_expression in this context?

Well.. IEEE Std. 1364.1-2002 says in 7.7.6

Loop bounds shall be statically computable for a for loop

and 3.15

statically computable expression: An expression whose value can be evaluated during compilation.

However, in the Yosys read_verilog front-end we only support constant_expressions as statically computable expressions.

Supporting IEEE Std. 1364.1-2002 to the full extend in this regard would require a complete rewrite of the front-end. (However, I’m sure no tool out there supports that to the full extend. In fact, I had to change designs to make them compatible with other tools because in some cases Yosys actually has better support for statically computable expressions than some other tools.)

@zachjs



Copy link


Collaborator

Author

I don’t think Yosys should be expected to employ more advanced analysis in attempting to unroll loops. The strategy I use in my PR to work around this is to turn function arguments into localparams (rather than wires) where trivially possible. Hopefully, this expands the capabilities of Yosys without compromise.

@clairexen

turn function arguments into localparams (rather than wires) where trivially possible

I think that’s a good way to do it. 👍

Recommend Projects

  • React photo

    React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo

    Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo

    Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo

    TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo

    Django

    The Web framework for perfectionists with deadlines.

  • Laravel photo

    Laravel

    A PHP framework for web artisans

  • D3 photo

    D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Visualization

    Some thing interesting about visualization, use data art

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo

    Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo

    Microsoft

    Open source projects and samples from Microsoft.

  • Google photo

    Google

    Google ❤️ Open Source for everyone.

  • Alibaba photo

    Alibaba

    Alibaba Open Source for everyone

  • D3 photo

    D3

    Data-Driven Documents codes.

  • Tencent photo

    Tencent

    China tencent open source team.

StefanoBettelli

The following module can be processed by Surelog v1.47,

module shifter
  #(parameter SBITS = 5,
    parameter NBITS = 32)
   (input  logic [NBITS-1:0] A,  // bit sequence to be shifted
    input  logic [SBITS-1:0] S,  // amount of shift
    output logic [NBITS-1:0] R); // shifted sequence
   localparam F = 0; // index offset
   wire    logic [NBITS-1:0] Output   [-1+F:SBITS-1+F];
   wire    logic [NBITS-1:0] LShifted [0:SBITS-1];
   assign Output[-1+F] = A;
   for (genvar i=0; i<SBITS; i=i+1) begin
      assign LShifted[i] = { Output[i-1+F][NBITS-1-2**i:0], {(2**i){1'b0}} };
      assign Output[i+F] = S[i] ? Output[i-1+F] : LShifted[i];
   end
   assign R = Output[SBITS-1+F];
endmodule

but cannot be read by the UHDM import plugin (commit d843c71) when F = 0

(i.e., when the Output array starts from -1 rather than 0.

Yosys 0.25+83 (git sha1 755b753e1, gcc 12.2.0-3ubuntu1 -fPIC -Os)
yosys> plugin -i systemverilog; read_uhdm slpp_all/surelog.uhdm
1. Executing UHDM frontend.
Generating RTLIL representation for module `shifter'.
Warning: Replacing memory LShifted with list of registers.
Warning: Replacing memory Output with list of registers.
[...]shifter.sv:16: ERROR: Failed to resolve identifier Output[-1] for width detection!

As long as I know this code is legal, and it compiles and executes correctly with verilator.

Being able to use negative indices in unpacked arrays makes the code a lot more expressive in some cases …

hzeller

In the latest UHDM, some enums have been renamed so that they will not clash with c++ 20 symbols

  • vpiInterface -> vpiInterfaceInst
  • vpiModule -> vpiModuleInst

(Note, in #436, I already prepared the code for some other aspect of current UHDM: to be ready to deal with the std::string_view return value of some fields)

forthyen

`package vproc_config;
parameter int unsigned PIPE_CNT = 1;
parameter int unsigned VREG_W = 128;
parameter int unsigned VPORT_RD_CNT = 2;
// parameter int unsigned VPORT_RD_W [VPORT_RD_CNT] = ‘{default: VREG_W};
parameter int unsigned VPORT_RD_W [VPORT_RD_CNT] = ‘{VREG_W,VREG_W};
parameter int unsigned VPORT_WR_CNT = 1;
// parameter int unsigned VPORT_WR_W [VPORT_WR_CNT] = ‘{default: VREG_W};
parameter int unsigned VPORT_WR_W [VPORT_WR_CNT] = ‘{VREG_W};
endpackage

module top #(
parameter int unsigned VPORT_CNT = 1,
parameter int unsigned MAX_VPORT_W = 128, // max port width
parameter int unsigned MAX_VADDR_W = 5, // max addr width
parameter int unsigned VREG_W = vproc_config::VREG_W,
parameter int unsigned VPORT_RD_CNT = vproc_config::VPORT_RD_CNT,
parameter int unsigned VPORT_RD_W[VPORT_RD_CNT] = vproc_config::VPORT_RD_W,
parameter int unsigned VPORT_WR_CNT = vproc_config::VPORT_WR_CNT,
parameter int unsigned VPORT_WR_W[VPORT_WR_CNT] = vproc_config::VPORT_WR_W
)(
);
typedef int unsigned ASSIGN_VADDR_RD_W_RET_T[VPORT_RD_CNT];
typedef int unsigned ASSIGN_VADDR_WR_W_RET_T[VPORT_WR_CNT];
function static ASSIGN_VADDR_RD_W_RET_T ASSIGN_VADDR_RD_W();
for (int i = 0; i < VPORT_RD_CNT; i++) begin
ASSIGN_VADDR_RD_W[i] = 5 + $clog2(VREG_W / VPORT_RD_W[i]);
end
endfunction
function static ASSIGN_VADDR_WR_W_RET_T ASSIGN_VADDR_WR_W();
for (int i = 0; i < VPORT_WR_CNT; i++) begin
ASSIGN_VADDR_WR_W[i] = 5 + $clog2(VREG_W / VPORT_WR_W[i]);
end
endfunction

localparam int unsigned VADDR_RD_W[VPORT_RD_CNT] = ASSIGN_VADDR_RD_W();
localparam int unsigned VADDR_WR_W[VPORT_WR_CNT] = ASSIGN_VADDR_WR_W();
if (VADDR_RD_W[0] != 5) begin
	$fatal(1,"--[0] should be 5 ");
end;
if (VADDR_RD_W[1] != 5) begin
	$fatal(1,"--[1] should be 5");
end;

endmodule

module main;
top #() top1;
endmodule`

meiniKi

When reading the picorv32 design through the SystemVerilog plugin, yosys runs into an assertion
ERROR: Assert `!wire->name.empty()' failed in kernel/rtlil.cc:2017.
Reading the same design with read_verilog does work.

I’m using the following setup:

FROM ubuntu:22.04
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y git wget libreadline-dev libtcl

WORKDIR /test
RUN git clone https://github.com/litex-hub/pythondata-cpu-picorv32.git
WORKDIR /test/pythondata-cpu-picorv32
RUN git checkout tags/2022.12
WORKDIR /test
RUN wget https://github.com/antmicro/yosys-systemverilog/releases/download/67941bc-2022-10-10/yosys-uhdm-integration-67941bc-Ubuntu-20.04-focal-x86_64.tar.gz
RUN tar -xvzf yosys-uhdm-integration-67941bc-Ubuntu-20.04-focal-x86_64.tar.gz

ENTRYPOINT ["/bin/bash"]

Reading with read_verilog:

image/bin/yosys -p "read_verilog -sv /test/pythondata-cpu-picorv32/pythondata_cpu_picorv32/verilog/picorv32.v"
[...]
Generating RTLIL representation for module `picorv32_wb'.
Successfully finished Verilog frontend.
[...]

Reading with read_systemverilog:

image/bin/yosys -p "plugin -i systemverilog; read_systemverilog /test/pythondata-cpu-picorv32/pythondata_cpu_picorv32/verilog/picorv32.v"
[...]
Generating RTLIL representation for module `$paramod$08824af6197f5f0eeae5e64f76c37c845b98bfe8picorv32'.
ERROR: Assert `!wire->name.empty()' failed in kernel/rtlil.cc:2017.

taylor-bsg

mglb

Use case:

module foo
  #(parameter p1)
  (input [p1-1:0] i);
endmodule

Causes segfault.

shushruthholla

I have been working on symbiyosys for formal tests along with it I am using the systemverilog plugin. Recently while runnig the sby script for a design, I encountered an assert error after elaboration as seen below
ERROR: Assert `AST_INTERNAL::current_scope.count(wiretype_node->str)' failed UhdmAst.cc:304.
It would be helpful to know what is causing it and if there is any fix.

mithro

There seems to be a single massive GitHub Action which takes ~3 hours to build.

Really there should be a GitHub Action per Yosys plugin.

mithro

If Yosys is compiled with the conda compilers then the plugins should also be compiled with the conda compilers.

tmichalak

In order to make the CI pass after the latest change in surelog the conda package had to be pinned to the previous one in #428.
This issue is to make sure that once the plugin is fixed we can unpin surelog again.

coolbreeze413

From this section:

The logic is causing the cell parameters in output blif to not be written if -no_adder flag is passed in to synth_quicklogic.
We are not sure of the reason behind this logic.
Should this logic be removed to always pass the cell parameters to blif?

This affects RAM scenarios, where the MODE_BITS are not appearing in the output blif, in case the -no_adder is set.

mglb

Enums like enum logic [2:0] are seen as 32 bit wide types. This is a problem only inside the plugin — yosys converts them to properly sized types in later stages.

Test case:

module mod(output int foo_size, output int bar_size, output int enum_size);
  typedef enum logic [2:0] {
      e_zero  = 0
    , e_one   = 1
    , e_two   = 2
    , e_three = 3
    , e_four  = 4
  } numbers_e;

  typedef struct packed {
    logic [31:0] f_member;
  } foo_t;

  typedef struct packed {
    numbers_e    b_member;
    logic [28:0] b_padding;
  }  bar_t;

  union packed {
    foo_t member_foo;
    bar_t member_bar;
  } union_s;

  assign foo_size = $bits(foo_t);
  assign bar_size = $bits(bar_t);
  assign enum_size = $bits(numbers_e);
endmodule

causes an error:

enum_width.sv:10: ERROR: member member_foo of a packed union has 32 bits, expecting 61

After commenting out the union and using write_verilog in yosys the sizes are correct:

  assign foo_size = 32'h00000020;
  assign bar_size = 32'h00000020;
  assign enum_size = 32'h00000003;

shakouri

The yosys verilog reader is not able to parse verilog code that other synthesis tools are able to parse. sv2v plugin is not working either.

  1. Allow parameter passing w/o use of parantheses (‘-‘ denotes original RTL, and ‘+’ denotes changes to make yosys read it in):

yosys_case1

  1. Allow use of ? during async portion of always block (‘-‘ denotes original RTL, and ‘+’ denotes changes to make yosys read it in):

yosys_case2

yosys_case3

  1. Allow use of logic as instance name(‘-‘ denotes original RTL, and ‘+’ denotes changes to make yosys read it in):

yosys_case4

hzeller

Looking through failures in sv-tests (all log-files that indicate failure: find out/logs/UhdmYosys/ -name "*.log" | xargs grep -l "tool_success: 0")

There are some assertions in UhdmAst or Yosys triggered. We should use these as an opportunity to handle these cases more gracefully.

Asserts seen:

Assert `AST_INTERNAL::current_scope.count(wiretype_node->str)' failed in UhdmAst.cc:303.
Assert `block != nullptr' failed in frontends/ast/genrtlil.cc:257.
Assert `!memories.count(node->str)' failed in UhdmAst.cc:382.
Assert `p[1] != 0' failed in ./kernel/rtlil.h:168.
Assert `ranges[i]->children[0]->type == AST::AST_CONSTANT' failed in UhdmAst.cc:189.
Assert `ranges[i]->children[1]->type == AST::AST_CONSTANT' failed in UhdmAst.cc:190.
Assert `struct_node' failed in UhdmAst.cc:570.
Assert `variables.count(str) != 0' failed in frontends/ast/simplify.cc:5260.

Darksecond

Currently read_uhdm (and by extension read_systemverilog) ignore the $past function that yosys read_verilog currently supports. This makes it fairly hard to write formal test benches as they tend to use the $past function.

alaindargelas

@rkapuscik , please update: uhdmastfrontend.cc: In member function ‘virtual Yosys::AST::AstNode* Yosys::UhdmAstFrontend::parse(std::string)’:
02:42:28 | uhdmastfrontend.cc:47:120: error: no matching function for call to ‘UHDM::SynthSubset::SynthSubset(UHDM::Serializer*, std::set<const UHDM::BaseClass*>&, bool)’
02:42:28 | 47 | UHDM::SynthSubset synthSubset = new UHDM::SynthSubset(&serializer, this->shared.nonSynthesizableObjects, false);
02:42:28 | | ^
02:42:28 | In file included from uhdmcommonfrontend.h:23,
02:42:28 | from uhdmastfrontend.cc:20:
02:42:28 | /root/Surelog/Surelog/yosys-uhdm-plugin-integration/image/include/uhdm/SynthSubset.h:39:3: note: candidate: ‘UHDM::SynthSubset::SynthSubset(UHDM::Serializer
, std::set<const UHDM::BaseClass*>&, bool, bool)’
02:42:28 | 39 | SynthSubset(Serializer* serializer,
02:42:28 | | ^~~~~~~~~~~
02:42:28 | /root/Surelog/Surelog/yosys-uhdm-plugin-integration/image/include/uhdm/SynthSubset.h:39:3: note: candidate expects 4 arguments, 3 provided
02:42:28 | /root/Surelog/Surelog/yosys-uhdm-plugin-integration/image/include/uhdm/SynthSubset.h:37:7: note: candidate: ‘UHDM::SynthSubset::SynthSubset(const UHDM::SynthSubset&)’
02:42:28 | 37 | class SynthSubset final : public VpiListener {
02:42:28 | | ^~~~~~~~~~~

hannesha

I tried to use 3-state outputs in a project, but the outputs are not driven at all. Setting T to 0 drives the outputs as expected.

I created a minimal example on a basys3 board with two switches to reproduce this issue.

Looking through the files revealed that .IO_LOC_PAIRS is set to "NONE" for the affected OBUFT, in the .eblif file.
Manually setting .IO_LOC_PAIRS on the OBUFT makes it work as expected. I verified that the output is floating with a voltmeter.

I attached a archive with the example, a f4pga flow config, my conda list output, the .eblif files and yosys logfiles of the working and broken state.
example.tar.gz

mglb

Yosys commands:

plugin -i systemverilog
read_systemverilog -debug -parse test.sv
proc
write_verilog -sv -norename -noattr -nodec /dev/stdout

Input (test.sv)

module A(output integer o);
  typedef struct packed {
    integer memb_a;
    integer memb_b;
  }  a_struct;

  localparam a_struct a_param = '{ memb_a: 32'haa551234, memb_b: 32'h00112233 };
  assign o = a_param.memb_b;
endmodule

module B(output integer o);
  A instance_of_A(o);
endmodule

write_verilog output

module A(o);
  output [31:0] o;
  wire [31:0] o;
  assign o = 32'bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx11;
endmodule

module B(o);
  output [31:0] o;
  wire [31:0] o;
  A instance_of_A (
    .o(o)
  );
endmodule

Similar examples with a correct behavior

A is top module, not an instance:

test.sv:

module A(output integer o);
  typedef struct packed {
    integer memb_a;
    integer memb_b;
  }  a_struct;

  localparam a_struct a_param = '{ memb_a: 32'haa551234, memb_b: 32'h00112233 };
  assign o = a_param.memb_b;
endmodule

module B(output integer o);

endmodule

write_verilog output

module A(o);
  output [31:0] o;
  wire [31:0] o;
  assign o = 32'h00112233;
endmodule

a_param is an integer, concat is not used

test.sv:

module A(output integer o);
  typedef struct packed {
    integer memb_a;
    integer memb_b;
  }  a_struct;

  localparam integer a_param = 32'h00112233;
  assign o = a_param;
endmodule

module B(input clk_i, input reset_i, output integer o);
  A instance_of_A(o);
endmodule

write_verilog output

module A(o);
  output [31:0] o;
  wire [31:0] o;
  assign o = 32'h00112233;
endmodule

module B(clk_i, reset_i, o);
  input clk_i;
  wire clk_i;
  output [31:0] o;
  wire [31:0] o;
  input reset_i;
  wire reset_i;
  A instance_of_A (
    .o(o)
  );
endmodule

mglb

Example (file.sv):

module foo(input clk, output int o);

    typedef union packed
    {
      integer unsigned u;
      integer signed i;
    } foo_u;

    typedef struct packed
    {
      logic [1:0] regular_member;
      foo_u union_member;
    } foo_t;

    always @(posedge clk) begin
      foo_t f;
      o = f.union_member.i;
    end

endmodule

Execute:

yosys -Xg 
      -p 'plugin -i systemverilog' 
      -p 'read_systemverilog -parse  ./file.sv'

Result:

...
[  FATAL] : 0
[ SYNTAX] : 0
[  ERROR] : 0
[WARNING] : 1
[   NOTE] : 5
#X# New IdString 'partial' with index 486.
#X# New IdString 'packed_ranges' with index 487.
#X# New IdString 'unpacked_ranges' with index 488.
#X# New IdString 'force_convert' with index 489.
ERROR: Found AST_UNION elem in struct that is currently unsupported!

Error source:

// Structs currently can only have AST_STRUCT or AST_STRUCT_ITEM
// so, it should never happen
log_error(«Found %s elem in struct that is currently unsupported!n«, type2str(current_struct_elem->type).c_str());

mglb

Example (file.sv):

module foo;
  enum logic [1:0] {e_reset, e_clear_tag, e_ready} state_n, state_r;
endmodule

Execute:

yosys 
      -p 'plugin -i systemverilog' 
      -p 'read_systemverilog -parse  ./file.sv'

Result:

...
file.sv:1: ERROR: enum item e_reset already exists

Clifford Wolf has written a nice tool, yosys-smtbmc, based upon his
yosys synthesys tool, that allows you to apply
formal methods
to your Verilog code. The promise of
formal methods
is that you can then mathematically prove that your code works, or if not
then the formal solver should be able to tell you where your code is failing.

I’ve only been working with these
methods
for a week or so, but already there are some things I can share.

The first project I tried applying these formal methods to was a simple
SPI-based A/D converter. This particular
controller is designed to interact with a
Digilent product containing a
MEMs based microphone. I’ve had
the project
built for some time, although I’ll admit I’ve never actually done anything
more with it than plug it in.

Since the project is simple enough, I
thought I’d try applying
formal methods
to it, to prove that my controller worked. Sure, I had a test
bench
that I had built some time earlier to convince me that the project worked.
The design worked
well against this test
bench,
so I didn’t expect to find many problems using
formal methods.

Imagine my surprise when I found several bugs instead. Not only that, many of
those bugs were within my FIFO
implementation–something
that I’d passed from one project to another for some time. You see, when I
built my FIFO I only tested
it in a fashion such as a “reasonable” person might use it. Under this
“reasonable use” scenario, the
FIFO
had done well.

The formal prover, however, didn’t limit itself to what I considered
“reasonable” usage of the
FIFO.
It created underruns and overruns, wrote to the
FIFO
when it was full, and read from the
FIFO
when it was empty.
It even wrote and read from the empty
FIFO
on the same clock, and it wrote and read from the full
FIFO
on the same clock as well.
When the internal logic didn’t “match” the criteria I gave the solver, it then
showed me where my FIFO
code
didn’t properly handle these conditions.

I guess I just didn’t have that much creativity when I created my test
bench
in the first place.

Was the result worth it? Keep in mind, I’ve never used
these methods
before. So did I think it was worth it? I think so. I haven’t “proved”
all of my projects yet, nor do I know if I will be able to, but I have added
proofs to some of them—and found bugs as a result.

Today, though, I’d like to share some of what I have learned.

State Sets

If you’ve never worked with
formal methods
before, the basic concept is that you will
go through your code and declare which states are valid and which are not.
You’ll then use a theorem prover to mathematically prove that you can
never enter an invalid state from a valid one. If the prover cannot
prove this, then typically you will have either a bug in your
code, or a bug in your formal assertions.

You can think of the “state” as the values in all of your
flip-flops,
together with the values of all of your inputs.

Fig 1: Bounded Model Check

BMC starts from a valid initial state, then wanders to see if it can get to an illegal state

The first step in yosys-smtbmc based theorem solving is the bounded model
checker
(BMC), figuratively shown in Fig 1. This
part of the theorem solver starts your design in its initial state,
and then walks through all of the state transitions that it can, stepping your
logic forward from one time step to the next, just to see if any set of
conditions will drive your model to an invalid state.

This may be the most straightforward part of using yosys-smtbmc, and the
easiest to understand. The problem with the BMC step is that your time is
limited. Therefore, you will only want to allow the BMC step to check some
finite number of transitions. This number needs to be chosen carefully,
otherwise there may be states you might eventually get into over time that it
won’t find.

You can also find these additional states via the second step:
the induction step.

The induction step is just like the mathematical
induction you learned in
Pre-calculus. You
first prove that some property is true for the first value,
n=1. This was the purpose of the BMC step above. If it is true for this
base case, you then proceed with the inductive step. This step assumes that
your logic is within some initially valid state, say state n, and it then
tries to prove that your logic will only transition to a valid state,
say state n+1.

That’s the idea.

Fig 2: The induction step

Induction starts from a random valid state, and tries to prove that the state will never become invalid

In practice, I’ve struggled with this induction step. The challenge
to the designer with the induction step is that you have to declare every
unreachable state as invalid, or it might start processing from an
unreachable state you aren’t expecting. As figure 2 shows, states
that are neither valid nor invalid,
but still states that the design will never reach, may easily become starting
states for induction. It is therefore up to the designer to clearly
indicate that all states must be either valid or invalid.

Fig 3: Unreachable states should be invalid

To make induction work, all unreachable states should be declared as invalid

Let me try to explain this a touch better. In a moment we’ll go over some
System Verilog statements that
yosys
will recognize. These statements declare only the state that you cannot
get to. They do this by either reducing the size of the total state space
examined, or by declaring particular states to be illegal. That part is the
job of the formal specification designer. The job of the
formal method
is to determine which states may be reached, and to then cross check these
states against the illegal ones.

Perhaps a simple table, such as the one in Fig 4, might help to explain this.

Fig 4: Unreachable vs Invalid states

What you want to know, as a designer, is whether or not there is any way that
you might reach an invalid state from a valid one. Hence, you want to know if a
particular illegal state is reachable from a valid state. This is the
purpose of formal methods.

The part I struggled with while working through the induction step is that any
state that isn’t declared to be invalid might be a starting point for
induction–even if the state is unreachable.

This should help give you an idea, should you try working with
formal methods
yourself, that you need to make certain that unreachable states
are either declared to be invalid or removed from the set of possible states.

Speaking of, that’s our next step: discussing how to declare states to be
invalid when using yosys.

Formal Declarations

yosys
can be made to understand some basic formal statements, drawn from a
subset of the System Verilog formal verification language. This can be
frustrating for a new user of
formal methods with
yosys,
since most of the material on line discusses the full System Verilog formal
description language subset. What yosys
supports is much less than that. Basically,
yosys supports assert(), assume(),
restrict(), and some expressions about transitions. Let’s examine those
formal verification statements here.

The first statement of interest is the assert() statement. At first blush,
this statement works very much like the assert() statement within C/C++.
The value given to the assert() statement must be true, or you your design
isn’t working as desired. assert()s do more than that, though.
assert()s declare states that are invalid within your design.

We’ll come back to that thought in a moment.

The other thing you need to know about assert()s is that within a simulation,
if the assert() is ever not true, the simulation will halt on a failure.
This allows you focus on what caused the problem within your design.

The next basic statement is the assume() statement. This statement is like
the assert(), but with the exception that the theorem prover doesn’t try to
prove that the assume() statement is true. Instead, it forces the assume()
to be true. Any logic path that would cause the assume() to be false
is quietly culled. From the perspective of the state space that will be
examined, the assume() statement removes particular states from the
realm of possibilities.

For example,

initial	last_clk = 1'b0;
always @($global_clock)
	assume(i_clk == !last_clk);

will force the i_clk input to the design to toggle with every
simulation step (that’s the meaning of the $global_clock–it’s true on
every change of the time step). States and state transitions where the
clock doesn’t toggle are just quietly removed from the realm of possibility.

assume() statements have one more feature: if during a simulation the
condition is invalid, the simulation will halt with an error just as it would
if the assert() statement were false.

The restrict() instruction is similar to the assume() instruction.
Like assume(), restrict() also reduces the size of the state space that
the theorem prover needs to work within. In that way, a restrict statement
is much like an assume() statement.
However, unlike the assume() statement, the simulator will ignore any
restrict() statements within your code.

I’ve also found several functions to be very valuable: $past(),
$stable(), $rose(), and $fell(). Since these are important,
let’s work our way through them.

The $past() function has the form of $past(expression, N), for arbitrary
expressions, and positive integers, N. This statement returns the value
of the expression N clocks ago. Hence, $past(expression,1) references what
the expression evaluated to during the last clock. The number of clocks
parameter, N, defaults to one, so $past(expression) is just the same as
$past(expression,1).

System Verilog allows two more arguments to the $past() function for a total
of four. Not so with yosys, however you
may not find these extra arguments necessary either. For example, the fourth
System Verilog argument to the $past() function specifies what clock and
clock edge you are referencing the $past() expression from. Instead,
yosys
only allows expressions of $past() values within a clocked
always block, and so it uses the clock specified in the always statement to
define the clock the $past() function is relative to.

There is one other trick with the $past() function: prior to the first
clock, the $past value is undefined and often assumed to be zero by many
formal theorem solvers. You’ll need to be careful, therefore, not to expect
the $past value to reference any initial value within your logic.

For this reason, I’ve gotten in the habit of creating a signal to tell me if
the past value is valid, such as:

initial	f_past_valid = 1'b0;
always @(posedge i_clk)
	f_past_valid <= 1'b1;

I can then use f_past_valid as part of an expression to determine whether or
not the inputs to a wishbone
slave will not
change once the strobe goes high until the stall line is low. Remember how
we discussed
that with wishbone nothing happens
until (i_wb_stb)&&(!o_wb_stall)? This means that once the
wishbone master
asserts the strobe signal, i_wb_stb, that it is likely to wait for the
o_wb_stall signal to lower before changing the bus request details.
To capture this thought, we’ll assume that once i_wb_stb
goes high, none of the bus request information will change until the
clock after o_wb_stall goes low:

always @(posedge i_clk)
	if ((f_past_valid)&&($past(i_wb_stb))&&($past(o_wb_stall)))
	begin
		assume(i_wb_stb);
		assume(i_wb_we   == $past(i_wb_we));
		assume(i_wb_addr == $past(i_wb_addr));
		assume(i_wb_data == $past(i_wb_data));
		assume(i_wb_sel  == $past(i_wb_sel ));
	end

Alternatively, instead of assuming that the current value was equal to the
last value, we could have instead assumed that these values were $stable()
for the same effect:

always @(posedge i_clk)
	if ((f_past_valid)&&($past(i_wb_stb))&&($past(o_wb_stall)))
	begin
		assume(i_wb_stb);
		assume($stable(i_wb_we));
		assume($stable(i_wb_addr));
		assume($stable(i_wb_data));
		assume($stable(i_wb_sel));
	end

The last of the basic commands you’ll want to know is the $rose() command.
This command returns true or false depending on whether the signal given to
it has risen (positive edge) over the last clock period or not.

This particular function is very useful for telling the theorem prover that
your inputs are only going to change on the positive edge of the clock,

always @($global_clock)
	// If it isn't the positive edge ...
	if (!$rose(i_wb_clk))
	begin
		// Then nothing changes
		assume(i_wb_stb);
		assume($stable(i_wb_we));
		assume($stable(i_wb_addr));
		assume($stable(i_wb_data));
		assume($stable(i_wb_sel));
	end

A similar $fell() primitive exists as well for testing negative clock edges.

yosys provides one more helpful feature.
Anytime you use
yosys
to generate a formal description of your code,
yosys defines the FORMAL flag. Hence, you
can surround your formal properties with ifdefs, as in:

`ifdef	FORMAL
// ...
always @(posedge i_clk)
	assert(!illegal_state);
// ...
`endif

These, therefore, are your basic formal declaration statements:
assert(), assume(), and restrict(). They are helped by the functions
$stable(), $past(), $rose(), $fell(), and perhaps some others that I
haven’t learned yet. (Remember, this is only my first week.) assert()
declares statements to be illegal, and assume() and restrict() are used
to limit the size of the state space.

With these basic principles, let’s look at some formal theorem proving
concepts.

Basic concept

The basic approach to formally describing your program is to assume() that
the inputs will be valid, and then to assert() that the outputs are valid.
You may also wish along the way to assert() particular internal states
are valid as well.

This works until you aggregate up one level, so that you have a higher level
module instantiating a lower level one. In that case, you want to assert()
the values that will be passed to the lower level module rather than
assume()ing them.

A FIFO example

Let’s work our way through a simple example–that of a
FIFO.
In this case, we’ll examine the
FIFO
I just worked with for my SPI-based microphone
ADC core.

As you may remember from our last
FIFO discussion, a
FIFO depends upon two
memory pointers: the write pointer, r_first, and the read pointer, r_last.
The only time r_first and r_last are equal is when the
FIFO is empty.
Likewise, the number of items within the
FIFO is
determined by r_first minus r_last.

There are some other rules associated with these two variables.
The first is that we cannot be allowed to read from the
FIFO
any time it is empty. The second rule is that we cannot
write to the FIFO when it
is full, unless we are also reading from the
FIFO at the same time.
Any attempt to read from an empty
FIFO, or write to a full
FIFO should generate an error.

In order to keep the state transitions from being dependent upon the
number of items in the
FIFO, I pre-compute two values:
will_overflow, which is true if the next write will overflow the
FIFO, and
will_underflow, which will be true if the next read will read from an
empty FIFO.

Further, this particular
FIFO also returns
a status value indicating 1) how many items are in the
FIFO,
2) whether or not the FIFO is non-empty, and 3) whether or not the
FIFO
is past half-full.

All of these details may also be derived from r_first and r_last alone. If
they don’t match, the FIFO
is in an illegal state. Therefore, these properties are a perfect match
for learning
formal methods

The first step is to gate all of our work so that the synthesis tool will
ignore it, unless we are working with the
formal verification methods.

`ifdef	FORMAL
// ... ALl of our formal specifications go here
`endif // This goes at the end of our formal specification

Next, within this FORMAL block we want to make certain that the assumptions
we are going to make regarding our inputs will become asserts when this core
is included into a larger design. We’ll do this by creating an ASSUME macro
that we can use to constrain our inputs.

`ifdef	SMPLFIFO
`define	ASSUME	assume
`else
`define	ASSUME	assert
`endif

Remember that you only want to constrain via ASSUME statements about
parameters that can be set by a higher level module, not external inputs.

Earlier, I described what it would take to assume that the clock toggles.
We’ll repeat that here. We’re also going to insist that this
FIFO
starts in it’s reset state, by insisting that the i_rst line is initially
valid.

initial restrict(i_rst);

always @($global_clock)
begin
	restrict(i_clk == !f_last_clk);
	f_last_clk <= i_clk;

Before leaving this beginning statement, let’s also insist that our
inputs only change on the positive edge of the clock.

	if (!$rose(i_clk))
	begin
		`ASSUME($stable(i_rst));
		`ASSUME($stable(i_wr));
		`ASSUME($stable(i_data));
		`ASSUME($stable(i_rd));
	end
end

We also discussed above the need to know whether the $past() function
would return valid results. We’ll use the f_past_valid register for this
purpose.

initial	f_past_valid = 1'b0;
always @(posedge i_clk)
	f_past_valid <= 1'b1;

This also highlights the fact that your formal verification logic may have
and use registers, just like the rest of your logic–even though you won’t
be using it within your design other than for formal verification.

Next, let’s look at making sure that our helper logic works.

First, the r_fill output should be equal to the number of
FIFO
memory entries that are full. This is given by the difference between
r_first and r_last. Above, we chose to use a clocked register to hold this
value. We did this for timing reasons, but there is the possibility that
we got this wrong. So, let’s check it here. Formally, one might say that
the state where r_fill doesn’t equal this difference is an illegal state.

assign	f_fill = r_first - r_last;
always @(posedge i_clk)
begin
	assert(f_fill == r_fill);

Now, let’s move on to our empty flag. Any time the
FIFO
is empty, we want to set the will_underflow flag. In addition, we want
o_empty_n to be true any time we are not empty. As I mentioned before, the
FIFO
is empty any time r_first is equal to r_last. We can use f_fill from
above for this purpose.

	if (f_fill == 0)
	begin
		assert(will_underflow);
		assert(!o_empty_n);
	end else begin
		assert(!will_underflow);
		assert(o_empty_n);
	end

In a similar value, any time the fill is one less than the number of items
in the buffer, then the buffer is “full”. Let’s make sure we got that logic
right too.

		if (f_fill == {(LGFLEN){1'b1}})
			assert(will_overflow);
		else
			assert(!will_overflow);

The
FIFO
code
also has a value, r_next, which is supposed to
reference the next value to be read. To know if we got this right, let’s add
one to the r_last pointer,

assign	f_next = r_last + 1'b1;

and then look to see if r_next equals this as desired,

	assert(r_next == f_next);
end

Finally, let’s examine the pointers under overflow and underflow conditions.
First, on any reset, both pointers will be set to zero and any output error
will be cleared.

always @(posedge i_clk)
if (f_past_valid)
begin
	if ($past(i_rst))
		assert(!o_err);
	else begin

If we are not in reset, we might have an underflow. Let’s check. If the
FIFO
was empty on the last clock, and if there was a request to read from the
FIFO
on that clock, then we had an underflow. In that case, assert that the
FIFO
read pointer, r_last, has not changed as a result.

		// Underflow detection
		if (($past(i_rd))&&($past(r_fill == 0)))
		begin
			// This core doesn't report underflow errors,
			// but quietly ignores them
			//
			// assert(o_err);
			//
			// On an underflow, we need to be careful not
			// to advance the pointer.
			assert(r_last == $past(r_last));
		end

Had this pointer changed, the
FIFO
might accidentally jump from the empty state to the full state with garbage in
the buffer. We want to avoid this.

We do almost the same thing on an overflow condition, but there are just a
couple differences.
First, in the case of a read and write on the same clock while we are full,
no overflow has taken place. Hence we need to check that a write without
a read has taken place. That’s the first difference. The second difference
is that this core reports overflow conditions, but not underflow conditions.
Hence, we assert that o_err is true on any overflow. Likewise, on any
overflow we also assert that the r_first pointer hasn’t changed.

		//
		// Overflow detection
		if (($past(i_wr))&&(!$past(i_rd))
				&&($past(will_overflow)))
		begin
			// Make sure we report this result
			assert(o_err);

			// Make sure we didn't advance our write
			// pointer on overflow
			assert(r_first == $past(r_first));
		end
	end
end

As with the underflow, a pointer change during an overflow condition can be
catastrophic as well. It could cause the
FIFO
to suddenly become empty, losing any of the data within it. This formal
check about tells the theorem prover that doing so would be illegal, and that
we want to know if anything would create such a condition.

What we haven’t discussed are the
instructions for installing
yosys,
SymbiYosys,
and the various theorem provers. These may be found
on line.
Neither have we discussed the
Makefile
I used to coordinate the proof, nor the yosys
config
that I used. Feel free to examine these on your own if you would like.

What did I find?

You may recall from earlier that I found several errors in my
FIFO as a result of using
these methods. If you are reading this, then you may be wondering just how
significant those errors were. Here are some of the things I found:

  • Originally, I had said that a write during an underflow would only
    take you out of the underflow condition if there was no read at the same
    time. This is wrong.

    A write to an empty
    FIFO
    will always succeed, independent of whether or not a read is taking place
    at the same time, and a read from an empty
    FIFO
    should always fail–independent of a write taking place at the same time.

    Fixing this required several changes throughout.

  • I hadn’t initialized all of my variables. In particular, r_next and
    r_fill weren’t originally initialized.

  • When calculating the number of elements in the
    FIFO,
    I had assumed that if the will_overflow value was true that any write to
    the FIFO would
    overflow the FIFO.
    This isn’t the case. If will_overflow is true, then any write without a
    concurrent read
    will overflow the
    FIFO.
    A read and write during the same clock period will not overflow the
    FIFO.

If you’d like, all of the changes are captured within the
github repository
on line, so you can review what I found
here.

Final Thoughts

Please keep in mind, I’m only a beginner at
formal methods.
I’ve never used any of them before this week, but I’ve already found several
problems in my own code using them. Are
formal methods
worth the effort? Well, for me and in this example, they were.

I’d like to come back to this topic in the future after I’ve learned some
more. I’d also like to apply these methods to many other problems as well.
However, I’ve also got some problems which I’m not yet certain how to prove.
For example, while I’ve managed to prove a low level QSPI flash
driver,
I have yet to figure out how to prove the entire protocol. Likewise, I’ve
managed to prove that my UART transmitter
(lite) works,
but not yet the receiver or the entire IP
core including the wishbone
interface.

For now, I think I’ll just see if I can’t prove my
WB to AXI4 bridge next.
I think that would be useful for all.

DAndrew

0 / 0 / 0

Регистрация: 20.12.2020

Сообщений: 4

1

20.12.2020, 14:47. Показов 6371. Ответов 7

Метки нет (Все метки)


Пытаюсь написать простую программу по выводу массива на экран. Visual Studio показывает 0 ошибок, но пи попытке компиляции выдаёт Index was outside the bounds of the array. Что делать, как исправить? Код программы:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
class Program
    {
        static void Main(string[] args)
        {
            int i;
            int[] MyArray = new int[5] { 1, 2, 3, 4, 5 };
            Console.WriteLine(MyArray[5]);
            for (i = 0; i < 5; i++)
            {
                MyArray[i] = int.Parse(Console.ReadLine());
            }
        }
    }

__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь



0



958 / 576 / 268

Регистрация: 20.12.2016

Сообщений: 1,506

20.12.2020, 14:49

2

Цитата
Сообщение от DAndrew
Посмотреть сообщение

Console.WriteLine(MyArray[5]);

индексы массива от 0 до 4



0



0 / 0 / 0

Регистрация: 20.12.2020

Сообщений: 4

20.12.2020, 14:57

 [ТС]

3

То есть записать так
Console.WriteLine(MyArray[5] { 0, 1, 2, 3, 4 }); ?

Добавлено через 3 минуты
Тут int[] MyArray = new int[5] { 1, 2, 3, 4, 5 }; поправил на int[] MyArray = new int[5] { 0, 1, 2, 3, 4 };
но не помогло



0



ProgItEasy

454 / 278 / 163

Регистрация: 17.04.2019

Сообщений: 1,603

20.12.2020, 14:59

4

DAndrew,

C#
1
Console.WriteLine(MyArray[4]);



0



JustinTime

958 / 576 / 268

Регистрация: 20.12.2016

Сообщений: 1,506

20.12.2020, 15:01

5

у вас массив int[] MyArray = new int[5] { 1, 2, 3, 4, 5 };, вы можете обращаться к его элементам указывая индекс от 0 до 4

C#
1
2
3
4
5
6
7
Console.WriteLine(MyArray[0]);
Console.WriteLine(MyArray[1]);
Console.WriteLine(MyArray[2]);
Console.WriteLine(MyArray[3]);
Console.WriteLine(MyArray[4]);
//а строка ниже с ошибкой, в массиве нет такого элемента, вы выходите за пределы массива
Console.WriteLine(MyArray[5]);



0



0 / 0 / 0

Регистрация: 20.12.2020

Сообщений: 4

20.12.2020, 15:07

 [ТС]

6

Console.WriteLine(MyArray[0]);
Console.WriteLine(MyArray[1]);
Console.WriteLine(MyArray[2]);
Console.WriteLine(MyArray[3]);
Console.WriteLine(MyArray[4]);
А можно ли это записать одной строкой?



0



JustinTime

958 / 576 / 268

Регистрация: 20.12.2016

Сообщений: 1,506

20.12.2020, 15:11

7

Лучший ответ Сообщение было отмечено DAndrew как решение

Решение

можно:

C#
1
Console.WriteLine(MyArray[0]);Console.WriteLine(MyArray[1]);Console.WriteLine(MyArray[2]);Console.WriteLine(MyArray[3]);Console.WriteLine(MyArray[4]);

:-) у вас есть цикл для ввода значений так же можно и выводить, или используйте

C#
1
Console.WriteLine(string.Join(" ", MyArray));



1



0 / 0 / 0

Регистрация: 20.12.2020

Сообщений: 4

20.12.2020, 15:13

 [ТС]

8

Спасибо, всё работает



0



IT_Exp

Эксперт

87844 / 49110 / 22898

Регистрация: 17.06.2006

Сообщений: 92,604

20.12.2020, 15:13

Помогаю со студенческими работами здесь

Ошибка System.IndexOutOfRangeException: «Index was outside the bounds of the array»
В двумерном массиве A=(a1, а2, …, аn) отрицательные элементы, имеющие четный порядковый номер,…

Ошибка «Index was outside the bounds of the array» при отправке сообщения с вложениями
При отправке сообщения с вложениями выскакивает вот эта ошибка:

Что это может быть?

Index was outside the bounds of the array
Скажите пожалуйста, почему у меня выдает ошибку, которая в заголовке. Причем эта ошибка указывает…

Index was outside the bounds of the array
Помогите пожалуйста. На другом компе все работало, на этом не хочет. В ответе выходило -48.
сейчас…

Index was outside the bounds of the array
Всем привет, есть задание, надо создать программу которая используя частотный анализ будет…

Index was outside the bounds of the array
Здравствуйте. Изучаю пример на VB2010. Считываю COMport. При первом считывании работает, а при…

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:

8

Понравилась статья? Поделить с друзьями:

Читайте также:

  • Yoast seo canonical плагин как изменить canonical
  • Ymaps script error
  • Yii2 отключить вывод ошибок
  • Yii2 validation error message
  • Yii2 setflash error

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии