This commit is contained in:
parent
2cfaf8b898
commit
6007426eb3
@ -1,54 +1,12 @@
|
||||
# Generated from CLion C/C++ Code Style settings
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignOperands: false
|
||||
AlignTrailingComments: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: true
|
||||
AfterClass: true
|
||||
AfterControlStatement: true
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
BeforeLambdaBody: true
|
||||
BeforeWhile: true
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBraces: Custom
|
||||
BreakConstructorInitializers: AfterColon
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
ColumnLimit: 120
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ContinuationIndentWidth: 2
|
||||
IncludeCategories:
|
||||
- Regex: '^<.*'
|
||||
Priority: 1
|
||||
- Regex: '^".*'
|
||||
Priority: 2
|
||||
- Regex: '.*'
|
||||
Priority: 3
|
||||
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||
IndentCaseBlocks: true
|
||||
InsertNewlineAtEOF: false
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 2
|
||||
NamespaceIndentation: All
|
||||
BasedOnStyle: GNU
|
||||
SpaceBeforeParens: ControlStatementsExceptControlMacros
|
||||
PointerAlignment: Left
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesInAngles: false
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
TabWidth: 4
|
||||
...
|
||||
UseTab: Never
|
||||
IndentWidth: 2
|
||||
ContinuationIndentWidth: 2
|
||||
ConstructorInitializerIndentWidth: 2
|
||||
BreakAfterReturnType: Automatic
|
||||
BreakConstructorInitializers: AfterColon
|
||||
PackConstructorInitializers: Never
|
||||
IncludeBlocks: Regroup
|
||||
BreakBeforeBraces: Allman
|
||||
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "vcppd"]
|
||||
path = vcppd
|
||||
url = https://git.shylie.info/shylie/vcppd.git
|
||||
@ -9,4 +9,5 @@ else()
|
||||
set(FOOT_TESTS OFF)
|
||||
endif()
|
||||
|
||||
add_subdirectory(vcppd)
|
||||
add_subdirectory(emulator)
|
||||
|
||||
@ -4,11 +4,14 @@ project(foot-emulator)
|
||||
|
||||
add_library(foot-emulator src/foot-emulator.cpp include/foot-emulator.h)
|
||||
target_include_directories(foot-emulator PUBLIC include)
|
||||
target_link_libraries(foot-emulator PUBLIC vcppd)
|
||||
set_target_properties(foot-emulator PROPERTIES CXX_STANDARD 20)
|
||||
|
||||
find_package(SDL3 REQUIRED CONFIG)
|
||||
|
||||
add_executable(foot-emulator-cli src/main.cpp)
|
||||
target_link_libraries(foot-emulator-cli PUBLIC foot-emulator SDL3::SDL3)
|
||||
set_target_properties(foot-emulator-cli PROPERTIES CXX_STANDARD 20)
|
||||
|
||||
if(FOOT_TESTS)
|
||||
add_subdirectory(tests)
|
||||
|
||||
@ -3,7 +3,9 @@
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <vcppd/vcppd.h>
|
||||
#include <vector>
|
||||
|
||||
namespace foot
|
||||
@ -26,6 +28,7 @@ struct Operand
|
||||
class Device
|
||||
{
|
||||
friend class Emulator;
|
||||
|
||||
public:
|
||||
virtual ~Device() = default;
|
||||
|
||||
@ -52,7 +55,7 @@ public:
|
||||
static constexpr uint8_t RA = 29;
|
||||
static constexpr uint8_t SP = 28;
|
||||
|
||||
Emulator();
|
||||
explicit Emulator(bool should_trace = false);
|
||||
|
||||
void run(const std::vector<uint32_t>& program);
|
||||
void run(const std::string& filename);
|
||||
@ -80,6 +83,10 @@ private:
|
||||
std::vector<std::pair<std::unique_ptr<Device>, unsigned int>> devices;
|
||||
uint32_t mapped_base;
|
||||
bool keep_running;
|
||||
std::unique_ptr<std::ofstream> vcd_file;
|
||||
std::unique_ptr<std::ostream> null_stream;
|
||||
vcppd::Vcd vcd;
|
||||
bool should_trace;
|
||||
|
||||
void run_internal();
|
||||
void read_instruction();
|
||||
@ -109,8 +116,11 @@ private:
|
||||
uint8_t simd_elements() const;
|
||||
uint8_t shift() const;
|
||||
|
||||
uint32_t apply_many_unary(uint32_t a, uint32_t (Emulator::*fn)(uint32_t a) const) const;
|
||||
uint32_t apply_many_binary(uint32_t a, uint32_t b, uint32_t (Emulator::*fn)(uint32_t a, uint32_t b) const) const;
|
||||
uint32_t apply_many_unary(uint32_t a,
|
||||
uint32_t (Emulator::*fn)(uint32_t a) const) const;
|
||||
uint32_t apply_many_binary(uint32_t a, uint32_t b,
|
||||
uint32_t (Emulator::*fn)(uint32_t a, uint32_t b)
|
||||
const) const;
|
||||
|
||||
uint32_t op_arithmetic_negate(uint32_t a) const;
|
||||
uint32_t op_logical_negate(uint32_t a) const;
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
#include "foot-emulator.h"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <elfio/elfio.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace foot
|
||||
{
|
||||
@ -10,13 +9,15 @@ namespace foot
|
||||
Operand::Operand(uint8_t bits) :
|
||||
addressing_mode(static_cast<AddressingMode>((bits & 0b01100000) >> 5)),
|
||||
register_index(bits & 0b00011111)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
Device::Device(uint16_t size, unsigned int update_frequency) :
|
||||
assigned_memory_base(nullptr),
|
||||
assigned_memory_size(size),
|
||||
update_frequency(update_frequency)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t& Device::memory(uint16_t index)
|
||||
{
|
||||
@ -27,11 +28,54 @@ uint32_t& Device::memory(uint16_t index)
|
||||
return assigned_memory_base[index];
|
||||
}
|
||||
|
||||
Emulator::Emulator() :
|
||||
Emulator::Emulator(bool should_trace) :
|
||||
memory{},
|
||||
registers{},
|
||||
configuration(0),
|
||||
mapped_base(0x00010000)
|
||||
mapped_base(0x00010000),
|
||||
vcd_file(should_trace ? std::make_unique<std::ofstream>("trace.vcd")
|
||||
: nullptr),
|
||||
null_stream(should_trace ? nullptr
|
||||
: std::make_unique<std::ostream>(nullptr)),
|
||||
vcd(vcppd::Builder(should_trace ? *vcd_file : *null_stream)
|
||||
.scope("CPU")
|
||||
.scope("REGISTERS")
|
||||
.trace("0", registers[0])
|
||||
.trace("1", registers[1])
|
||||
.trace("2", registers[2])
|
||||
.trace("3", registers[3])
|
||||
.trace("4", registers[4])
|
||||
.trace("5", registers[5])
|
||||
.trace("6", registers[6])
|
||||
.trace("7", registers[7])
|
||||
.trace("8", registers[8])
|
||||
.trace("9", registers[9])
|
||||
.trace("10", registers[10])
|
||||
.trace("11", registers[11])
|
||||
.trace("12", registers[12])
|
||||
.trace("13", registers[13])
|
||||
.trace("14", registers[14])
|
||||
.trace("15", registers[15])
|
||||
.trace("16", registers[16])
|
||||
.trace("17", registers[17])
|
||||
.trace("18", registers[18])
|
||||
.trace("19", registers[19])
|
||||
.trace("20", registers[20])
|
||||
.trace("21", registers[21])
|
||||
.trace("22", registers[22])
|
||||
.trace("23", registers[23])
|
||||
.trace("24", registers[24])
|
||||
.trace("25", registers[25])
|
||||
.trace("26", registers[26])
|
||||
.trace("27", registers[27])
|
||||
.trace("28", registers[28])
|
||||
.trace("29", registers[29])
|
||||
.trace("30", registers[30])
|
||||
.trace("31", registers[31])
|
||||
.unscope()
|
||||
.unscope()
|
||||
.build()),
|
||||
should_trace(should_trace)
|
||||
{
|
||||
registers[SP] = 0xFFFF; // stack pointer
|
||||
}
|
||||
@ -47,13 +91,21 @@ void Emulator::run(const std::string& filename)
|
||||
{
|
||||
ELFIO::elfio reader;
|
||||
|
||||
if (!reader.load(filename)) { return; }
|
||||
if (!reader.load(filename))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& segment : reader.segments)
|
||||
{
|
||||
if (segment->get_type() != ELFIO::PT_LOAD) { continue; }
|
||||
if (segment->get_type() != ELFIO::PT_LOAD)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(reinterpret_cast<char*>(memory.data()) + segment->get_virtual_address(), segment->get_data(), segment->get_file_size());
|
||||
memcpy(reinterpret_cast<char*>(memory.data())
|
||||
+ segment->get_virtual_address(),
|
||||
segment->get_data(), segment->get_file_size());
|
||||
}
|
||||
|
||||
registers[PC] = reader.get_entry() / 4;
|
||||
@ -68,10 +120,7 @@ void Emulator::map_device(std::unique_ptr<Device>&& device)
|
||||
devices.emplace_back(std::move(device), 0);
|
||||
}
|
||||
|
||||
uint32_t& Emulator::memory_at(uint32_t address)
|
||||
{
|
||||
return memory[address];
|
||||
}
|
||||
uint32_t& Emulator::memory_at(uint32_t address) { return memory[address]; }
|
||||
|
||||
uint32_t& Emulator::decode_operand(Operand operand)
|
||||
{
|
||||
@ -95,13 +144,15 @@ uint32_t& Emulator::decode_operand(Operand operand)
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t& Emulator::register_at(uint8_t index)
|
||||
{
|
||||
return registers[index];
|
||||
}
|
||||
uint32_t& Emulator::register_at(uint8_t index) { return registers[index]; }
|
||||
|
||||
void Emulator::run_instruction()
|
||||
{
|
||||
if (should_trace)
|
||||
{
|
||||
vcd.tick();
|
||||
}
|
||||
|
||||
read_instruction();
|
||||
|
||||
if (!should_run())
|
||||
@ -114,7 +165,10 @@ void Emulator::run_instruction()
|
||||
|
||||
for (int iteration = 0; iteration < loop_count; iteration++)
|
||||
{
|
||||
if (rep) { registers[LC] = iteration; }
|
||||
if (rep)
|
||||
{
|
||||
registers[LC] = iteration;
|
||||
}
|
||||
|
||||
switch ((instruction & 0x0F000000) >> 24)
|
||||
{
|
||||
@ -204,7 +258,10 @@ void Emulator::run_instruction()
|
||||
}
|
||||
}
|
||||
|
||||
if (rep) { registers[LC] = loop_count; }
|
||||
if (rep)
|
||||
{
|
||||
registers[LC] = loop_count;
|
||||
}
|
||||
}
|
||||
|
||||
void Emulator::run_internal()
|
||||
@ -229,12 +286,15 @@ void Emulator::run_internal()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vcd_file)
|
||||
{
|
||||
vcd_file->flush();
|
||||
vcd_file->close();
|
||||
}
|
||||
}
|
||||
|
||||
void Emulator::read_instruction()
|
||||
{
|
||||
instruction = memory[registers[PC]++];
|
||||
}
|
||||
void Emulator::read_instruction() { instruction = memory[registers[PC]++]; }
|
||||
|
||||
void Emulator::CNST()
|
||||
{
|
||||
@ -426,78 +486,85 @@ bool Emulator::should_run() const
|
||||
return status_register == Status::Equal;
|
||||
|
||||
case 4:
|
||||
return status_register == Status::Greater || status_register == Status::Equal;
|
||||
return status_register == Status::Greater
|
||||
|| status_register == Status::Equal;
|
||||
|
||||
case 5:
|
||||
return status_register == Status::Greater;
|
||||
|
||||
case 6:
|
||||
return status_register == Status::Less || status_register == Status::Greater;
|
||||
return status_register == Status::Less
|
||||
|| status_register == Status::Greater;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Emulator::repeats() const
|
||||
{
|
||||
return instruction & 0x10000000;
|
||||
}
|
||||
bool Emulator::repeats() const { return instruction & 0x10000000; }
|
||||
|
||||
uint8_t Emulator::simd_elements() const
|
||||
{
|
||||
uint8_t bits = 0;
|
||||
if (instruction & (1 << 7)) { bits |= 0b01; }
|
||||
if (instruction & (1 << 23)) { bits |= 0b10; }
|
||||
if (instruction & (1 << 7))
|
||||
{
|
||||
bits |= 0b01;
|
||||
}
|
||||
if (instruction & (1 << 23))
|
||||
{
|
||||
bits |= 0b10;
|
||||
}
|
||||
|
||||
return 1 << bits;
|
||||
}
|
||||
|
||||
uint8_t Emulator::shift() const
|
||||
{
|
||||
return configuration & 0x0000001F;
|
||||
}
|
||||
uint8_t Emulator::shift() const { return configuration & 0x0000001F; }
|
||||
|
||||
uint32_t Emulator::apply_many_unary(uint32_t a, uint32_t (Emulator::*fn)(uint32_t a) const) const
|
||||
uint32_t Emulator::apply_many_unary(uint32_t a,
|
||||
uint32_t (Emulator::*fn)(uint32_t a)
|
||||
const) const
|
||||
{
|
||||
uint32_t result = 0;
|
||||
|
||||
for (int i = 0; i < simd_elements(); i++)
|
||||
{
|
||||
uint32_t simd_width_mask = ((uint64_t(1) << (32 / simd_elements())) - 1);
|
||||
uint32_t simd_element_a = (a >> (i * 32 / simd_elements())) & simd_width_mask;
|
||||
uint32_t simd_result = ((this->*fn)(simd_element_a) & simd_width_mask) << (i * 32 / simd_elements());
|
||||
uint32_t simd_element_a
|
||||
= (a >> (i * 32 / simd_elements())) & simd_width_mask;
|
||||
uint32_t simd_result = ((this->*fn)(simd_element_a)&simd_width_mask)
|
||||
<< (i * 32 / simd_elements());
|
||||
result |= simd_result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t Emulator::apply_many_binary(uint32_t a, uint32_t b, uint32_t (Emulator::*fn)(uint32_t a, uint32_t b) const) const
|
||||
uint32_t Emulator::apply_many_binary(uint32_t a, uint32_t b,
|
||||
uint32_t (Emulator::*fn)(uint32_t a,
|
||||
uint32_t b)
|
||||
const) const
|
||||
{
|
||||
uint32_t result = 0;
|
||||
|
||||
for (int i = 0; i < simd_elements(); i++)
|
||||
{
|
||||
uint32_t simd_width_mask = ((uint64_t(1) << (32 / simd_elements())) - 1);
|
||||
uint32_t simd_element_a = (a >> (i * 32 / simd_elements())) & simd_width_mask;
|
||||
uint32_t simd_element_b = (b >> (i * 32 / simd_elements())) & simd_width_mask;
|
||||
uint32_t simd_result = ((this->*fn)(simd_element_a, simd_element_b) & simd_width_mask) << (i * 32 / simd_elements());
|
||||
uint32_t simd_element_a
|
||||
= (a >> (i * 32 / simd_elements())) & simd_width_mask;
|
||||
uint32_t simd_element_b
|
||||
= (b >> (i * 32 / simd_elements())) & simd_width_mask;
|
||||
uint32_t simd_result
|
||||
= ((this->*fn)(simd_element_a, simd_element_b) & simd_width_mask)
|
||||
<< (i * 32 / simd_elements());
|
||||
result |= simd_result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t Emulator::op_arithmetic_negate(uint32_t a) const
|
||||
{
|
||||
return -a;
|
||||
}
|
||||
uint32_t Emulator::op_arithmetic_negate(uint32_t a) const { return -a; }
|
||||
|
||||
uint32_t Emulator::op_logical_negate(uint32_t a) const
|
||||
{
|
||||
return !a;
|
||||
}
|
||||
uint32_t Emulator::op_logical_negate(uint32_t a) const { return !a; }
|
||||
|
||||
uint32_t Emulator::op_pad_zero_right_shift(uint32_t a, uint32_t b) const
|
||||
{
|
||||
@ -519,15 +586,9 @@ uint32_t Emulator::op_circular_left_shift(uint32_t a, uint32_t b) const
|
||||
return (a << b) | (a >> (32 - b));
|
||||
}
|
||||
|
||||
uint32_t Emulator::op_add(uint32_t a, uint32_t b) const
|
||||
{
|
||||
return a + b;
|
||||
}
|
||||
uint32_t Emulator::op_add(uint32_t a, uint32_t b) const { return a + b; }
|
||||
|
||||
uint32_t Emulator::op_sub(uint32_t a, uint32_t b) const
|
||||
{
|
||||
return a - b;
|
||||
}
|
||||
uint32_t Emulator::op_sub(uint32_t a, uint32_t b) const { return a - b; }
|
||||
|
||||
uint32_t Emulator::op_mul(uint32_t a, uint32_t b) const
|
||||
{
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
#include "foot-emulator.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -36,16 +34,14 @@ public:
|
||||
MemoryViewDevice(SDL_Renderer* render, uint8_t width, uint8_t height) :
|
||||
Device(width * height, 10000),
|
||||
render(render),
|
||||
texture(SDL_CreateTexture(render, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STREAMING, width, height)),
|
||||
texture(SDL_CreateTexture(render, SDL_PIXELFORMAT_RGBA32,
|
||||
SDL_TEXTUREACCESS_STREAMING, width, height)),
|
||||
width(width),
|
||||
height(height)
|
||||
{
|
||||
SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_NEAREST);
|
||||
}
|
||||
~MemoryViewDevice()
|
||||
{
|
||||
SDL_DestroyTexture(texture);
|
||||
}
|
||||
~MemoryViewDevice() { SDL_DestroyTexture(texture); }
|
||||
|
||||
bool update() override
|
||||
{
|
||||
@ -100,9 +96,10 @@ int main(int argc, char** argv)
|
||||
SDL_Renderer* render;
|
||||
|
||||
SDL_Init(SDL_INIT_VIDEO);
|
||||
SDL_CreateWindowAndRenderer("foot emulator", WIDTH * 8, HEIGHT * 8, 0, &window, &render);
|
||||
SDL_CreateWindowAndRenderer("foot emulator", WIDTH * 8, HEIGHT * 8, 0,
|
||||
&window, &render);
|
||||
|
||||
foot::Emulator emu;
|
||||
foot::Emulator emu(true);
|
||||
emu.map_device(std::make_unique<PrintDevice>());
|
||||
emu.map_device(std::make_unique<MemoryViewDevice>(render, WIDTH, HEIGHT));
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ function(test name)
|
||||
add_executable(foot-emulator-test-${name} ${name}.cpp test-common.h)
|
||||
target_link_libraries(foot-emulator-test-${name} PUBLIC foot-emulator)
|
||||
add_test(NAME ${name} COMMAND foot-emulator-test-${name})
|
||||
set_target_properties(foot-emulator-test-${name} PROPERTIES CXX_STANDARD 20)
|
||||
endfunction()
|
||||
|
||||
test(cnst-instruction)
|
||||
|
||||
@ -12,7 +12,10 @@ int main(int argc, char** argv)
|
||||
// b - 2, Immediate
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00204567, 0x09200220 });
|
||||
if (!check(0x00004569, emu.register_at(0))) { return 1; }
|
||||
if (!check(0x00004569, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -11,7 +11,10 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00204567, 0x01200220 });
|
||||
if (!check(0xFFFFBA99, emu.register_at(0))) { return 1; }
|
||||
if (!check(0xFFFFBA99, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// CNST
|
||||
@ -23,7 +26,10 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00204567, 0x01A002A0 });
|
||||
if (!check(0x0000CBA9, emu.register_at(0))) { return 1; }
|
||||
if (!check(0x0000CBA9, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -15,8 +15,12 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
// b - 1, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00204567, 0x00212345, 0x03202021 });
|
||||
if (!check(0x00004567 & 0x00002345, emu.register_at(0))) { return 1; }
|
||||
foot::Emulator emu
|
||||
= run_instructions({ 0x00204567, 0x00212345, 0x03202021 });
|
||||
if (!check(0x00004567 & 0x00002345, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -11,7 +11,10 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00204567, 0x01200120 });
|
||||
if (!check(0xFFFFBA98, emu.register_at(0))) { return 1; }
|
||||
if (!check(0xFFFFBA98, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -15,8 +15,12 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
// b - 1, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00204567, 0x00212345, 0x02202021 });
|
||||
if (!check(0x00004567 | 0x00002345, emu.register_at(0))) { return 1; }
|
||||
foot::Emulator emu
|
||||
= run_instructions({ 0x00204567, 0x00212345, 0x02202021 });
|
||||
if (!check(0x00004567 | 0x00002345, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -15,8 +15,12 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
// b - 1, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00204567, 0x00212345, 0x04202021 });
|
||||
if (!check(0x00004567 ^ 0x00002345, emu.register_at(0))) { return 1; }
|
||||
foot::Emulator emu
|
||||
= run_instructions({ 0x00204567, 0x00212345, 0x04202021 });
|
||||
if (!check(0x00004567 ^ 0x00002345, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -12,7 +12,10 @@ int main(int argc, char** argv)
|
||||
// b - 2, Immediate
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00204567, 0x08201820 });
|
||||
if (!check(0x67000045, emu.register_at(0))) { return 1; }
|
||||
if (!check(0x67000045, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -7,7 +7,10 @@ int main(int argc, char** argv)
|
||||
// imm - 0xFFFF
|
||||
{
|
||||
foot::Emulator emu = run_instruction(0x0020FFFF);
|
||||
if (!check(0xFFFF, emu.register_at(0))) { return 1; }
|
||||
if (!check(0xFFFF, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// CNST
|
||||
@ -19,7 +22,10 @@ int main(int argc, char** argv)
|
||||
// imm = 0x7777
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x0020FFFF, 0x00407777 });
|
||||
if (!check(0x7777, emu.memory_at(0xFFFF))) { return 1; }
|
||||
if (!check(0x7777, emu.memory_at(0xFFFF)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// CNST
|
||||
@ -34,10 +40,16 @@ int main(int argc, char** argv)
|
||||
foot::Emulator emu = run_instructions({ 0x003E0010, 0x10601234 });
|
||||
for (int i = 0; i < 0x10; i++)
|
||||
{
|
||||
if (!check(0x1234, emu.memory_at(i))) { failed = true; }
|
||||
if (!check(0x1234, emu.memory_at(i)))
|
||||
{
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (failed) { return 1; }
|
||||
if (failed)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -12,7 +12,10 @@ int main(int argc, char** argv)
|
||||
// b - 2, Immediate
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00200005, 0x0C200220 });
|
||||
if (!check(0x00000002, emu.register_at(0))) { return 1; }
|
||||
if (!check(0x00000002, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// CNST
|
||||
@ -28,8 +31,12 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
// b - 1, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00200007, 0x01210207, 0x0C202120 });
|
||||
if (!check(0xFFFFFFFF, emu.register_at(0))) { return 1; }
|
||||
foot::Emulator emu
|
||||
= run_instructions({ 0x00200007, 0x01210207, 0x0C202120 });
|
||||
if (!check(0xFFFFFFFF, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// ARNG
|
||||
@ -45,8 +52,12 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
// b - 1, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instructions({0x01200207, 0x01210207, 0x0C202120 });
|
||||
if (!check(0x1, emu.register_at(0))) { return 1; }
|
||||
foot::Emulator emu
|
||||
= run_instructions({ 0x01200207, 0x01210207, 0x0C202120 });
|
||||
if (!check(0x1, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// CNST
|
||||
@ -66,9 +77,14 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
// b - 1, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00200002, 0x00210001, 0x01000401, 0x0C202120 });
|
||||
foot::Emulator emu
|
||||
= run_instructions({ 0x00200002, 0x00210001, 0x01000401, 0x0C202120 });
|
||||
// 1 / 0.5 = 2
|
||||
if (!check(2 << 1 /* shift 1 for 31.1 fixed-point format */, emu.register_at(0))) { return 1; }
|
||||
if (!check(2 << 1 /* shift 1 for 31.1 fixed-point format */,
|
||||
emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -11,7 +11,10 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00204567, 0x01200320 });
|
||||
if (!check(0x00000000, emu.register_at(0))) { return 1; }
|
||||
if (!check(0x00000000, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// LONG
|
||||
@ -19,7 +22,10 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instruction(0x01200320);
|
||||
if (!check(0x00000001, emu.register_at(0))) { return 1; }
|
||||
if (!check(0x00000001, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// CNST
|
||||
@ -31,9 +37,11 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00200230, 0x01A003A0 });
|
||||
if (!check(0x11111001, emu.register_at(0))) { return 1; }
|
||||
if (!check(0x11111001, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -12,7 +12,10 @@ int main(int argc, char** argv)
|
||||
// b - 2, Immediate
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00200005, 0x0D200220 });
|
||||
if (!check(0x1, emu.register_at(0))) { return 1; }
|
||||
if (!check(0x1, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// CNST
|
||||
@ -28,8 +31,12 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
// b - 1, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00200005, 0x01210202, 0x0D202120 });
|
||||
if (!check(0x1, emu.register_at(0))) { return 1; }
|
||||
foot::Emulator emu
|
||||
= run_instructions({ 0x00200005, 0x01210202, 0x0D202120 });
|
||||
if (!check(0x1, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// ARNG
|
||||
@ -45,8 +52,12 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
// b - 1, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x01200202, 0x00210005, 0x0D202120 });
|
||||
if (!check(0xFFFFFFFE, emu.register_at(0))) { return 1; }
|
||||
foot::Emulator emu
|
||||
= run_instructions({ 0x01200202, 0x00210005, 0x0D202120 });
|
||||
if (!check(0xFFFFFFFE, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// CNST
|
||||
@ -66,9 +77,13 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
// b - 1, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00200005, 0x00210003, 0x01000401, 0x0D202120 });
|
||||
foot::Emulator emu
|
||||
= run_instructions({ 0x00200005, 0x00210003, 0x01000401, 0x0D202120 });
|
||||
|
||||
if (!check(0x2, emu.register_at(0))) { return 1; }
|
||||
if (!check(0x2, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -12,7 +12,10 @@ int main(int argc, char** argv)
|
||||
// b - 2, Immediate
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00200003, 0x0B200220 });
|
||||
if (!check(0x0006, emu.register_at(0))) { return 1; }
|
||||
if (!check(0x0006, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// CNST
|
||||
@ -28,8 +31,12 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
// b - 1, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00200007, 0x01210207, 0x0B202120 });
|
||||
if (!check(0xFFFFFFCF, emu.register_at(0))) { return 1; }
|
||||
foot::Emulator emu
|
||||
= run_instructions({ 0x00200007, 0x01210207, 0x0B202120 });
|
||||
if (!check(0xFFFFFFCF, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// ARNG
|
||||
@ -45,8 +52,12 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
// b - 1, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x01200207, 0x01210207, 0x0B202120 });
|
||||
if (!check(0x31, emu.register_at(0))) { return 1; }
|
||||
foot::Emulator emu
|
||||
= run_instructions({ 0x01200207, 0x01210207, 0x0B202120 });
|
||||
if (!check(0x31, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// CNST
|
||||
@ -66,9 +77,14 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
// b - 1, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00200007, 0x00210007, 0x01000401, 0x0B202120 });
|
||||
foot::Emulator emu
|
||||
= run_instructions({ 0x00200007, 0x00210007, 0x01000401, 0x0B202120 });
|
||||
// 3.5 * 3.5 = 12.25 -- truncated to 12 with 31.1 fixed-point format
|
||||
if (!check(12 << 1 /* shift 1 for 31.1 fixed-point format */, emu.register_at(0))) { return 1; }
|
||||
if (!check(12 << 1 /* shift 1 for 31.1 fixed-point format */,
|
||||
emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -12,7 +12,10 @@ int main(int argc, char** argv)
|
||||
// b - 2, Immediate
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00204567, 0x06200220 });
|
||||
if (!check(0x4567 >> 2, emu.register_at(0))) { return 1; }
|
||||
if (!check(0x4567 >> 2, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// ARNG
|
||||
@ -24,7 +27,10 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x01200204, 0x06200220 });
|
||||
if (!check((-2) >> 2, emu.register_at(0))) { return 1; }
|
||||
if (!check((-2) >> 2, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// CNST
|
||||
@ -40,8 +46,12 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
// b - 1, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00208686, 0x00211122, 0x06A021A0 });
|
||||
if (!check(0x4321, emu.register_at(0))) { return 1; }
|
||||
foot::Emulator emu
|
||||
= run_instructions({ 0x00208686, 0x00211122, 0x06A021A0 });
|
||||
if (!check(0x4321, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -12,7 +12,10 @@ int main(int argc, char** argv)
|
||||
// b - 2, Immediate
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00204567, 0x0A200220 });
|
||||
if (!check(0x4565, emu.register_at(0))) { return 1; }
|
||||
if (!check(0x4565, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// CNST
|
||||
@ -28,8 +31,12 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
// b - 1, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00204567, 0x01210202, 0x0A202120 });
|
||||
if (!check(0x4569, emu.register_at(0))) { return 1; }
|
||||
foot::Emulator emu
|
||||
= run_instructions({ 0x00204567, 0x01210202, 0x0A202120 });
|
||||
if (!check(0x4569, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
#include <foot-emulator.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
inline foot::Emulator run_instruction(uint32_t instruction)
|
||||
@ -12,7 +11,8 @@ inline foot::Emulator run_instruction(uint32_t instruction)
|
||||
return emu;
|
||||
}
|
||||
|
||||
inline foot::Emulator run_instructions(const std::vector<uint32_t>& instructions)
|
||||
inline foot::Emulator
|
||||
run_instructions(const std::vector<uint32_t>& instructions)
|
||||
{
|
||||
foot::Emulator emu;
|
||||
for (int i = 0; i < instructions.size(); i++)
|
||||
@ -32,7 +32,8 @@ inline bool check(uint32_t expected, uint32_t actual)
|
||||
{
|
||||
if (actual != expected)
|
||||
{
|
||||
std::cout << std::hex << "Expected " << expected << ", got " << actual << ".\n";
|
||||
std::cout << std::hex << "Expected " << expected << ", got " << actual
|
||||
<< ".\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -12,7 +12,10 @@ int main(int argc, char** argv)
|
||||
// b - 2, Immediate
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00204567, 0x07200220 });
|
||||
if (!check(0x0001159C, emu.register_at(0))) { return 1; }
|
||||
if (!check(0x0001159C, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// CNST
|
||||
@ -28,10 +31,13 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
// b - 1, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00204343, 0x00211122, 0x07A021A0 });
|
||||
if (!check(0x860C, emu.register_at(0))) { return 1; }
|
||||
foot::Emulator emu
|
||||
= run_instructions({ 0x00204343, 0x00211122, 0x07A021A0 });
|
||||
if (!check(0x860C, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -12,7 +12,10 @@ int main(int argc, char** argv)
|
||||
// b - 2, Immediate
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00204567, 0x05200220 });
|
||||
if (!check(0x1159, emu.register_at(0))) { return 1; }
|
||||
if (!check(0x1159, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// CNST
|
||||
@ -28,8 +31,12 @@ int main(int argc, char** argv)
|
||||
// a - 0, Direct
|
||||
// b - 1, Direct
|
||||
{
|
||||
foot::Emulator emu = run_instructions({ 0x00204343, 0x00211122, 0x05A021A0 });
|
||||
if (!check(0x2110, emu.register_at(0))) { return 1; }
|
||||
foot::Emulator emu
|
||||
= run_instructions({ 0x00204343, 0x00211122, 0x05A021A0 });
|
||||
if (!check(0x2110, emu.register_at(0)))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
15
foot.script
15
foot.script
@ -7,5 +7,18 @@ ENTRY(entry);
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x0;
|
||||
.text :
|
||||
{
|
||||
*(.text)
|
||||
*(.text.*)
|
||||
_etext = .;
|
||||
}
|
||||
|
||||
.data : AT(_etext)
|
||||
{
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
*(.data)
|
||||
*(.data.*)
|
||||
}
|
||||
}
|
||||
|
||||
1
vcppd
Submodule
1
vcppd
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 83ff5b450cf5590d222aeb13e4dbd3f7fcf47f63
|
||||
Loading…
x
Reference in New Issue
Block a user