Add some tests for SIMD instruction variants
All checks were successful
Test / build (push) Successful in 11s

This commit is contained in:
shylie 2025-08-19 08:03:58 -04:00
parent 80d83f2062
commit e647b9e146
11 changed files with 113 additions and 61 deletions

View File

@ -1,8 +1,8 @@
#include "foot.asm" #include "foot.asm"
CNST. r0, #0xFFFF CNST. r1, #0xFFFF
loop: loop:
CNST. [r0], #65 CNST. [r1], #65
CNST. [r0], #66 CNST. [r1], #66
CNST. r31, #loop CNST. r31, #loop

View File

@ -2,12 +2,10 @@
#subruledef operand #subruledef operand
{ {
#{immediate: i5} => 0b000 @ immediate #{immediate: i5} => 0b00 @ immediate
r{register: u5} => 0b001 @ register r{register: u5} => 0b01 @ register
[r{register: u5}++] => 0b010 @ register [r{register: u5}] => 0b10 @ register
[r{register: u5}--] => 0b011 @ register [r{register: u5}++] => 0b11 @ register
[r{register: u5}] => 0b100 @ register
[r{register: u5} + {offset: u2}] => 0b1 @ offset @ register
} }
#subruledef crflags #subruledef crflags
@ -30,28 +28,29 @@
#ruledef #ruledef
{ {
CNST{flags: crflags} {dst: operand}, #{imm: i16} => imm @ flags @ 0b0000 @ dst CNST{flags: crflags} {dst: operand}, #{imm: i16} => imm[7:0] @ imm[15:8] @ 0b0 @ dst @ flags @ 0b0000
CMPR{flags: crflags} {dst: operand}, {a: operand} => 0x00 @ a @ flags @ 0b0001 @ dst CMPR{flags: crflags} {dst: operand}, {a: operand} => 0b0 @ a @ 0x00 @ 0b0 @ dst @ flags @ 0b0001
BWNG{flags: crflags} {dst: operand}, {a: operand} => 0x01 @ a @ flags @ 0b0001 @ dst BWNG{flags: crflags} {dst: operand}, {a: operand} => 0b0 @ a @ 0x01 @ 0b0 @ dst @ flags @ 0b0001
ARNG{flags: crflags} {dst: operand}, {a: operand} => 0x02 @ a @ flags @ 0b0001 @ dst ARNG{flags: crflags} {dst: operand}, {a: operand} => 0b0 @ a @ 0x02 @ 0b0 @ dst @ flags @ 0b0001
LONG{flags: crflags} {dst: operand}, {a: operand} => 0x03 @ a @ flags @ 0b0001 @ dst LONG{flags: crflags} {dst: operand}, {a: operand} => 0b0 @ a @ 0x03 @ 0b0 @ dst @ flags @ 0b0001
BWOR{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b0010 @ dst CONF{flags: crflags} {dst: operand}, {a: operand} => 0b0 @ a @ 0x04 @ 0b0 @ dst @ flags @ 0b0001
BAND{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b0011 @ dst BWOR{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => 0b0 @ a @ 0b0 @ b @ 0b0 @ dst @ flags @ 0b0010
BXOR{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b0100 @ dst BAND{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => 0b0 @ a @ 0b0 @ b @ 0b0 @ dst @ flags @ 0b0011
URSH{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b0101 @ dst BXOR{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => 0b0 @ a @ 0b0 @ b @ 0b0 @ dst @ flags @ 0b0100
SRSH{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b0110 @ dst SRSH{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => 0b0 @ a @ 0b0 @ b @ 0b0 @ dst @ flags @ 0b0110
ZLSH{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b0111 @ dst ZLSH{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => 0b0 @ a @ 0b0 @ b @ 0b0 @ dst @ flags @ 0b0111
CLSH{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1000 @ dst CLSH{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => 0b0 @ a @ 0b0 @ b @ 0b0 @ dst @ flags @ 0b1000
ADDI{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1001 @ dst ADDI{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => 0b0 @ a @ 0b0 @ b @ 0b0 @ dst @ flags @ 0b1001
SUBT{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1010 @ dst ADDI{flags: crflags}v {dst: operand}, {a: operand}, {b: operand} => 0b1 @ a @ 0b0 @ b @ 0b1 @ dst @ flags @ 0b1001
MULT{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1011 @ dst SUBT{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => 0b0 @ a @ 0b0 @ b @ 0b0 @ dst @ flags @ 0b1010
DIVI{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1110 @ dst MULT{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => 0b0 @ a @ 0b0 @ b @ 0b0 @ dst @ flags @ 0b1011
MODU{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => b @ a @ flags @ 0b1111 @ dst DIVI{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => 0b0 @ a @ 0b0 @ b @ 0b0 @ dst @ flags @ 0b1100
MODU{flags: crflags} {dst: operand}, {a: operand}, {b: operand} => 0b0 @ a @ 0b0 @ b @ 0b0 @ dst @ flags @ 0b1101
} }
#bankdef mem #bankdef mem
{ {
#bits 16 #bits 32
#addr 0 #addr 0
#size 0x10000 #size 0x10000
#outp 0 #outp 0

View File

@ -4,5 +4,7 @@ CNST. r30, #0x1000
loop: loop:
CNST. r0, #0xEFFE CNST. r0, #0xEFFE
CNST.r [r0++], #29 ADDI.r [r0++], [r0], r30
CNST. r0, #0xEFFE
ADDI.rv [r0++], [r0], r30
CNST. r31, #loop CNST. r31, #loop

View File

@ -17,8 +17,8 @@ struct Operand
{ {
Immediate = 0, Immediate = 0,
Direct, Direct,
IndirectAutoIncrement, Indirect,
Indirect IndirectAutoIncrement
} addressing_mode; } addressing_mode;
uint8_t register_index; uint8_t register_index;
}; };

View File

@ -369,8 +369,9 @@ uint32_t Emulator::apply_many_unary(uint32_t a, uint32_t (Emulator::*fn)(uint32_
for (int i = 0; i < simd_elements(); i++) for (int i = 0; i < simd_elements(); i++)
{ {
uint32_t simd_element_a = (a >> (i * 32 / simd_elements())) & ((uint64_t(1) << (32 / simd_elements())) - 1); uint32_t simd_width_mask = ((uint64_t(1) << (32 / simd_elements())) - 1);
uint32_t simd_result = (this->*fn)(simd_element_a) << (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; result |= simd_result;
} }
@ -383,9 +384,10 @@ uint32_t Emulator::apply_many_binary(uint32_t a, uint32_t b, uint32_t (Emulator:
for (int i = 0; i < simd_elements(); i++) for (int i = 0; i < simd_elements(); i++)
{ {
uint32_t simd_element_a = (a >> (i * 32 / simd_elements())) & ((uint64_t(1) << (32 / simd_elements())) - 1); uint32_t simd_width_mask = ((uint64_t(1) << (32 / simd_elements())) - 1);
uint32_t simd_element_b = (b >> (i * 32 / simd_elements())) & ((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_element_b) << (i * 32 / simd_elements()); 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; result |= simd_result;
} }

View File

@ -15,14 +15,14 @@ std::vector<uint32_t> read_file(std::istream& stream)
std::streampos pos = stream.tellg(); std::streampos pos = stream.tellg();
stream.seekg(0, std::ios::end); stream.seekg(0, std::ios::end);
pos = stream.tellg() - pos; pos = stream.tellg() - pos;
buf.resize(pos / 2); buf.resize(pos / 4);
stream.seekg(0, std::ios::beg); stream.seekg(0, std::ios::beg);
for (int i = 0; i < buf.size(); i++) for (int i = 0; i < buf.size(); i++)
{ {
char value[4] = {}; unsigned char value[4] = {};
stream.read(value, 4); stream.read((char*)value, 4);
buf[i] = uint32_t(value[0]) | uint32_t(value[1]) << 8 | uint32_t(value[2]) << 16 | uint32_t(value[3]) << 24; buf[i] = uint32_t(value[0]) | (uint32_t(value[1]) << 8) | (uint32_t(value[2]) << 16) | (uint32_t(value[3]) << 24);
} }
return buf; return buf;
@ -53,12 +53,14 @@ class MemoryViewDevice : public foot::Device
{ {
public: public:
MemoryViewDevice(SDL_Renderer* render, uint8_t width, uint8_t height) : MemoryViewDevice(SDL_Renderer* render, uint8_t width, uint8_t height) :
Device(width * height / 2), Device(width * height),
render(render), render(render),
texture(SDL_CreateTexture(render, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, width, height)), texture(SDL_CreateTexture(render, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STREAMING, width, height)),
width(width), width(width),
height(height) height(height)
{} {
SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_NEAREST);
}
~MemoryViewDevice() ~MemoryViewDevice()
{ {
SDL_DestroyTexture(texture); SDL_DestroyTexture(texture);
@ -67,34 +69,22 @@ public:
bool update() override bool update() override
{ {
int pitch; int pitch;
uint8_t* pixels; uint32_t* pixels;
if (!SDL_LockTexture(texture, nullptr, (void**)&pixels, &pitch)) if (!SDL_LockTexture(texture, nullptr, (void**)&pixels, &pitch))
{ {
std::cout << SDL_GetError() << std::endl; std::cout << SDL_GetError() << std::endl;
} }
int idx = 0; int idx = 0;
for (int i = 0; i < width / 2; i++) for (int i = 0; i < width; i++)
{ {
for (int j = 0; j < height; j++) for (int j = 0; j < height; j++)
{ {
//TODO: fix pixels[i + j * width] = memory(i + j * width);
const uint16_t mem = memory(i + j * width / 2);
const uint8_t left = mem & 0xFF;
const uint8_t right = mem >> 8;
pixels[idx + 0] = left;
pixels[idx + 1] = left;
pixels[idx + 2] = left;
pixels[idx + 3] = right;
pixels[idx + 4] = right;
pixels[idx + 5] = right;
idx += 6;
} }
} }
SDL_UnlockTexture(texture); SDL_UnlockTexture(texture);
SDL_RenderTexture(render, texture, nullptr, nullptr);
SDL_RenderPresent(render); SDL_RenderPresent(render);
SDL_Event event; SDL_Event event;
@ -121,7 +111,6 @@ private:
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
if (argc > 1) if (argc > 1)
{ {
constexpr int WIDTH = 64; constexpr int WIDTH = 64;
@ -139,7 +128,7 @@ int main(int argc, char** argv)
SDL_Renderer* render; SDL_Renderer* render;
SDL_Init(SDL_INIT_VIDEO); SDL_Init(SDL_INIT_VIDEO);
SDL_CreateWindowAndRenderer("foot emulator", WIDTH * 4, HEIGHT * 4, 0, &window, &render); SDL_CreateWindowAndRenderer("foot emulator", WIDTH * 8, HEIGHT * 8, 0, &window, &render);
foot::Emulator emu; foot::Emulator emu;
emu.map_device(std::make_unique<PrintDevice>()); emu.map_device(std::make_unique<PrintDevice>());

View File

@ -14,5 +14,17 @@ int main(int argc, char** argv)
if (!check(0xFFFFBA99, emu.register_at(0))) { return 1; } if (!check(0xFFFFBA99, emu.register_at(0))) { return 1; }
} }
// CNST
// dst - 0, Direct
// imm - 0x4567
//
// ARNG 4-bit SIMD
// dst - 0, Direct
// a - 0, Direct
{
foot::Emulator emu = run_instructions({ 0x00204567, 0x01A002A0 });
if (!check(0x0000CBA9, emu.register_at(0))) { return 1; }
}
return 0; return 0;
} }

View File

@ -31,7 +31,7 @@ int main(int argc, char** argv)
// imm = 0x1234 // imm = 0x1234
{ {
bool failed = false; bool failed = false;
foot::Emulator emu = run_instructions({ 0x003E0010, 0x10501234 }); foot::Emulator emu = run_instructions({ 0x003E0010, 0x10601234 });
for (int i = 0; i < 0x10; i++) 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; }

View File

@ -22,5 +22,18 @@ int main(int argc, char** argv)
if (!check(0x00000001, emu.register_at(0))) { return 1; } if (!check(0x00000001, emu.register_at(0))) { return 1; }
} }
// CNST
// dst - 0, Direct
// imm - 0x0230
//
// LONG 4-bit SIMD
// dst - 0, Direct
// a - 0, Direct
{
foot::Emulator emu = run_instructions({ 0x00200230, 0x01A003A0 });
if (!check(0x11111001, emu.register_at(0))) { return 1; }
}
return 0; return 0;
} }

View File

@ -27,5 +27,22 @@ int main(int argc, char** argv)
if (!check((-2) >> 2, emu.register_at(0))) { return 1; } if (!check((-2) >> 2, emu.register_at(0))) { return 1; }
} }
// CNST
// dst - 0, Direct
// imm - 0x8686
//
// CNST
// dst - 1, Direct
// imm - 0x1122
//
// SRSH - 4-bit SIMD
// dst - 0, Direct
// a - 0, Direct
// b - 1, Direct
{
foot::Emulator emu = run_instructions({ 0x00208686, 0x00211122, 0x06A021A0 });
if (!check(0x4321, emu.register_at(0))) { return 1; }
}
return 0; return 0;
} }

View File

@ -15,5 +15,23 @@ int main(int argc, char** argv)
if (!check(0x0001159C, emu.register_at(0))) { return 1; } if (!check(0x0001159C, emu.register_at(0))) { return 1; }
} }
// CNST
// dst - 0, Direct
// imm - 0x4343
//
// CNST
// dst - 1, Direct
// imm - 0x1122
//
// ZLSH - 4-bit SIMD
// dst - 0, Direct
// a - 0, Direct
// b - 1, Direct
{
foot::Emulator emu = run_instructions({ 0x00204343, 0x00211122, 0x07A021A0 });
if (!check(0x860C, emu.register_at(0))) { return 1; }
}
return 0; return 0;
} }