Merge pull request 'Annotated assembly output' (#2) from tagged-asm into master
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #2
This commit is contained in:
commit
fd36be8599
|
@ -7,6 +7,7 @@ set(SOURCE_FILES
|
|||
src/ImageFormat.cpp src/ImageFormat.h
|
||||
src/SmallFirmwareFormat.cpp src/SmallFirmwareFormat.h
|
||||
|
||||
src/instructions/AddressOffset.h
|
||||
src/instructions/Instruction.cpp src/instructions/Instruction.h
|
||||
src/instructions/Write.cpp src/instructions/Write.h
|
||||
src/instructions/Copy.cpp src/instructions/Copy.h
|
||||
|
@ -26,7 +27,8 @@ set(SOURCE_FILES
|
|||
src/Registers.cpp src/Registers.h
|
||||
src/AnalysisState.cpp src/AnalysisState.h
|
||||
src/Configuration.cpp src/Configuration.h
|
||||
)
|
||||
src/OutputContext.cpp src/OutputContext.h
|
||||
)
|
||||
|
||||
add_library(rrcimage STATIC ${SOURCE_FILES})
|
||||
|
||||
|
|
|
@ -34,4 +34,16 @@ uint32_t AnalysisState::getAddressOffset(uint8_t offsetEntry) const {
|
|||
return 0;
|
||||
}
|
||||
return getRegister((uint32_t) KnownRegisters::BSM_ADDR_OFFSET_0 + offsetEntry);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t AnalysisState::getRegister(const Instruction::AddressWithOffset &address) const {
|
||||
return getRegister(getAddressWithOffset(address));
|
||||
}
|
||||
|
||||
void AnalysisState::setRegister(const Instruction::AddressWithOffset &address, uint32_t value) {
|
||||
setRegister(getAddressWithOffset(address), value);
|
||||
}
|
||||
|
||||
uint32_t AnalysisState::getAddressWithOffset(const Instruction::AddressWithOffset &address) const {
|
||||
return address.address + getAddressOffset(address.offset);
|
||||
}
|
||||
|
|
|
@ -30,10 +30,24 @@
|
|||
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include "SmallFirmwareFormat.h"
|
||||
#include "instructions/AddressOffset.h"
|
||||
|
||||
enum class JumpKind {
|
||||
Continue,
|
||||
Absolute,
|
||||
Speculative,
|
||||
Branch,
|
||||
Loop,
|
||||
Return
|
||||
};
|
||||
|
||||
typedef std::unordered_map<uint32_t, std::vector<std::pair<uint32_t, JumpKind>>> AnalysisJumpTable;
|
||||
|
||||
class AnalysisState {
|
||||
public:
|
||||
|
||||
std::unordered_map<uint32_t, uint32_t> memory;
|
||||
uint32_t previous;
|
||||
uint32_t current;
|
||||
|
@ -41,13 +55,26 @@ public:
|
|||
SmallFirmwareFormat pciSPICOFirmware;
|
||||
SmallFirmwareFormat pciSerDesFirmware;
|
||||
|
||||
AnalysisState(uint32_t initial) : current(initial), previous(0) {
|
||||
|
||||
AnalysisJumpTable &jumpTable;
|
||||
|
||||
void addKnownJump(uint32_t to, uint32_t from, JumpKind kind) {
|
||||
if (jumpTable.find(to) == jumpTable.end()) {
|
||||
jumpTable[to] = std::vector<std::pair<uint32_t, JumpKind>>{{from, kind}};
|
||||
} else if (std::find(jumpTable[to].begin(), jumpTable[to].end(), std::pair<uint32_t, JumpKind>(from, kind)) ==
|
||||
jumpTable[to].end()) {
|
||||
jumpTable[to].emplace_back(from, kind);
|
||||
}
|
||||
}
|
||||
|
||||
AnalysisState(uint32_t initial, AnalysisJumpTable &table) : current(initial), previous(0), jumpTable(table) {
|
||||
|
||||
}
|
||||
|
||||
AnalysisState(const AnalysisState &oldState) : current(oldState.current), previous(oldState.previous),
|
||||
memory(oldState.memory), pciSPICOFirmware(oldState.pciSPICOFirmware),
|
||||
pciSerDesFirmware(oldState.pciSerDesFirmware) {
|
||||
pciSerDesFirmware(oldState.pciSerDesFirmware),
|
||||
jumpTable(oldState.jumpTable) {
|
||||
|
||||
}
|
||||
|
||||
|
@ -55,13 +82,19 @@ public:
|
|||
return current == other.current && memory == other.memory;
|
||||
}
|
||||
|
||||
void setRegister(const Instruction::AddressWithOffset &address, uint32_t value);
|
||||
|
||||
void setRegister(uint32_t addr, uint32_t value) {
|
||||
memory[addr] = value;
|
||||
}
|
||||
|
||||
uint32_t getRegister(const Instruction::AddressWithOffset &address) const;
|
||||
|
||||
uint32_t getRegister(uint32_t addr) const {
|
||||
return memory.find(addr) == memory.end() ? 0 : memory.at(addr);
|
||||
}
|
||||
|
||||
uint32_t getAddressWithOffset(const Instruction::AddressWithOffset &address) const;
|
||||
|
||||
uint32_t getAddressOffset(uint8_t offsetEntry) const;
|
||||
};
|
|
@ -112,7 +112,7 @@ ImageFormat ImageFormat::fromBytes(const std::vector<uint8_t> &imageBytes) {
|
|||
|
||||
std::vector<uint8_t> ImageFormat::toBytes() const {
|
||||
std::vector<uint8_t> bytes;
|
||||
bytes.resize(baseImage.size() - 1, 0xFF);
|
||||
bytes.resize(getBaseImage().size() - 1, 0xFF);
|
||||
|
||||
uint32_t offset = 0;
|
||||
|
||||
|
@ -123,7 +123,7 @@ std::vector<uint8_t> ImageFormat::toBytes() const {
|
|||
bytes[offset++] = header.baseAddress & 0xFF;
|
||||
|
||||
for (; offset < CFG_HEADER; ++offset) {
|
||||
bytes[offset] = baseImage[offset];
|
||||
bytes[offset] = getBaseImage()[offset];
|
||||
}
|
||||
|
||||
bytes[offset++] = cfgHeader.length;
|
||||
|
@ -132,7 +132,7 @@ std::vector<uint8_t> ImageFormat::toBytes() const {
|
|||
bytes[offset++] = cfgHeader.base & 0xFF;
|
||||
|
||||
for (; offset < CFG_SIGNATURE; ++offset) {
|
||||
bytes[offset] = baseImage[offset];
|
||||
bytes[offset] = getBaseImage()[offset];
|
||||
}
|
||||
|
||||
std::copy(imageSignature.begin(), imageSignature.end(), bytes.begin() + offset);
|
||||
|
@ -140,7 +140,7 @@ std::vector<uint8_t> ImageFormat::toBytes() const {
|
|||
offset += imageSignature.length();
|
||||
|
||||
for (; offset < cfgHeader.base; ++offset) {
|
||||
bytes[offset] = baseImage[offset];
|
||||
bytes[offset] = getBaseImage()[offset];
|
||||
}
|
||||
|
||||
bytes[offset++] = cfg.fileFormat;
|
||||
|
@ -150,7 +150,7 @@ std::vector<uint8_t> ImageFormat::toBytes() const {
|
|||
bytes[offset++] = (cfg.length >> 4) & 0xFF;
|
||||
|
||||
for (; offset < cfgHeader.base + CFG_LENGTH; ++offset) {
|
||||
bytes[offset] = baseImage[offset];
|
||||
bytes[offset] = getBaseImage()[offset];
|
||||
}
|
||||
|
||||
if (cfg.version == 0) {
|
||||
|
@ -168,7 +168,7 @@ std::vector<uint8_t> ImageFormat::toBytes() const {
|
|||
bytes[offset] = 0xFF;
|
||||
}
|
||||
|
||||
std::copy(baseImage.begin() + offset, baseImage.end(), bytes.begin() + offset);
|
||||
std::copy(getBaseImage().begin() + offset, getBaseImage().end(), bytes.begin() + offset);
|
||||
|
||||
for (const auto &entry : instructions) {
|
||||
auto data = entry.second->toBytes();
|
||||
|
@ -180,17 +180,20 @@ std::vector<uint8_t> ImageFormat::toBytes() const {
|
|||
|
||||
|
||||
void ImageFormat::decodeAnalyzeInstructionsAt(uint32_t offset) {
|
||||
jumpTable.clear();
|
||||
|
||||
std::queue<AnalysisState> savedStates;
|
||||
std::vector<AnalysisState> branchingStates;
|
||||
|
||||
std::unordered_map<uint32_t, bool> jumpsUsed;
|
||||
|
||||
AnalysisState baseState(offset);
|
||||
AnalysisState baseState(offset, jumpTable);
|
||||
|
||||
savedStates.push(baseState);
|
||||
|
||||
uint32_t maxUnchangedExecutions = 1000;
|
||||
uint32_t maxTotalExecutions = 20000;
|
||||
uint32_t speculativeJumps = 0;
|
||||
|
||||
while (!savedStates.empty()) {
|
||||
AnalysisState state = savedStates.front();
|
||||
|
@ -201,6 +204,10 @@ void ImageFormat::decodeAnalyzeInstructionsAt(uint32_t offset) {
|
|||
|
||||
do {
|
||||
|
||||
if (jumpsUsed.find(state.current) != jumpsUsed.end() && !jumpsUsed[state.current]) {
|
||||
speculativeJumps++;
|
||||
}
|
||||
|
||||
jumpsUsed[state.current] = true;
|
||||
|
||||
if (state.current >= 0x100000 || (findInstructionByAddress(state.current) == nullptr &&
|
||||
|
@ -209,7 +216,7 @@ void ImageFormat::decodeAnalyzeInstructionsAt(uint32_t offset) {
|
|||
break;
|
||||
} else if (findInstructionByAddress(state.current) == nullptr) {
|
||||
auto decodedInstruction = Instruction::Instruction::decodeInstructionFromBytes(state.current,
|
||||
baseImage);
|
||||
getBaseImage());
|
||||
instructions[decodedInstruction->getAddress()] = std::move(decodedInstruction);
|
||||
}
|
||||
|
||||
|
@ -227,6 +234,10 @@ void ImageFormat::decodeAnalyzeInstructionsAt(uint32_t offset) {
|
|||
|
||||
auto possibleBranches = instruction->execute(state);
|
||||
|
||||
if (jumpsUsed.find(state.current) != jumpsUsed.end() && !jumpsUsed[state.current]) {
|
||||
jumpsUsed.erase(state.current); //Clear to recognize a non-speculative jump
|
||||
}
|
||||
|
||||
if ((instruction->getCommand() == Instruction::Instruction::CommandOp::JUMP ||
|
||||
instruction->getCommand() == Instruction::Instruction::CommandOp::RETURN) &&
|
||||
jumpsUsed.find(instruction->getEndAddress()) == jumpsUsed.end()) {
|
||||
|
@ -268,7 +279,7 @@ void ImageFormat::decodeAnalyzeInstructionsAt(uint32_t offset) {
|
|||
|
||||
for (const auto &branch : possibleBranches) {
|
||||
AnalysisState newState(state);
|
||||
newState.current = branch.first & 0xfffffffc;
|
||||
newState.current = branch.first;
|
||||
for (const auto &entry : branch.second) {
|
||||
newState.setRegister(entry.first, entry.second);
|
||||
}
|
||||
|
@ -293,6 +304,7 @@ void ImageFormat::decodeAnalyzeInstructionsAt(uint32_t offset) {
|
|||
for (auto &visited : jumpsUsed) {
|
||||
if (!visited.second && visited.first >= offset && visited.first <= 0x100000) {
|
||||
baseState.current = visited.first;
|
||||
baseState.addKnownJump(visited.first, 0, JumpKind::Speculative);
|
||||
savedStates.push(baseState);
|
||||
break;
|
||||
}
|
||||
|
@ -300,7 +312,8 @@ void ImageFormat::decodeAnalyzeInstructionsAt(uint32_t offset) {
|
|||
}
|
||||
|
||||
std::cerr << "Next state, branched states left: " << std::dec << savedStates.size()
|
||||
<< /*", executed states: " << std::dec << createdStates.size() <<*/ ", total instructions decoded: "
|
||||
<< /*", executed states: " << std::dec << createdStates.size() <<*/ ", speculative jumps: "
|
||||
<< std::dec << speculativeJumps << ", total instructions decoded: "
|
||||
<< std::dec << instructions.size() << "\n";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,6 +63,30 @@ public:
|
|||
|
||||
void decodeAnalyzeInstructionsAt(uint32_t offset);
|
||||
|
||||
const std::unique_ptr<Instruction::Instruction> &
|
||||
findConstInstructionByAddress(uint32_t addr, bool indirect = false) const {
|
||||
if (instructions.find(addr) != instructions.end()) {
|
||||
return instructions.find(addr)->second;
|
||||
}
|
||||
|
||||
if (indirect) {
|
||||
for (auto &instruction : instructions) {
|
||||
if (
|
||||
(instruction.second->getEndAddress() == 0 && addr == instruction.second->getAddress())
|
||||
|| (
|
||||
instruction.second->getEndAddress() != 0
|
||||
&& addr >= instruction.second->getAddress()
|
||||
&& addr < instruction.second->getEndAddress()
|
||||
)
|
||||
) {
|
||||
return instruction.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL_INSTRUCTION;
|
||||
}
|
||||
|
||||
std::unique_ptr<Instruction::Instruction> &findInstructionByAddress(uint32_t addr, bool indirect = false) {
|
||||
if (instructions.find(addr) != instructions.end()) {
|
||||
return instructions.find(addr)->second;
|
||||
|
@ -98,6 +122,10 @@ public:
|
|||
return instructions;
|
||||
}
|
||||
|
||||
const auto &getJumpTable() const {
|
||||
return jumpTable;
|
||||
}
|
||||
|
||||
const auto &getBaseImage() const {
|
||||
return baseImage;
|
||||
}
|
||||
|
@ -145,4 +173,6 @@ private:
|
|||
std::map<uint32_t, std::unique_ptr<Instruction::Instruction>> instructions;
|
||||
|
||||
std::vector<uint8_t> baseImage;
|
||||
|
||||
AnalysisJumpTable jumpTable;
|
||||
};
|
199
src/OutputContext.cpp
Normal file
199
src/OutputContext.cpp
Normal file
|
@ -0,0 +1,199 @@
|
|||
/*****************************************************************************
|
||||
* Copyright (c) 2020, rrcSmall FM10K-Documentation Contributors
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include "OutputContext.h"
|
||||
#include "instructions/Write.h"
|
||||
#include "instructions/Jump.h"
|
||||
#include "Registers.h"
|
||||
|
||||
std::string OutputContext::getLabel(uint32_t location, bool force) const {
|
||||
if (mappings.find(location) != mappings.end() && (!force || !mappings.at(location).empty())) {
|
||||
return mappings.at(location);
|
||||
}
|
||||
if (force) {
|
||||
std::stringstream s;
|
||||
s << "loc_" << std::hex << std::setw(6) << std::setfill('0') << location;
|
||||
return s.str();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string OutputContext::getComment(uint32_t location) const {
|
||||
if (comments.find(location) != comments.end()) {
|
||||
return " ; " + comments.at(location);
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
std::string OutputContext::getDataHeader(uint32_t location) const {
|
||||
std::stringstream s;
|
||||
s << std::hex << std::setw(6) << std::setfill('0') << location << " ";
|
||||
for (uint32_t i = location; i < location + 4; ++i) {
|
||||
s << std::hex << std::setw(2) << std::setfill('0') << (uint32_t) image.getBaseImage().at(i) << " ";
|
||||
}
|
||||
s << " ";
|
||||
return s.str();
|
||||
}
|
||||
|
||||
std::string OutputContext::getDataEntry(uint32_t location, const std::string &representation) const {
|
||||
std::string result = getDataHeader(location) + representation;
|
||||
uint32_t padLength = 80;
|
||||
if (result.size() < padLength) {
|
||||
result.append(padLength - result.size(), ' ');
|
||||
}
|
||||
result += getComment(location);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string OutputContext::getInstructionString(const Instruction::Instruction &instruction) const {
|
||||
std::string output;
|
||||
for (auto &l : instruction.toOutputFormat(*this)) {
|
||||
output += getDataEntry(l.location, l.format) + "\n";
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
void OutputContext::analyze() {
|
||||
const auto &table = image.getJumpTable();
|
||||
|
||||
for (auto &e : table) {
|
||||
std::stringstream from;
|
||||
from << "XREF.CallFrom: ";
|
||||
bool hasContinue = false;
|
||||
bool justAbsolute = true;
|
||||
bool justReturn = true;
|
||||
for (auto &j : e.second) {
|
||||
if (j.second != JumpKind::Return && j.second != JumpKind::Speculative) {
|
||||
justReturn = false;
|
||||
}
|
||||
if (j.second != JumpKind::Absolute && j.second != JumpKind::Speculative) {
|
||||
justAbsolute = false;
|
||||
}
|
||||
if (j.second != JumpKind::Continue) {
|
||||
from << std::hex << std::setw(6) << std::setfill('0') << j.first << "(";
|
||||
switch (j.second) {
|
||||
case JumpKind::Speculative:
|
||||
from << "Speculative";
|
||||
break;
|
||||
case JumpKind::Absolute:
|
||||
from << "Absolute";
|
||||
break;
|
||||
case JumpKind::Branch:
|
||||
from << "Branch";
|
||||
break;
|
||||
case JumpKind::Loop:
|
||||
from << "Loop";
|
||||
break;
|
||||
case JumpKind::Return:
|
||||
from << "Return";
|
||||
break;
|
||||
}
|
||||
from << "), ";
|
||||
} else {
|
||||
hasContinue = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (justReturn || justAbsolute) {
|
||||
if (!e.second.empty() && justReturn) {
|
||||
auto &instruction = image.findConstInstructionByAddress(e.first - 1, true);
|
||||
if (instruction != nullptr && (instruction->getCommand() == Instruction::Instruction::CommandOp::JUMP ||
|
||||
instruction->getCommand() ==
|
||||
Instruction::Instruction::CommandOp::RETURN)) {
|
||||
|
||||
|
||||
std::string locText = "RETURN location for call";
|
||||
bool foundReturn = false;
|
||||
uint32_t addressLocation = instruction->getAddress() - 1;
|
||||
|
||||
if (instruction->getCommand() == Instruction::Instruction::CommandOp::JUMP) {
|
||||
auto &jumpInstruction = dynamic_cast<const Instruction::Jump &>(*instruction);
|
||||
locText = "RETURN location for " + getLabel(jumpInstruction.jumpAddress);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
auto &instructionBefore = image.findConstInstructionByAddress(addressLocation, true);
|
||||
if (instructionBefore != nullptr &&
|
||||
instructionBefore->getCommand() == Instruction::Instruction::CommandOp::WRITE) {
|
||||
auto &writeInstruction = dynamic_cast<const Instruction::Write &>(*instructionBefore);
|
||||
if (writeInstruction.data.size() == 1 &&
|
||||
writeInstruction.data[0] == e.first) { //Return value!
|
||||
//TODO: mark join?
|
||||
addComment(writeInstruction.getAddress() + 4, locText);
|
||||
foundReturn = true;
|
||||
break;
|
||||
}
|
||||
addressLocation = instructionBefore->getAddress() - 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundReturn) {
|
||||
addMapping(e.first, getLabel(e.first, true));
|
||||
}
|
||||
} else {
|
||||
addMapping(e.first, getLabel(e.first, true));
|
||||
}
|
||||
} else {
|
||||
addMapping(e.first, getLabel(e.first, true));
|
||||
}
|
||||
}
|
||||
|
||||
if (e.second.size() > 1 || (!hasContinue && !e.second.empty())) {
|
||||
addComment(e.first, "<" + getLabel(e.first, true) + "> " + from.str());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void OutputContext::addMapping(uint32_t location, const std::string &name, bool force) {
|
||||
if (mappings.find(location) == comments.end() || (force && !mappings[location].empty())) {
|
||||
mappings[location] = name;
|
||||
}
|
||||
}
|
||||
|
||||
void OutputContext::addComment(uint32_t location, const std::string &comment) {
|
||||
|
||||
if (comments.find(location) != comments.end()) {
|
||||
comments[location] = comment + " --- " + comments[location];
|
||||
} else {
|
||||
comments[location] = comment;
|
||||
}
|
||||
}
|
||||
|
||||
std::string OutputContext::getAddressRegisterName(uint32_t addr, uint8_t offset) const {
|
||||
if (offset || registers.find(addr) == registers.end()) {
|
||||
return ::getAddressRegisterName(addr, offset);
|
||||
} else {
|
||||
return registers.at(addr);
|
||||
}
|
||||
}
|
77
src/OutputContext.h
Normal file
77
src/OutputContext.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*****************************************************************************
|
||||
* Copyright (c) 2020, rrcSmall FM10K-Documentation Contributors
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include "ImageFormat.h"
|
||||
|
||||
class OutputContext {
|
||||
public:
|
||||
|
||||
private:
|
||||
const ImageFormat ℑ
|
||||
std::unordered_map<uint32_t, std::string> mappings;
|
||||
std::unordered_map<uint32_t, std::string> comments;
|
||||
std::unordered_map<uint32_t, std::string> registers;
|
||||
|
||||
public:
|
||||
|
||||
OutputContext(const ImageFormat &image) : image(image) {
|
||||
|
||||
}
|
||||
|
||||
void addMapping(uint32_t location, const std::string &name, bool force = false);
|
||||
|
||||
void addComment(uint32_t location, const std::string &comment);
|
||||
|
||||
void addRegister(uint32_t addr, const std::string &name) {
|
||||
registers[addr] = name;
|
||||
}
|
||||
|
||||
std::string getAddressRegisterName(uint32_t addr, uint8_t offset) const;
|
||||
|
||||
std::string getAddressRegisterName(const Instruction::AddressWithOffset &address) const {
|
||||
return getAddressRegisterName(address.address, address.offset);
|
||||
}
|
||||
|
||||
std::string getLabel(uint32_t location, bool force = true) const;
|
||||
|
||||
std::string getComment(uint32_t location) const;
|
||||
|
||||
std::string getDataHeader(uint32_t location) const;
|
||||
|
||||
std::string getDataEntry(uint32_t location, const std::string &representation = "") const;
|
||||
|
||||
std::string getInstructionString(const Instruction::Instruction &instruction) const;
|
||||
|
||||
void analyze();
|
||||
};
|
|
@ -144,8 +144,10 @@ std::string getRegisterName(KnownRegisters addr) {
|
|||
return "REI_CTRL";
|
||||
case KnownRegisters::REI_STAT:
|
||||
return "REI_STAT";
|
||||
case KnownRegisters::BIST_CTRL:
|
||||
return "BIST_CTRL";
|
||||
case KnownRegisters::BIST_CTRL_0:
|
||||
return "BIST_CTRL[0]";
|
||||
case KnownRegisters::BIST_CTRL_1:
|
||||
return "BIST_CTRL[1]";
|
||||
case KnownRegisters::PCIE_CLKMON_RATIO_CFG:
|
||||
return "PCIE_CLKMON_RATIO_CFG";
|
||||
case KnownRegisters::PCIE_CLKMON_TOLERANCE_CFG:
|
||||
|
@ -180,6 +182,10 @@ std::string getAddressRegisterName(uint32_t addr, uint8_t offset) {
|
|||
return s.str();
|
||||
}
|
||||
|
||||
std::string getAddressRegisterName(const Instruction::AddressWithOffset &address) {
|
||||
return getAddressRegisterName(address.address, address.offset);
|
||||
}
|
||||
|
||||
KnownRegisters getScratchRegister(uint32_t offset) {
|
||||
return static_cast<KnownRegisters>((uint32_t) KnownRegisters::BSM_SCRATCH_START + offset);
|
||||
}
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include "instructions/AddressOffset.h"
|
||||
|
||||
enum class KnownRegisters : uint32_t {
|
||||
PCIE_MASTER_SPICO_FIRMWARE_SPECIAL_REGISTER = 0x0,
|
||||
|
@ -66,7 +67,8 @@ enum class KnownRegisters : uint32_t {
|
|||
BSM_COUNTER_0 = 0x000C08,
|
||||
BSM_COUNTER_1 = BSM_COUNTER_0 + 1,
|
||||
|
||||
BIST_CTRL = 0x000C10,
|
||||
BIST_CTRL_0 = 0x000C10,
|
||||
BIST_CTRL_1 = 0x000C11,
|
||||
|
||||
REI_CTRL = 0x000C12,
|
||||
REI_STAT = 0x000C13,
|
||||
|
@ -124,4 +126,6 @@ KnownRegisters getScratchRegister(uint32_t offset);
|
|||
|
||||
std::string getRegisterName(KnownRegisters addr);
|
||||
|
||||
std::string getAddressRegisterName(uint32_t addr, uint8_t offset = 0);
|
||||
std::string getAddressRegisterName(uint32_t addr, uint8_t offset = 0);
|
||||
|
||||
std::string getAddressRegisterName(const Instruction::AddressWithOffset &address);
|
35
src/instructions/AddressOffset.h
Normal file
35
src/instructions/AddressOffset.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*****************************************************************************
|
||||
* Copyright (c) 2020, rrcSmall FM10K-Documentation Contributors
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the copyright holder nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Instruction {
|
||||
typedef struct {
|
||||
uint32_t address: 24;
|
||||
uint8_t offset: 2;
|
||||
} AddressWithOffset;
|
||||
}
|
|
@ -29,6 +29,7 @@
|
|||
#include "../Registers.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include "../OutputContext.h"
|
||||
|
||||
void Instruction::Branch::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
|
||||
_address = offset;
|
||||
|
@ -36,11 +37,11 @@ void Instruction::Branch::fromBytes(uint32_t offset, const std::vector<uint8_t>
|
|||
uint32_t command = bytes[offset++];
|
||||
|
||||
equality = (command >> 2) & 0b1;
|
||||
addressOffset = command & 0b11;
|
||||
address.offset = command & 0b11;
|
||||
|
||||
address = bytes[offset++] << 16;
|
||||
address |= bytes[offset++] << 8;
|
||||
address |= bytes[offset++];
|
||||
address.address = bytes[offset++] << 16;
|
||||
address.address |= bytes[offset++] << 8;
|
||||
address.address |= bytes[offset++];
|
||||
|
||||
value = bytes[offset++] << 24;
|
||||
value |= bytes[offset++] << 16;
|
||||
|
@ -64,7 +65,7 @@ void Instruction::Branch::fromBytes(uint32_t offset, const std::vector<uint8_t>
|
|||
|
||||
std::string Instruction::Branch::toString() const {
|
||||
std::stringstream op;
|
||||
op << "BRANCH IF (" << getAddressRegisterName(address, addressOffset) << " & 0x" << std::hex << std::setw(8)
|
||||
op << "BRANCH IF (" << getAddressRegisterName(address) << " & 0x" << std::hex << std::setw(8)
|
||||
<< std::setfill('0') << mask << ")";
|
||||
if (equality) {
|
||||
op << " == ";
|
||||
|
@ -77,6 +78,28 @@ std::string Instruction::Branch::toString() const {
|
|||
return op.str();
|
||||
}
|
||||
|
||||
std::vector<Instruction::OutputFormat> Instruction::Branch::toOutputFormat(const OutputContext &context) const {
|
||||
return std::vector<OutputFormat>{
|
||||
OutputFormat{getAddress(), dynamic_cast<std::stringstream &>(std::stringstream("") << "BRANCH" << " "
|
||||
<< context.getAddressRegisterName(
|
||||
address)
|
||||
<< (equality ? " == "
|
||||
: " != ")).str()},
|
||||
OutputFormat{getAddress() + 4,
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << " VALUE 0x" << std::hex
|
||||
<< std::setw(8) << std::setfill('0')
|
||||
<< value).str()},
|
||||
OutputFormat{getAddress() + 8,
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << " MASK 0x" << std::hex
|
||||
<< std::setw(8) << std::setfill('0')
|
||||
<< mask).str()},
|
||||
OutputFormat{getAddress() + 12,
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << " JUMP_ADDRESS <"
|
||||
<< context.getLabel(jumpAddress)
|
||||
<< ">").str()},
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<uint32_t> Instruction::Branch::getPossibleBranches() const {
|
||||
return std::vector<uint32_t>{_endAddress, jumpAddress};
|
||||
}
|
||||
|
@ -85,35 +108,37 @@ std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
|
|||
Instruction::Branch::execute(AnalysisState &state) const {
|
||||
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>> branches;
|
||||
|
||||
uint32_t memoryOffset = state.getAddressOffset(addressOffset);
|
||||
|
||||
if ((state.getRegister(memoryOffset + address) & mask) == value) {
|
||||
if ((state.getRegister(address) & mask) == value) {
|
||||
state.current = equality ? jumpAddress : _endAddress;
|
||||
|
||||
std::unordered_map<uint32_t, uint32_t> branchedState;
|
||||
branchedState[memoryOffset + address] =
|
||||
state.getRegister(memoryOffset + address) | (equality ? ~value & mask : value);
|
||||
branchedState[state.getAddressWithOffset(address)] =
|
||||
state.getRegister(address) | (equality ? ~value & mask : value);
|
||||
branches.emplace_back(equality ? _endAddress : jumpAddress, std::move(branchedState));
|
||||
} else {
|
||||
state.current = equality ? _endAddress : jumpAddress;
|
||||
|
||||
std::unordered_map<uint32_t, uint32_t> branchedState;
|
||||
branchedState[memoryOffset + address] =
|
||||
state.getRegister(memoryOffset + address) | (equality ? value : ~value & mask);
|
||||
branchedState[state.getAddressWithOffset(address)] =
|
||||
state.getRegister(address) | (equality ? value : ~value & mask);
|
||||
branches.emplace_back(equality ? jumpAddress : _endAddress, std::move(branchedState));
|
||||
}
|
||||
|
||||
|
||||
state.addKnownJump(getEndAddress(), getAddress(), JumpKind::Continue);
|
||||
state.addKnownJump(jumpAddress, getAddress(), JumpKind::Branch);
|
||||
|
||||
return branches;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Instruction::Branch::toBytes() const {
|
||||
std::vector<uint8_t> bytes;
|
||||
|
||||
bytes.emplace_back((uint8_t) getCommand() | (equality << 2) | addressOffset);
|
||||
bytes.emplace_back((uint8_t) getCommand() | (equality << 2) | address.offset);
|
||||
|
||||
bytes.emplace_back((address >> 16) & 0xFF);
|
||||
bytes.emplace_back((address >> 8) & 0xFF);
|
||||
bytes.emplace_back(address & 0xFF);
|
||||
bytes.emplace_back((address.address >> 16) & 0xFF);
|
||||
bytes.emplace_back((address.address >> 8) & 0xFF);
|
||||
bytes.emplace_back(address.address & 0xFF);
|
||||
|
||||
bytes.emplace_back((value >> 24) & 0xFF);
|
||||
bytes.emplace_back((value >> 16) & 0xFF);
|
||||
|
|
|
@ -46,15 +46,16 @@ namespace Instruction {
|
|||
|
||||
std::string toString() const override;
|
||||
|
||||
std::vector<OutputFormat> toOutputFormat(const OutputContext &context) const override;
|
||||
|
||||
std::vector<uint32_t> getPossibleBranches() const override;
|
||||
|
||||
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
|
||||
execute(AnalysisState &state) const override;
|
||||
|
||||
|
||||
uint8_t addressOffset;
|
||||
uint8_t equality;
|
||||
uint32_t address;
|
||||
AddressWithOffset address;
|
||||
uint32_t value;
|
||||
uint32_t mask;
|
||||
uint32_t jumpAddress;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "../Registers.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include "../OutputContext.h"
|
||||
|
||||
void Instruction::Calc::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
|
||||
_address = offset;
|
||||
|
@ -92,6 +93,51 @@ std::string Instruction::Calc::toString() const {
|
|||
return op.str();
|
||||
}
|
||||
|
||||
std::vector<Instruction::OutputFormat> Instruction::Calc::toOutputFormat(const OutputContext &context) const {
|
||||
std::stringstream opname;
|
||||
switch (operation) {
|
||||
case Operation::AND:
|
||||
opname << "AND";
|
||||
break;
|
||||
case Operation::OR:
|
||||
opname << "OR";
|
||||
break;
|
||||
case Operation::ADD:
|
||||
opname << "ADD";
|
||||
break;
|
||||
case Operation::SUB:
|
||||
opname << "SUB";
|
||||
break;
|
||||
case Operation::LSHIFT:
|
||||
opname << "LSHIFT";
|
||||
break;
|
||||
case Operation::RSHIFT:
|
||||
opname << "RSHIFT";
|
||||
break;
|
||||
case Operation::ARSHIFT:
|
||||
opname << "ARSHIFT";
|
||||
break;
|
||||
case Operation::UNDEFINED:
|
||||
opname << "UNDEFINED";
|
||||
break;
|
||||
}
|
||||
|
||||
return std::vector<OutputFormat>{
|
||||
OutputFormat{getAddress(), dynamic_cast<std::stringstream &>(opname << " "
|
||||
<< context.getAddressRegisterName(
|
||||
addressDestination,
|
||||
addressOffset) << " = ").str()},
|
||||
OutputFormat{getAddress() + 4, dynamic_cast<std::stringstream &>(std::stringstream("") << " SOURCE "
|
||||
<< context.getAddressRegisterName(
|
||||
addressSource,
|
||||
addressOffset)).str()},
|
||||
OutputFormat{getAddress() + 8, dynamic_cast<std::stringstream &>(std::stringstream("") << " TARGET "
|
||||
<< context.getAddressRegisterName(
|
||||
addressTarget,
|
||||
addressOffset)).str()},
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<uint32_t> Instruction::Calc::getPossibleBranches() const {
|
||||
return std::vector<uint32_t>{_endAddress};
|
||||
}
|
||||
|
@ -132,6 +178,8 @@ Instruction::Calc::execute(AnalysisState &state) const {
|
|||
|
||||
state.current = _endAddress;
|
||||
|
||||
state.addKnownJump(getEndAddress(), getAddress(), JumpKind::Continue);
|
||||
|
||||
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,8 @@ namespace Instruction {
|
|||
|
||||
std::string toString() const override;
|
||||
|
||||
std::vector<OutputFormat> toOutputFormat(const OutputContext &context) const override;
|
||||
|
||||
std::vector<uint32_t> getPossibleBranches() const override;
|
||||
|
||||
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "../Registers.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include "../OutputContext.h"
|
||||
|
||||
void Instruction::CalcImm::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
|
||||
_address = offset;
|
||||
|
@ -92,6 +93,51 @@ std::string Instruction::CalcImm::toString() const {
|
|||
return op.str();
|
||||
}
|
||||
|
||||
std::vector<Instruction::OutputFormat> Instruction::CalcImm::toOutputFormat(const OutputContext &context) const {
|
||||
std::stringstream opname;
|
||||
switch (operation) {
|
||||
case Calc::Operation::AND:
|
||||
opname << "AND";
|
||||
break;
|
||||
case Calc::Operation::OR:
|
||||
opname << "OR";
|
||||
break;
|
||||
case Calc::Operation::ADD:
|
||||
opname << "ADD";
|
||||
break;
|
||||
case Calc::Operation::SUB:
|
||||
opname << "SUB";
|
||||
break;
|
||||
case Calc::Operation::LSHIFT:
|
||||
opname << "LSHIFT";
|
||||
break;
|
||||
case Calc::Operation::RSHIFT:
|
||||
opname << "RSHIFT";
|
||||
break;
|
||||
case Calc::Operation::ARSHIFT:
|
||||
opname << "ARSHIFT";
|
||||
break;
|
||||
case Calc::Operation::UNDEFINED:
|
||||
opname << "UNDEFINED";
|
||||
break;
|
||||
}
|
||||
|
||||
return std::vector<OutputFormat>{
|
||||
OutputFormat{getAddress(), dynamic_cast<std::stringstream &>(opname << "_IMM "
|
||||
<< context.getAddressRegisterName(
|
||||
addressDestination,
|
||||
addressOffset) << " = ").str()},
|
||||
OutputFormat{getAddress() + 4, dynamic_cast<std::stringstream &>(std::stringstream("") << " SOURCE "
|
||||
<< context.getAddressRegisterName(
|
||||
addressSource,
|
||||
addressOffset)).str()},
|
||||
OutputFormat{getAddress() + 8,
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << " TARGET 0x" << std::hex
|
||||
<< std::setw(8) << std::setfill('0')
|
||||
<< value).str()},
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<uint32_t> Instruction::CalcImm::getPossibleBranches() const {
|
||||
return std::vector<uint32_t>{_endAddress};
|
||||
}
|
||||
|
@ -131,6 +177,8 @@ Instruction::CalcImm::execute(AnalysisState &state) const {
|
|||
|
||||
state.current = _endAddress;
|
||||
|
||||
state.addKnownJump(getEndAddress(), getAddress(), JumpKind::Continue);
|
||||
|
||||
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,8 @@ namespace Instruction {
|
|||
|
||||
std::string toString() const override;
|
||||
|
||||
std::vector<OutputFormat> toOutputFormat(const OutputContext &context) const override;
|
||||
|
||||
std::vector<uint32_t> getPossibleBranches() const override;
|
||||
|
||||
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "../Registers.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include "../OutputContext.h"
|
||||
|
||||
void Instruction::Copy::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
|
||||
_address = offset;
|
||||
|
@ -36,18 +37,18 @@ void Instruction::Copy::fromBytes(uint32_t offset, const std::vector<uint8_t> &b
|
|||
uint32_t command = bytes[offset++];
|
||||
|
||||
count = (1 + ((command >> 4) & 0b11));
|
||||
addressOffsetBB = (command >> 2) & 0b11;
|
||||
addressOffsetAA = command & 0b11;
|
||||
addressBB.offset = (command >> 2) & 0b11;
|
||||
addressAA.offset = command & 0b11;
|
||||
|
||||
addressAA = bytes[offset++] << 16;
|
||||
addressAA |= bytes[offset++] << 8;
|
||||
addressAA |= bytes[offset++];
|
||||
addressAA.address = bytes[offset++] << 16;
|
||||
addressAA.address |= bytes[offset++] << 8;
|
||||
addressAA.address |= bytes[offset++];
|
||||
|
||||
offset++;
|
||||
|
||||
addressBB = bytes[offset++] << 16;
|
||||
addressBB |= bytes[offset++] << 8;
|
||||
addressBB |= bytes[offset++];
|
||||
addressBB.address = bytes[offset++] << 16;
|
||||
addressBB.address |= bytes[offset++] << 8;
|
||||
addressBB.address |= bytes[offset++];
|
||||
|
||||
|
||||
_endAddress = offset;
|
||||
|
@ -56,11 +57,24 @@ void Instruction::Copy::fromBytes(uint32_t offset, const std::vector<uint8_t> &b
|
|||
std::string Instruction::Copy::toString() const {
|
||||
std::stringstream op;
|
||||
op << "COPY " << std::dec << (uint32_t) count << " WORDS FROM "
|
||||
<< getAddressRegisterName(addressAA, addressOffsetAA) << " TO "
|
||||
<< getAddressRegisterName(addressBB, addressOffsetBB);
|
||||
<< getAddressRegisterName(addressAA) << " TO "
|
||||
<< getAddressRegisterName(addressBB);
|
||||
return op.str();
|
||||
}
|
||||
|
||||
std::vector<Instruction::OutputFormat> Instruction::Copy::toOutputFormat(const OutputContext &context) const {
|
||||
return std::vector<OutputFormat>{
|
||||
OutputFormat{getAddress(),
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << "COPY" << " " << std::dec
|
||||
<< (uint32_t) count << ", "
|
||||
<< context.getAddressRegisterName(
|
||||
addressAA)).str()},
|
||||
OutputFormat{getAddress() + 4, dynamic_cast<std::stringstream &>(std::stringstream("") << " TO "
|
||||
<< context.getAddressRegisterName(
|
||||
addressBB)).str()}
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<uint32_t> Instruction::Copy::getPossibleBranches() const {
|
||||
return std::vector<uint32_t>{_endAddress};
|
||||
}
|
||||
|
@ -68,15 +82,15 @@ std::vector<uint32_t> Instruction::Copy::getPossibleBranches() const {
|
|||
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
|
||||
Instruction::Copy::execute(AnalysisState &state) const {
|
||||
|
||||
uint32_t memoryOffsetAA = state.getAddressOffset(addressOffsetAA);
|
||||
uint32_t memoryOffsetBB = state.getAddressOffset(addressOffsetBB);
|
||||
|
||||
for (uint32_t i = 0; i < count; ++i) {
|
||||
state.setRegister(memoryOffsetAA + addressOffsetAA + i, state.getRegister(memoryOffsetBB + addressBB));
|
||||
state.setRegister(addressBB.offset + addressBB.address + i,
|
||||
state.getRegister(addressAA.offset + addressAA.address + i));
|
||||
}
|
||||
|
||||
state.current = _endAddress;
|
||||
|
||||
state.addKnownJump(getEndAddress(), getAddress(), JumpKind::Continue);
|
||||
|
||||
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
|
||||
}
|
||||
|
||||
|
@ -84,17 +98,17 @@ Instruction::Copy::execute(AnalysisState &state) const {
|
|||
std::vector<uint8_t> Instruction::Copy::toBytes() const {
|
||||
std::vector<uint8_t> bytes;
|
||||
|
||||
bytes.emplace_back((uint8_t) getCommand() | ((count - 1) << 4) | (addressOffsetBB << 2) | addressOffsetAA);
|
||||
bytes.emplace_back((uint8_t) getCommand() | ((count - 1) << 4) | (addressBB.offset << 2) | addressAA.offset);
|
||||
|
||||
bytes.emplace_back((addressAA >> 16) & 0xFF);
|
||||
bytes.emplace_back((addressAA >> 8) & 0xFF);
|
||||
bytes.emplace_back(addressAA & 0xFF);
|
||||
bytes.emplace_back((addressAA.address >> 16) & 0xFF);
|
||||
bytes.emplace_back((addressAA.address >> 8) & 0xFF);
|
||||
bytes.emplace_back(addressAA.address & 0xFF);
|
||||
|
||||
bytes.emplace_back(0);
|
||||
|
||||
bytes.emplace_back((addressBB >> 16) & 0xFF);
|
||||
bytes.emplace_back((addressBB >> 8) & 0xFF);
|
||||
bytes.emplace_back(addressBB & 0xFF);
|
||||
bytes.emplace_back((addressBB.address >> 16) & 0xFF);
|
||||
bytes.emplace_back((addressBB.address >> 8) & 0xFF);
|
||||
bytes.emplace_back(addressBB.address & 0xFF);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
|
|
@ -46,6 +46,8 @@ namespace Instruction {
|
|||
|
||||
std::string toString() const override;
|
||||
|
||||
std::vector<OutputFormat> toOutputFormat(const OutputContext &context) const override;
|
||||
|
||||
std::vector<uint32_t> getPossibleBranches() const override;
|
||||
|
||||
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
|
||||
|
@ -53,9 +55,7 @@ namespace Instruction {
|
|||
|
||||
|
||||
uint8_t count;
|
||||
uint8_t addressOffsetBB;
|
||||
uint8_t addressOffsetAA;
|
||||
uint32_t addressAA;
|
||||
uint32_t addressBB;
|
||||
AddressWithOffset addressAA;
|
||||
AddressWithOffset addressBB;
|
||||
};
|
||||
}
|
|
@ -26,6 +26,8 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#include "End.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
void Instruction::End::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
|
||||
_address = offset;
|
||||
|
@ -43,6 +45,12 @@ std::string Instruction::End::toString() const {
|
|||
return "END";
|
||||
}
|
||||
|
||||
std::vector<Instruction::OutputFormat> Instruction::End::toOutputFormat(const OutputContext &context) const {
|
||||
return std::vector<OutputFormat>{
|
||||
OutputFormat{getAddress(), "END"}
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<uint32_t> Instruction::End::getPossibleBranches() const {
|
||||
return std::vector<uint32_t>();
|
||||
}
|
||||
|
|
|
@ -46,6 +46,8 @@ namespace Instruction {
|
|||
|
||||
std::string toString() const override;
|
||||
|
||||
std::vector<OutputFormat> toOutputFormat(const OutputContext &context) const override;
|
||||
|
||||
std::vector<uint32_t> getPossibleBranches() const override;
|
||||
|
||||
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
|
||||
|
|
|
@ -77,6 +77,12 @@ std::string Instruction::Init::toString() const {
|
|||
return op.str();
|
||||
}
|
||||
|
||||
std::vector<Instruction::OutputFormat> Instruction::Init::toOutputFormat(const OutputContext &context) const {
|
||||
return std::vector<OutputFormat>{
|
||||
//TODO
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<uint32_t> Instruction::Init::getPossibleBranches() const {
|
||||
return std::vector<uint32_t>{_endAddress};
|
||||
}
|
||||
|
@ -89,6 +95,8 @@ Instruction::Init::execute(AnalysisState &state) const {
|
|||
|
||||
state.current = _endAddress;
|
||||
|
||||
state.addKnownJump(getEndAddress(), getAddress(), JumpKind::Continue);
|
||||
|
||||
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,8 @@ namespace Instruction {
|
|||
|
||||
std::string toString() const override;
|
||||
|
||||
std::vector<OutputFormat> toOutputFormat(const OutputContext &context) const override;
|
||||
|
||||
std::vector<uint32_t> getPossibleBranches() const override;
|
||||
|
||||
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
|
||||
|
|
|
@ -34,7 +34,13 @@
|
|||
#include <memory>
|
||||
#include "../AnalysisState.h"
|
||||
|
||||
class OutputContext;
|
||||
|
||||
namespace Instruction {
|
||||
typedef struct {
|
||||
uint32_t location;
|
||||
std::string format;
|
||||
} OutputFormat;
|
||||
|
||||
class Instruction {
|
||||
protected:
|
||||
|
@ -42,18 +48,6 @@ namespace Instruction {
|
|||
uint32_t _endAddress{};
|
||||
public:
|
||||
|
||||
/*Instruction(){
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
Instruction(const Instruction& instruction) : address(instruction.address), endAddress(instruction.endAddress), command(instruction.command), parameters(instruction.parameters){
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
enum class CommandOp : uint8_t {
|
||||
WRITE = 0b00000000,
|
||||
COPY = 0b01000000,
|
||||
|
@ -76,17 +70,14 @@ namespace Instruction {
|
|||
|
||||
static CommandOp getCommandFromByte(uint8_t command);
|
||||
|
||||
/*
|
||||
Instruction(uint32_t address, uint32_t command, std::vector<uint32_t> parameters) : address(address), command(command), parameters(std::move(parameters)), endAddress(0){
|
||||
|
||||
}*/
|
||||
|
||||
virtual void fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) = 0;
|
||||
|
||||
virtual std::vector<uint8_t> toBytes() const = 0;
|
||||
|
||||
virtual std::string toString() const = 0;
|
||||
|
||||
virtual std::vector<OutputFormat> toOutputFormat(const OutputContext &context) const = 0;
|
||||
|
||||
virtual std::vector<uint32_t> getPossibleBranches() const = 0;
|
||||
|
||||
virtual std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "../Registers.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include "../OutputContext.h"
|
||||
|
||||
void Instruction::Jump::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
|
||||
_address = offset;
|
||||
|
@ -50,6 +51,15 @@ std::string Instruction::Jump::toString() const {
|
|||
return op.str();
|
||||
}
|
||||
|
||||
std::vector<Instruction::OutputFormat> Instruction::Jump::toOutputFormat(const OutputContext &context) const {
|
||||
return std::vector<OutputFormat>{
|
||||
OutputFormat{getAddress(), dynamic_cast<std::stringstream &>(std::stringstream("") << "JUMP" << " <"
|
||||
<< context.getLabel(
|
||||
jumpAddress)
|
||||
<< ">").str()}
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<uint32_t> Instruction::Jump::getPossibleBranches() const {
|
||||
return std::vector<uint32_t>{jumpAddress};
|
||||
}
|
||||
|
@ -58,6 +68,8 @@ std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
|
|||
Instruction::Jump::execute(AnalysisState &state) const {
|
||||
state.current = jumpAddress;
|
||||
|
||||
state.addKnownJump(jumpAddress, getAddress(), JumpKind::Absolute);
|
||||
|
||||
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,8 @@ namespace Instruction {
|
|||
|
||||
std::string toString() const override;
|
||||
|
||||
std::vector<OutputFormat> toOutputFormat(const OutputContext &context) const override;
|
||||
|
||||
std::vector<uint32_t> getPossibleBranches() const override;
|
||||
|
||||
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "../Registers.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include "../OutputContext.h"
|
||||
|
||||
void Instruction::Load::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
|
||||
_address = offset;
|
||||
|
@ -111,6 +112,91 @@ std::string Instruction::Load::toString() const {
|
|||
return op.str();
|
||||
}
|
||||
|
||||
std::vector<Instruction::OutputFormat> Instruction::Load::toOutputFormat(const OutputContext &context) const {
|
||||
if (addressOffset == 0 && increment == 0 &&
|
||||
address == (uint32_t) KnownRegisters::PCIE_MASTER_SPICO_FIRMWARE_SPECIAL_REGISTER) {
|
||||
uint32_t offset = 0;
|
||||
|
||||
std::vector<OutputFormat> f{
|
||||
OutputFormat{getAddress() + offset++ * 4,
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << "LOAD"
|
||||
<< " PCIE_MASTER_SPICO_FIRMWARE").str()}
|
||||
};
|
||||
|
||||
f.emplace_back(OutputFormat{getAddress() + offset++ * 4,
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << " COUNT " << std::dec
|
||||
<< data.size()).str()});
|
||||
|
||||
for (auto d : data) {
|
||||
f.emplace_back(OutputFormat{getAddress() + offset * 4,
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << " 0x" << std::hex
|
||||
<< std::setw(8)
|
||||
<< std::setfill('0')
|
||||
<< d).str()});
|
||||
offset++;
|
||||
}
|
||||
|
||||
return f;
|
||||
} else if (addressOffset == 0 && increment == 0 &&
|
||||
address == (uint32_t) KnownRegisters::PCIE_BROADCAST_SERDES_FIRMWARE_SPECIAL_REGISTER) {
|
||||
uint32_t offset = 0;
|
||||
|
||||
std::vector<OutputFormat> f{
|
||||
OutputFormat{getAddress() + offset++ * 4,
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << "LOAD"
|
||||
<< " PCIE_BROADCAST_SERDES_FIRMWARE").str()},
|
||||
};
|
||||
|
||||
f.emplace_back(OutputFormat{getAddress() + offset++ * 4,
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << " COUNT " << std::dec
|
||||
<< data.size()).str()});
|
||||
|
||||
for (auto d : data) {
|
||||
f.emplace_back(OutputFormat{getAddress() + offset * 4,
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << " 0x" << std::hex
|
||||
<< std::setw(8)
|
||||
<< std::setfill('0')
|
||||
<< d).str()});
|
||||
offset++;
|
||||
}
|
||||
|
||||
return f;
|
||||
} else {
|
||||
uint32_t offset = 0;
|
||||
|
||||
std::vector<OutputFormat> f{
|
||||
OutputFormat{getAddress() + offset++ * 4,
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << "LOAD" << " "
|
||||
<< context.getAddressRegisterName(
|
||||
address, addressOffset)
|
||||
<< ", INC " << std::dec
|
||||
<< (uint32_t) increment).str()}
|
||||
};
|
||||
|
||||
f.emplace_back(OutputFormat{getAddress() + offset++ * 4,
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << " COUNT " << std::dec
|
||||
<< data.size()).str()});
|
||||
|
||||
for (auto d : data) {
|
||||
f.emplace_back(OutputFormat{getAddress() + offset * 4,
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << " "
|
||||
<< context.getAddressRegisterName(
|
||||
address +
|
||||
offset - 2,
|
||||
addressOffset)
|
||||
<< " = 0x" << std::hex
|
||||
<< std::setw(8)
|
||||
<< std::setfill('0')
|
||||
<< d).str()});
|
||||
offset++;
|
||||
}
|
||||
|
||||
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<uint32_t> Instruction::Load::getPossibleBranches() const {
|
||||
return std::vector<uint32_t>{_endAddress};
|
||||
}
|
||||
|
@ -132,6 +218,8 @@ Instruction::Load::execute(AnalysisState &state) const {
|
|||
|
||||
state.current = _endAddress;
|
||||
|
||||
state.addKnownJump(getEndAddress(), getAddress(), JumpKind::Continue);
|
||||
|
||||
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,8 @@ namespace Instruction {
|
|||
|
||||
std::string toString() const override;
|
||||
|
||||
std::vector<OutputFormat> toOutputFormat(const OutputContext &context) const override;
|
||||
|
||||
std::vector<uint32_t> getPossibleBranches() const override;
|
||||
|
||||
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "../Registers.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include "../OutputContext.h"
|
||||
|
||||
void Instruction::Loop::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
|
||||
_address = offset;
|
||||
|
@ -52,6 +53,19 @@ std::string Instruction::Loop::toString() const {
|
|||
return op.str();
|
||||
}
|
||||
|
||||
std::vector<Instruction::OutputFormat> Instruction::Loop::toOutputFormat(const OutputContext &context) const {
|
||||
return std::vector<OutputFormat>{
|
||||
OutputFormat{getAddress(), dynamic_cast<std::stringstream &>(std::stringstream("") << "LOOP" << " "
|
||||
<< context.getAddressRegisterName(
|
||||
(uint32_t) KnownRegisters::BSM_COUNTER_0 +
|
||||
counter, 0)
|
||||
<< ", <"
|
||||
<< context.getLabel(
|
||||
jumpAddress)
|
||||
<< ">").str()},
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<uint32_t> Instruction::Loop::getPossibleBranches() const {
|
||||
return std::vector<uint32_t>{_endAddress, jumpAddress};
|
||||
}
|
||||
|
@ -77,6 +91,9 @@ Instruction::Loop::execute(AnalysisState &state) const {
|
|||
branches.emplace_back(_endAddress, std::move(branchedState));
|
||||
}
|
||||
|
||||
state.addKnownJump(getEndAddress(), getAddress(), JumpKind::Continue);
|
||||
state.addKnownJump(jumpAddress, getAddress(), JumpKind::Loop);
|
||||
|
||||
return branches;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,8 @@ namespace Instruction {
|
|||
|
||||
std::string toString() const override;
|
||||
|
||||
std::vector<OutputFormat> toOutputFormat(const OutputContext &context) const override;
|
||||
|
||||
std::vector<uint32_t> getPossibleBranches() const override;
|
||||
|
||||
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "../Registers.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include "../OutputContext.h"
|
||||
|
||||
void Instruction::Poll::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
|
||||
_address = offset;
|
||||
|
@ -36,11 +37,11 @@ void Instruction::Poll::fromBytes(uint32_t offset, const std::vector<uint8_t> &b
|
|||
uint32_t command = bytes[offset++];
|
||||
|
||||
equality = (command >> 2) & 0b1;
|
||||
addressOffset = command & 0b11;
|
||||
address.offset = command & 0b11;
|
||||
|
||||
address = bytes[offset++] << 16;
|
||||
address |= bytes[offset++] << 8;
|
||||
address |= bytes[offset++];
|
||||
address.address = bytes[offset++] << 16;
|
||||
address.address |= bytes[offset++] << 8;
|
||||
address.address |= bytes[offset++];
|
||||
|
||||
value = bytes[offset++] << 24;
|
||||
value |= bytes[offset++] << 16;
|
||||
|
@ -70,7 +71,7 @@ void Instruction::Poll::fromBytes(uint32_t offset, const std::vector<uint8_t> &b
|
|||
|
||||
std::string Instruction::Poll::toString() const {
|
||||
std::stringstream op;
|
||||
op << "POLL IF (" << getAddressRegisterName(address, addressOffset) << " & 0x" << std::hex << std::setw(8)
|
||||
op << "POLL IF (" << getAddressRegisterName(address) << " & 0x" << std::hex << std::setw(8)
|
||||
<< std::setfill('0') << mask << ")";
|
||||
if (equality) {
|
||||
op << " != ";
|
||||
|
@ -84,6 +85,32 @@ std::string Instruction::Poll::toString() const {
|
|||
return op.str();
|
||||
}
|
||||
|
||||
std::vector<Instruction::OutputFormat> Instruction::Poll::toOutputFormat(const OutputContext &context) const {
|
||||
return std::vector<OutputFormat>{
|
||||
OutputFormat{getAddress(), dynamic_cast<std::stringstream &>(std::stringstream("") << "POLL" << " "
|
||||
<< context.getAddressRegisterName(
|
||||
address)
|
||||
<< (equality ? " == "
|
||||
: " != ")).str()},
|
||||
OutputFormat{getAddress() + 4,
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << " VALUE 0x" << std::hex
|
||||
<< std::setw(8) << std::setfill('0')
|
||||
<< value).str()},
|
||||
OutputFormat{getAddress() + 8,
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << " MASK 0x" << std::hex
|
||||
<< std::setw(8) << std::setfill('0')
|
||||
<< mask).str()},
|
||||
OutputFormat{getAddress() + 12,
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << " RETRY MAX " << std::dec
|
||||
<< maxRetry << " INTERVAL " << std::dec
|
||||
<< retryInterval).str()},
|
||||
OutputFormat{getAddress() + 16,
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << " JUMP_ADDRESS <"
|
||||
<< context.getLabel(jumpAddress)
|
||||
<< ">").str()},
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<uint32_t> Instruction::Poll::getPossibleBranches() const {
|
||||
return std::vector<uint32_t>{_endAddress, jumpAddress};
|
||||
}
|
||||
|
@ -92,35 +119,36 @@ std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
|
|||
Instruction::Poll::execute(AnalysisState &state) const {
|
||||
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>> branches;
|
||||
|
||||
uint32_t memoryOffset = state.getAddressOffset(addressOffset);
|
||||
|
||||
if ((state.getRegister(memoryOffset + address) & mask) == value) {
|
||||
if ((state.getRegister(address) & mask) == value) {
|
||||
state.current = equality ? _endAddress : jumpAddress;
|
||||
|
||||
std::unordered_map<uint32_t, uint32_t> branchedState;
|
||||
branchedState[memoryOffset + address] =
|
||||
state.getRegister(memoryOffset + address) | (equality ? value : ~value & mask);
|
||||
branchedState[state.getAddressWithOffset(address)] =
|
||||
state.getRegister(address) | (equality ? value : ~value & mask);
|
||||
branches.emplace_back(equality ? jumpAddress : _endAddress, std::move(branchedState));
|
||||
} else {
|
||||
state.current = equality ? jumpAddress : _endAddress;
|
||||
|
||||
std::unordered_map<uint32_t, uint32_t> branchedState;
|
||||
branchedState[memoryOffset + address] =
|
||||
state.getRegister(memoryOffset + address) | (equality ? ~value & mask : value);
|
||||
branchedState[state.getAddressWithOffset(address)] =
|
||||
state.getRegister(address) | (equality ? ~value & mask : value);
|
||||
branches.emplace_back(equality ? _endAddress : jumpAddress, std::move(branchedState));
|
||||
}
|
||||
|
||||
state.addKnownJump(getEndAddress(), getAddress(), JumpKind::Continue);
|
||||
state.addKnownJump(jumpAddress, getAddress(), JumpKind::Branch);
|
||||
|
||||
return branches;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Instruction::Poll::toBytes() const {
|
||||
std::vector<uint8_t> bytes;
|
||||
|
||||
bytes.emplace_back((uint8_t) getCommand() | (equality << 2) | addressOffset);
|
||||
bytes.emplace_back((uint8_t) getCommand() | (equality << 2) | address.offset);
|
||||
|
||||
bytes.emplace_back((address >> 16) & 0xFF);
|
||||
bytes.emplace_back((address >> 8) & 0xFF);
|
||||
bytes.emplace_back(address & 0xFF);
|
||||
bytes.emplace_back((address.address >> 16) & 0xFF);
|
||||
bytes.emplace_back((address.address >> 8) & 0xFF);
|
||||
bytes.emplace_back(address.address & 0xFF);
|
||||
|
||||
bytes.emplace_back((value >> 24) & 0xFF);
|
||||
bytes.emplace_back((value >> 16) & 0xFF);
|
||||
|
|
|
@ -46,15 +46,16 @@ namespace Instruction {
|
|||
|
||||
std::string toString() const override;
|
||||
|
||||
std::vector<OutputFormat> toOutputFormat(const OutputContext &context) const override;
|
||||
|
||||
std::vector<uint32_t> getPossibleBranches() const override;
|
||||
|
||||
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
|
||||
execute(AnalysisState &state) const override;
|
||||
|
||||
|
||||
uint8_t addressOffset;
|
||||
uint8_t equality;
|
||||
uint32_t address;
|
||||
AddressWithOffset address;
|
||||
uint32_t value;
|
||||
uint32_t mask;
|
||||
uint16_t maxRetry;
|
||||
|
|
|
@ -29,17 +29,18 @@
|
|||
#include "../Registers.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include "../OutputContext.h"
|
||||
|
||||
void Instruction::Return::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
|
||||
_address = offset;
|
||||
|
||||
uint8_t command = bytes[offset++];
|
||||
|
||||
addressOffset = command & 0b11;
|
||||
address.offset = command & 0b11;
|
||||
|
||||
address = bytes[offset++] << 16;
|
||||
address |= bytes[offset++] << 8;
|
||||
address |= bytes[offset++];
|
||||
address.address = bytes[offset++] << 16;
|
||||
address.address |= bytes[offset++] << 8;
|
||||
address.address |= bytes[offset++];
|
||||
|
||||
|
||||
_endAddress = offset;
|
||||
|
@ -47,22 +48,31 @@ void Instruction::Return::fromBytes(uint32_t offset, const std::vector<uint8_t>
|
|||
|
||||
std::string Instruction::Return::toString() const {
|
||||
std::stringstream op;
|
||||
op << "RETURN " << getAddressRegisterName(address, addressOffset);
|
||||
op << "RETURN " << getAddressRegisterName(address);
|
||||
|
||||
return op.str();
|
||||
}
|
||||
|
||||
std::vector<Instruction::OutputFormat> Instruction::Return::toOutputFormat(const OutputContext &context) const {
|
||||
return std::vector<OutputFormat>{
|
||||
OutputFormat{getAddress(), dynamic_cast<std::stringstream &>(std::stringstream("") << "RETURN" << " ["
|
||||
<< context.getAddressRegisterName(
|
||||
address)
|
||||
<< "]").str()}
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<uint32_t> Instruction::Return::getPossibleBranches() const {
|
||||
return std::vector<uint32_t>();
|
||||
}
|
||||
|
||||
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
|
||||
Instruction::Return::execute(AnalysisState &state) const {
|
||||
uint32_t memoryOffset = state.getAddressOffset(addressOffset);
|
||||
|
||||
uint32_t jumpAddress = state.getRegister(memoryOffset + address);
|
||||
uint32_t jumpAddress = state.getRegister(address);
|
||||
state.current = jumpAddress;
|
||||
|
||||
state.addKnownJump(jumpAddress, getAddress(), JumpKind::Return);
|
||||
|
||||
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
|
||||
}
|
||||
|
||||
|
@ -70,11 +80,11 @@ Instruction::Return::execute(AnalysisState &state) const {
|
|||
std::vector<uint8_t> Instruction::Return::toBytes() const {
|
||||
std::vector<uint8_t> bytes;
|
||||
|
||||
bytes.emplace_back((uint8_t) getCommand() | addressOffset);
|
||||
bytes.emplace_back((uint8_t) getCommand() | address.offset);
|
||||
|
||||
bytes.emplace_back((address >> 16) & 0xFF);
|
||||
bytes.emplace_back((address >> 8) & 0xFF);
|
||||
bytes.emplace_back(address & 0xFF);
|
||||
bytes.emplace_back((address.address >> 16) & 0xFF);
|
||||
bytes.emplace_back((address.address >> 8) & 0xFF);
|
||||
bytes.emplace_back(address.address & 0xFF);
|
||||
|
||||
return bytes;
|
||||
}
|
|
@ -46,12 +46,13 @@ namespace Instruction {
|
|||
|
||||
std::string toString() const override;
|
||||
|
||||
std::vector<OutputFormat> toOutputFormat(const OutputContext &context) const override;
|
||||
|
||||
std::vector<uint32_t> getPossibleBranches() const override;
|
||||
|
||||
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
|
||||
execute(AnalysisState &state) const override;
|
||||
|
||||
uint8_t addressOffset;
|
||||
uint32_t address;
|
||||
AddressWithOffset address;
|
||||
};
|
||||
}
|
|
@ -29,17 +29,18 @@
|
|||
#include "../Registers.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include "../OutputContext.h"
|
||||
|
||||
void Instruction::Set::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
|
||||
_address = offset;
|
||||
|
||||
uint8_t command = bytes[offset++];
|
||||
|
||||
addressOffset = command & 0b11;
|
||||
address.offset = command & 0b11;
|
||||
|
||||
address = bytes[offset++] << 16;
|
||||
address |= bytes[offset++] << 8;
|
||||
address |= bytes[offset++];
|
||||
address.address = bytes[offset++] << 16;
|
||||
address.address |= bytes[offset++] << 8;
|
||||
address.address |= bytes[offset++];
|
||||
|
||||
value = bytes[offset++] << 24;
|
||||
value |= bytes[offset++] << 16;
|
||||
|
@ -57,35 +58,51 @@ void Instruction::Set::fromBytes(uint32_t offset, const std::vector<uint8_t> &by
|
|||
|
||||
std::string Instruction::Set::toString() const {
|
||||
std::stringstream op;
|
||||
op << "SET " << getAddressRegisterName(address, addressOffset) << " = ("
|
||||
<< getAddressRegisterName(address, addressOffset) << " & ~0x" << std::hex << std::setw(8) << std::setfill('0')
|
||||
op << "SET " << getAddressRegisterName(address) << " = ("
|
||||
<< getAddressRegisterName(address) << " & ~0x" << std::hex << std::setw(8) << std::setfill('0')
|
||||
<< mask << ") | " << "0x" << std::hex << std::setw(8) << std::setfill('0') << value;
|
||||
return op.str();
|
||||
}
|
||||
|
||||
std::vector<Instruction::OutputFormat> Instruction::Set::toOutputFormat(const OutputContext &context) const {
|
||||
return std::vector<OutputFormat>{
|
||||
OutputFormat{getAddress(), dynamic_cast<std::stringstream &>(std::stringstream("") << "SET" << " "
|
||||
<< context.getAddressRegisterName(
|
||||
address)).str()},
|
||||
OutputFormat{getAddress() + 4,
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << " VALUE 0x" << std::hex
|
||||
<< std::setw(8) << std::setfill('0')
|
||||
<< value).str()},
|
||||
OutputFormat{getAddress() + 8,
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << " MASK 0x" << std::hex
|
||||
<< std::setw(8) << std::setfill('0')
|
||||
<< mask).str()}
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<uint32_t> Instruction::Set::getPossibleBranches() const {
|
||||
return std::vector<uint32_t>{_endAddress};
|
||||
}
|
||||
|
||||
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
|
||||
Instruction::Set::execute(AnalysisState &state) const {
|
||||
uint32_t memoryOffset = state.getAddressOffset(addressOffset);
|
||||
|
||||
state.setRegister(memoryOffset + address, (state.getRegister(memoryOffset + address) & ~mask) | value);
|
||||
state.setRegister(address, (state.getRegister(address) & ~mask) | value);
|
||||
|
||||
state.current = _endAddress;
|
||||
|
||||
state.addKnownJump(getEndAddress(), getAddress(), JumpKind::Continue);
|
||||
|
||||
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Instruction::Set::toBytes() const {
|
||||
std::vector<uint8_t> bytes;
|
||||
|
||||
bytes.emplace_back((uint8_t) getCommand() | addressOffset);
|
||||
bytes.emplace_back((uint8_t) getCommand() | address.offset);
|
||||
|
||||
bytes.emplace_back((address >> 16) & 0xFF);
|
||||
bytes.emplace_back((address >> 8) & 0xFF);
|
||||
bytes.emplace_back(address & 0xFF);
|
||||
bytes.emplace_back((address.address >> 16) & 0xFF);
|
||||
bytes.emplace_back((address.address >> 8) & 0xFF);
|
||||
bytes.emplace_back(address.address & 0xFF);
|
||||
|
||||
bytes.emplace_back((value >> 24) & 0xFF);
|
||||
bytes.emplace_back((value >> 16) & 0xFF);
|
||||
|
|
|
@ -46,13 +46,14 @@ namespace Instruction {
|
|||
|
||||
std::string toString() const override;
|
||||
|
||||
std::vector<OutputFormat> toOutputFormat(const OutputContext &context) const override;
|
||||
|
||||
std::vector<uint32_t> getPossibleBranches() const override;
|
||||
|
||||
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
|
||||
execute(AnalysisState &state) const override;
|
||||
|
||||
uint8_t addressOffset;
|
||||
uint32_t address;
|
||||
AddressWithOffset address;
|
||||
uint32_t value;
|
||||
uint32_t mask;
|
||||
};
|
||||
|
|
|
@ -50,6 +50,14 @@ std::string Instruction::Wait::toString() const {
|
|||
return op.str();
|
||||
}
|
||||
|
||||
std::vector<Instruction::OutputFormat> Instruction::Wait::toOutputFormat(const OutputContext &context) const {
|
||||
return std::vector<OutputFormat>{
|
||||
OutputFormat{getAddress(),
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << "WAIT" << " " << std::dec
|
||||
<< time).str()}
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<uint32_t> Instruction::Wait::getPossibleBranches() const {
|
||||
return std::vector<uint32_t>{_endAddress};
|
||||
}
|
||||
|
@ -60,6 +68,8 @@ Instruction::Wait::execute(AnalysisState &state) const {
|
|||
|
||||
state.current = _endAddress;
|
||||
|
||||
state.addKnownJump(getEndAddress(), getAddress(), JumpKind::Continue);
|
||||
|
||||
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,8 @@ namespace Instruction {
|
|||
|
||||
std::string toString() const override;
|
||||
|
||||
std::vector<OutputFormat> toOutputFormat(const OutputContext &context) const override;
|
||||
|
||||
std::vector<uint32_t> getPossibleBranches() const override;
|
||||
|
||||
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "../Registers.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include "../OutputContext.h"
|
||||
|
||||
void Instruction::Write::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
|
||||
_address = offset;
|
||||
|
@ -64,6 +65,35 @@ std::string Instruction::Write::toString() const {
|
|||
return op.str();
|
||||
}
|
||||
|
||||
std::vector<Instruction::OutputFormat> Instruction::Write::toOutputFormat(const OutputContext &context) const {
|
||||
uint32_t offset = 0;
|
||||
|
||||
std::vector<OutputFormat> f{
|
||||
OutputFormat{getAddress() + offset++ * 4,
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << "WRITE" << " "
|
||||
<< context.getAddressRegisterName(
|
||||
address, addressOffset) << ", "
|
||||
<< std::dec
|
||||
<< (uint32_t) data.size()).str()}
|
||||
};
|
||||
|
||||
for (auto d : data) {
|
||||
f.emplace_back(OutputFormat{getAddress() + offset * 4,
|
||||
dynamic_cast<std::stringstream &>(std::stringstream("") << " "
|
||||
<< context.getAddressRegisterName(
|
||||
address + offset -
|
||||
1, addressOffset)
|
||||
<< " = 0x" << std::hex
|
||||
<< std::setw(8)
|
||||
<< std::setfill('0')
|
||||
<< d).str()});
|
||||
offset++;
|
||||
}
|
||||
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> Instruction::Write::getPossibleBranches() const {
|
||||
return std::vector<uint32_t>{_endAddress};
|
||||
}
|
||||
|
@ -78,6 +108,10 @@ Instruction::Write::execute(AnalysisState &state) const {
|
|||
|
||||
state.current = _endAddress;
|
||||
|
||||
state.addKnownJump(getEndAddress(), getAddress(), JumpKind::Continue);
|
||||
|
||||
state.addKnownJump(getEndAddress(), getAddress(), JumpKind::Continue);
|
||||
|
||||
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
|
||||
}
|
||||
|
||||
|
|
|
@ -34,12 +34,6 @@
|
|||
namespace Instruction {
|
||||
class Write : public Instruction {
|
||||
public:
|
||||
Write(uint32_t address, uint8_t addressOffset, std::vector<uint32_t> data) : address(address),
|
||||
addressOffset(addressOffset),
|
||||
data(std::move(data)) {
|
||||
|
||||
}
|
||||
|
||||
Write() {
|
||||
|
||||
}
|
||||
|
@ -54,6 +48,8 @@ namespace Instruction {
|
|||
|
||||
std::string toString() const override;
|
||||
|
||||
std::vector<OutputFormat> toOutputFormat(const OutputContext &context) const override;
|
||||
|
||||
std::vector<uint32_t> getPossibleBranches() const override;
|
||||
|
||||
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
|
||||
|
|
283
src/main.cpp
283
src/main.cpp
|
@ -33,6 +33,7 @@
|
|||
#include "ImageFormat.h"
|
||||
#include "Registers.h"
|
||||
#include "instructions/Load.h"
|
||||
#include "OutputContext.h"
|
||||
|
||||
void decodeImage(const std::string &fileName) {
|
||||
|
||||
|
@ -54,21 +55,277 @@ void decodeImage(const std::string &fileName) {
|
|||
std::cout << k << "\n";
|
||||
}
|
||||
|
||||
OutputContext ctx(imageObject);
|
||||
|
||||
std::unordered_map<uint32_t, std::string> knownNames{
|
||||
{0x1000, "load_bootCfg_pep_serialNumber"},
|
||||
{0x1054, "load_bootCfg_customMac"},
|
||||
|
||||
{0x080600, "config_systimeClockSource"},
|
||||
{0x080700, "config_startClocks"},
|
||||
{0x080800, "config_pcie_pep_modes"},
|
||||
{0x080900, "config_pcie_pep_enable"},
|
||||
|
||||
{0x083000, "config_?serdes?_pep"},
|
||||
{0x084000, "reset_BSM_ARGS_init__ENTRYPOINT"},
|
||||
|
||||
|
||||
{0x085a0c, "config_pep0_offsets"},
|
||||
{0x085a58, "config_pep1_offsets"},
|
||||
{0x085aa4, "config_pep2_offsets"},
|
||||
{0x085af0, "config_pep3_offsets"},
|
||||
{0x085b3c, "config_pep4_offsets"},
|
||||
{0x085b88, "config_pep5_offsets"},
|
||||
{0x085bd4, "config_pep6_offsets"},
|
||||
{0x085c20, "config_pep7_offsets"},
|
||||
{0x085c6c, "config_pep8_offsets"},
|
||||
|
||||
{0x088000, "load_bootCfg_pep0_vpd"},
|
||||
{0x0881c7, "load_bootCfg_pep1_vpd"},
|
||||
{0x08838e, "load_bootCfg_pep2_vpd"},
|
||||
{0x088555, "load_bootCfg_pep3_vpd"},
|
||||
{0x08871c, "load_bootCfg_pep4_vpd"},
|
||||
{0x0888e3, "load_bootCfg_pep5_vpd"},
|
||||
{0x088aaa, "load_bootCfg_pep6_vpd"},
|
||||
{0x088c71, "load_bootCfg_pep7_vpd"},
|
||||
{0x088e38, "load_bootCfg_pep8_vpd"},
|
||||
|
||||
{0x089000, "load_bootCfg_systimeClockSource"},
|
||||
|
||||
{0x089010, "load_bootCfg_pep0_mode"},
|
||||
{0x089020, "load_bootCfg_pep2_mode"},
|
||||
{0x089030, "load_bootCfg_pep4_mode"},
|
||||
{0x089040, "load_bootCfg_pep6_mode"},
|
||||
|
||||
{0x089050, "load_bootCfg_pep0_enable"},
|
||||
{0x089060, "load_bootCfg_pep1_enable"},
|
||||
{0x089070, "load_bootCfg_pep2_enable"},
|
||||
{0x089080, "load_bootCfg_pep3_enable"},
|
||||
{0x089090, "load_bootCfg_pep4_enable"},
|
||||
{0x0890a0, "load_bootCfg_pep5_enable"},
|
||||
{0x0890b0, "load_bootCfg_pep6_enable"},
|
||||
{0x0890c0, "load_bootCfg_pep7_enable"},
|
||||
{0x0890d0, "load_bootCfg_pep8_enable"},
|
||||
|
||||
{0x0890e0, "load_bootCfg_GPIO_PIN14_DRIVE"},
|
||||
|
||||
{0x0890f0, "load_bootCfg_spiTransferMode"},
|
||||
{0x089100, "load_bootCfg_spiTransferSpeed"},
|
||||
|
||||
{0x089120, "load_bootCfg_skipPcieInitialization"},
|
||||
{0x089130, "load_bootCfg_pep_numberOfLanes"},
|
||||
|
||||
{0x0891f0, "load_bootCfg_pep_mgmtPep"},
|
||||
{0x089230, "load_bootCfg_pep_vendor_device"},
|
||||
{0x089260, "load_bootCfg_pep_subVendor_subDevice"},
|
||||
|
||||
{0x0892f0, "load_bootCfg_pep_gen"},
|
||||
|
||||
{0x089380, "load_bootCfg_pep_ASPMEnable"},
|
||||
|
||||
{0x0839fc, "lock_PCIE_SBUS_take"},
|
||||
{0x083aac, "lock_PCIE_SBUS_release"},
|
||||
|
||||
|
||||
{0x083900, "execute_SerialBus_PCIE_Command"},
|
||||
{0x080b00, "mark_SOFT_RESET_ClocksStable_ColdReset"},
|
||||
|
||||
{0x081100, "init_MASTER_SPICO"},
|
||||
{0x0812ac, "FAIL_init_MASTER_SPICO"},
|
||||
{0x08a004, "load_MASTER_SPICO_FW"},
|
||||
|
||||
{0x081400, "init_SERDES"},
|
||||
{0x081b8c, "FAIL_init_SERDES"},
|
||||
{0x08c004, "load_SERDES_FW"},
|
||||
|
||||
//Merge function
|
||||
{0x080004, ""},
|
||||
{0x080008, ""},
|
||||
{0x08000c, ""},
|
||||
{0x08001c, ""},
|
||||
{0x080038, ""},
|
||||
{0x080068, ""},
|
||||
|
||||
{0x0870c4, ""},
|
||||
|
||||
//Unknown
|
||||
{0x089110, "loc_089110_load_config_unknown_1"},
|
||||
{0x089160, "loc_089160_load_config_unknown_9"},
|
||||
{0x089190, "loc_089190_load_config_unknown_9"},
|
||||
{0x0891c0, "loc_0891c0_load_config_unknown_9"},
|
||||
{0x089220, "load_eeprom_major_version"},
|
||||
{0x089290, "loc_089290_load_config_unknown_9"},
|
||||
{0x0892c0, "loc_0892c0_load_config_unknown_9"},
|
||||
{0x089320, "loc_089320_load_config_unknown_9"},
|
||||
{0x089350, "loc_089350_load_config_unknown_9"},
|
||||
{0x0893b0, "load_bootCfg_skipPcieInitialization_skipMemRepair"},
|
||||
{0x080d00, "config_memRepair"},
|
||||
{0x0893c0, "load_pcie_clkmon_settings"},
|
||||
};
|
||||
|
||||
knownNames[imageObject.getHeader().baseAddress] = "__ENTRYPOINT";
|
||||
|
||||
std::unordered_map<uint32_t, std::string> comments{
|
||||
{0x080260, "Setting BSM_ARGS means this will be called again when reset, BSM_SCRATCH[0x149] is set to ~ 084000"},
|
||||
{0x084000, "XREF From BSM_ARGS"},
|
||||
|
||||
{0x080800, "Reset DEVICE_CFG to all 0"},
|
||||
{0x080828, "set DEVICE_CFG.PCIeMode[0] to 1x8 (default 2x4)"},
|
||||
{0x080850, "set DEVICE_CFG.PCIeMode[1] to 1x8 (default 2x4)"},
|
||||
{0x080878, "set DEVICE_CFG.PCIeMode[2] to 1x8 (default 2x4)"},
|
||||
{0x0808a0, "set DEVICE_CFG.PCIeMode[3] to 1x8 (default 2x4)"},
|
||||
{0x08061c, "set DEVICE_CFG.SystimeClockSource to IEEE1588_REFCLK (default PCIE_REFCLK)"},
|
||||
{0x080010, "set DEVICE_CFG.PCIeEnable[0..8] to enabled"},
|
||||
{0x083958, "set SBUS_PCIE_COMMAND.Op to READ [0x21]"},
|
||||
{0x083970, "set SBUS_PCIE_COMMAND.Op to WRITE [0x22]"},
|
||||
};
|
||||
|
||||
std::unordered_map<uint32_t, std::string> registerRename{
|
||||
{(uint32_t) KnownRegisters::MGMT_SCRATCH_0, "custom_RETURN_VALUE"},
|
||||
{(uint32_t) KnownRegisters::MGMT_SCRATCH_1, "custom_RETURN_TO"},
|
||||
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0, "api_SPI_LOCK_STATE"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 1, "api_PCIE_SBUS_LOCK_STATE"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 2, "api_SOFT_RESET_LOCK_STATE"},
|
||||
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 3, "api_RECOVERY_STATUS_VECTOR"},
|
||||
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 10, "api_PEP_MAC_BASE"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 100, "api_CUSTOM_MAC_BASE"},
|
||||
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x141, "custom_PEP_CONFIG_serial0"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x142, "custom_PEP_CONFIG_serial1"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x143, "custom_PEP_CONFIG_mgmtPep"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x144, "custom_PEP_CONFIG_vendor_device"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x145, "custom_PEP_CONFIG_subVendor_subDevice"},
|
||||
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x145, "custom_PEP_CONFIG_gen"},
|
||||
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x13c, "custom_PEP_CONFIG_numberOfLanes"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x17f, "custom_PEP_CONFIG_ASPMEnable"},
|
||||
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x139, "custom_PEP_ADDR_OFFSET"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x154, "custom_PEP_NUMBER"},
|
||||
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x12e, "param_SBUS_PCIE_REQUEST_-_SBUS_PCIE_RESPONSE"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x12f, "param_SBUS_PCIE_COMMAND_doWrite"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x130, "param_SBUS_PCIE_COMMAND.DeviceAddress"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x131, "param_SBUS_PCIE_COMMAND.Register"},
|
||||
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x132, "custom_param_RETURN_TO_SUCCESS"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x133, "custom_param_RETURN_TO_FAILURE"},
|
||||
|
||||
/**
|
||||
* api_BSM_STATUS: Step[0-7]
|
||||
*
|
||||
* Step 0x0D/0x0F: core = (bsmStatus >> 20 ) & 0xFFF;
|
||||
* Step 0x0E: Master version ((bsmStatus >> 24) & 0x1), Master CRC ((bsmStatus >> 20) & 0x1), Serdes version ((bsmStatus >> 24) & 0x2), Serdes CRC ((bsmStatus >> 20) & 0x2)
|
||||
* Step 0x11: host = (bsmStatus >> 16 ) & 0xF;
|
||||
*/
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x190, "api_BSM_STATUS"},
|
||||
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x191, "api_EEPROM_IMAGE_VERSION"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x192, "api_MASTER_FW_VERSION"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x193, "api_SERDES_FW_VERSION"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x194, "api_SERDES_STATUS_1"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x195, "api_SERDES_STATUS_2"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x196, "api_SERDES_STATUS_3"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x197, "api_SERDES_STATUS_4"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x198, "api_PCIE_MASTER_STATUS"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x199, "api_PCIE_SERDES_STATUS"},
|
||||
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1ae, "api_DE_COLD_RESET_STATUS"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1af, "api_SBUS_RESET_STATUS"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1b0, "api_MEMORY_REPAIR_STATUS"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1b1, "api_MEMORY_INIT_STATUS"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1b2, "api_PCIE_PCS_DIS_STATUS"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1b3, "api_PCIE_MASTER_FW_DL_STATUS"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1b4, "api_PCIE_FW_CHECK_STATUS"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1b5, "api_PCIE_SERDES_FW_DL_STATUS"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1b6, "api_PCIE_SERDES_INIT_STATUS"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1b7, "api_PCIE_PCS_EN_STATUS"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1b8, "api_PCIE_DE_WARM_RESET_STATUS"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1b9, "api_PCIE_ISR_STATUS_0"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1ba, "api_PCIE_ISR_STATUS_1"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1bb, "api_PCIE_ISR_STATUS_2"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1bc, "api_PCIE_ISR_STATUS_3"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1bd, "api_PCIE_ISR_STATUS_4"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1be, "api_PCIE_ISR_STATUS_5"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1bf, "api_PCIE_ISR_STATUS_6"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1c0, "api_PCIE_ISR_STATUS_7"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1c1, "api_PCIE_ISR_STATUS_8"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1c2, "api_SERDES_OOR_STATUS_PASS_1"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1c3, "api_SERDES_OOR_STATUS_PASS_2"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1c4, "api_SW_LOCK_ERR_STATUS"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1c5, "api_PCIE_EN_REFCLK_STATUS"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1c6, "api_RE_RESET_MASK_STATUS_1"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1c7, "api_RE_RESET_MASK_STATUS_2"},
|
||||
{(uint32_t) KnownRegisters::BSM_SCRATCH_START + 0x1c8, "api_RE_RESET_ERR_STATUS"},
|
||||
|
||||
};
|
||||
|
||||
for (auto &e : knownNames) {
|
||||
ctx.addMapping(e.first, e.second);
|
||||
}
|
||||
|
||||
for (auto &c : comments) {
|
||||
ctx.addComment(c.first, c.second);
|
||||
}
|
||||
|
||||
for(uint32_t i = 10; i < 200; ++i){
|
||||
if(registerRename.find((uint32_t) KnownRegisters::BSM_SCRATCH_START + i) == registerRename.end()){
|
||||
std::stringstream s;
|
||||
s << "api_MASK_BSM_CONFIG_" << std::dec << i;
|
||||
registerRename[(uint32_t) KnownRegisters::BSM_SCRATCH_START + i] = s.str();
|
||||
}
|
||||
}
|
||||
|
||||
for(uint32_t i = 400; i < 410; ++i){
|
||||
if(registerRename.find((uint32_t) KnownRegisters::BSM_SCRATCH_START + i) == registerRename.end()){
|
||||
std::stringstream s;
|
||||
s << "api_MASK_BSM_INIT_STATUS_" << std::dec << i;
|
||||
registerRename[(uint32_t) KnownRegisters::BSM_SCRATCH_START + i] = s.str();
|
||||
}
|
||||
}
|
||||
|
||||
for(uint32_t i = 430; i < 441; ++i){
|
||||
if(registerRename.find((uint32_t) KnownRegisters::BSM_SCRATCH_START + i) == registerRename.end()){
|
||||
std::stringstream s;
|
||||
s << "api_MASK_BSM_INIT_STATUS_ARCHIVE_" << std::dec << i;
|
||||
registerRename[(uint32_t) KnownRegisters::BSM_SCRATCH_START + i] = s.str();
|
||||
}
|
||||
}
|
||||
|
||||
for(uint32_t i = 450; i < 452; ++i){
|
||||
if(registerRename.find((uint32_t) KnownRegisters::BSM_SCRATCH_START + i) == registerRename.end()){
|
||||
std::stringstream s;
|
||||
s << "api_MASK_BSM_INIT_OOR_" << std::dec << i;
|
||||
registerRename[(uint32_t) KnownRegisters::BSM_SCRATCH_START + i] = s.str();
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &r : registerRename) {
|
||||
ctx.addRegister(r.first, r.second);
|
||||
}
|
||||
|
||||
ctx.analyze();
|
||||
|
||||
uint32_t prevAddress = 0;
|
||||
for (const auto &entry : imageObject.getInstructions()) {
|
||||
const auto &instruction = entry.second;
|
||||
if (instruction->getAddress() < prevAddress) {
|
||||
std::cout << "====== DECODE ERROR? ========== " << std::hex << std::setw(8) << std::setfill('0')
|
||||
std::cout << "========== DECODE ERROR? ========== " << std::hex << std::setw(8) << std::setfill('0')
|
||||
<< prevAddress << " - " << std::hex << std::setw(8) << std::setfill('0')
|
||||
<< instruction->getAddress() << "\n";
|
||||
} else if ((instruction->getAddress() - prevAddress) >= 4 &&
|
||||
(instruction->getAddress() - prevAddress) < 1024) {
|
||||
std::cout << "\n\n";
|
||||
for (uint32_t addr = prevAddress; addr < instruction->getAddress(); addr += 4) {
|
||||
std::stringstream op;
|
||||
std::string printable;
|
||||
op << std::hex << std::setw(8) << std::setfill('0') << addr << ": ";
|
||||
op << std::hex << std::setw(6) << std::setfill('0') << addr << " ";
|
||||
for (uint32_t i = 0; i < 4; ++i) {
|
||||
op << std::hex << std::setw(2) << std::setfill('0') << (uint32_t) bytes[addr + i];
|
||||
op << std::hex << std::setw(2) << std::setfill('0') << (uint32_t) bytes[addr + i] << " ";
|
||||
if (bytes[addr + i] >= 0x20 && bytes[addr + i] < 0x7F) {
|
||||
printable += bytes[addr + i];
|
||||
} else {
|
||||
|
@ -80,12 +337,17 @@ void decodeImage(const std::string &fileName) {
|
|||
std::cout << op.str();
|
||||
}
|
||||
} else if ((instruction->getAddress() - prevAddress) >= 1024) {
|
||||
std::cout << "================ " << std::hex << std::setw(8) << std::setfill('0') << prevAddress
|
||||
std::cout << "\n\n================ " << std::hex << std::setw(8) << std::setfill('0') << prevAddress
|
||||
<< " - " << std::hex << std::setw(8) << std::setfill('0') << instruction->getAddress()
|
||||
<< "\n";
|
||||
}
|
||||
std::cout << std::hex << std::setw(8) << std::setfill('0') << instruction->getAddress() << ": ";
|
||||
std::cout << instruction->toString() << "\n";
|
||||
|
||||
if (!ctx.getLabel(instruction->getAddress(), false).empty()) {
|
||||
std::cout << "\n\n; ================ FUNCTION " << ctx.getLabel(instruction->getAddress())
|
||||
<< " ================\n";
|
||||
}
|
||||
|
||||
std::cout << ctx.getInstructionString(*instruction);
|
||||
prevAddress = instruction->getEndAddress();
|
||||
}
|
||||
}
|
||||
|
@ -175,7 +437,7 @@ patchImage(const std::string &originalImage, const std::string &settingsFile, co
|
|||
// (BSM_ARGS = BSM_SCRATCH[0x149])
|
||||
|
||||
// 0x9110 LOAD 1 = 0x1 ???? do pcie init? IF 0: JUMP 0x081b78: OTHERWISE BIG BLOCK INIT?
|
||||
// 0x9120 LOAD 1 = 0x0 ???? IF 0: SOFT_RESET.EPLReset = 0, SOFT_RESET.SwitchReset = 0 (RESET) ELSE: JUMP 0x080464
|
||||
// 0x9120 LOAD 1 = 0x0 api.platform.config.switch.0.bootCfg.skipPcieInitialization
|
||||
//
|
||||
// ==0x9130 LOAD 9 api.platform.config.switch.0.bootCfg.pep.0.numberOfLanes
|
||||
// 0x9160 LOAD 9 0, 4, 0, 4 ... ???? BSM_SCRATCH[0x13d]
|
||||
|
@ -183,6 +445,7 @@ patchImage(const std::string &originalImage, const std::string &settingsFile, co
|
|||
// 0x91c0 LOAD 9 ???? BSM_SCRATCH[0x13f] IF 0: JUMP 0x084da0 ELSE: PCIE_CTRL.RxLaneflipEn = 1
|
||||
|
||||
// ==0x91f0 LOAD 9 bar4Allowed + api.platform.config.switch.0.bootCfg.mgmtPep
|
||||
// 0x9220 LOAD 1 = 0 EEPROM Major version (0x0222, 02.22 < first 0)
|
||||
// ==0x9230 LOAD 9 vendor/device
|
||||
// ==0x9260 LOAD 9 subVendor/subDevice
|
||||
|
||||
|
@ -193,7 +456,7 @@ patchImage(const std::string &originalImage, const std::string &settingsFile, co
|
|||
// 0x9350 LOAD 9 ???? BSM_SCRATCH[0x17e], (val & 0x000000ff) something PCIe value?
|
||||
// ==0x9380 LOAD 9 api.platform.config.switch.0.bootCfg.pep.0.ASPMEnable BSM_SCRATCH[0x17f] IF NOT 0: JUMP ELSE SET PCIE_CFG_PCIE_LINK_CAP.ActiveStateLinkPMSupport = 0
|
||||
//
|
||||
// 0x93b0 LOAD 1 = 0x00 ???? IF 0: JUMP 0x080d38 ELSE WRITE BSM_SCRATCH[0x1b0] = 0x41000c ???? DEAD code?
|
||||
// 0x93b0 LOAD 1 = 0x00 api.platform.config.switch.0.bootCfg.skipMemRepair
|
||||
// 0x93c0 LOAD 1 = 0x492550f0 PCIE_CLK_CTRL |= (value & 0xfffff0f0)
|
||||
// 0x93cc LOAD 1 = 0x0000000f PCIE_CLK_CTRL_2 = value & 0xf
|
||||
// 0x93d8 LOAD 1 = 0x00000064 PCIE_WARM_RESET_DELAY = value
|
||||
|
@ -254,7 +517,7 @@ patchImage(const std::string &originalImage, const std::string &settingsFile, co
|
|||
if (entry.type == Configuration::ConfigurationNode::Type::ValueText &&
|
||||
!entry.value.empty()) {
|
||||
auto value = entry.getEUI64ToInteger();
|
||||
if(value.first == 0xFFFFFFFF && value.second == 0xFFFFFFFF){
|
||||
if (value.first == 0xFFFFFFFF && value.second == 0xFFFFFFFF) {
|
||||
value.first &= 0xFF000100 | pepOffset;
|
||||
value.second &= 0x000000FF;
|
||||
}
|
||||
|
@ -280,7 +543,7 @@ patchImage(const std::string &originalImage, const std::string &settingsFile, co
|
|||
if (entry.type == Configuration::ConfigurationNode::Type::ValueText &&
|
||||
!entry.value.empty()) {
|
||||
auto value = entry.getEUI64ToInteger();
|
||||
if(value.first == 0xFFFFFFFF && value.second == 0xFFFFFFFF){
|
||||
if (value.first == 0xFFFFFFFF && value.second == 0xFFFFFFFF) {
|
||||
value.first &= 0xFF000100 | customMacOffset;
|
||||
value.second &= 0x000000FF;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue