diff --git a/README.md b/README.md index 69511a5d..d0c6902f 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ The SRecord package understands a number of file formats: * **Fairchild Fairbug**: input/output * **Formatted Binary**: input/output * **Four Packed Code (FPC)**: input/output +* **Gowin fs**: input; * **Hexdump**: output only; a simple hexdump * **HP64000 Absolute**: input only * **IDT/sim**: input/output diff --git a/doc/dictionaries/names.txt b/doc/dictionaries/names.txt index 844eb274..de9e24db 100644 --- a/doc/dictionaries/names.txt +++ b/doc/dictionaries/names.txt @@ -57,6 +57,7 @@ Giancristofaro Gracic GraphViz groff +Gowin Hanspeter Heilig hexdump diff --git a/doc/etc/README.man b/doc/etc/README.man index dc0b7acd..d0600a16 100644 --- a/doc/etc/README.man +++ b/doc/etc/README.man @@ -103,6 +103,9 @@ The Formatted Binary format is understood for both reading and writing. Four Packed Code (FPC) The FPC format is understood for both reading and writing. .\" ---------- G --------------------------------------------------------- +.TP +Gowin Bitstream +The Gowin bitstream format is understood for reading only. .\" ---------- H --------------------------------------------------------- .TP Hexdump diff --git a/doc/html/index.html b/doc/html/index.html index 2e53e888..0c9d416e 100644 --- a/doc/html/index.html +++ b/doc/html/index.html @@ -169,6 +169,11 @@ The FPC format is understood for both reading and writing.

.\" ---------- G --------------------------------------------------------- +

+Gowin bitstream +
+The Gowin bitstream format is understood for reading only. +

.\" ---------- H ---------------------------------------------------------

Hexdump diff --git a/doc/man1/srec_input.1 b/doc/man1/srec_input.1 index 821274b6..67510474 100644 --- a/doc/man1/srec_input.1 +++ b/doc/man1/srec_input.1 @@ -122,6 +122,10 @@ This option says to use the FPC format to read the file. See \f[I]srec_fpc\fP(5) for a description of this file format. .\" ---------- G --------------------------------------------------------- .TP 8n +\fB\-GOwin_fs\fP +This option says to use the Gowin bitstream format to read the file. +See \f[I]srec_gowin\fP(5) for a description of this file format. +.TP 8n \fB\-Guess\fP This option may be used to ask the command to guess the input format. This is slower than specifying an explicit format, diff --git a/doc/man5/srec_gowin.5 b/doc/man5/srec_gowin.5 new file mode 100644 index 00000000..2777c766 --- /dev/null +++ b/doc/man5/srec_gowin.5 @@ -0,0 +1,56 @@ +'\" t +.\" srecord - manipulate eprom load files +.\" Copyright (C) 2023 Daniel Anselmi +.\" +.\" This program is free software; you can redistribute it and/or modify +.\" it under the terms of the GNU General Public License as published by +.\" the Free Software Foundation; either version 3 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, see +.\" . +.\" +.ds n) srec_gowin +.TH \*(n) 5 SRecord "Reference Manual" +.if require_index \{ +.XX "srec_gowin(5)" "Gowin bitstream file format" +.\} +.SH NAME +srec_gowin \- Gowin bitstream file format +.SH DESCRIPTION +This format is the Gowin bitstream file format. It is generated by the IDE from Gowin to program their FPGAs. + +Lines starting with "//" contain comments. +Each byte is represented by a string containing 8 chars of '0' or '1' for each byte. +A line can contain multiple bytes. +There is no spacing between multiple bytes except an optional newline. +Each line contains a multiple of 8 bits (except comment lines). + +There is no addressing and no checksum in this format. + +.SH EXAMPLE +Here is an example Gowin bitstream file. +It contains the data \[lq]Hello, World\[rq]. +.RS +.nf +.ft CW +//comment +01001000 +0110010101101100 +01101100 +0110111100101100 +00100000 +010101110110111101110010 +0110110001100100 +.ft P +.fi +.RE + +.ds n) srec_cat +.so man1/z_copyright.so diff --git a/srecord/arglex/tool.cc b/srecord/arglex/tool.cc index 2382a7e4..3c4011ca 100644 --- a/srecord/arglex/tool.cc +++ b/srecord/arglex/tool.cc @@ -119,6 +119,7 @@ srecord::arglex_tool::arglex_tool(int argc, char **argv) : { "-GENerate", token_generator }, { "-GENerator", token_generator }, { "-Gnu_CRypt", token_gcrypt }, // undocumented + { "-GOwin_fs", token_gowin_fs }, { "-GUess", token_guess, }, { "-HAVal", token_haval, }, { "-HEXadecimal_Dump", token_hexdump, }, diff --git a/srecord/arglex/tool.h b/srecord/arglex/tool.h index f2a462eb..cacdd8c4 100644 --- a/srecord/arglex/tool.h +++ b/srecord/arglex/tool.h @@ -112,6 +112,7 @@ class arglex_tool: token_four_packed_code, token_gcrypt, token_generator, + token_gowin_fs, token_guess, token_haval, token_hexdump, diff --git a/srecord/arglex/tool/input.cc b/srecord/arglex/tool/input.cc index a2fb9540..7699a8e0 100644 --- a/srecord/arglex/tool/input.cc +++ b/srecord/arglex/tool/input.cc @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -347,6 +348,11 @@ srecord::arglex_tool::get_simple_input() ifp = input_file_four_packed_code::create(fn); break; + case token_gowin_fs: + token_next(); + ifp = input_file_gowin_fs::create(fn); + break; + case token_guess: token_next(); ifp = input_file::guess(fn, *this); diff --git a/srecord/input/file/gowin_fs.cc b/srecord/input/file/gowin_fs.cc new file mode 100644 index 00000000..567406ad --- /dev/null +++ b/srecord/input/file/gowin_fs.cc @@ -0,0 +1,128 @@ +// +// srecord - manipulate eprom load files +// Copyright (C) 2023 Daniel Anselmi +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 3 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 Lesser General Public +// License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +#include +#include + +#include +#include +#include + + +srecord::input_file_gowin_fs::input_file_gowin_fs( + const std::string &a_filename +) : + input_file(a_filename), + address(0), + done(false) +{ +} + +srecord::input_file::pointer +srecord::input_file_gowin_fs::create(const std::string &a_filename) +{ + return pointer(new input_file_gowin_fs(a_filename)); +} + +// See base class for documentation. +bool srecord::input_file_gowin_fs::read(record &record) +{ + if (done) + return false; + + int length = 0; + srecord::record::data_t data[srecord::record::max_data_length]; + + for (;;) + { + int c = peek_char(); + if (c == EOF) + { + done = true; + break; + } + else if (c == '/') + { + skip_until_eol(); + continue; + } + else if (c == '\n' || c == ' ' || c == '\t') + { + // Files from Gowin IDE don't have spaces or tabs between the + // data or lines with only spaces. We accept them here anyway. + get_char(); + continue; + } + + /* reading 8 chars to get a byte */ + srecord::record::data_t d = get_byte_binary(); + data[length++] = d; + + if (length >= (int)sizeof(data)) + break; + } + + record = srecord::record(srecord::record::type_data, address, data, length); + address += length; + return true; +} + +void +srecord::input_file_gowin_fs::skip_until_eol() +{ + while (get_char() != '\n'); +} + +int +srecord::input_file_gowin_fs::get_byte_binary() +{ + int val = 0; + for (int i = 0x80; i; i >>= 1) + { + int c = get_binary_digit_value(); + if (c < 0) + fatal_error("expecting binary digit"); + if (c) + val |= i; + } + return val; +} + +int +srecord::input_file_gowin_fs::get_binary_digit_value() +{ + int c = get_char(); + if (c != '0' && c != '1') + return -1; + return c - '0'; +} + +const char * +srecord::input_file_gowin_fs::get_file_format_name() + const +{ + return "Gowin bitstream"; +} + + +int +srecord::input_file_gowin_fs::format_option_number() + const +{ + return arglex_tool::token_gowin_fs; +} diff --git a/srecord/input/file/gowin_fs.h b/srecord/input/file/gowin_fs.h new file mode 100644 index 00000000..6e00ecdf --- /dev/null +++ b/srecord/input/file/gowin_fs.h @@ -0,0 +1,120 @@ +// +// srecord - manipulate eprom load files +// Copyright (C) 2023 Daniel Anselmi +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation; either version 3 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 Lesser General Public +// License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see . +// + +#ifndef SRECORD_INPUT_GOWIN_FS_H +#define SRECORD_INPUT_GOWIN_FS_H + +#include + +namespace srecord { + +/** + * The srecord::input_file_gowin_fs class is used to represent the parse + * state when reading a gowin .fs file. + */ +class input_file_gowin_fs: + public input_file +{ +public: + /** + * The destructor. + */ + virtual ~input_file_gowin_fs() = default; + + /** + * The create class method is used to create new dynamically + * allocated instances of this class. + * + * @param file_name + * The name of the file to be read. + * @returns + * smart pointer to new instance + */ + static pointer create(const std::string &file_name); + + /** + * The default constructor. + */ + input_file_gowin_fs() = delete; + + /** + * The copy constructor. + */ + input_file_gowin_fs(const input_file_gowin_fs &) = delete; + + /** + * The assignment operator. Do not use. + */ + input_file_gowin_fs &operator=(const input_file_gowin_fs &) = delete; + +protected: + // See base class for documentation. + bool read(record &record); + + // See base class for documentation. + const char *get_file_format_name() const; + + // See base class for documentation. + int format_option_number() const; + +private: + /** + * The constructor. + * + * @param file_name + * The name of the file to be read. + */ + input_file_gowin_fs(const std::string &file_name); + + /** + * The address instance variable is used to remember the current + * address of the next data record. This is set and advanced by + * the #read method. + */ + uint32_t address; + + /** + * The done instance variable is used to remember that we + * don't expect more input data. + */ + bool done; + + /** + * The get_byte_binary method is used to fetch a byte value from + * the input. It calls get_binary_digit_value 8 times, and + * assembles them big-endian (most significant bit first). + */ + int get_byte_binary(); + + /** + * The get_binary_digit_value method is used to fetch one binary digit + * from the input, via the get_char method. It returns a value from 0 to 1. + * If there's currently not a binary digit in the input stream + * it returns -1. + */ + int get_binary_digit_value(); + + /** + * skip input until there is a newline in the input. + */ + void skip_until_eol(); +}; + +}; + +#endif // SRECORD_INPUT_GOWIN_FS_H diff --git a/srecord/input/file/guess.cc b/srecord/input/file/guess.cc index bb0a6118..e0ca13be 100644 --- a/srecord/input/file/guess.cc +++ b/srecord/input/file/guess.cc @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -78,6 +79,7 @@ static func_p table[] = srecord::input_file_fastload::create, srecord::input_file_formatted_binary::create, srecord::input_file_four_packed_code::create, + srecord::input_file_gowin_fs::create, srecord::input_file_hp64k::create, srecord::input_file_idt::create, srecord::input_file_intel::create, diff --git a/srecord/srecord.h b/srecord/srecord.h index b1a0d70f..cb9722ce 100644 --- a/srecord/srecord.h +++ b/srecord/srecord.h @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include diff --git a/test/02/t0268a.sh b/test/02/t0268a.sh new file mode 100755 index 00000000..ebc698c9 --- /dev/null +++ b/test/02/t0268a.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# +# srecord - Manipulate EPROM load files +# Copyright (C) 2023 Daniel Anselmi +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 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, see . +# + +TEST_SUBJECT="input gowin" +. test_prelude.sh + +cat > test.bit << 'fubar' +//comment line +01001000 +0110010101101100 +01100101 +0110111100101100 +00100000 +010101110110111101110010 +0110110001100100 +fubar +if test $? -ne 0; then no_result; fi + +cat > test.ok << 'fubar' +S0220000687474703A2F2F737265636F72642E736F75726365666F7267652E6E65742F1D +S10F000048656C656F2C20576F726C64AF +S5030001FB +fubar +if test $? -ne 0; then no_result; fi + +srec_cat test.bit -gowin -o test.out +if test $? -ne 0; then fail; fi + +diff test.ok test.out +if test $? -ne 0; then fail; fi + +# +# The things tested here, worked. +# No other guarantees are made. +# +pass