1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "bitstream.hpp"
10 // Based on https://prjtrellis.readthedocs.io/en/latest/architecture/bitstream_format.html ,
11 // Lattice Diamond programmer operation's I2C dump and "ECP5 and ECP5-5G sysCONFIG Usage Guide"
13 #define SECTION_ASCII_COMMENTS_BEGIN 0xFF00
14 #define SECTION_PREAMBLE_WORD_1 0xFFFF
15 #define SECTION_PREAMBLE_WORD_2 0xBDB3
17 struct tBitstreamCmd {
18 enum class tId: uint8_t {
19 LSC_PROG_CNTRL0 = 0x22,
21 LSC_INIT_ADDRESS = 0x46,
22 ISC_PROGRAM_DONE = 0x5E,
23 LSC_PROG_INCR_RTI = 0x82,
24 LSC_PROG_SED_CRC = 0xA2,
26 ISC_PROGRAM_USERCODE = 0xC2,
27 ISC_PROGRAM_SECURITY = 0xCE,
29 LSC_EBR_ADDRESS = 0xF6,
33 tBitstreamCmd::tId m_eId;
34 std::array<uint8_t, 3> m_Operands;
35 std::vector<uint8_t> m_vData;
37 tBitstreamCmd(std::ifstream &FileIn);
40 tBitstream::tBitstream(const std::string &FilePath)
43 FileIn.open(FilePath.c_str(), std::ifstream::in | std::ifstream::binary);
45 throw std::runtime_error("Couldn't open file");
49 nFile::readBigEndian(FileIn, uwSectionId);
50 if(uwSectionId == SECTION_ASCII_COMMENTS_BEGIN) {
54 while(!FileIn.eof()) {
55 nFile::readBigEndian(FileIn, c);
60 m_vComments.push_back(Comment);
68 // Continue reading until we hit preamble
69 nFile::readBigEndian(FileIn, uwSectionId);
72 if(uwSectionId != SECTION_PREAMBLE_WORD_1) {
73 // I want std::format so bad :(
75 ss << "Unexpected bitstream section: " << std::setfill('0') <<
76 std::setw(4) << std::ios::hex << uwSectionId;
77 throw std::runtime_error(ss.str());
80 // Read final part of preamble
81 uint16_t uwPreambleEnd;
82 nFile::readBigEndian(FileIn, uwPreambleEnd);
83 if(uwPreambleEnd != SECTION_PREAMBLE_WORD_2) {
84 // I want std::format so bad :(
86 ss << "Unexpected preamble ending" << std::setfill('0') <<
87 std::setw(4) << std::ios::hex << uwPreambleEnd;
88 throw std::runtime_error(ss.str());
91 while(!FileIn.eof()) {
92 // Read bitstream commands
93 tBitstreamCmd Cmd(FileIn);
95 // Last read haven't been successfull - no more data
99 // Read extra data, if any
101 case tBitstreamCmd::tId::ISC_NOOP:
102 case tBitstreamCmd::tId::LSC_RESET_CRC:
103 case tBitstreamCmd::tId::LSC_INIT_ADDRESS:
104 // No additional data
106 case tBitstreamCmd::tId::LSC_VERIFY_ID:
107 nFile::readData(FileIn, m_DeviceId.data(), m_DeviceId.size());
109 case tBitstreamCmd::tId::LSC_PROG_CNTRL0:
110 nFile::readBigEndian(FileIn, m_ulCtlReg0);
112 case tBitstreamCmd::tId::LSC_PROG_INCR_RTI: {
113 // Store program data
114 // bool isCrcVerify = Cmd.m_Operands[0] & 0x80;
115 // bool isCrcAtEnd = !(Cmd.m_Operands[0] & 0x40);
116 // bool isDummyBits = !(Cmd.m_Operands[0] & 0x20);
117 // bool isDummyBytes = !(Cmd.m_Operands[0] & 0x10);
118 auto DummyBytesCount = Cmd.m_Operands[0] & 0xF;
119 uint16_t uwRowCount = (Cmd.m_Operands[1] << 8) | Cmd.m_Operands[2];
121 for(auto RowIdx = 0; RowIdx < uwRowCount; ++RowIdx) {
122 // TODO: where to get the size of each data row? From comment?
123 std::vector<uint8_t> vRow;
126 nFile::readData(FileIn, vRow.data(), vRow.size());
127 nFile::readBigEndian(FileIn, uwCrc);
129 // I want std::format so bad :(
130 std::stringstream ss;
131 ss << "Empty CRC near pos " << std::hex << FileIn.tellg();
132 throw std::runtime_error(ss.str());
134 m_vProgramData.push_back(vRow);
135 FileIn.seekg(DummyBytesCount, std::ios::cur);
138 case tBitstreamCmd::tId::ISC_PROGRAM_USERCODE:
139 // Read usercode, skip CRC
140 nFile::readData(FileIn, m_UserCode.data(), m_UserCode.size());
141 FileIn.seekg(2, std::ios::cur);
143 case tBitstreamCmd::tId::ISC_PROGRAM_DONE:
146 // I want std::format so bad :(
147 std::stringstream ss;
148 ss << "Unhandled bitstream cmd near file pos 0x" << std::hex <<
149 FileIn.tellg() << ": 0x" << std::setw(2) << std::setfill('0') <<
151 throw std::runtime_error(ss.str());
157 tBitstreamCmd::tBitstreamCmd(std::ifstream &FileIn)
160 nFile::readBigEndian(FileIn, ulCmdRaw);
161 m_eId = tBitstreamCmd::tId(ulCmdRaw >> 24);
162 m_Operands[0] = (ulCmdRaw >> 16) & 0xFF;
163 m_Operands[1] = (ulCmdRaw >> 8) & 0xFF;
164 m_Operands[2] = (ulCmdRaw >> 0) & 0xFF;