mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
merged jump/call implementation, removed jumpr
This commit is contained in:
parent
ee6958a729
commit
149a8b6276
9 changed files with 114 additions and 74 deletions
|
|
@ -58,7 +58,7 @@ static const uint32_t NbRegs = sizeof(AllRegs) / sizeof(AllRegs[0]);
|
||||||
// Keep same order than the opcodes list!!
|
// Keep same order than the opcodes list!!
|
||||||
static const std::string Mnemonics[] = {
|
static const std::string Mnemonics[] = {
|
||||||
"nop", "halt", "syscall", "lcons", "mov", "push", "pop", "store", "load", "add", "addi", "sub", "subi", "mul", "div",
|
"nop", "halt", "syscall", "lcons", "mov", "push", "pop", "store", "load", "add", "addi", "sub", "subi", "mul", "div",
|
||||||
"shiftl", "shiftr", "ishiftr", "and", "or", "xor", "not", "call", "ret", "jump", "jumpr", "skipz", "skipnz",
|
"shiftl", "shiftr", "ishiftr", "and", "or", "xor", "not", "call", "ret", "jump", "skipz", "skipnz",
|
||||||
"eq", "gt", "lt"
|
"eq", "gt", "lt"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -200,7 +200,7 @@ bool Assembler::CompileMnemonicArguments(std::shared_ptr<Instr> instr)
|
||||||
instr->compiledArgs.push_back(ra);
|
instr->compiledArgs.push_back(ra);
|
||||||
// Detect address or immedate value
|
// Detect address or immedate value
|
||||||
if ((instr->args[1].at(0) == '$') || (instr->args[1].at(0) == '.')) {
|
if ((instr->args[1].at(0) == '$') || (instr->args[1].at(0) == '.')) {
|
||||||
instr->useLabel = true;
|
instr->labelIndex = 1;
|
||||||
leu32_put(instr->compiledArgs, 0); // reserve 4 bytes
|
leu32_put(instr->compiledArgs, 0); // reserve 4 bytes
|
||||||
} else { // immediate value
|
} else { // immediate value
|
||||||
leu32_put(instr->compiledArgs, convertStringToLong(instr->args[1]));
|
leu32_put(instr->compiledArgs, convertStringToLong(instr->args[1]));
|
||||||
|
|
@ -210,7 +210,6 @@ bool Assembler::CompileMnemonicArguments(std::shared_ptr<Instr> instr)
|
||||||
case OP_PUSH:
|
case OP_PUSH:
|
||||||
case OP_SKIPZ:
|
case OP_SKIPZ:
|
||||||
case OP_SKIPNZ:
|
case OP_SKIPNZ:
|
||||||
case OP_JUMPR:
|
|
||||||
case OP_NOT:
|
case OP_NOT:
|
||||||
GET_REG(instr->args[0], ra);
|
GET_REG(instr->args[0], ra);
|
||||||
instr->compiledArgs.push_back(ra);
|
instr->compiledArgs.push_back(ra);
|
||||||
|
|
@ -246,10 +245,40 @@ bool Assembler::CompileMnemonicArguments(std::shared_ptr<Instr> instr)
|
||||||
}
|
}
|
||||||
case OP_CALL:
|
case OP_CALL:
|
||||||
case OP_JUMP:
|
case OP_JUMP:
|
||||||
// Reserve 4 bytes for address, it will be filled at the end
|
{
|
||||||
instr->useLabel = true;
|
// 5 bytes
|
||||||
instr->compiledArgs.reserve(4);
|
// first byte is option: register based or address
|
||||||
|
// Then 4 bytes (address or just one byte for register)
|
||||||
|
|
||||||
|
// We allow two forms of writing:
|
||||||
|
// - call @r0 ; call the address located in R0
|
||||||
|
// - jump .myFunction ; jump to the label
|
||||||
|
//
|
||||||
|
char prefix = instr->args[0].at(0);
|
||||||
|
|
||||||
|
if (prefix == '@')
|
||||||
|
{
|
||||||
|
instr->compiledArgs.push_back(0); // option zero
|
||||||
|
GET_REG(instr->args[0], ra);
|
||||||
|
instr->compiledArgs.push_back(ra);
|
||||||
|
// Three more bytes to keep same size
|
||||||
|
instr->compiledArgs.push_back(0);
|
||||||
|
instr->compiledArgs.push_back(0);
|
||||||
|
instr->compiledArgs.push_back(0);
|
||||||
|
}
|
||||||
|
else if (prefix == '.')
|
||||||
|
{
|
||||||
|
// Reserve 4 bytes for address, it will be filled at the end
|
||||||
|
instr->labelIndex = 1;
|
||||||
|
instr->compiledArgs.push_back(1); // option 1
|
||||||
|
leu32_put(instr->compiledArgs, 0); // reserve 4 bytes
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CHIP32_CHECK(instr, false, "Jump/Call argument must be @R0 or .myLabel")
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case OP_STORE: // store @r4, r1, 2
|
case OP_STORE: // store @r4, r1, 2
|
||||||
CHIP32_CHECK(instr, instr->args[0].at(0) == '@', "Missing @ sign before register")
|
CHIP32_CHECK(instr, instr->args[0].at(0) == '@', "Missing @ sign before register")
|
||||||
instr->args[0].erase(0, 1);
|
instr->args[0].erase(0, 1);
|
||||||
|
|
@ -270,17 +299,23 @@ bool Assembler::CompileMnemonicArguments(std::shared_ptr<Instr> instr)
|
||||||
// Register based
|
// Register based
|
||||||
if (prefix == '@')
|
if (prefix == '@')
|
||||||
{
|
{
|
||||||
|
// 3 bytes total for arguments
|
||||||
instr->args[1].erase(0, 1); // delete @ character
|
instr->args[1].erase(0, 1); // delete @ character
|
||||||
GET_REG(instr->args[0], ra);
|
GET_REG(instr->args[0], ra);
|
||||||
GET_REG(instr->args[1], rb);
|
GET_REG(instr->args[1], rb);
|
||||||
instr->compiledArgs.push_back(ra);
|
instr->compiledArgs.push_back(ra);
|
||||||
instr->compiledArgs.push_back(rb);
|
instr->compiledArgs.push_back(rb);
|
||||||
instr->compiledArgs.push_back(static_cast<uint32_t>(strtol(instr->args[2].c_str(), NULL, 0)));
|
instr->compiledArgs.push_back(static_cast<uint32_t>(strtol(instr->args[2].c_str(), NULL, 0)));
|
||||||
|
// Three more bytes to keep same size
|
||||||
|
instr->compiledArgs.push_back(0);
|
||||||
|
instr->compiledArgs.push_back(0);
|
||||||
|
instr->compiledArgs.push_back(0);
|
||||||
}
|
}
|
||||||
// Variable based
|
// Variable based
|
||||||
else if (prefix == '$')
|
else if (prefix == '$')
|
||||||
{
|
{
|
||||||
instr->useLabel = true;
|
// 6 bytes
|
||||||
|
instr->labelIndex = 1;
|
||||||
GET_REG(instr->args[0], ra);
|
GET_REG(instr->args[0], ra);
|
||||||
instr->compiledArgs.push_back(ra | 0x80); // Flag this register with a bit to indicate an immediate address is following
|
instr->compiledArgs.push_back(ra | 0x80); // Flag this register with a bit to indicate an immediate address is following
|
||||||
leu32_put(instr->compiledArgs, 0); // reserve 4 bytes
|
leu32_put(instr->compiledArgs, 0); // reserve 4 bytes
|
||||||
|
|
@ -312,7 +347,7 @@ bool Assembler::CompileMnemonicArguments(std::shared_ptr<Instr> instr)
|
||||||
|
|
||||||
bool Assembler::CompileConstantArgument(std::shared_ptr<Instr> instr, const std::string &a)
|
bool Assembler::CompileConstantArgument(std::shared_ptr<Instr> instr, const std::string &a)
|
||||||
{
|
{
|
||||||
instr->compiledArgs.clear(); instr->args.clear(); instr->useLabel = false;
|
instr->compiledArgs.clear(); instr->args.clear(); instr->labelIndex = -1;
|
||||||
|
|
||||||
// Check string
|
// Check string
|
||||||
if (a.size() > 2)
|
if (a.size() > 2)
|
||||||
|
|
@ -332,7 +367,7 @@ bool Assembler::CompileConstantArgument(std::shared_ptr<Instr> instr, const std:
|
||||||
{
|
{
|
||||||
// Label must be 32-bit, throw an error if not the case
|
// Label must be 32-bit, throw an error if not the case
|
||||||
CHIP32_CHECK(instr, instr->dataTypeSize == 32, "Labels must be stored in a 32-bit area (DC32)")
|
CHIP32_CHECK(instr, instr->dataTypeSize == 32, "Labels must be stored in a 32-bit area (DC32)")
|
||||||
instr->useLabel = true;
|
instr->labelIndex = 1;
|
||||||
instr->args.push_back(a);
|
instr->args.push_back(a);
|
||||||
leu32_put(instr->compiledArgs, 0); // reserve 4 bytes
|
leu32_put(instr->compiledArgs, 0); // reserve 4 bytes
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -555,13 +590,21 @@ Position of Data in RAM
|
||||||
// 3. Third pass: replace all label or RAM data by the real address in memory
|
// 3. Third pass: replace all label or RAM data by the real address in memory
|
||||||
for (auto &instr : m_instructions)
|
for (auto &instr : m_instructions)
|
||||||
{
|
{
|
||||||
if (instr->useLabel && (instr->args.size() > 0))
|
if ((instr->labelIndex >=0 ) && (instr->args.size() > 0))
|
||||||
{
|
{
|
||||||
// label is the first argument for JUMP and CALL, second position for LCONS and LOAD
|
// label is the first argument for JUMP and CALL, second position for LCONS and LOAD
|
||||||
uint16_t argsIndex = 1;
|
|
||||||
if ((instr->code.opcode == OP_JUMP) || (instr->code.opcode == OP_CALL)) {
|
// Look where is the label
|
||||||
argsIndex = 0;
|
uint16_t argsIndex = 0;
|
||||||
|
for (auto &arg : instr->args)
|
||||||
|
{
|
||||||
|
if ((arg[0] == '.') || (arg[0] == '$'))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
argsIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string label = instr->args[argsIndex];
|
std::string label = instr->args[argsIndex];
|
||||||
CHIP32_CHECK(instr, m_labels.count(label) > 0, "label not found: " + label);
|
CHIP32_CHECK(instr, m_labels.count(label) > 0, "label not found: " + label);
|
||||||
uint32_t addr = m_labels[label]->addr;
|
uint32_t addr = m_labels[label]->addr;
|
||||||
|
|
@ -570,11 +613,10 @@ Position of Data in RAM
|
||||||
{
|
{
|
||||||
addr |= CHIP32_RAM_OFFSET;
|
addr |= CHIP32_RAM_OFFSET;
|
||||||
}
|
}
|
||||||
|
instr->compiledArgs[instr->labelIndex] = (uint8_t)(addr & 0xFF);
|
||||||
instr->compiledArgs[argsIndex] = addr & 0xFF;
|
instr->compiledArgs[instr->labelIndex + 1] = (uint8_t)((addr >> 8) & 0xFF);
|
||||||
instr->compiledArgs[argsIndex+1] = (addr >> 8U) & 0xFF;
|
instr->compiledArgs[instr->labelIndex + 2] = (uint8_t)((addr >> 16) & 0xFF);
|
||||||
instr->compiledArgs[argsIndex+2] = (addr >> 16U) & 0xFF;
|
instr->compiledArgs[instr->labelIndex + 3] = (uint8_t)((addr >> 24) & 0xFF);
|
||||||
instr->compiledArgs[argsIndex+3] = (addr >> 24U) & 0xFF;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,9 +50,9 @@ struct Instr {
|
||||||
std::string mnemonic;
|
std::string mnemonic;
|
||||||
uint16_t dataTypeSize{0};
|
uint16_t dataTypeSize{0};
|
||||||
uint16_t dataLen{0};
|
uint16_t dataLen{0};
|
||||||
|
int8_t labelIndex{-1}; // index of label in compiled argument (-1 means no label)
|
||||||
|
|
||||||
bool isLabel{false}; //!< If true, this is a label, otherwise it is an instruction
|
bool isLabel{false}; //!< If true, this is a label, otherwise it is an instruction
|
||||||
bool useLabel{false}; //!< If true, the instruction uses a label
|
|
||||||
bool isRomData{false}; //!< True if constant data in ROM (DC)
|
bool isRomData{false}; //!< True if constant data in ROM (DC)
|
||||||
bool isRamData{false}; //!< True if RAM variable (DV or DZ)
|
bool isRamData{false}; //!< True if RAM variable (DV or DZ)
|
||||||
bool isZeroData{false}; //!< True if zero-initialized RAM (DZ only)
|
bool isZeroData{false}; //!< True if zero-initialized RAM (DZ only)
|
||||||
|
|
|
||||||
|
|
@ -204,30 +204,16 @@ chip32_result_t chip32_step(chip32_ctx_t *ctx)
|
||||||
ctx->registers[reg] = pop(ctx);
|
ctx->registers[reg] = pop(ctx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_CALL:
|
|
||||||
{
|
|
||||||
ctx->registers[RA] = ctx->registers[PC] + 4; // set return address to next instruction after CALL (+4 is for address size)
|
|
||||||
const uint8_t reg = _NEXT_BYTE;
|
|
||||||
_CHECK_REGISTER_VALID(reg)
|
|
||||||
ctx->registers[PC] = ctx->registers[reg] - 1;
|
|
||||||
|
|
||||||
// Save Tx registers on stack
|
|
||||||
_CHECK_CAN_PUSH(10)
|
|
||||||
for (int i = 0; i < 10; i++) {
|
|
||||||
push(ctx, ctx->registers[T0 + i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case OP_RET:
|
case OP_RET:
|
||||||
{
|
{
|
||||||
ctx->registers[PC] = ctx->registers[RA] - 1;
|
ctx->registers[PC] = ctx->registers[RA] - 1;
|
||||||
|
_CHECK_CAN_POP(11)
|
||||||
_CHECK_CAN_POP(10)
|
|
||||||
// restore Tx registers from stack
|
// restore Tx registers from stack
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
ctx->registers[T9 - i] = pop(ctx);
|
ctx->registers[T9 - i] = pop(ctx);
|
||||||
}
|
}
|
||||||
|
// restore previous RA
|
||||||
|
ctx->registers[RA] = pop(ctx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OP_STORE:
|
case OP_STORE:
|
||||||
|
|
@ -273,6 +259,7 @@ chip32_result_t chip32_step(chip32_ctx_t *ctx)
|
||||||
_CHECK_REGISTER_VALID(reg2);
|
_CHECK_REGISTER_VALID(reg2);
|
||||||
size = _NEXT_BYTE;
|
size = _NEXT_BYTE;
|
||||||
addr = ctx->registers[reg2];
|
addr = ctx->registers[reg2];
|
||||||
|
ctx->registers[PC] += 3; // skip unused 3 bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isRam = addr & CHIP32_RAM_OFFSET;
|
bool isRam = addr & CHIP32_RAM_OFFSET;
|
||||||
|
|
@ -406,18 +393,48 @@ chip32_result_t chip32_step(chip32_ctx_t *ctx)
|
||||||
ctx->registers[reg1] = ~ctx->registers[reg1];
|
ctx->registers[reg1] = ~ctx->registers[reg1];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OP_CALL:
|
||||||
case OP_JUMP:
|
case OP_JUMP:
|
||||||
{
|
{
|
||||||
ctx->registers[PC] = _NEXT_SHORT(ctx) - 1;
|
const uint8_t option = _NEXT_BYTE;
|
||||||
break;
|
uint32_t target_addr;
|
||||||
}
|
|
||||||
case OP_JUMPR:
|
if (option == 0)
|
||||||
{
|
{
|
||||||
const uint8_t reg = _NEXT_BYTE;
|
// Register-based: @R0
|
||||||
_CHECK_REGISTER_VALID(reg)
|
const uint8_t reg = _NEXT_BYTE;
|
||||||
ctx->registers[PC] = ctx->registers[reg] - 1;
|
_CHECK_REGISTER_VALID(reg)
|
||||||
|
target_addr = ctx->registers[reg];
|
||||||
|
|
||||||
|
// Skip 3 padding bytes
|
||||||
|
ctx->registers[PC] += 3;
|
||||||
|
}
|
||||||
|
else // option == 1
|
||||||
|
{
|
||||||
|
// Address-based: .myLabel
|
||||||
|
target_addr = _NEXT_INT(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If CALL, we have more work to do, saving state to prepare a ret
|
||||||
|
if (instr == OP_CALL)
|
||||||
|
{
|
||||||
|
_CHECK_CAN_PUSH(1)
|
||||||
|
push(ctx, ctx->registers[RA]); // save previous RA
|
||||||
|
ctx->registers[RA] = ctx->registers[PC] + 1;
|
||||||
|
// Save Tx registers on stack
|
||||||
|
_CHECK_CAN_PUSH(10)
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
push(ctx, ctx->registers[T0 + i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform jump
|
||||||
|
ctx->registers[PC] = target_addr - 1;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OP_SKIPZ:
|
case OP_SKIPZ:
|
||||||
case OP_SKIPNZ:
|
case OP_SKIPNZ:
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -80,14 +80,13 @@ typedef enum
|
||||||
OP_CALL = 22, ///< set register RA to the next instruction and jump to subroutine, e.g.: call 0x10 0x00
|
OP_CALL = 22, ///< set register RA to the next instruction and jump to subroutine, e.g.: call 0x10 0x00
|
||||||
OP_RET = 23, ///< return to the address of last callee (RA), e.g.: ret
|
OP_RET = 23, ///< return to the address of last callee (RA), e.g.: ret
|
||||||
OP_JUMP = 24, ///< jump to address (can use label or address), e.g.: jump .my_label
|
OP_JUMP = 24, ///< jump to address (can use label or address), e.g.: jump .my_label
|
||||||
OP_JUMPR = 25, ///< jump to address contained in a register, e.g.: jumpr t9
|
OP_SKIPZ = 25, ///< skip next instruction if zero, e.g.: skipz r0
|
||||||
OP_SKIPZ = 26, ///< skip next instruction if zero, e.g.: skipz r0
|
OP_SKIPNZ = 26, ///< skip next instruction if not zero, e.g.: skipnz r2
|
||||||
OP_SKIPNZ = 27, ///< skip next instruction if not zero, e.g.: skipnz r2
|
|
||||||
|
|
||||||
// Comparison
|
// Comparison
|
||||||
OP_CMP_EQ = 28, ///< compare two registers for equality, result in first e.g.: eq r4, r0, r1 ; similar to: r4 = (r0 == r1 ? 1 : 0
|
OP_CMP_EQ = 27, ///< compare two registers for equality, result in first e.g.: eq r4, r0, r1 ; similar to: r4 = (r0 == r1 ? 1 : 0
|
||||||
OP_CMP_GT = 29, ///< compare if first register is greater than the second, result in first e.g.: gt r4, r0, r1 ; similar to: r4 = (r0 > r1 ? 1 : 0
|
OP_CMP_GT = 28, ///< compare if first register is greater than the second, result in first e.g.: gt r4, r0, r1 ; similar to: r4 = (r0 > r1 ? 1 : 0
|
||||||
OP_CMP_LT = 30, ///< compare if first register is less than the second, result in first e.g.: lt r4, r0, r1 ; similar to: r4 = (r0 < r1 ? 1 : 0
|
OP_CMP_LT = 29, ///< compare if first register is less than the second, result in first e.g.: lt r4, r0, r1 ; similar to: r4 = (r0 < r1 ? 1 : 0
|
||||||
|
|
||||||
INSTRUCTION_COUNT
|
INSTRUCTION_COUNT
|
||||||
} chip32_instruction_t;
|
} chip32_instruction_t;
|
||||||
|
|
@ -161,11 +160,11 @@ typedef struct {
|
||||||
|
|
||||||
#define OPCODES_LIST { { OP_NOP, 0, 0 }, { OP_HALT, 0, 0 }, { OP_SYSCALL, 1, 1 }, { OP_LCONS, 2, 5 }, \
|
#define OPCODES_LIST { { OP_NOP, 0, 0 }, { OP_HALT, 0, 0 }, { OP_SYSCALL, 1, 1 }, { OP_LCONS, 2, 5 }, \
|
||||||
{ OP_MOV, 2, 2 }, { OP_PUSH, 1, 1 }, {OP_POP, 1, 1 }, \
|
{ OP_MOV, 2, 2 }, { OP_PUSH, 1, 1 }, {OP_POP, 1, 1 }, \
|
||||||
{ OP_STORE, 3, 3 }, { OP_LOAD, 3, 3 }, \
|
{ OP_STORE, 3, 3 }, { OP_LOAD, 3, 6 }, \
|
||||||
{ OP_ADD, 2, 2 }, { OP_ADDI, 2, 2 }, { OP_SUB, 2, 2 }, { OP_SUBI, 2, 2 }, { OP_MUL, 2, 2 }, \
|
{ OP_ADD, 2, 2 }, { OP_ADDI, 2, 2 }, { OP_SUB, 2, 2 }, { OP_SUBI, 2, 2 }, { OP_MUL, 2, 2 }, \
|
||||||
{ OP_DIV, 2, 2 }, { OP_SHL, 2, 2 }, { OP_SHR, 2, 2 }, { OP_ISHR, 2, 2 }, { OP_AND, 2, 2 }, \
|
{ OP_DIV, 2, 2 }, { OP_SHL, 2, 2 }, { OP_SHR, 2, 2 }, { OP_ISHR, 2, 2 }, { OP_AND, 2, 2 }, \
|
||||||
{ OP_OR, 2, 2 }, { OP_XOR, 2, 2 }, { OP_NOT, 1, 1 }, { OP_CALL, 1, 1 }, { OP_RET, 0, 0 }, \
|
{ OP_OR, 2, 2 }, { OP_XOR, 2, 2 }, { OP_NOT, 1, 1 }, { OP_CALL, 1, 5 }, { OP_RET, 0, 0 }, \
|
||||||
{ OP_JUMP, 1, 2 }, { OP_JUMPR, 1, 1 }, { OP_SKIPZ, 1, 1 }, { OP_SKIPNZ, 1, 1 }, \
|
{ OP_JUMP, 1, 5 }, { OP_SKIPZ, 1, 1 }, { OP_SKIPNZ, 1, 1 }, \
|
||||||
{ OP_CMP_EQ, 3, 3 }, { OP_CMP_GT, 3, 3 }, { OP_CMP_LT, 3, 3 } }
|
{ OP_CMP_EQ, 3, 3 }, { OP_CMP_GT, 3, 3 }, { OP_CMP_LT, 3, 3 } }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -310,19 +310,6 @@ TEST_CASE_METHOD(VmTestContext, "JUMP - Unconditional jump", "[vm][control][jump
|
||||||
REQUIRE(machine.ctx.registers[R0] == 42);
|
REQUIRE(machine.ctx.registers[R0] == 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE_METHOD(VmTestContext, "JUMPR - Jump to register", "[vm][control][jumpr]") {
|
|
||||||
static const std::string test = R"(
|
|
||||||
lcons r0, .target
|
|
||||||
jumpr r0
|
|
||||||
lcons r1, 99
|
|
||||||
.target:
|
|
||||||
lcons r1, 42
|
|
||||||
halt
|
|
||||||
)";
|
|
||||||
Execute(test);
|
|
||||||
REQUIRE(machine.ctx.registers[R1] == 42);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
// CONTROL FLOW - SKIP
|
// CONTROL FLOW - SKIP
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ void httpServer() async {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Démarrer le serveur
|
// Démarrer le serveur
|
||||||
io.serve(router, 'localhost', 8080).then((server) {
|
io.serve(router.call, 'localhost', 8080).then((server) {
|
||||||
logger.d('Serving at http://${server.address.host}:${server.port}');
|
logger.d('Serving at http://${server.address.host}:${server.port}');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
library libstory;
|
library;
|
||||||
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
library libstory;
|
library;
|
||||||
|
|
||||||
import 'dart:ffi';
|
import 'dart:ffi';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
import 'package:flutter/material.dart' hide Router;
|
import 'package:flutter/material.dart' hide Router;
|
||||||
import 'package:path/path.dart';
|
|
||||||
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:convert';
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
|
@ -10,10 +8,7 @@ import 'dart:typed_data';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:audioplayers/audioplayers.dart';
|
import 'package:audioplayers/audioplayers.dart';
|
||||||
import 'package:file_picker/file_picker.dart';
|
import 'package:file_picker/file_picker.dart';
|
||||||
import 'package:external_path/external_path.dart';
|
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
|
||||||
import 'package:logger/logger.dart';
|
import 'package:logger/logger.dart';
|
||||||
import 'package:file_picker/file_picker.dart';
|
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
import 'libstory/storyvm.dart';
|
import 'libstory/storyvm.dart';
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue