Add vcd waveform tracing
Some checks failed
Test / build (push) Failing after 4s

This commit is contained in:
shylie 2026-03-25 01:43:20 -04:00
parent 2cfaf8b898
commit 6007426eb3
27 changed files with 391 additions and 218 deletions

View File

@ -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
View File

@ -0,0 +1,3 @@
[submodule "vcppd"]
path = vcppd
url = https://git.shylie.info/shylie/vcppd.git

View File

@ -9,4 +9,5 @@ else()
set(FOOT_TESTS OFF)
endif()
add_subdirectory(vcppd)
add_subdirectory(emulator)

View File

@ -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)

View File

@ -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;
@ -39,7 +42,7 @@ protected:
private:
uint32_t* assigned_memory_base;
uint32_t assigned_memory_size;
uint32_t assigned_memory_size;
unsigned int update_frequency;
};
@ -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;
@ -127,4 +137,4 @@ private:
}
#endif//FOOT_EMULATOR
#endif // FOOT_EMULATOR

View File

@ -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)
{
@ -88,20 +137,22 @@ uint32_t& Emulator::decode_operand(Operand operand)
return memory[registers[operand.register_index]++];
case Operand::AddressingMode::Indirect:
return memory[registers[operand.register_index]];
return memory[registers[operand.register_index]];
default:
return dummy_value;
}
}
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()
{
@ -262,7 +322,7 @@ void Emulator::CMPR()
void Emulator::BWNG()
{
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = ~a;
@ -270,7 +330,7 @@ void Emulator::BWNG()
void Emulator::ARNG()
{
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = apply_many_unary(a, &Emulator::op_arithmetic_negate);
@ -278,7 +338,7 @@ void Emulator::ARNG()
void Emulator::LONG()
{
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = apply_many_unary(a, &Emulator::op_logical_negate);
@ -286,7 +346,7 @@ void Emulator::LONG()
void Emulator::CONF()
{
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = configuration;
@ -295,7 +355,7 @@ void Emulator::CONF()
void Emulator::COPY()
{
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = a;
@ -303,8 +363,8 @@ void Emulator::COPY()
void Emulator::BWOR()
{
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = a | b;
@ -312,8 +372,8 @@ void Emulator::BWOR()
void Emulator::BAND()
{
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = a & b;
@ -321,8 +381,8 @@ void Emulator::BAND()
void Emulator::BXOR()
{
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = a ^ b;
@ -330,8 +390,8 @@ void Emulator::BXOR()
void Emulator::ZRSH()
{
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = apply_many_binary(a, b, &Emulator::op_pad_zero_right_shift);
@ -339,8 +399,8 @@ void Emulator::ZRSH()
void Emulator::SRSH()
{
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = apply_many_binary(a, b, &Emulator::op_signed_right_shift);
@ -348,8 +408,8 @@ void Emulator::SRSH()
void Emulator::ZLSH()
{
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = apply_many_binary(a, b, &Emulator::op_pad_zero_left_shift);
@ -357,8 +417,8 @@ void Emulator::ZLSH()
void Emulator::CLSH()
{
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = apply_many_binary(a, b, &Emulator::op_circular_left_shift);
@ -366,8 +426,8 @@ void Emulator::CLSH()
void Emulator::ADDI()
{
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = apply_many_binary(a, b, &Emulator::op_add);
@ -375,8 +435,8 @@ void Emulator::ADDI()
void Emulator::SUBT()
{
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = apply_many_binary(a, b, &Emulator::op_sub);
@ -384,8 +444,8 @@ void Emulator::SUBT()
void Emulator::MULT()
{
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = apply_many_binary(a, b, &Emulator::op_mul);
@ -393,8 +453,8 @@ void Emulator::MULT()
void Emulator::DIVI()
{
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = apply_many_binary(a, b, &Emulator::op_div);
@ -402,8 +462,8 @@ void Emulator::DIVI()
void Emulator::MODU()
{
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t a = decode_operand(instruction & 0x000000FF);
uint32_t b = decode_operand((instruction & 0x0000FF00) >> 8);
uint32_t& d = decode_operand((instruction & 0x00FF0000) >> 16);
d = apply_many_binary(a, b, &Emulator::op_mod);
@ -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
{
@ -545,4 +606,4 @@ uint32_t Emulator::op_mod(uint32_t a, uint32_t b) const
return int32_t(a) % int32_t(b);
}
}
}

View File

@ -1,9 +1,7 @@
#include "foot-emulator.h"
#include <fstream>
#include <iostream>
#include <SDL3/SDL.h>
#include <iostream>
namespace
{
@ -26,7 +24,7 @@ public:
value = 0;
}
return false;
return false;
}
};
@ -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));

View File

@ -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)
@ -23,4 +24,4 @@ test(addi-instruction)
test(subt-instruction)
test(mult-instruction)
test(divi-instruction)
test(modu-instruction)
test(modu-instruction)

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -1,4 +1,4 @@
#include "test-common.h"
#include "test-common.h"
int main(int argc, char** argv)
{
@ -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;
}

View File

@ -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;

View File

@ -7,5 +7,18 @@ ENTRY(entry);
SECTIONS
{
. = 0x0;
.text :
{
*(.text)
*(.text.*)
_etext = .;
}
.data : AT(_etext)
{
*(.rodata)
*(.rodata.*)
*(.data)
*(.data.*)
}
}

1
vcppd Submodule

@ -0,0 +1 @@
Subproject commit 83ff5b450cf5590d222aeb13e4dbd3f7fcf47f63