From 6ef35c04dffe685ece08212201c4c032baf8aa86 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Thu, 1 Dec 2022 13:09:26 +0000 Subject: [PATCH] Fix verilog output when the width is > 1. PR 25202 bfd * bfd.c (VerilogDataEndianness): New variable. (verilog_write_record): Use VerilogDataEndianness, if set, to choose the endianness of the output. (verilog_write_section): Adjust the address by the data width. binutils* objcopy.c (copy_object): Set VerilogDataEndianness to the endianness of the input file. (copy_main): Verifiy the value set by the --verilog-data-width option. * testsuite/binutils-all/objcopy.exp: Add tests of the new behaviour. * testsuite/binutils-all/verilog-I4.hex: New file. --- bfd/ChangeLog | 8 ++++ bfd/verilog.c | 23 +++++++++-- binutils/ChangeLog | 10 +++++ binutils/objcopy.c | 25 +++++++++++- binutils/testsuite/binutils-all/objcopy.exp | 38 ++++++++++++++++++- .../testsuite/binutils-all/verilog-I4.hex | 6 +++ 6 files changed, 102 insertions(+), 8 deletions(-) create mode 100644 binutils/testsuite/binutils-all/verilog-I4.hex diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 24aa783e1a7..eee5d42d6bb 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,11 @@ +2022-12-01 Nick Clifton + + PR 25202 + * bfd.c (VerilogDataEndianness): New variable. + (verilog_write_record): Use VerilogDataEndianness, if set, to + choose the endianness of the output. + (verilog_write_section): Adjust the address by the data width. + 2022-11-21 Nick Clifton PR 29764 diff --git a/bfd/verilog.c b/bfd/verilog.c index baf0e044c42..52c42c5fdd9 100644 --- a/bfd/verilog.c +++ b/bfd/verilog.c @@ -62,6 +62,10 @@ Data width in bytes. */ unsigned int VerilogDataWidth = 1; +/* Modified by obcopy.c + Data endianness. */ +enum bfd_endian VerilogDataEndianness = BFD_ENDIAN_UNKNOWN; + /* Macros for converting between hex and binary. */ static const char digs[] = "0123456789ABCDEF"; @@ -105,7 +109,7 @@ verilog_set_arch_mach (bfd *abfd, enum bfd_architecture arch, unsigned long mach return true; } -/* We have to save up all the outpu for a splurge before output. */ +/* We have to save up all the output for a splurge before output. */ static bool verilog_set_section_contents (bfd *abfd, @@ -238,7 +242,8 @@ verilog_write_record (bfd *abfd, *dst++ = ' '; } } - else if (bfd_little_endian (abfd)) + else if ((VerilogDataEndianness == BFD_ENDIAN_UNKNOWN && bfd_little_endian (abfd)) /* FIXME: Can this happen ? */ + || (VerilogDataEndianness == BFD_ENDIAN_LITTLE)) { /* If the input byte stream contains: 05 04 03 02 01 00 @@ -263,8 +268,10 @@ verilog_write_record (bfd *abfd, TOHEX (dst, *end); dst += 2; } + + /* FIXME: Should padding bytes be inserted here ? */ } - else + else /* Big endian output. */ { for (src = data; src < end;) { @@ -274,6 +281,7 @@ verilog_write_record (bfd *abfd, if ((src - data) % VerilogDataWidth == 0) *dst++ = ' '; } + /* FIXME: Should padding bytes be inserted here ? */ } *dst++ = '\r'; @@ -291,7 +299,14 @@ verilog_write_section (bfd *abfd, unsigned int octets_written = 0; bfd_byte *location = list->data; - verilog_write_address (abfd, list->where); + /* Insist that the starting address is a multiple of the data width. */ + if (list->where % VerilogDataWidth) + { + bfd_set_error (bfd_error_invalid_operation); + return false; + } + + verilog_write_address (abfd, list->where / VerilogDataWidth); while (octets_written < list->size) { unsigned int octets_this_chunk = list->size - octets_written; diff --git a/binutils/ChangeLog b/binutils/ChangeLog index dfa5f1f22c8..6ec81ebd099 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,13 @@ +2022-12-01 Nick Clifton + + PR 25202 + * objcopy.c (copy_object): Set VerilogDataEndianness to the + endianness of the input file. + (copy_main): Verifiy the value set by the --verilog-data-width + option. + * testsuite/binutils-all/objcopy.exp: Add tests of the new behaviour. + * testsuite/binutils-all/verilog-I4.hex: New file. + 2022-11-21 Nick Clifton PR 29764 diff --git a/binutils/objcopy.c b/binutils/objcopy.c index 3d886240ce1..6814e20a2fc 100644 --- a/binutils/objcopy.c +++ b/binutils/objcopy.c @@ -546,6 +546,11 @@ extern bool _bfd_srec_forceS3; the --verilog-data-width parameter. */ extern unsigned int VerilogDataWidth; +/* Endianness of data for verilog output. + This variable is declared in bfd/verilog.c and is set in the + copy_object() function. */ +extern enum bfd_endian VerilogDataEndianness; + /* Forward declarations. */ static void setup_section (bfd *, asection *, void *); static void setup_bfd_headers (bfd *, bfd *); @@ -2655,6 +2660,12 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) return false; } + /* Set the Verilog output endianness based upon the input file's + endianness. We may not be producing verilog format output, + but testing this just adds extra code this is not really + necessary. */ + VerilogDataEndianness = ibfd->xvec->byteorder; + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) { if ((do_debug_sections & compress) != 0 @@ -5847,8 +5858,18 @@ copy_main (int argc, char *argv[]) case OPTION_VERILOG_DATA_WIDTH: VerilogDataWidth = parse_vma (optarg, "--verilog-data-width"); - if (VerilogDataWidth < 1) - fatal (_("verilog data width must be at least 1 byte")); + switch (VerilogDataWidth) + { + case 1: + case 2: + case 4: + case 8: + case 16: /* We do not support widths > 16 because the verilog + data is handled internally in 16 byte wide packets. */ + break; + default: + fatal (_("error: verilog data width must be 1, 2, 4, 8 or 16")); + } break; case 0: diff --git a/binutils/testsuite/binutils-all/objcopy.exp b/binutils/testsuite/binutils-all/objcopy.exp index aebfdb2090b..de6f3aaaef2 100644 --- a/binutils/testsuite/binutils-all/objcopy.exp +++ b/binutils/testsuite/binutils-all/objcopy.exp @@ -155,13 +155,13 @@ proc objcopy_test_verilog {testname} { } set got [binutils_run $OBJCOPY "-O verilog --verilog-data-width 0 $binfile $verilog-0.hex"] - if ![regexp "verilog data width must be at least 1 byte" $got] then { + if ![regexp "error: verilog data width must be 1, 2, 4, 8 or 16" $got] then { fail "objcopy ($testname 0) {$got}" } else { pass "objcopy ($testname 0)" } - foreach width {1 2 4 8} { + foreach width {1 2} { set got [binutils_run $OBJCOPY "-O verilog --verilog-data-width $width $binfile $verilog-$width.hex"] if ![string equal "" $got] then { fail "objcopy ($testname $width)" @@ -173,6 +173,40 @@ proc objcopy_test_verilog {testname} { fail "objcopy ($testname $width)" } } + + # 16-bit little-endian targets fail the following tests because the + # verilog backend does not convert from 16-bits to 32-bits before it + # converts from internal format to little endian format. + if { [istarget tic54*-*-*] || [istarget pdp11-*-*] } { + untested "verilog width-4 and width-8 tests" + return + } + + foreach width {4 8} { + set got [binutils_run $OBJCOPY "-O verilog --verilog-data-width $width $binfile $verilog-$width.hex"] + if ![string equal "" $got] then { + fail "objcopy ($testname $width)" + } + send_log "regexp_diff $verilog-$width.hex $srcdir/$subdir/verilog-$width.hex\n" + if {! [regexp_diff "$verilog-$width.hex" "$srcdir/$subdir/verilog-$width.hex"]} { + pass "objcopy ($testname $width)" + } else { + fail "objcopy ($testname $width)" + } + } + + # Test generating endian correct output. + set testname "objcopy (verilog output endian-ness == input endian-ness)" + set got [binutils_run $OBJCOPY "-O verilog --verilog-data-width 4 $binfile $verilog-I4.hex"] + if ![string equal "" $got] then { + fail $testname + } + send_log "regexp_diff $verilog-I4.hex $srcdir/$subdir/verilog-I4.hex\n" + if {! [regexp_diff "$verilog-I4.hex" "$srcdir/$subdir/verilog-I4.hex"]} { + pass $testname + } else { + fail $testname + } } objcopy_test_verilog "verilog data width" diff --git a/binutils/testsuite/binutils-all/verilog-I4.hex b/binutils/testsuite/binutils-all/verilog-I4.hex new file mode 100644 index 00000000000..4fa1a5c9691 --- /dev/null +++ b/binutils/testsuite/binutils-all/verilog-I4.hex @@ -0,0 +1,6 @@ +@00000000 +(01020304|04030201) 00000000.* +@000000.. +(02000000|00000002).* +#pass + -- 2.30.2