Rewrite instructions to separate files, fix a few inconsistencies
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
DataHoarder 2020-12-22 00:31:39 +01:00
parent cc06f25ee4
commit 56bccd2168
38 changed files with 2835 additions and 1346 deletions

View file

@ -3,4 +3,27 @@ project(rrcSmall)
set(CMAKE_CXX_STANDARD 14)
add_executable(rrcSmall src/main.cpp src/ImageFormat.cpp src/ImageFormat.h src/SmallFirmwareFormat.cpp src/SmallFirmwareFormat.h)
add_executable(rrcSmall
src/main.cpp
src/ImageFormat.cpp src/ImageFormat.h
src/SmallFirmwareFormat.cpp src/SmallFirmwareFormat.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
src/instructions/Load.cpp src/instructions/Load.h
src/instructions/Init.cpp src/instructions/Init.h
src/instructions/Calc.cpp src/instructions/Calc.h
src/instructions/CalcImm.cpp src/instructions/CalcImm.h
src/instructions/Branch.cpp src/instructions/Branch.h
src/instructions/Poll.cpp src/instructions/Poll.h
src/instructions/Loop.cpp src/instructions/Loop.h
src/instructions/Jump.cpp src/instructions/Jump.h
src/instructions/Return.cpp src/instructions/Return.h
src/instructions/Set.cpp src/instructions/Set.h
src/instructions/Wait.cpp src/instructions/Wait.h
src/instructions/End.cpp src/instructions/End.h
src/Registers.cpp src/Registers.h
src/AnalysisState.cpp src/AnalysisState.h
)

37
src/AnalysisState.cpp Normal file
View file

@ -0,0 +1,37 @@
/*****************************************************************************
* 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 "AnalysisState.h"
#include "Registers.h"
uint32_t AnalysisState::getAddressOffset(uint8_t offsetEntry) const {
if(offsetEntry == 0){
return 0;
}
return getRegister((uint32_t)KnownRegisters::BSM_ADDR_OFFSET_0 + offsetEntry);
}

64
src/AnalysisState.h Normal file
View file

@ -0,0 +1,64 @@
/*****************************************************************************
* 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 "SmallFirmwareFormat.h"
class AnalysisState{
public:
std::unordered_map<uint32_t, uint32_t> memory;
uint32_t previous;
uint32_t current;
SmallFirmwareFormat pciSPICOFirmware;
SmallFirmwareFormat pciSerDesFirmware;
AnalysisState(uint32_t initial) : current(initial), previous(0){
}
AnalysisState(const AnalysisState& oldState) : current(oldState.current), previous(oldState.previous), memory(oldState.memory), pciSPICOFirmware(oldState.pciSPICOFirmware), pciSerDesFirmware(oldState.pciSerDesFirmware){
}
bool operator==(const AnalysisState &other) const{
return current == other.current && memory == other.memory;
}
void setRegister(uint32_t addr, uint32_t value){
memory[addr] = value;
}
uint32_t getRegister(uint32_t addr) const{
return memory.find(addr) == memory.end() ? 0 : memory.at(addr);
}
uint32_t getAddressOffset(uint8_t offsetEntry) const;
};

View file

@ -32,6 +32,10 @@
#include <queue>
#include <fstream>
#include "ImageFormat.h"
#include "Registers.h"
#include "instructions/Write.h"
const std::unique_ptr<Instruction::Instruction> ImageFormat::NULL_INSTRUCTION(nullptr);
ImageFormat ImageFormat::fromBytes(const std::vector<uint8_t>& imageBytes, bool prefetchInitialZone) {
ImageFormat image;
@ -100,18 +104,18 @@ ImageFormat ImageFormat::fromBytes(const std::vector<uint8_t>& imageBytes, bool
/*if(prefetchInitialZone){
offset = image.header.baseAddress;
Instruction::Command lastOp;
Instruction::CommandOp lastOp;
do{
auto instruction = Instruction::fromBytes(offset, image.baseImage);
offset = instruction.endAddress;
lastOp = instruction.getCommand();
if(instruction.getCommand() != Instruction::Command::NOP){
if(instruction.getCommand() != Instruction::CommandOp::NOP){
auto nextBranches = instruction.getPossibleBranches();
branches.insert(branches.end(), nextBranches.begin(), nextBranches.end());
image.instructions.push_back(std::move(instruction));
}
} while (lastOp != Instruction::Command::END && lastOp != Instruction::Command::NOP);
} while (lastOp != Instruction::CommandOp::END && lastOp != Instruction::CommandOp::NOP);
}else{*/
branches.push_back(image.header.baseAddress);
//}
@ -133,8 +137,6 @@ void ImageFormat::decodeAnalyzeInstructionsAt(uint32_t offset) {
savedStates.push(baseState);
std::unordered_map<uint32_t, Instruction> decodedInstructions;
uint32_t maxUnchangedExecutions = 1000;
uint32_t maxTotalExecutions = 20000;
@ -149,10 +151,9 @@ void ImageFormat::decodeAnalyzeInstructionsAt(uint32_t offset) {
if(state.current >= 0x100000 || state.current % 4 != 0){
break;
}else if(decodedInstructions.find(state.current) == decodedInstructions.end()){
auto decodedInstruction = Instruction::fromBytes(state.current, baseImage);
decodedInstructions[decodedInstruction.address] = decodedInstruction;
instructions.emplace_back(decodedInstruction);
}else if(findInstructionByAddress(state.current) == nullptr){
auto decodedInstruction = Instruction::Instruction::decodeInstructionFromBytes(state.current, baseImage);
instructions[decodedInstruction->getAddress()] = std::move(decodedInstruction);
}
if(loopsSinceLastModification > 800){
@ -163,18 +164,18 @@ void ImageFormat::decodeAnalyzeInstructionsAt(uint32_t offset) {
jumpsUsed[state.current] = true;
state.previous = state.current;
const auto& instruction = decodedInstructions[state.current];
auto& instruction = findInstructionByAddress(state.current);
state.current &= 0xfffffffc;
if(instruction.getCommand() == Instruction::Command::NOP){
if(instruction == nullptr || instruction->getCommand() == Instruction::Instruction::CommandOp::NOP){
break;
}
auto possibleBranches = instruction.execute(state);
auto possibleBranches = instruction->execute(state);
if((instruction.getCommand() == Instruction::Command::JUMP || instruction.getCommand() == Instruction::Command::RETURN) && jumpsUsed.find(instruction.endAddress) == jumpsUsed.end()){
jumpsUsed[instruction.endAddress] = false;
if((instruction->getCommand() == Instruction::Instruction::CommandOp::JUMP || instruction->getCommand() == Instruction::Instruction::CommandOp::RETURN) && jumpsUsed.find(instruction->getEndAddress()) == jumpsUsed.end()){
jumpsUsed[instruction->getEndAddress()] = false;
}
if(state.current == 0){
@ -182,24 +183,25 @@ void ImageFormat::decodeAnalyzeInstructionsAt(uint32_t offset) {
break;
}
if(instruction.getCommand() == Instruction::Command::JUMP){
auto previousInstruction = findInstructionByAddress(instruction.address - 1);
while (previousInstruction != nullptr){
const Instruction& prevInstructionRef = *previousInstruction;
if(previousInstruction->getCommand() == Instruction::Command::WRITE){
if(instruction->getCommand() == Instruction::Instruction::CommandOp::JUMP){
uint32_t nextAddress = instruction->getAddress() - 1;
while (true){
const auto& previousInstruction = findInstructionByAddress(nextAddress, true);
if(previousInstruction != nullptr && previousInstruction->getCommand() == Instruction::Instruction::CommandOp::WRITE){
const auto& writeInstruction = reinterpret_cast<const std::unique_ptr<Instruction::Write>&>(previousInstruction);
if(
(
previousInstruction->parameters[0] == (uint32_t)Instruction::KnownRegisters::MGMT_SCRATCH_1
|| (previousInstruction->parameters[0] >= (uint32_t)Instruction::KnownRegisters::BSM_SCRATCH_START && previousInstruction->parameters[0] < (uint32_t)Instruction::KnownRegisters::BSM_SCRATCH_END)
writeInstruction->address == (uint32_t)KnownRegisters::MGMT_SCRATCH_1
|| (writeInstruction->address >= (uint32_t)KnownRegisters::BSM_SCRATCH_START && writeInstruction->address < (uint32_t)KnownRegisters::BSM_SCRATCH_END)
)
&& previousInstruction->parameters.size() == 2
&& writeInstruction->data.size() == 1
){ //This is commonly used before jumps to mark return values or switch statements
if(jumpsUsed.find(previousInstruction->parameters[1]) == jumpsUsed.end()){
jumpsUsed[previousInstruction->parameters[1]] = false;
if(jumpsUsed.find(writeInstruction->data[0]) == jumpsUsed.end()){
jumpsUsed[writeInstruction->data[0]] = false;
}
}
previousInstruction = findInstructionByAddress(previousInstruction->address - 1);
nextAddress = previousInstruction->getAddress() - 1;
} else {
break;
}
@ -240,1103 +242,6 @@ 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: " << std::dec << decodedInstructions.size() << "\n";
std::cerr << "Next state, branched states left: " << std::dec << savedStates.size() << /*", executed states: " << std::dec << createdStates.size() <<*/ ", total instructions decoded: " << std::dec << instructions.size() << "\n";
}
struct by_address {
bool operator()(const ImageFormat::Instruction &a, const ImageFormat::Instruction &b) const {
return a.address < b.address;
}
};
std::sort(instructions.begin(), instructions.end(), by_address());
}
void ImageFormat::decodeInstructionsAt(const std::vector<uint32_t>& offset) {
std::vector<uint32_t> branches;
std::vector<std::pair<uint32_t,uint32_t>> possibleBranches;
branches.insert(branches.end(), offset.begin(), offset.end());
while (!branches.empty()){
uint32_t currentBranchOffset = branches.back();
branches.pop_back();
if(findInstructionByAddress(currentBranchOffset) != nullptr){
continue;
}
//std::cout << "BRANCH ADDR 0x" << std::hex << std::setw(8) << std::setfill('0') << currentBranchOffset << "\n";
if(currentBranchOffset < baseImage.size()){
auto instruction = Instruction::fromBytes(currentBranchOffset, baseImage);
if(instruction.getCommand() != Instruction::Command::NOP){
auto nextBranches = instruction.getPossibleBranches();
if(instruction.getCommand() == Instruction::Command::JUMP){ //Do additional checks to find plausible RETURN jump values
auto previousInstruction = findInstructionByAddress(instruction.address - 1);
while (previousInstruction != nullptr){
const Instruction& prevInstructionRef = *previousInstruction;
if(previousInstruction->getCommand() == Instruction::Command::WRITE){
if(
(
previousInstruction->parameters[0] == (uint32_t)Instruction::KnownRegisters::MGMT_SCRATCH_1
|| (previousInstruction->parameters[0] >= (uint32_t)Instruction::KnownRegisters::BSM_SCRATCH_START && previousInstruction->parameters[0] < (uint32_t)Instruction::KnownRegisters::BSM_SCRATCH_END)
)
&& previousInstruction->parameters.size() == 2
){ //This is commonly used before jumps to mark return values or switch statements
bool registerReturnExists = false;
for (const auto& ins : instructions){
if(ins.getCommand() == Instruction::Command::RETURN && ins.parameters[0] == previousInstruction->parameters[0]){
registerReturnExists = true;
break;
}
}
if(registerReturnExists){
branches.push_back(previousInstruction->parameters[1]);
}else{
possibleBranches.emplace_back(previousInstruction->parameters[0], previousInstruction->parameters[1]);
}
}
previousInstruction = findInstructionByAddress(previousInstruction->address - 1);
} else {
break;
}
}
}else if(instruction.getCommand() == Instruction::Command::RETURN){ //Find possible values, and if used, add to list to check
for(auto& entry : possibleBranches){
if(entry.first == instruction.parameters[0]){
branches.push_back(entry.second);
}
}
}
branches.insert(branches.end(), nextBranches.begin(), nextBranches.end());
instructions.push_back(std::move(instruction));
}
}
}
struct by_address {
bool operator()(const ImageFormat::Instruction &a, const ImageFormat::Instruction &b) const {
return a.address < b.address;
}
};
std::sort(instructions.begin(), instructions.end(), by_address());
}
ImageFormat::Instruction ImageFormat::Instruction::fromBytes(uint32_t offset, const std::vector<uint8_t>& bytes) {
Instruction instruction;
instruction.address = offset;
instruction.command = bytes[offset++];
switch (instruction.getCommand()) {
case Command::WRITE:
{
uint8_t len = 1 + (instruction.command >> 2) & 0b1111;
uint32_t arg;
arg = bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
while (len-- > 0){
arg = bytes[offset++] << 24;
arg |= bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
}
}
break;
case Command::COPY:
{
uint32_t arg;
arg = bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
offset++;
arg = bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
}
break;
case Command::LOAD:
{
uint32_t arg;
arg = bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
offset++;
//This prevents a value of 0 from underflowing below
int32_t count = bytes[offset++] << 16;
count |= bytes[offset++] << 8;
count |= bytes[offset++];
instruction.parameters.push_back(count);
while (count-- > 0){
arg = bytes[offset++] << 24;
arg |= bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
}
}
break;
case Command::INIT:
{
uint32_t arg;
arg = bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
offset++;
arg = bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
arg = bytes[offset++] << 24;
arg |= bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
arg = bytes[offset++] << 24;
arg |= bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
}
break;
case Command::CALC:
{
uint32_t arg;
arg = bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
offset++;
arg = bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
offset++;
arg = bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
}
break;
case Command::CALC_IMM:
{
uint32_t arg;
arg = bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
offset++;
arg = bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
arg = bytes[offset++] << 24;
arg |= bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
}
break;
case Command::BRANCH:
{
uint32_t arg;
arg = bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
arg = bytes[offset++] << 24;
arg |= bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
arg = bytes[offset++] << 24;
arg |= bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
offset++;
arg = bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
}
break;
case Command::POLL:
{
uint32_t arg;
arg = bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
arg = bytes[offset++] << 24;
arg |= bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
arg = bytes[offset++] << 24;
arg |= bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
arg = bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
arg = bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
offset++;
arg = bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
}
break;
case Command::LOOP:
{
uint32_t arg;
arg = bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
}
break;
case Command::JUMP:
{
uint32_t arg;
arg = bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
}
break;
case Command::RETURN:
{
uint32_t arg;
arg = bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
}
break;
case Command::SET:
{
uint32_t arg;
arg = bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
arg = bytes[offset++] << 24;
arg |= bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
arg = bytes[offset++] << 24;
arg |= bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
}
break;
case Command::WAIT:
{
uint32_t arg;
arg = bytes[offset++] << 16;
arg |= bytes[offset++] << 8;
arg |= bytes[offset++];
instruction.parameters.push_back(arg);
}
break;
case Command::END:
{
}
break;
case Command::NOP:
{
}
break;
}
while ((offset % 4) != 0){
offset++;
}
instruction.endAddress = offset;
return instruction;
}
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>> ImageFormat::Instruction::execute(AnalysisState& state) const {
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>> branches;
switch (getCommand()) {
case Command::WRITE:
{
uint32_t memoryOffset = state.getAddressOffset(command & 0b11);
uint32_t index = 0;
for (auto it = parameters.begin() + 1; it != parameters.end(); ++it) {
state.setRegister(memoryOffset + parameters[0] + index, *it);
index++;
}
state.current = endAddress;
}
break;
case Command::COPY:
{
uint32_t memoryOffsetAA = state.getAddressOffset(command & 0b11);
uint32_t memoryOffsetBB = state.getAddressOffset((command >> 2) & 0b11);
uint8_t words = (1 + ((command >> 4) & 0b11)) * 4;
for (uint32_t index = 0; index < words; ++index) {
state.setRegister(memoryOffsetAA + parameters[0] + index, state.getRegister(memoryOffsetBB + parameters[1] + index));
}
state.current = endAddress;
}
break;
case Command::LOAD:
{
uint32_t memoryOffset = state.getAddressOffset(command & 0b11);
uint8_t increment = ((command >> 2) & 0b1);
if((command & 0b11) == 0 && increment == 0 && parameters[0] == (uint32_t)KnownRegisters::PCIE_MASTER_SPICO_FIRMWARE_SPECIAL_REGISTER){
state.pciSPICOFirmware = SmallFirmwareFormat::fromBSMLoad(parameters, 2);
}else if((command & 0b11) == 0 && increment == 0 && parameters[0] == (uint32_t)KnownRegisters::PCIE_BROADCAST_SERDES_FIRMWARE_SPECIAL_REGISTER){
state.pciSerDesFirmware = SmallFirmwareFormat::fromBSMLoad(parameters, 2);
}else{
uint32_t index = 0;
for (auto it = parameters.begin() + 2; it != parameters.end(); ++it) {
state.setRegister(memoryOffset + parameters[0] + index, *it);
index += increment;
}
}
state.current = endAddress;
}
break;
case Command::INIT:
{
uint32_t memoryOffset = state.getAddressOffset(command & 0b11);
uint8_t increment = ((command >> 2) & 0b1);
for (uint32_t index = 0; index < parameters[1]; ++index) {
state.setRegister(memoryOffset + parameters[0] + (increment ? index : 0), state.getRegister(parameters[2] + parameters[3] * index));
}
state.current = endAddress;
}
break;
case Command::CALC:
{
uint32_t memoryOffset = state.getAddressOffset(command & 0b11);
uint8_t operation = ((command >> 2) & 0b111);
uint32_t v_a = state.getRegister(memoryOffset + parameters[1]);
uint32_t v_b = state.getRegister(memoryOffset + parameters[2]);
switch (operation) {
case 0:
state.setRegister(parameters[0], v_a & v_b);
break;
case 1:
state.setRegister(parameters[0], v_a | v_b);
break;
case 2:
state.setRegister(parameters[0], v_a + v_b);
break;
case 3:state.setRegister(parameters[0], v_a - v_b);
break;
case 4:state.setRegister(parameters[0], v_a << v_b);
break;
case 5:
state.setRegister(parameters[0], v_a >> v_b);
break;
case 6:
state.setRegister(parameters[0], (uint32_t)((int32_t)v_a >> v_b));
break;
case 7:
//TODO: Undefined?
break;
}
state.current = endAddress;
}
break;
case Command::CALC_IMM:
{
uint32_t memoryOffset = state.getAddressOffset(command & 0b11);
uint8_t operation = ((command >> 2) & 0b111);
uint32_t v_a = state.getRegister(memoryOffset + parameters[1]);
uint32_t v_b = parameters[2];
switch (operation) {
case 0:
state.setRegister(parameters[0], v_a & v_b);
break;
case 1:
state.setRegister(parameters[0], v_a | v_b);
break;
case 2:
state.setRegister(parameters[0], v_a + v_b);
break;
case 3:state.setRegister(parameters[0], v_a - v_b);
break;
case 4:state.setRegister(parameters[0], v_a << v_b);
break;
case 5:
state.setRegister(parameters[0], v_a >> v_b);
break;
case 6:
state.setRegister(parameters[0], (uint32_t)((int32_t)v_a >> v_b));
break;
case 7:
//TODO: Undefined?
break;
}
state.current = endAddress;
}
break;
case Command::BRANCH:
{
uint32_t memoryOffset = state.getAddressOffset(command & 0b11);
uint8_t equality = (command >> 2) & 0b1;
/*if((memoryOffset + parameters[3]) % 4 != 0){
state.current = 0;
} else {*/
if((state.getRegister(memoryOffset + parameters[0]) & parameters[2]) == parameters[1]){
state.current = equality ? parameters[3] : endAddress;
std::unordered_map<uint32_t, uint32_t> branchedState;
branchedState[memoryOffset + parameters[0]] = state.getRegister(memoryOffset + parameters[0]) | (equality ? ~parameters[1] & parameters[2] : parameters[1]);
branches.emplace_back(equality ? endAddress : parameters[3], std::move(branchedState));
}else{
state.current = equality ? endAddress : parameters[3];
std::unordered_map<uint32_t, uint32_t> branchedState;
branchedState[memoryOffset + parameters[0]] = state.getRegister(memoryOffset + parameters[0]) | (equality ? parameters[1] : ~parameters[1] & parameters[2]);
branches.emplace_back(equality ? parameters[3] : endAddress, std::move(branchedState));
}
//}
}
break;
case Command::POLL:
{
uint32_t memoryOffset = state.getAddressOffset(command & 0b11);
uint8_t equality = (command >> 2) & 0b1;
/*if((memoryOffset + parameters[5]) % 4 != 0){
state.current = 0;
} else {*/
if((state.getRegister(memoryOffset + parameters[0]) & parameters[2]) == parameters[1]){
state.current = equality ? endAddress : parameters[5];
std::unordered_map<uint32_t, uint32_t> branchedState;
branchedState[memoryOffset + parameters[0]] = state.getRegister(memoryOffset + parameters[0]) | (equality ? parameters[1] : ~parameters[1] & parameters[2]);
branches.emplace_back(equality ? parameters[5] : endAddress, std::move(branchedState));
}else{
state.current = equality ? parameters[5] : endAddress;
std::unordered_map<uint32_t, uint32_t> branchedState;
branchedState[memoryOffset + parameters[0]] = state.getRegister(memoryOffset + parameters[0]) | (equality ? ~parameters[1] & parameters[2] : parameters[1]);
branches.emplace_back(equality ? endAddress : parameters[5], std::move(branchedState));
}
//}
}
break;
case Command::LOOP:
{
uint32_t counterAddress = (uint32_t)KnownRegisters::BSM_COUNTER_0 + (command & 0b1);
/*if(parameters[0] % 4 != 0){
state.current = 0;
} else {*/
if(state.getRegister(counterAddress) == 0){
state.current = endAddress;
std::unordered_map<uint32_t, uint32_t> branchedState;
branchedState[counterAddress] = 1;
branches.emplace_back(parameters[0], std::move(branchedState));
}else{
state.current = parameters[0];
std::unordered_map<uint32_t, uint32_t> branchedState;
branchedState[counterAddress] = 0;
branches.emplace_back(endAddress, std::move(branchedState));
}
//}
}
break;
case Command::JUMP:
{
/*if(parameters[0] % 4 != 0){
state.current = 0;
} else {*/
state.current = parameters[0];
//}
}
break;
case Command::RETURN:
{
uint32_t memoryOffset = state.getAddressOffset(command & 0b11);
//TODO: is this maybe instead: state.getRegister(parameters[0]) + memoryOffset;
uint32_t jumpAddress = state.getRegister(memoryOffset + parameters[0]);
//std::cout << std::hex << address << ": RETURN @ " << getAddressRegisterName(parameters[0]) << " : 0x" << jumpAddress << "\n";
/*if(jumpAddress % 4 != 0){
state.current = 0;
} else {*/
state.current = jumpAddress;
//}
}
break;
case Command::SET:
{
uint32_t memoryOffset = state.getAddressOffset(command & 0b11);
state.setRegister(memoryOffset + parameters[0], (state.getRegister(memoryOffset + parameters[0]) & ~parameters[2]) | parameters[1]);
state.current = endAddress;
}
case Command::WAIT:
//TODO: do we even wait when simulating?
state.current = endAddress;
break;
case Command::END:
case Command::NOP:
state.current = 0;
break;
}
return branches;
}
std::vector<uint32_t> ImageFormat::Instruction::getPossibleBranches() const{
std::vector<uint32_t> branches;
switch (getCommand()) {
case Command::WRITE:
case Command::COPY:
case Command::LOAD:
case Command::INIT:
case Command::CALC:
case Command::CALC_IMM:
case Command::SET:
case Command::WAIT:
branches.push_back(endAddress);
break;
case Command::BRANCH:
branches.push_back(endAddress);
branches.push_back(parameters[3]);
break;
case Command::POLL:
branches.push_back(endAddress);
branches.push_back(parameters[5]);
break;
case Command::LOOP:
branches.push_back(endAddress);
branches.push_back(parameters[0]);
break;
case Command::JUMP:
branches.push_back(parameters[0]);
break;
case Command::RETURN:
break;
case Command::END:
case Command::NOP:
break;
}
return branches;
}
std::string ImageFormat::Instruction::toString() const{
std::stringstream op;
op << std::hex << std::setw(8) << std::setfill('0') << address << ": ";
switch (getCommand()) {
case Command::WRITE:
{
uint8_t offset = (command & 0b11);
op << "WRITE " << getAddressRegisterName(parameters[0]);
if(offset){
op << "(" << std::hex << std::setw(6) << std::setfill('0') << parameters[0] << ") + BSM_ADDR_OFFSET[" << std::dec << (uint32_t)offset << "]";
}
op << " = 0x";
for (auto it = parameters.begin() + 1; it != parameters.end(); ++it) {
op << std::hex << std::setw(parameters.size() == 2 ? 2 : 8) << std::setfill('0') << *it;
}
}
break;
case Command::COPY:
{
uint8_t offsetAA = (command & 0b11);
uint8_t offsetBB = ((command >> 2) & 0b11);
uint8_t words = (1 + ((command >> 4) & 0b11)) * 4;
op << "COPY " << (uint32_t) words << " BYTES FROM " << getAddressRegisterName(parameters[0]);
if(offsetAA){
op << "(" << std::hex << std::setw(6) << std::setfill('0') << parameters[0] << ") + BSM_ADDR_OFFSET[" << std::dec << (uint32_t)offsetAA << "]";
}
op << " TO " << getAddressRegisterName(parameters[1]);
if(offsetBB){
op << "(" << std::hex << std::setw(6) << std::setfill('0') << parameters[1] << ") + BSM_ADDR_OFFSET[" << std::dec << (uint32_t)offsetBB << "]";
}
}
break;
case Command::LOAD:
{
uint8_t offset = (command & 0b11);
uint8_t increment = ((command >> 2) & 0b1);
if(offset == 0 && increment == 0 && parameters[0] == (uint32_t)KnownRegisters::PCIE_MASTER_SPICO_FIRMWARE_SPECIAL_REGISTER){
op << "LOAD PCIE_MASTER_SPICO_FIRMWARE DATA 0x";
for (auto it = parameters.begin() + 2; it != parameters.end(); ++it) {
op << std::hex << std::setw(8) << std::setfill('0') << *it;
}
op << "\n";
auto fw = SmallFirmwareFormat::fromBSMLoad(parameters, 2);
uint32_t off = 0;
for (auto it = fw.firmware.begin(); it != fw.firmware.end(); ++it) {
op << " - SPICO_FW[" << std::hex << std::setw(4) << std::setfill('0') << off++ << "]";
op << " = 0x" << std::hex << std::setw(3) << std::setfill('0') << *it << "\n";
}
}else if(offset == 0 && increment == 0 && parameters[0] == (uint32_t)KnownRegisters::PCIE_BROADCAST_SERDES_FIRMWARE_SPECIAL_REGISTER){
op << "LOAD PCIE_BROADCAST_SERDES_FIRMWARE DATA 0x";
for (auto it = parameters.begin() + 2; it != parameters.end(); ++it) {
op << std::hex << std::setw(8) << std::setfill('0') << *it;
}
op << "\n";
auto fw = SmallFirmwareFormat::fromBSMLoad(parameters, 2);
uint32_t off = 0;
for (auto it = fw.firmware.begin(); it != fw.firmware.end(); ++it) {
op << " - SERDES_FW[" << std::hex << std::setw(4) << std::setfill('0') << off++ << "]";
op << " = 0x" << std::hex << std::setw(3) << std::setfill('0') << *it << "\n";
}
}else{
op << "LOAD INTO " << getAddressRegisterName(parameters[0]);
if(offset){
op << "(" << std::hex << std::setw(6) << std::setfill('0') << parameters[0] << ") + *BSM_ADDR_OFFSET[" << std::dec << (uint32_t)offset << "]";
}
if(parameters[1] > 1 && increment){
op << " UNTIL " << getAddressRegisterName(parameters[0] + (parameters[1] - 1));
if(offset){
op << "(" << std::hex << std::setw(6) << std::setfill('0') << parameters[0] + (parameters[1] - 1) << ") + *BSM_ADDR_OFFSET[" << std::dec << (uint32_t)offset << "]";
}
}
op << " INCREMENT " << std::dec << (uint32_t)increment;
op << " DATA 0x";
for (auto it = parameters.begin() + 2; it != parameters.end(); ++it) {
op << std::hex << std::setw(8) << std::setfill('0') << *it;
}
if(parameters[1] > 1){
op << "\n";
uint32_t off = 0;
for (auto it = parameters.begin() + 2; it != parameters.end(); ++it) {
op << " - " << getAddressRegisterName(parameters[0] + (increment ? off++ : 0));
if(offset){
op << "(" << std::hex << std::setw(6) << std::setfill('0') << parameters[0] + (increment ? off - 1 : 0) << ") + *BSM_ADDR_OFFSET[" << std::dec << (uint32_t)offset << "]";
}
op << " = 0x" << std::hex << std::setw(2) << std::setfill('0') << *it << "\n";
}
}
}
}
break;
case Command::INIT:
{
uint8_t offset = (command & 0b11);
uint8_t increment = ((command >> 2) & 0b1);
op << "INIT " << getAddressRegisterName(parameters[0]);
if(offset){
op << "(" << std::hex << std::setw(6) << std::setfill('0') << parameters[0] << ") + *BSM_ADDR_OFFSET[" << std::dec << (uint32_t)offset << "]";
}
op << " COUNT " << std::hex << std::setw(6) << std::setfill('0') << parameters[1];
op << " INCREMENT " << std::dec << (uint32_t)increment;
op << " DATA 0x" << std::hex << std::setw(8) << std::setfill('0') << parameters[2];
op << " INC 0x" << std::hex << std::setw(8) << std::setfill('0') << parameters[3];
}
break;
case Command::CALC:
{
uint8_t offset = (command & 0b11);
uint8_t operation = ((command >> 2) & 0b111);
op << "CALC " << getAddressRegisterName(parameters[0]);
if(offset){
op << "(" << std::hex << std::setw(6) << std::setfill('0') << parameters[0] << ") + *BSM_ADDR_OFFSET[" << std::dec << (uint32_t)offset << "]";
}
op << " = " << getAddressRegisterName(parameters[1]);
if(offset){
op << "(" << std::hex << std::setw(6) << std::setfill('0') << parameters[1] << ") + *BSM_ADDR_OFFSET[" << std::dec << (uint32_t)offset << "]";
}
op << " ";
switch (operation) {
case 0:
op << "&";
break;
case 1:
op << "|";
break;
case 2:
op << "+";
break;
case 3:
op << "-";
break;
case 4:
op << "<<";
break;
case 5:
op << ">>>";
break;
case 6:
op << ">>";
break;
case 7:
op << "UNDEFINED";
break;
}
op << " " << getAddressRegisterName(parameters[2]);
if(offset){
op << "(" << std::hex << std::setw(6) << std::setfill('0') << parameters[2] << ") + *BSM_ADDR_OFFSET[" << std::dec << (uint32_t)offset << "]";
}
}
break;
case Command::CALC_IMM:
{
uint8_t offset = (command & 0b11);
uint8_t operation = ((command >> 2) & 0b111);
op << "CALC_IMM " << getAddressRegisterName(parameters[0]);
if(offset){
op << "(" << std::hex << std::setw(6) << std::setfill('0') << parameters[0] << ") + *BSM_ADDR_OFFSET[" << std::dec << (uint32_t)offset << "]";
}
op << " = " << getAddressRegisterName(parameters[1]);
if(offset){
op << "(" << std::hex << std::setw(6) << std::setfill('0') << parameters[1] << ") + *BSM_ADDR_OFFSET[" << std::dec << (uint32_t)offset << "]";
}
op << " ";
switch (operation) {
case 0:
op << "&";
break;
case 1:
op << "|";
break;
case 2:
op << "+";
break;
case 3:
op << "-";
break;
case 4:
op << "<<";
break;
case 5:
op << ">>>";
break;
case 6:
op << ">>";
break;
case 7:
op << "UNDEFINED";
break;
}
op << " 0x" << std::hex << std::setw(2) << std::setfill('0') << parameters[2];
}
break;
case Command::BRANCH:
{
uint8_t equality = ((command >> 2) & 0b1);
uint8_t offset = (command & 0b11);
op << "BRANCH IF (" << getAddressRegisterName(parameters[0]);
if(offset){
op << "(" << std::hex << std::setw(6) << std::setfill('0') << parameters[0] << ") + *BSM_ADDR_OFFSET[" << std::dec << (uint32_t)offset << "]";
}
//op << " & ~0x" << std::hex << std::setw(8) << std::setfill('0') << parameters[2] << ")";
op << " & 0x" << std::hex << std::setw(8) << std::setfill('0') << parameters[2] << ")";
if(equality){
op << " == ";
}else{
op << " != ";
}
op << "0x" << std::hex << std::setw(2) << std::setfill('0') << parameters[1] << " JUMP 0x" << std::hex << std::setw(6) << std::setfill('0') << parameters[3];
}
break;
case Command::POLL:
{
uint8_t equality = ((command >> 2) & 0b1);
uint8_t offset = (command & 0b11);
op << "POLL IF (" << getAddressRegisterName(parameters[0]);
if(offset){
op << "(" << std::hex << std::setw(6) << std::setfill('0') << parameters[0] << ") + *BSM_ADDR_OFFSET[" << std::dec << (uint32_t)offset << "]";
}
//op << " & ~0x" << std::hex << std::setw(8) << std::setfill('0') << parameters[2] << ")";
op << " & 0x" << std::hex << std::setw(8) << std::setfill('0') << parameters[2] << ")";
if(equality){
op << " != ";
}else{
op << " == ";
}
op << "0x" << std::hex << std::setw(2) << std::setfill('0') << parameters[1] << " WAIT " << std::dec << parameters[4] << " MAX " << std::dec << parameters[3] << " EXCEED JUMP 0x" << std::hex << std::setw(6) << std::setfill('0') << parameters[3];
}
break;
case Command::LOOP:
{
uint8_t counter = (command & 0b1);
op << "LOOP IF BSM_COUNTER[" << std::dec << (uint32_t)counter << "] != 0 JUMP 0x" << std::hex << std::setw(6) << std::setfill('0') << parameters[0];
}
break;
case Command::JUMP:
op << "JUMP 0x" << std::hex << std::setw(6) << std::setfill('0') << parameters[0];
break;
case Command::RETURN:
{
uint8_t offset = (command & 0b11);
op << "RETURN " << getAddressRegisterName(parameters[0]);
//TODO: maybe other offset way?
if(offset){
op << "(" << std::hex << std::setw(6) << std::setfill('0') << parameters[0] << ") + *BSM_ADDR_OFFSET[" << std::dec << (uint32_t)offset << "]";
}
}
break;
case Command::SET:
{
uint8_t offset = (command & 0b11);
op << "SET " << getAddressRegisterName(parameters[0]);
if(offset){
op << "(" << std::hex << std::setw(6) << std::setfill('0') << parameters[0] << ") + *BSM_ADDR_OFFSET[" << std::dec << (uint32_t)offset << "]";
}
op << " = (" << getAddressRegisterName(parameters[0]);
if(offset){
op << "(" << std::hex << std::setw(6) << std::setfill('0') << parameters[0] << ") + *BSM_ADDR_OFFSET[" << std::dec << (uint32_t)offset << "]";
}
//op << " & ~0x" << std::hex << std::setw(8) << std::setfill('0') << parameters[2] << ") | 0x" << std::hex << std::setw(8) << std::setfill('0') << parameters[1];
op << " & 0x" << std::hex << std::setw(8) << std::setfill('0') << ~parameters[2] << ") | 0x" << std::hex << std::setw(2) << std::setfill('0') << parameters[1];
break;
}
case Command::WAIT:
op << "WAIT " << std::dec << parameters[0];
break;
case Command::END:
op << "END";
break;
case Command::NOP:
op << "NOP 0x" << std::hex << std::setw(2) << std::setfill('0') << command;
break;
}
return op.str();
}
std::string ImageFormat::Instruction::getRegisterName(ImageFormat::Instruction::KnownRegisters addr) {
if((uint32_t)addr >= (uint32_t)KnownRegisters::BSM_SCRATCH_START && (uint32_t)addr <= (uint32_t)KnownRegisters::BSM_SCRATCH_END){
std::stringstream s;
s << "BSM_SCRATCH[0x" << std::hex << std::setw(3) << std::setfill('0') << (((uint32_t)addr) - (uint32_t)KnownRegisters::BSM_SCRATCH_START) << "]";
return s.str();
}
switch (addr) {
case KnownRegisters::FATAL_CODE:
return "FATAL_CODE";
case KnownRegisters::LAST_FATAL_CODE:
return "LAST_FATAL_CODE";
case KnownRegisters::SOFT_RESET:
return "SOFT_RESET";
case KnownRegisters::DEVICE_CFG:
return "DEVICE_CFG";
case KnownRegisters::RESET_CFG:
return "RESET_CFG";
case KnownRegisters::WATCHDOG_CFG:
return "WATCHDOG_CFG";
case KnownRegisters::MGMT_SCRATCH_0:
return "MGMT_SCRATCH[0]";
case KnownRegisters::MGMT_SCRATCH_1:
return "MGMT_SCRATCH[1]";
case KnownRegisters::VITAL_PRODUCT_DATA:
return "VITAL_PRODUCT_DATA";
case KnownRegisters::GLOBAL_INTERRUPT_DETECT:
return "GLOBAL_INTERRUPT_DETECT";
case KnownRegisters::INTERRUPT_MASK_BSM:
return "INTERRUPT_MASK_BSM";
case KnownRegisters::CHIP_VERSION:
return "CHIP_VERSION";
case KnownRegisters::BSM_ARGS:
return "BSM_ARGS";
case KnownRegisters::BSM_ADDR_OFFSET_0:
return "BSM_ADDR_OFFSET[0]";
case KnownRegisters::BSM_ADDR_OFFSET_1:
return "BSM_ADDR_OFFSET[1]";
case KnownRegisters::BSM_ADDR_OFFSET_2:
return "BSM_ADDR_OFFSET[2]";
case KnownRegisters::BSM_ADDR_OFFSET_3:
return "BSM_ADDR_OFFSET[3]";
case KnownRegisters::BSM_COUNTER_0:
return "BSM_COUNTER[0]";
case KnownRegisters::BSM_COUNTER_1:
return "BSM_COUNTER[1]";
case KnownRegisters::PLL_PCIE_CTRL:
return "PLL_PCIE_CTRL";
case KnownRegisters::PLL_PCIE_STAT:
return "PLL_PCIE_STAT";
case KnownRegisters::PCIE_XPLL_CTRL:
return "PCIE_XPLL_CTRL";
case KnownRegisters::PCIE_CLK_CTRL:
return "PCIE_CLK_CTRL";
case KnownRegisters::PCIE_CLK_CTRL_2:
return "PCIE_CLK_CTRL_2";
case KnownRegisters::PLL_EPL_CTRL:
return "PLL_EPL_CTRL";
case KnownRegisters::PLL_EPL_STAT:
return "PLL_EPL_STAT";
case KnownRegisters::PLL_FABRIC_CTRL:
return "PLL_FABRIC_CTRL";
case KnownRegisters::PLL_FABRIC_STAT:
return "PLL_FABRIC_STAT";
case KnownRegisters::PLL_FABRIC_LOCK:
return "PLL_FABRIC_LOCK";
case KnownRegisters::SBUS_EPL_CFG:
return "SBUS_EPL_CFG";
case KnownRegisters::SBUS_EPL_COMMAND:
return "SBUS_EPL_COMMAND";
case KnownRegisters::SBUS_EPL_REQUEST:
return "SBUS_EPL_REQUEST";
case KnownRegisters::SBUS_EPL_RESPONSE:
return "SBUS_EPL_RESPONSE";
case KnownRegisters::SBUS_EPL_SPICO_IN:
return "SBUS_EPL_SPICO_IN";
case KnownRegisters::SBUS_EPL_SPICO_OUT:
return "SBUS_EPL_SPICO_OUT";
case KnownRegisters::SBUS_EPL_IP:
return "SBUS_EPL_IP";
case KnownRegisters::SBUS_EPL_IM:
return "SBUS_EPL_IM";
case KnownRegisters::PM_CLKOBS_CTRL:
return "PM_CLKOBS_CTRL";
case KnownRegisters::GPIO_CFG:
return "GPIO_CFG";
case KnownRegisters::GPIO_DATA:
return "GPIO_DATA";
case KnownRegisters::GPIO_IP:
return "GPIO_IP";
case KnownRegisters::GPIO_IM:
return "GPIO_IM";
case KnownRegisters::SBUS_PCIE_CFG:
return "SBUS_PCIE_CFG";
case KnownRegisters::SBUS_PCIE_COMMAND:
return "SBUS_PCIE_COMMAND";
case KnownRegisters::SBUS_PCIE_REQUEST:
return "SBUS_PCIE_REQUEST";
case KnownRegisters::SBUS_PCIE_RESPONSE:
return "SBUS_PCIE_RESPONSE";
case KnownRegisters::SBUS_PCIE_SPICO_IN:
return "SBUS_PCIE_SPICO_IN";
case KnownRegisters::SBUS_PCIE_SPICO_OUT:
return "SBUS_PCIE_SPICO_OUT";
case KnownRegisters::SBUS_PCIE_IP:
return "SBUS_PCIE_IP";
case KnownRegisters::SBUS_PCIE_IM:
return "SBUS_PCIE_IM";
case KnownRegisters::REI_CTRL:
return "REI_CTRL";
case KnownRegisters::REI_STAT:
return "REI_STAT";
case KnownRegisters::BIST_CTRL:
return "BIST_CTRL";
case KnownRegisters::PCIE_CLKMON_RATIO_CFG:
return "PCIE_CLKMON_RATIO_CFG";
case KnownRegisters::PCIE_CLKMON_TOLERANCE_CFG:
return "PCIE_CLKMON_TOLERANCE_CFG";
case KnownRegisters::PCIE_CLKMON_DEADLINES_CFG:
return "PCIE_CLKMON_DEADLINES_CFG";
case KnownRegisters::PCIE_CLK_STAT:
return "PCIE_CLK_STAT";
case KnownRegisters::PCIE_CLK_IP:
return "PCIE_CLK_IP";
case KnownRegisters::PCIE_CLK_IM:
return "PCIE_CLK_IM";
case KnownRegisters::PCIE_WARM_RESET_DELAY:
return "PCIE_WARM_RESET_DELAY";
default:
break;
}
std::stringstream s;
s << "register[0x" << std::hex << std::setw(6) << std::setfill('0') << (uint32_t)addr << "]";
return s.str();
}
uint32_t ImageFormat::AnalysisState::getAddressOffset(uint8_t offsetEntry) const {
if(offsetEntry == 0){
return 0;
}
return getRegister((uint32_t)ImageFormat::Instruction::KnownRegisters::BSM_ADDR_OFFSET_0 + offsetEntry);
}
}

View file

@ -30,218 +30,15 @@
#include <utility>
#include <vector>
#include <cstdint>
#include <unordered_map>
#include <map>
#include "SmallFirmwareFormat.h"
#include "instructions/Instruction.h"
class ImageFormat{
public:
class AnalysisState{
public:
std::unordered_map<uint32_t, uint32_t> memory;
uint32_t previous;
uint32_t current;
SmallFirmwareFormat pciSPICOFirmware;
SmallFirmwareFormat pciSerDesFirmware;
AnalysisState(uint32_t initial) : current(initial), previous(0){
}
AnalysisState(const AnalysisState& oldState) : current(oldState.current), previous(oldState.previous), memory(oldState.memory), pciSPICOFirmware(oldState.pciSPICOFirmware), pciSerDesFirmware(oldState.pciSerDesFirmware){
}
bool operator==(const AnalysisState &other) const{
return current == other.current && memory == other.memory;
}
void setRegister(uint32_t addr, uint32_t value){
memory[addr] = value;
}
uint32_t getRegister(uint32_t addr) const{
return memory.find(addr) == memory.end() ? 0 : memory.at(addr);
}
uint32_t getAddressOffset(uint8_t offsetEntry) const;
};
class Instruction{
public:
Instruction(){
}
Instruction(const Instruction& instruction) : address(instruction.address), endAddress(instruction.endAddress), command(instruction.command), parameters(instruction.parameters){
}
enum class KnownRegisters : uint32_t {
PCIE_MASTER_SPICO_FIRMWARE_SPECIAL_REGISTER = 0x0,
FATAL_CODE = 0x0,
PCIE_BROADCAST_SERDES_FIRMWARE_SPECIAL_REGISTER = 0x1,
LAST_FATAL_CODE = 0x1,
SOFT_RESET = 0x3,
DEVICE_CFG = 0x4,
RESET_CFG = 0x5,
WATCHDOG_CFG = 0x6,
MGMT_SCRATCH_0 = 0x8,
MGMT_SCRATCH_1 = MGMT_SCRATCH_0 + 1,
VITAL_PRODUCT_DATA = 0x304,
GLOBAL_INTERRUPT_DETECT = 0x400,
INTERRUPT_MASK_BSM = 0x442,
CHIP_VERSION = 0x452,
BSM_SCRATCH_START = 0x800,
BSM_SCRATCH_END = BSM_SCRATCH_START + 0x400 - 1,
BSM_ARGS = 0x000C01,
BSM_ADDR_OFFSET_0 = 0x000C04,
BSM_ADDR_OFFSET_1 = BSM_ADDR_OFFSET_0 + 1,
BSM_ADDR_OFFSET_2 = BSM_ADDR_OFFSET_0 + 2,
BSM_ADDR_OFFSET_3 = BSM_ADDR_OFFSET_0 + 3,
BSM_COUNTER_0 = 0x000C08,
BSM_COUNTER_1 = BSM_COUNTER_0 + 1,
BIST_CTRL = 0x000C10,
REI_CTRL = 0x000C12,
REI_STAT = 0x000C13,
GPIO_CFG = 0x000C15,
GPIO_DATA = 0x000C16,
GPIO_IP = 0x000C17,
GPIO_IM = 0x000C18,
PLL_PCIE_CTRL = 0x2241,
PLL_PCIE_STAT = 0x2242,
SBUS_PCIE_CFG = 0x2243,
SBUS_PCIE_COMMAND = 0x2244,
SBUS_PCIE_REQUEST = 0x2245,
SBUS_PCIE_RESPONSE = 0x2246,
SBUS_PCIE_SPICO_IN = 0x2247,
SBUS_PCIE_SPICO_OUT = 0x2248,
SBUS_PCIE_IP = 0x2249,
SBUS_PCIE_IM = 0x224a,
PCIE_XPLL_CTRL = 0x3000,
PCIE_CLK_CTRL = 0x3001,
PCIE_CLK_CTRL_2 = 0x3002,
PCIE_CLKMON_RATIO_CFG = 0x3003,
PCIE_CLKMON_TOLERANCE_CFG = 0x3004,
PCIE_CLKMON_DEADLINES_CFG = 0x3005,
PCIE_CLK_STAT = 0x3006,
PCIE_CLK_IP = 0x3007,
PCIE_CLK_IM = 0x3008,
PCIE_WARM_RESET_DELAY = 0x3009,
PORTS_MGMT_BASE_ADDRESS = 0xE8000,
PLL_EPL_CTRL = PORTS_MGMT_BASE_ADDRESS + 0x0,
PLL_EPL_STAT = PORTS_MGMT_BASE_ADDRESS + 0x1,
PLL_FABRIC_CTRL = PORTS_MGMT_BASE_ADDRESS + 0x2,
PLL_FABRIC_STAT = PORTS_MGMT_BASE_ADDRESS + 0x3,
PLL_FABRIC_LOCK = PORTS_MGMT_BASE_ADDRESS + 0x4,
SBUS_EPL_CFG = PORTS_MGMT_BASE_ADDRESS + 0x5,
SBUS_EPL_COMMAND = PORTS_MGMT_BASE_ADDRESS + 0x6,
SBUS_EPL_REQUEST = PORTS_MGMT_BASE_ADDRESS + 0x7,
SBUS_EPL_RESPONSE = PORTS_MGMT_BASE_ADDRESS + 0x8,
SBUS_EPL_SPICO_IN = PORTS_MGMT_BASE_ADDRESS + 0x9,
SBUS_EPL_SPICO_OUT = PORTS_MGMT_BASE_ADDRESS + 0xa,
SBUS_EPL_IP = PORTS_MGMT_BASE_ADDRESS + 0xb,
SBUS_EPL_IM = PORTS_MGMT_BASE_ADDRESS + 0xc,
PM_CLKOBS_CTRL = PORTS_MGMT_BASE_ADDRESS + 0x12,
PCIE_PF_BASE_ADDRESS = 0x100000,
NOP = 0xFFFFFFFF
};
static std::string getAddressRegisterName(uint32_t addr){
return getRegisterName(static_cast<KnownRegisters>(addr));
}
static std::string getRegisterName(KnownRegisters addr);
enum class Command : uint8_t {
WRITE = 0,
COPY,
LOAD,
INIT,
CALC,
CALC_IMM,
BRANCH,
POLL,
LOOP,
JUMP,
RETURN,
SET,
WAIT,
END,
NOP = 0xFF
};
uint32_t address;
uint32_t endAddress;
uint32_t command;
std::vector<uint32_t> parameters;
static Instruction fromBytes(uint32_t offset, const std::vector<uint8_t>& bytes);
Instruction(uint32_t address, uint32_t command, std::vector<uint32_t> parameters) : address(address), command(command), parameters(std::move(parameters)), endAddress(0){
}
std::string toString() const;
std::vector<uint32_t> getPossibleBranches() const;
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>> execute(AnalysisState& state) const;
Command getCommand() const{
if(((command >> 6) & 0b11) == 0b00){
return Command::WRITE;
}else if(((command >> 6) & 0b11) == 0b01){
return Command::COPY;
}else if(((command >> 3) & 0b11111) == 0b11000){
return Command::LOAD;
}else if(((command >> 3) & 0b11111) == 0b11001){
return Command::INIT;
}else if(((command >> 5) & 0b111) == 0b100){
return Command::CALC;
}else if(((command >> 5) & 0b111) == 0b101){
return Command::CALC_IMM;
}else if(((command >> 3) & 0b11111) == 0b11010){
return Command::BRANCH;
}else if(((command >> 3) & 0b11111) == 0b11011){
return Command::POLL;
}else if(((command >> 1) & 0b1111111) == 0b1110000){
return Command::LOOP;
}else if(command == 0b11101000){
return Command::JUMP;
}else if(((command >> 2) & 0b111111) == 0b111100){
return Command::RETURN;
}else if(((command >> 2) & 0b111111) == 0b111110){
return Command::SET;
}else if(command == 0xFE){
return Command::WAIT;
}else if(command == 0xFF){
return Command::END;
}
return Command::NOP;
}
};
enum class HeaderSpeed : uint8_t {
SPEED_390_KHZ = 0,
SPEED_780_KHZ,
@ -263,17 +60,29 @@ public:
static ImageFormat fromBytes(const std::vector<uint8_t>& image, bool prefetchInitialZone = false);
void decodeInstructionsAt(const std::vector<uint32_t>& offset);
void decodeAnalyzeInstructionsAt(uint32_t offset);
const Instruction* findInstructionByAddress(uint32_t addr){
for(const auto& instruction : instructions){
if((instruction.endAddress == 0 && addr == instruction.address ) || (instruction.endAddress != 0 && addr >= instruction.address && addr < instruction.endAddress)){
return &instruction;
const std::unique_ptr<Instruction::Instruction>& findInstructionByAddress(uint32_t addr, bool indirect = false){
if(instructions.find(addr) != instructions.end()){
return instructions.find(addr)->second;
}
if(indirect){
for(const 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 nullptr;
return NULL_INSTRUCTION;
}
ImageFormat(){
@ -308,6 +117,8 @@ private:
static const int CFG_HEADER = 0x4 << 2;
static const int CFG_LENGTH = 16;
static const std::unique_ptr<Instruction::Instruction> NULL_INSTRUCTION;
struct {
uint8_t length : 8;
uint32_t base : 24;
@ -321,7 +132,7 @@ private:
std::vector<std::string> bootConfig;
std::vector<Instruction> instructions;
std::map<uint32_t, std::unique_ptr<Instruction::Instruction>> instructions;
std::vector<uint8_t> baseImage;
};

179
src/Registers.cpp Normal file
View file

@ -0,0 +1,179 @@
/*****************************************************************************
* 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 <iostream>
#include <sstream>
#include <iomanip>
#include "Registers.h"
std::string getRegisterName(KnownRegisters addr) {
if((uint32_t)addr >= (uint32_t)KnownRegisters::BSM_SCRATCH_START && (uint32_t)addr <= (uint32_t)KnownRegisters::BSM_SCRATCH_END){
std::stringstream s;
s << "BSM_SCRATCH[0x" << std::hex << std::setw(3) << std::setfill('0') << (((uint32_t)addr) - (uint32_t)KnownRegisters::BSM_SCRATCH_START) << "]";
return s.str();
}
switch (addr) {
case KnownRegisters::FATAL_CODE:
return "FATAL_CODE";
case KnownRegisters::LAST_FATAL_CODE:
return "LAST_FATAL_CODE";
case KnownRegisters::SOFT_RESET:
return "SOFT_RESET";
case KnownRegisters::DEVICE_CFG:
return "DEVICE_CFG";
case KnownRegisters::RESET_CFG:
return "RESET_CFG";
case KnownRegisters::WATCHDOG_CFG:
return "WATCHDOG_CFG";
case KnownRegisters::MGMT_SCRATCH_0:
return "MGMT_SCRATCH[0]";
case KnownRegisters::MGMT_SCRATCH_1:
return "MGMT_SCRATCH[1]";
case KnownRegisters::VITAL_PRODUCT_DATA:
return "VITAL_PRODUCT_DATA";
case KnownRegisters::GLOBAL_INTERRUPT_DETECT:
return "GLOBAL_INTERRUPT_DETECT";
case KnownRegisters::INTERRUPT_MASK_BSM:
return "INTERRUPT_MASK_BSM";
case KnownRegisters::CHIP_VERSION:
return "CHIP_VERSION";
case KnownRegisters::BSM_ARGS:
return "BSM_ARGS";
case KnownRegisters::BSM_ADDR_OFFSET_0:
return "BSM_ADDR_OFFSET[0]";
case KnownRegisters::BSM_ADDR_OFFSET_1:
return "BSM_ADDR_OFFSET[1]";
case KnownRegisters::BSM_ADDR_OFFSET_2:
return "BSM_ADDR_OFFSET[2]";
case KnownRegisters::BSM_ADDR_OFFSET_3:
return "BSM_ADDR_OFFSET[3]";
case KnownRegisters::BSM_COUNTER_0:
return "BSM_COUNTER[0]";
case KnownRegisters::BSM_COUNTER_1:
return "BSM_COUNTER[1]";
case KnownRegisters::PLL_PCIE_CTRL:
return "PLL_PCIE_CTRL";
case KnownRegisters::PLL_PCIE_STAT:
return "PLL_PCIE_STAT";
case KnownRegisters::PCIE_XPLL_CTRL:
return "PCIE_XPLL_CTRL";
case KnownRegisters::PCIE_CLK_CTRL:
return "PCIE_CLK_CTRL";
case KnownRegisters::PCIE_CLK_CTRL_2:
return "PCIE_CLK_CTRL_2";
case KnownRegisters::PLL_EPL_CTRL:
return "PLL_EPL_CTRL";
case KnownRegisters::PLL_EPL_STAT:
return "PLL_EPL_STAT";
case KnownRegisters::PLL_FABRIC_CTRL:
return "PLL_FABRIC_CTRL";
case KnownRegisters::PLL_FABRIC_STAT:
return "PLL_FABRIC_STAT";
case KnownRegisters::PLL_FABRIC_LOCK:
return "PLL_FABRIC_LOCK";
case KnownRegisters::SBUS_EPL_CFG:
return "SBUS_EPL_CFG";
case KnownRegisters::SBUS_EPL_COMMAND:
return "SBUS_EPL_COMMAND";
case KnownRegisters::SBUS_EPL_REQUEST:
return "SBUS_EPL_REQUEST";
case KnownRegisters::SBUS_EPL_RESPONSE:
return "SBUS_EPL_RESPONSE";
case KnownRegisters::SBUS_EPL_SPICO_IN:
return "SBUS_EPL_SPICO_IN";
case KnownRegisters::SBUS_EPL_SPICO_OUT:
return "SBUS_EPL_SPICO_OUT";
case KnownRegisters::SBUS_EPL_IP:
return "SBUS_EPL_IP";
case KnownRegisters::SBUS_EPL_IM:
return "SBUS_EPL_IM";
case KnownRegisters::PM_CLKOBS_CTRL:
return "PM_CLKOBS_CTRL";
case KnownRegisters::GPIO_CFG:
return "GPIO_CFG";
case KnownRegisters::GPIO_DATA:
return "GPIO_DATA";
case KnownRegisters::GPIO_IP:
return "GPIO_IP";
case KnownRegisters::GPIO_IM:
return "GPIO_IM";
case KnownRegisters::SBUS_PCIE_CFG:
return "SBUS_PCIE_CFG";
case KnownRegisters::SBUS_PCIE_COMMAND:
return "SBUS_PCIE_COMMAND";
case KnownRegisters::SBUS_PCIE_REQUEST:
return "SBUS_PCIE_REQUEST";
case KnownRegisters::SBUS_PCIE_RESPONSE:
return "SBUS_PCIE_RESPONSE";
case KnownRegisters::SBUS_PCIE_SPICO_IN:
return "SBUS_PCIE_SPICO_IN";
case KnownRegisters::SBUS_PCIE_SPICO_OUT:
return "SBUS_PCIE_SPICO_OUT";
case KnownRegisters::SBUS_PCIE_IP:
return "SBUS_PCIE_IP";
case KnownRegisters::SBUS_PCIE_IM:
return "SBUS_PCIE_IM";
case KnownRegisters::REI_CTRL:
return "REI_CTRL";
case KnownRegisters::REI_STAT:
return "REI_STAT";
case KnownRegisters::BIST_CTRL:
return "BIST_CTRL";
case KnownRegisters::PCIE_CLKMON_RATIO_CFG:
return "PCIE_CLKMON_RATIO_CFG";
case KnownRegisters::PCIE_CLKMON_TOLERANCE_CFG:
return "PCIE_CLKMON_TOLERANCE_CFG";
case KnownRegisters::PCIE_CLKMON_DEADLINES_CFG:
return "PCIE_CLKMON_DEADLINES_CFG";
case KnownRegisters::PCIE_CLK_STAT:
return "PCIE_CLK_STAT";
case KnownRegisters::PCIE_CLK_IP:
return "PCIE_CLK_IP";
case KnownRegisters::PCIE_CLK_IM:
return "PCIE_CLK_IM";
case KnownRegisters::PCIE_WARM_RESET_DELAY:
return "PCIE_WARM_RESET_DELAY";
default:
break;
}
std::stringstream s;
s << "register[0x" << std::hex << std::setw(6) << std::setfill('0') << (uint32_t)addr << "]";
return s.str();
}
std::string getAddressRegisterName(uint32_t addr, uint8_t offset){
std::stringstream s;
if(offset){
s << getRegisterName(static_cast<KnownRegisters>((uint32_t)KnownRegisters::BSM_ADDR_OFFSET_0 + offset)) << " + " << "0x" << std::hex << std::setw(6) << std::setfill('0') << addr;
} else {
s << getRegisterName(static_cast<KnownRegisters>(addr));
}
return s.str();
}

125
src/Registers.h Normal file
View file

@ -0,0 +1,125 @@
/*****************************************************************************
* 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 <string>
enum class KnownRegisters : uint32_t {
PCIE_MASTER_SPICO_FIRMWARE_SPECIAL_REGISTER = 0x0,
FATAL_CODE = 0x0,
PCIE_BROADCAST_SERDES_FIRMWARE_SPECIAL_REGISTER = 0x1,
LAST_FATAL_CODE = 0x1,
SOFT_RESET = 0x3,
DEVICE_CFG = 0x4,
RESET_CFG = 0x5,
WATCHDOG_CFG = 0x6,
MGMT_SCRATCH_0 = 0x8,
MGMT_SCRATCH_1 = MGMT_SCRATCH_0 + 1,
VITAL_PRODUCT_DATA = 0x304,
GLOBAL_INTERRUPT_DETECT = 0x400,
INTERRUPT_MASK_BSM = 0x442,
CHIP_VERSION = 0x452,
BSM_SCRATCH_START = 0x800,
BSM_SCRATCH_END = BSM_SCRATCH_START + 0x400 - 1,
BSM_ARGS = 0x000C01,
BSM_ADDR_OFFSET_0 = 0x000C04,
BSM_ADDR_OFFSET_1 = BSM_ADDR_OFFSET_0 + 1,
BSM_ADDR_OFFSET_2 = BSM_ADDR_OFFSET_0 + 2,
BSM_ADDR_OFFSET_3 = BSM_ADDR_OFFSET_0 + 3,
BSM_COUNTER_0 = 0x000C08,
BSM_COUNTER_1 = BSM_COUNTER_0 + 1,
BIST_CTRL = 0x000C10,
REI_CTRL = 0x000C12,
REI_STAT = 0x000C13,
GPIO_CFG = 0x000C15,
GPIO_DATA = 0x000C16,
GPIO_IP = 0x000C17,
GPIO_IM = 0x000C18,
PLL_PCIE_CTRL = 0x2241,
PLL_PCIE_STAT = 0x2242,
SBUS_PCIE_CFG = 0x2243,
SBUS_PCIE_COMMAND = 0x2244,
SBUS_PCIE_REQUEST = 0x2245,
SBUS_PCIE_RESPONSE = 0x2246,
SBUS_PCIE_SPICO_IN = 0x2247,
SBUS_PCIE_SPICO_OUT = 0x2248,
SBUS_PCIE_IP = 0x2249,
SBUS_PCIE_IM = 0x224a,
PCIE_XPLL_CTRL = 0x3000,
PCIE_CLK_CTRL = 0x3001,
PCIE_CLK_CTRL_2 = 0x3002,
PCIE_CLKMON_RATIO_CFG = 0x3003,
PCIE_CLKMON_TOLERANCE_CFG = 0x3004,
PCIE_CLKMON_DEADLINES_CFG = 0x3005,
PCIE_CLK_STAT = 0x3006,
PCIE_CLK_IP = 0x3007,
PCIE_CLK_IM = 0x3008,
PCIE_WARM_RESET_DELAY = 0x3009,
PORTS_MGMT_BASE_ADDRESS = 0xE8000,
PLL_EPL_CTRL = PORTS_MGMT_BASE_ADDRESS + 0x0,
PLL_EPL_STAT = PORTS_MGMT_BASE_ADDRESS + 0x1,
PLL_FABRIC_CTRL = PORTS_MGMT_BASE_ADDRESS + 0x2,
PLL_FABRIC_STAT = PORTS_MGMT_BASE_ADDRESS + 0x3,
PLL_FABRIC_LOCK = PORTS_MGMT_BASE_ADDRESS + 0x4,
SBUS_EPL_CFG = PORTS_MGMT_BASE_ADDRESS + 0x5,
SBUS_EPL_COMMAND = PORTS_MGMT_BASE_ADDRESS + 0x6,
SBUS_EPL_REQUEST = PORTS_MGMT_BASE_ADDRESS + 0x7,
SBUS_EPL_RESPONSE = PORTS_MGMT_BASE_ADDRESS + 0x8,
SBUS_EPL_SPICO_IN = PORTS_MGMT_BASE_ADDRESS + 0x9,
SBUS_EPL_SPICO_OUT = PORTS_MGMT_BASE_ADDRESS + 0xa,
SBUS_EPL_IP = PORTS_MGMT_BASE_ADDRESS + 0xb,
SBUS_EPL_IM = PORTS_MGMT_BASE_ADDRESS + 0xc,
PM_CLKOBS_CTRL = PORTS_MGMT_BASE_ADDRESS + 0x12,
PCIE_PF_BASE_ADDRESS = 0x100000,
NOP = 0xFFFFFFFF
};
std::string getRegisterName(KnownRegisters addr);
std::string getAddressRegisterName(uint32_t addr, uint8_t offset = 0);

105
src/instructions/Branch.cpp Normal file
View file

@ -0,0 +1,105 @@
/*****************************************************************************
* 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 "Branch.h"
#include "../Registers.h"
#include <iostream>
#include <iomanip>
void Instruction::Branch::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
_address = offset;
uint32_t command = bytes[offset++];
equality = (command >> 2) & 0b1;
addressOffset = command & 0b11;
address = bytes[offset++] << 16;
address |= bytes[offset++] << 8;
address |= bytes[offset++];
value = bytes[offset++] << 24;
value |= bytes[offset++] << 16;
value |= bytes[offset++] << 8;
value |= bytes[offset++];
mask = bytes[offset++] << 24;
mask |= bytes[offset++] << 16;
mask |= bytes[offset++] << 8;
mask |= bytes[offset++];
offset++;
jumpAddress = bytes[offset++] << 16;
jumpAddress |= bytes[offset++] << 8;
jumpAddress |= bytes[offset++];
while ((offset % 4) != 0){
offset++;
}
_endAddress = offset;
}
std::string Instruction::Branch::toString() const {
std::stringstream op;
op << "BRANCH IF (" << getAddressRegisterName(address, addressOffset) << " & 0x" << std::hex << std::setw(8) << std::setfill('0') << mask << ")";
if(equality){
op << " == ";
}else{
op << " != ";
}
op << "0x" << std::hex << std::setw(8) << std::setfill('0') << value << " JUMP 0x" << std::hex << std::setw(6) << std::setfill('0') << jumpAddress;
return op.str();
}
std::vector<uint32_t> Instruction::Branch::getPossibleBranches() const {
return std::vector<uint32_t>{_endAddress, jumpAddress};
}
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){
state.current = equality ? jumpAddress : _endAddress;
std::unordered_map<uint32_t, uint32_t> branchedState;
branchedState[memoryOffset + address] = state.getRegister(memoryOffset + 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);
branches.emplace_back(equality ? jumpAddress : _endAddress, std::move(branchedState));
}
return branches;
}

59
src/instructions/Branch.h Normal file
View file

@ -0,0 +1,59 @@
/*****************************************************************************
* 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 "Instruction.h"
namespace Instruction{
class Branch : public Instruction {
public:
Branch(){
}
CommandOp getCommand() const override{
return CommandOp::BRANCH;
};
void fromBytes(uint32_t offset, const std::vector<uint8_t>& bytes) override;
std::string toString() 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;
bool equality;
uint32_t address;
uint32_t value;
uint32_t mask;
uint32_t jumpAddress;
};
}

137
src/instructions/Calc.cpp Normal file
View file

@ -0,0 +1,137 @@
/*****************************************************************************
* 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 "Calc.h"
#include "../Registers.h"
#include <iostream>
#include <iomanip>
void Instruction::Calc::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
_address = offset;
uint32_t command = bytes[offset++];
operation = static_cast<Operation>((command >> 2) & 0b111);
addressOffset = command & 0b11;
addressDestination = bytes[offset++] << 16;
addressDestination |= bytes[offset++] << 8;
addressDestination |= bytes[offset++];
offset++;
addressSource = bytes[offset++] << 16;
addressSource |= bytes[offset++] << 8;
addressSource |= bytes[offset++];
offset++;
addressTarget = bytes[offset++] << 16;
addressTarget |= bytes[offset++] << 8;
addressTarget |= bytes[offset++];
while ((offset % 4) != 0){
offset++;
}
_endAddress = offset;
}
std::string Instruction::Calc::toString() const {
std::stringstream op;
op << "CALC " << getAddressRegisterName(addressDestination, addressOffset) << " = " << getAddressRegisterName(addressSource, addressOffset);
switch (operation) {
case Operation::AND:
op << " & ";
break;
case Operation::OR:
op << " | ";
break;
case Operation::ADD:
op << " + ";
break;
case Operation::SUB:
op << " - ";
break;
case Operation::LSHIFT:
op << " << ";
break;
case Operation::RSHIFT:
op << " >> ";
break;
case Operation::ARSHIFT:
op << " >>> ";
break;
case Operation::UNDEFINED:
op << " UNDEFINED ";
break;
}
op << getAddressRegisterName(addressTarget, addressOffset);
return op.str();
}
std::vector<uint32_t> Instruction::Calc::getPossibleBranches() const {
return std::vector<uint32_t>{_endAddress};
}
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>> Instruction::Calc::execute(AnalysisState &state) const {
uint32_t memoryOffset = state.getAddressOffset(addressOffset);
uint32_t v_a = state.getRegister(memoryOffset + addressSource);
uint32_t v_b = state.getRegister(memoryOffset + addressTarget);
switch (operation) {
case Operation::AND:
state.setRegister(addressDestination, v_a & v_b);
break;
case Operation::OR:
state.setRegister(addressDestination, v_a | v_b);
break;
case Operation::ADD:
state.setRegister(addressDestination, v_a + v_b);
break;
case Operation::SUB:
state.setRegister(addressDestination, v_a - v_b);
break;
case Operation::LSHIFT:
state.setRegister(addressDestination, v_a << v_b);
break;
case Operation::RSHIFT:
state.setRegister(addressDestination, v_a >> v_b);
break;
case Operation::ARSHIFT:
state.setRegister(addressDestination, (uint32_t)((int32_t)v_a >> v_b));
break;
case Operation::UNDEFINED:
break;
}
state.current = _endAddress;
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
}

70
src/instructions/Calc.h Normal file
View file

@ -0,0 +1,70 @@
/*****************************************************************************
* 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 "Instruction.h"
namespace Instruction{
class Calc : public Instruction {
public:
enum class Operation : uint8_t {
AND = 0,
OR = 1,
ADD = 2,
SUB = 3,
LSHIFT = 4,
RSHIFT = 5,
ARSHIFT = 6,
UNDEFINED = 7
};
Calc(){
}
CommandOp getCommand() const override{
return CommandOp::CALC;
};
void fromBytes(uint32_t offset, const std::vector<uint8_t>& bytes) override;
std::string toString() 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;
Operation operation;
uint8_t addressOffset;
uint32_t addressDestination;
uint32_t addressSource;
uint32_t addressTarget;
};
}

View file

@ -0,0 +1,136 @@
/*****************************************************************************
* 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 "CalcImm.h"
#include "../Registers.h"
#include <iostream>
#include <iomanip>
void Instruction::CalcImm::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
_address = offset;
uint32_t command = bytes[offset++];
operation = static_cast<Calc::Operation>((command >> 2) & 0b111);
addressOffset = command & 0b11;
addressDestination = bytes[offset++] << 16;
addressDestination |= bytes[offset++] << 8;
addressDestination |= bytes[offset++];
offset++;
addressSource = bytes[offset++] << 16;
addressSource |= bytes[offset++] << 8;
addressSource |= bytes[offset++];
value = bytes[offset++] << 24;
value |= bytes[offset++] << 16;
value |= bytes[offset++] << 8;
value |= bytes[offset++];
while ((offset % 4) != 0){
offset++;
}
_endAddress = offset;
}
std::string Instruction::CalcImm::toString() const {
std::stringstream op;
op << "CALC_IMM " << getAddressRegisterName(addressDestination, addressOffset) << " = " << getAddressRegisterName(addressSource, addressOffset);
switch (operation) {
case Calc::Operation::AND:
op << " & ";
break;
case Calc::Operation::OR:
op << " | ";
break;
case Calc::Operation::ADD:
op << " + ";
break;
case Calc::Operation::SUB:
op << " - ";
break;
case Calc::Operation::LSHIFT:
op << " << ";
break;
case Calc::Operation::RSHIFT:
op << " >> ";
break;
case Calc::Operation::ARSHIFT:
op << " >>> ";
break;
case Calc::Operation::UNDEFINED:
op << " UNDEFINED ";
break;
}
op << "0x" << std::hex << std::setw(8) << std::setfill('0') << value;
return op.str();
}
std::vector<uint32_t> Instruction::CalcImm::getPossibleBranches() const {
return std::vector<uint32_t>{_endAddress};
}
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>> Instruction::CalcImm::execute(AnalysisState &state) const {
uint32_t memoryOffset = state.getAddressOffset(addressOffset);
uint32_t v_a = state.getRegister(memoryOffset + addressSource);
switch (operation) {
case Calc::Operation::AND:
state.setRegister(addressDestination, v_a & value);
break;
case Calc::Operation::OR:
state.setRegister(addressDestination, v_a | value);
break;
case Calc::Operation::ADD:
state.setRegister(addressDestination, v_a + value);
break;
case Calc::Operation::SUB:
state.setRegister(addressDestination, v_a - value);
break;
case Calc::Operation::LSHIFT:
state.setRegister(addressDestination, v_a << value);
break;
case Calc::Operation::RSHIFT:
state.setRegister(addressDestination, v_a >> value);
break;
case Calc::Operation::ARSHIFT:
state.setRegister(addressDestination, (uint32_t)((int32_t)v_a >> value));
break;
case Calc::Operation::UNDEFINED:
break;
}
state.current = _endAddress;
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
}

View file

@ -0,0 +1,60 @@
/*****************************************************************************
* 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 "Instruction.h"
#include "Calc.h"
namespace Instruction{
class CalcImm : public Instruction {
public:
CalcImm(){
}
CommandOp getCommand() const override{
return CommandOp::CALC_IMM;
};
void fromBytes(uint32_t offset, const std::vector<uint8_t>& bytes) override;
std::string toString() 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;
Calc::Operation operation;
uint8_t addressOffset;
uint32_t addressDestination;
uint32_t addressSource;
uint32_t value;
};
}

81
src/instructions/Copy.cpp Normal file
View file

@ -0,0 +1,81 @@
/*****************************************************************************
* 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 "Copy.h"
#include "../Registers.h"
#include <iostream>
#include <iomanip>
void Instruction::Copy::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
_address = offset;
uint32_t command = bytes[offset++];
count = (1 + ((command >> 4) & 0b11));
addressOffsetBB = (command >> 2) & 0b11;
addressOffsetAA = command & 0b11;
addressAA = bytes[offset++] << 16;
addressAA |= bytes[offset++] << 8;
addressAA |= bytes[offset++];
offset++;
addressBB = bytes[offset++] << 16;
addressBB |= bytes[offset++] << 8;
addressBB |= bytes[offset++];
while ((offset % 4) != 0){
offset++;
}
_endAddress = offset;
}
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);
return op.str();
}
std::vector<uint32_t> Instruction::Copy::getPossibleBranches() const {
return std::vector<uint32_t>{_endAddress};
}
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.current = _endAddress;
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
}

58
src/instructions/Copy.h Normal file
View file

@ -0,0 +1,58 @@
/*****************************************************************************
* 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 "Instruction.h"
namespace Instruction{
class Copy : public Instruction {
public:
Copy(){
}
CommandOp getCommand() const override{
return CommandOp::COPY;
};
void fromBytes(uint32_t offset, const std::vector<uint8_t>& bytes) override;
std::string toString() 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 count;
uint8_t addressOffsetBB;
uint8_t addressOffsetAA;
uint32_t addressAA;
uint32_t addressBB;
};
}

54
src/instructions/End.cpp Normal file
View file

@ -0,0 +1,54 @@
/*****************************************************************************
* 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 "End.h"
void Instruction::End::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
_address = offset;
offset++;
while ((offset % 4) != 0){
offset++;
}
_endAddress = offset;
}
std::string Instruction::End::toString() const {
return "END";
}
std::vector<uint32_t> Instruction::End::getPossibleBranches() const {
return std::vector<uint32_t>();
}
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>> Instruction::End::execute(AnalysisState &state) const {
state.current = 0;
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
}

52
src/instructions/End.h Normal file
View file

@ -0,0 +1,52 @@
/*****************************************************************************
* 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 "Instruction.h"
namespace Instruction{
class End : public Instruction {
public:
End(){
}
CommandOp getCommand() const override{
return CommandOp::END;
};
void fromBytes(uint32_t offset, const std::vector<uint8_t>& bytes) override;
std::string toString() 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;
};
}

95
src/instructions/Init.cpp Normal file
View file

@ -0,0 +1,95 @@
/*****************************************************************************
* 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 "Init.h"
#include "../Registers.h"
#include <iostream>
#include <iomanip>
void Instruction::Init::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
_address = offset;
uint32_t command = bytes[offset++];
increment = (command >> 2) & 0b1;
addressOffset = command & 0b11;
address = bytes[offset++] << 16;
address |= bytes[offset++] << 8;
address |= bytes[offset++];
offset++;
count = bytes[offset++] << 16;
count |= bytes[offset++] << 8;
count |= bytes[offset++];
data = bytes[offset++] << 24;
data |= bytes[offset++] << 16;
data |= bytes[offset++] << 8;
data |= bytes[offset++];
data_add = bytes[offset++] << 24;
data_add |= bytes[offset++] << 16;
data_add |= bytes[offset++] << 8;
data_add |= bytes[offset++];
while ((offset % 4) != 0){
offset++;
}
_endAddress = offset;
}
std::string Instruction::Init::toString() const {
std::stringstream op;
op << "INIT INTO " << getAddressRegisterName(address, addressOffset);
if(count > 1 && increment){
op << " UNTIL " << getAddressRegisterName(address + count - 1, addressOffset);
}
op << " COUNT " << std::hex << std::setw(6) << std::setfill('0') << count;
op << " INCREMENT " << std::dec << (uint32_t)increment;
op << " DATA 0x" << std::hex << std::setw(8) << std::setfill('0') << data;
op << " INC 0x" << std::hex << std::setw(8) << std::setfill('0') << data_add;
return op.str();
}
std::vector<uint32_t> Instruction::Init::getPossibleBranches() const {
return std::vector<uint32_t>{_endAddress};
}
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>> Instruction::Init::execute(AnalysisState &state) const {
for (uint32_t i = 0; i < count; ++i) {
state.setRegister(address + (increment ? i : 0), data + data_add * i);
}
state.current = _endAddress;
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
}

59
src/instructions/Init.h Normal file
View file

@ -0,0 +1,59 @@
/*****************************************************************************
* 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 "Instruction.h"
namespace Instruction{
class Init : public Instruction {
public:
Init(){
}
CommandOp getCommand() const override{
return CommandOp::INIT;
};
void fromBytes(uint32_t offset, const std::vector<uint8_t>& bytes) override;
std::string toString() 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;
bool increment;
uint32_t address;
uint32_t count;
uint32_t data;
uint32_t data_add;
};
}

View file

@ -0,0 +1,139 @@
/*****************************************************************************
* 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 "Instruction.h"
#include "Write.h"
#include "Copy.h"
#include "Load.h"
#include "Init.h"
#include "Calc.h"
#include "CalcImm.h"
#include "Branch.h"
#include "Poll.h"
#include "Loop.h"
#include "Jump.h"
#include "Return.h"
#include "Set.h"
#include "Wait.h"
#include "End.h"
namespace Instruction{
std::unique_ptr<Instruction> Instruction::Instruction::decodeInstructionFromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
auto result = std::unique_ptr<Instruction>(nullptr);
CommandOp command = getCommandFromByte(bytes[offset]);
switch (command) {
case CommandOp::WRITE:
result = std::make_unique<Write>();
break;
case CommandOp::COPY:
result = std::make_unique<Copy>();
break;
case CommandOp::LOAD:
result = std::make_unique<Load>();
break;
case CommandOp::INIT:
result = std::make_unique<Init>();
break;
case CommandOp::CALC:
result = std::make_unique<Calc>();
break;
case CommandOp::CALC_IMM:
result = std::make_unique<CalcImm>();
break;
case CommandOp::BRANCH:
result = std::make_unique<Branch>();
break;
case CommandOp::POLL:
result = std::make_unique<Poll>();
break;
case CommandOp::LOOP:
result = std::make_unique<Loop>();
break;
case CommandOp::JUMP:
result = std::make_unique<Jump>();
break;
case CommandOp::RETURN:
result = std::make_unique<Return>();
break;
case CommandOp::SET:
result = std::make_unique<Set>();
break;
case CommandOp::WAIT:
result = std::make_unique<Wait>();
break;
case CommandOp::END:
result = std::make_unique<End>();
break;
case CommandOp::NOP:
break;
}
if(result != nullptr){
result->fromBytes(offset, bytes);
}
return result;
}
Instruction::CommandOp Instruction::getCommandFromByte(uint8_t command) {
if(((command >> 6) & 0b11) == 0b00){
return CommandOp::WRITE;
}else if(((command >> 6) & 0b11) == 0b01){
return CommandOp::COPY;
}else if(((command >> 3) & 0b11111) == 0b11000){
return CommandOp::LOAD;
}else if(((command >> 3) & 0b11111) == 0b11001){
return CommandOp::INIT;
}else if(((command >> 5) & 0b111) == 0b100){
return CommandOp::CALC;
}else if(((command >> 5) & 0b111) == 0b101){
return CommandOp::CALC_IMM;
}else if(((command >> 3) & 0b11111) == 0b11010){
return CommandOp::BRANCH;
}else if(((command >> 3) & 0b11111) == 0b11011){
return CommandOp::POLL;
}else if(((command >> 1) & 0b1111111) == 0b1110000){
return CommandOp::LOOP;
}else if(command == 0b11101000){
return CommandOp::JUMP;
}else if(((command >> 2) & 0b111111) == 0b111100){
return CommandOp::RETURN;
}else if(((command >> 2) & 0b111111) == 0b111110){
return CommandOp::SET;
}else if(command == 0xFE){
return CommandOp::WAIT;
}else if(command == 0xFF){
return CommandOp::END;
}
return CommandOp::NOP;
}
}

View file

@ -0,0 +1,103 @@
/*****************************************************************************
* 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 <string>
#include <vector>
#include <unordered_map>
#include <memory>
#include "../AnalysisState.h"
namespace Instruction{
class Instruction{
protected:
uint32_t _address;
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 = 0,
COPY,
LOAD,
INIT,
CALC,
CALC_IMM,
BRANCH,
POLL,
LOOP,
JUMP,
RETURN,
SET,
WAIT,
END,
NOP = 0xFF
};
static std::unique_ptr<Instruction> decodeInstructionFromBytes(uint32_t offset, const std::vector<uint8_t>& bytes);
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::string toString() const = 0;
virtual std::vector<uint32_t> getPossibleBranches() const = 0;
virtual std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>> execute(AnalysisState& state) const = 0;
virtual CommandOp getCommand() const = 0;
uint32_t getAddress() const{
return _address;
}
uint32_t getEndAddress() const{
return _endAddress;
}
};
};

64
src/instructions/Jump.cpp Normal file
View file

@ -0,0 +1,64 @@
/*****************************************************************************
* 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 "Jump.h"
#include "../Registers.h"
#include <iostream>
#include <iomanip>
void Instruction::Jump::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
_address = offset;
offset++;
jumpAddress = bytes[offset++] << 16;
jumpAddress |= bytes[offset++] << 8;
jumpAddress |= bytes[offset++];
while ((offset % 4) != 0){
offset++;
}
_endAddress = offset;
}
std::string Instruction::Jump::toString() const {
std::stringstream op;
op << "JUMP 0x" << std::hex << std::setw(6) << std::setfill('0') << jumpAddress;
return op.str();
}
std::vector<uint32_t> Instruction::Jump::getPossibleBranches() const {
return std::vector<uint32_t>{jumpAddress};
}
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>> Instruction::Jump::execute(AnalysisState &state) const {
state.current = jumpAddress;
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
}

53
src/instructions/Jump.h Normal file
View file

@ -0,0 +1,53 @@
/*****************************************************************************
* 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 "Instruction.h"
namespace Instruction{
class Jump : public Instruction {
public:
Jump(){
}
CommandOp getCommand() const override{
return CommandOp::JUMP;
};
void fromBytes(uint32_t offset, const std::vector<uint8_t>& bytes) override;
std::string toString() 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;
uint32_t jumpAddress;
};
}

134
src/instructions/Load.cpp Normal file
View file

@ -0,0 +1,134 @@
/*****************************************************************************
* 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 "Load.h"
#include "../Registers.h"
#include <iostream>
#include <iomanip>
void Instruction::Load::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
_address = offset;
uint32_t command = bytes[offset++];
increment = (command >> 2) & 0b1;
addressOffset = command & 0b11;
address = bytes[offset++] << 16;
address |= bytes[offset++] << 8;
address |= bytes[offset++];
offset++;
uint32_t count = bytes[offset++] << 16;
count |= bytes[offset++] << 8;
count |= bytes[offset++];
for(uint32_t i = 0; i < count; ++i){
uint32_t entry = bytes[offset++] << 24;
entry |= bytes[offset++] << 16;
entry |= bytes[offset++] << 8;
entry |= bytes[offset++];
data.emplace_back(entry);
}
while ((offset % 4) != 0){
offset++;
}
_endAddress = offset;
}
std::string Instruction::Load::toString() const {
std::stringstream op;
if(addressOffset == 0 && increment == 0 && address == (uint32_t)KnownRegisters::PCIE_MASTER_SPICO_FIRMWARE_SPECIAL_REGISTER){
op << "LOAD PCIE_MASTER_SPICO_FIRMWARE DATA 0x";
for (auto d : data) {
op << std::hex << std::setw(8) << std::setfill('0') << d;
}
op << "\n";
auto fw = SmallFirmwareFormat::fromBSMLoad(data, 0);
for (uint32_t i = 0; i < fw.firmware.size(); ++i) {
op << " SPICO_FW[" << std::hex << std::setw(4) << std::setfill('0') << i << "]";
op << " = 0x" << std::hex << std::setw(3) << std::setfill('0') << fw.firmware[i] << "\n";
}
} else if(addressOffset == 0 && increment == 0 && address == (uint32_t)KnownRegisters::PCIE_BROADCAST_SERDES_FIRMWARE_SPECIAL_REGISTER){
op << "LOAD PCIE_BROADCAST_SERDES_FIRMWARE DATA 0x";
for (auto d : data) {
op << std::hex << std::setw(8) << std::setfill('0') << d;
}
op << "\n";
auto fw = SmallFirmwareFormat::fromBSMLoad(data, 0);
for (uint32_t i = 0; i < fw.firmware.size(); ++i) {
op << " SERDES_FW[" << std::hex << std::setw(4) << std::setfill('0') << i << "]";
op << " = 0x" << std::hex << std::setw(3) << std::setfill('0') << fw.firmware[i] << "\n";
}
}else{
op << "LOAD INTO " << getAddressRegisterName(address, addressOffset);
if(data.size() > 1 && increment){
op << " UNTIL " << getAddressRegisterName(address + data.size() - 1, addressOffset);
}
op << " INCREMENT " << std::dec << (uint32_t) increment;
op << " DATA 0x";
for (auto d : data) {
op << std::hex << std::setw(8) << std::setfill('0') << d;
}
if(data.size() > 1){
for (uint32_t i = 0; i < data.size(); ++i) {
op << "\n " << getAddressRegisterName(address + (increment ? i : 0)) << " = 0x" << std::hex << std::setw(8) << std::setfill('0') << data[i];
}
}
}
return op.str();
}
std::vector<uint32_t> Instruction::Load::getPossibleBranches() const {
return std::vector<uint32_t>{_endAddress};
}
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>> Instruction::Load::execute(AnalysisState &state) const {
if(addressOffset == 0 && increment == 0 && address == (uint32_t)KnownRegisters::PCIE_MASTER_SPICO_FIRMWARE_SPECIAL_REGISTER){
state.pciSPICOFirmware = SmallFirmwareFormat::fromBSMLoad(data, 0);
} else if(addressOffset == 0 && increment == 0 && address == (uint32_t)KnownRegisters::PCIE_BROADCAST_SERDES_FIRMWARE_SPECIAL_REGISTER){
state.pciSerDesFirmware = SmallFirmwareFormat::fromBSMLoad(data, 0);
}else{
for (uint32_t i = 0; i < data.size(); ++i) {
state.setRegister(address + (increment ? i : 0), data[i]);
}
}
state.current = _endAddress;
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
}

57
src/instructions/Load.h Normal file
View file

@ -0,0 +1,57 @@
/*****************************************************************************
* 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 "Instruction.h"
namespace Instruction{
class Load : public Instruction {
public:
Load(){
}
CommandOp getCommand() const override{
return CommandOp::LOAD;
};
void fromBytes(uint32_t offset, const std::vector<uint8_t>& bytes) override;
std::string toString() 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;
bool increment;
uint32_t address;
std::vector<uint32_t> data;
};
}

82
src/instructions/Loop.cpp Normal file
View file

@ -0,0 +1,82 @@
/*****************************************************************************
* 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 "Loop.h"
#include "../Registers.h"
#include <iostream>
#include <iomanip>
void Instruction::Loop::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
_address = offset;
uint32_t command = bytes[offset++];
counter = command & 0b1;
jumpAddress = bytes[offset++] << 16;
jumpAddress |= bytes[offset++] << 8;
jumpAddress |= bytes[offset++];
while ((offset % 4) != 0){
offset++;
}
_endAddress = offset;
}
std::string Instruction::Loop::toString() const {
std::stringstream op;
op << "LOOP IF " << getRegisterName(static_cast<KnownRegisters>((uint32_t)KnownRegisters::BSM_COUNTER_0 + counter)) << " != 0 JUMP 0x" << std::hex << std::setw(6) << std::setfill('0') << jumpAddress;
return op.str();
}
std::vector<uint32_t> Instruction::Loop::getPossibleBranches() const {
return std::vector<uint32_t>{_endAddress, jumpAddress};
}
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>> Instruction::Loop::execute(AnalysisState &state) const {
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>> branches;
uint32_t counterAddress = (uint32_t)KnownRegisters::BSM_COUNTER_0 + counter;
if(state.getRegister(counterAddress) == 0){
state.current = _endAddress;
std::unordered_map<uint32_t, uint32_t> branchedState;
branchedState[counterAddress] = 1;
branches.emplace_back(jumpAddress, std::move(branchedState));
}else{
state.setRegister(counterAddress, state.getRegister(counterAddress) - 1);
state.current = jumpAddress;
std::unordered_map<uint32_t, uint32_t> branchedState;
branchedState[counterAddress] = 0;
branches.emplace_back(_endAddress, std::move(branchedState));
}
return branches;
}

55
src/instructions/Loop.h Normal file
View file

@ -0,0 +1,55 @@
/*****************************************************************************
* 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 "Instruction.h"
namespace Instruction{
class Loop : public Instruction {
public:
Loop(){
}
CommandOp getCommand() const override{
return CommandOp::LOOP;
};
void fromBytes(uint32_t offset, const std::vector<uint8_t>& bytes) override;
std::string toString() 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 counter;
uint32_t jumpAddress;
};
}

111
src/instructions/Poll.cpp Normal file
View file

@ -0,0 +1,111 @@
/*****************************************************************************
* 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 "Poll.h"
#include "../Registers.h"
#include <iostream>
#include <iomanip>
void Instruction::Poll::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
_address = offset;
uint32_t command = bytes[offset++];
equality = (command >> 2) & 0b1;
addressOffset = command & 0b11;
address = bytes[offset++] << 16;
address |= bytes[offset++] << 8;
address |= bytes[offset++];
value = bytes[offset++] << 24;
value |= bytes[offset++] << 16;
value |= bytes[offset++] << 8;
value |= bytes[offset++];
mask = bytes[offset++] << 24;
mask |= bytes[offset++] << 16;
mask |= bytes[offset++] << 8;
mask |= bytes[offset++];
maxRetry = bytes[offset++] << 8;
maxRetry |= bytes[offset++];
retryInterval = bytes[offset++] << 8;
retryInterval |= bytes[offset++];
offset++;
jumpAddress = bytes[offset++] << 16;
jumpAddress |= bytes[offset++] << 8;
jumpAddress |= bytes[offset++];
while ((offset % 4) != 0){
offset++;
}
_endAddress = offset;
}
std::string Instruction::Poll::toString() const {
std::stringstream op;
op << "POLL IF (" << getAddressRegisterName(address, addressOffset) << " & 0x" << std::hex << std::setw(8) << std::setfill('0') << mask << ")";
if(equality){
op << " != ";
}else{
op << " == ";
}
op << "0x" << std::hex << std::setw(8) << std::setfill('0') << value << " WAIT " << std::dec << retryInterval << " MAX " << std::dec << maxRetry << " EXCEED JUMP 0x" << std::hex << std::setw(6) << std::setfill('0') << jumpAddress;
return op.str();
}
std::vector<uint32_t> Instruction::Poll::getPossibleBranches() const {
return std::vector<uint32_t>{_endAddress, jumpAddress};
}
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){
state.current = equality ? _endAddress : jumpAddress;
std::unordered_map<uint32_t, uint32_t> branchedState;
branchedState[memoryOffset + address] = state.getRegister(memoryOffset + 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);
branches.emplace_back(equality ? _endAddress : jumpAddress, std::move(branchedState));
}
return branches;
}

61
src/instructions/Poll.h Normal file
View file

@ -0,0 +1,61 @@
/*****************************************************************************
* 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 "Instruction.h"
namespace Instruction{
class Poll : public Instruction {
public:
Poll(){
}
CommandOp getCommand() const override{
return CommandOp::POLL;
};
void fromBytes(uint32_t offset, const std::vector<uint8_t>& bytes) override;
std::string toString() 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;
bool equality;
uint32_t address;
uint32_t value;
uint32_t mask;
uint16_t maxRetry;
uint16_t retryInterval;
uint32_t jumpAddress;
};
}

View file

@ -0,0 +1,69 @@
/*****************************************************************************
* 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 "Return.h"
#include "../Registers.h"
#include <iostream>
#include <iomanip>
void Instruction::Return::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
_address = offset;
uint8_t command = bytes[offset++];
addressOffset = command & 0b11;
address = bytes[offset++] << 16;
address |= bytes[offset++] << 8;
address |= bytes[offset++];
while ((offset % 4) != 0){
offset++;
}
_endAddress = offset;
}
std::string Instruction::Return::toString() const {
std::stringstream op;
op << "RETURN " << getAddressRegisterName(address, addressOffset);
return op.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);
state.current = jumpAddress;
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
}

54
src/instructions/Return.h Normal file
View file

@ -0,0 +1,54 @@
/*****************************************************************************
* 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 "Instruction.h"
namespace Instruction{
class Return : public Instruction {
public:
Return(){
}
CommandOp getCommand() const override{
return CommandOp::RETURN;
};
void fromBytes(uint32_t offset, const std::vector<uint8_t>& bytes) override;
std::string toString() 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;
};
}

79
src/instructions/Set.cpp Normal file
View file

@ -0,0 +1,79 @@
/*****************************************************************************
* 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 "Set.h"
#include "../Registers.h"
#include <iostream>
#include <iomanip>
void Instruction::Set::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
_address = offset;
uint8_t command = bytes[offset++];
addressOffset = command & 0b11;
address = bytes[offset++] << 16;
address |= bytes[offset++] << 8;
address |= bytes[offset++];
value = bytes[offset++] << 24;
value |= bytes[offset++] << 16;
value |= bytes[offset++] << 8;
value |= bytes[offset++];
mask = bytes[offset++] << 24;
mask |= bytes[offset++] << 16;
mask |= bytes[offset++] << 8;
mask |= bytes[offset++];
while ((offset % 4) != 0){
offset++;
}
_endAddress = offset;
}
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') << mask << ") | " << "0x" << std::hex << std::setw(8) << std::setfill('0') << value;
return op.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.current = _endAddress;
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
}

56
src/instructions/Set.h Normal file
View file

@ -0,0 +1,56 @@
/*****************************************************************************
* 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 "Instruction.h"
namespace Instruction{
class Set : public Instruction {
public:
Set(){
}
CommandOp getCommand() const override{
return CommandOp::SET;
};
void fromBytes(uint32_t offset, const std::vector<uint8_t>& bytes) override;
std::string toString() 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;
uint32_t value;
uint32_t mask;
};
}

66
src/instructions/Wait.cpp Normal file
View file

@ -0,0 +1,66 @@
/*****************************************************************************
* 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 "Wait.h"
#include "../Registers.h"
#include <iostream>
#include <iomanip>
void Instruction::Wait::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
_address = offset;
offset++;
time = bytes[offset++] << 16;
time |= bytes[offset++] << 8;
time |= bytes[offset++];
while ((offset % 4) != 0){
offset++;
}
_endAddress = offset;
}
std::string Instruction::Wait::toString() const {
std::stringstream op;
op << "WAIT " << std::dec << time;
return op.str();
}
std::vector<uint32_t> Instruction::Wait::getPossibleBranches() const {
return std::vector<uint32_t>{_endAddress};
}
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>> Instruction::Wait::execute(AnalysisState &state) const {
//How to wait?
state.current = _endAddress;
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
}

53
src/instructions/Wait.h Normal file
View file

@ -0,0 +1,53 @@
/*****************************************************************************
* 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 "Instruction.h"
namespace Instruction{
class Wait : public Instruction {
public:
Wait(){
}
CommandOp getCommand() const override{
return CommandOp::WAIT;
};
void fromBytes(uint32_t offset, const std::vector<uint8_t>& bytes) override;
std::string toString() 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;
uint32_t time;
};
}

View file

@ -0,0 +1,85 @@
/*****************************************************************************
* 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 "Write.h"
#include "../Registers.h"
#include <iostream>
#include <iomanip>
void Instruction::Write::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
_address = offset;
uint32_t command = bytes[offset++];
uint8_t count = (1 + (command >> 2) & 0b1111);
addressOffset = command & 0b11;
address = bytes[offset++] << 16;
address |= bytes[offset++] << 8;
address |= bytes[offset++];
for(uint32_t i = 0; i < count; ++i){
uint32_t entry = bytes[offset++] << 24;
entry |= bytes[offset++] << 16;
entry |= bytes[offset++] << 8;
entry |= bytes[offset++];
data.emplace_back(entry);
}
while ((offset % 4) != 0){
offset++;
}
_endAddress = offset;
}
std::string Instruction::Write::toString() const {
std::stringstream op;
op << "WRITE " << getAddressRegisterName(address, addressOffset) << " = 0x";
for (auto d : data) {
op << std::hex << std::setw(8) << std::setfill('0') << d;
}
return op.str();
}
std::vector<uint32_t> Instruction::Write::getPossibleBranches() const {
return std::vector<uint32_t>{_endAddress};
}
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>> Instruction::Write::execute(AnalysisState &state) const {
auto memoryOffset = state.getAddressOffset(addressOffset);
for(uint32_t i = 0; i < data.size(); ++i){
state.setRegister(memoryOffset + address + i, data[i]);
}
state.current = _endAddress;
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
}

56
src/instructions/Write.h Normal file
View file

@ -0,0 +1,56 @@
/*****************************************************************************
* 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 "Instruction.h"
namespace Instruction{
class Write : public Instruction {
public:
Write(){
}
CommandOp getCommand() const override{
return CommandOp::WRITE;
};
void fromBytes(uint32_t offset, const std::vector<uint8_t>& bytes) override;
std::string toString() 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;
std::vector<uint32_t> data;
};
}

View file

@ -60,11 +60,12 @@ int main(int argc, char* argv[]) {
}
uint32_t prevAddress = 0;
for(const auto& instruction : imageObject.getInstructions()){
if(instruction.address < prevAddress){
std::cout << "====== DECODE ERROR? ========== " << std::hex << std::setw(8) << std::setfill('0') << prevAddress << " - " << std::hex << std::setw(8) << std::setfill('0') << instruction.address << "\n";
}else if((instruction.address - prevAddress) >= 4 && (instruction.address - prevAddress) < 1024){
for(uint32_t addr = prevAddress; addr < instruction.address; addr += 4){
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') << prevAddress << " - " << std::hex << std::setw(8) << std::setfill('0') << instruction->getAddress() << "\n";
}else if((instruction->getAddress() - prevAddress) >= 4 && (instruction->getAddress() - prevAddress) < 1024){
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 << ": ";
@ -80,11 +81,12 @@ int main(int argc, char* argv[]) {
std::cout << op.str();
}
}else if((instruction.address - prevAddress) >= 1024){
std::cout << "================ " << std::hex << std::setw(8) << std::setfill('0') << prevAddress << " - " << std::hex << std::setw(8) << std::setfill('0') << instruction.address << "\n";
}else if((instruction->getAddress() - prevAddress) >= 1024){
std::cout << "================ " << std::hex << std::setw(8) << std::setfill('0') << prevAddress << " - " << std::hex << std::setw(8) << std::setfill('0') << instruction->getAddress() << "\n";
}
std::cout << instruction.toString() << "\n";
prevAddress = instruction.endAddress;
std::cout << std::hex << std::setw(8) << std::setfill('0') << instruction->getAddress() << ": ";
std::cout << instruction->toString() << "\n";
prevAddress = instruction->getEndAddress();
}
}