Implemented POPP stack peeking op. Start stdlib.asm and init
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
- implement std_multiply
This commit is contained in:
parent
7d541611dd
commit
bb8df3aae2
|
@ -54,6 +54,8 @@ set(SOURCE_FILES
|
|||
ADD_RESOURCES(embeddedResources
|
||||
asm/registers.asm
|
||||
asm/api.asm
|
||||
asm/init.asm
|
||||
asm/stdlib.asm
|
||||
)
|
||||
|
||||
add_executable(rrc-as src/rrcas.cpp ${SOURCE_FILES} ${embeddedResources})
|
|
@ -20,10 +20,13 @@ Assembler and linker, kind-of 2-Pass. Quite loose token syntax defined in [Token
|
|||
|
||||
### Usage
|
||||
* `$ ./rrc-as code.asm [code2.asm ...] output.bin`
|
||||
* The function named `entrypoint` will be called by init asm
|
||||
* Multiple asm files can be specified. They are interpreted from first in arguments to last.
|
||||
* You can call functions across files, as they will be linked together.
|
||||
* Directive resolution occurs at parsing time, so while you can override values it does not affect previously parsed files.
|
||||
* Directives like `.constant` are passed to the next files.
|
||||
* These files will be automatically included in front every time:
|
||||
* *[asm/registers.asm](asm/registers.asm)*: Base named registers for platform.
|
||||
* *[asm/api.asm](asm/api.asm)*: Registers used for some driver/switch manager operations.
|
||||
* *[asm/api.asm](asm/api.asm)*: Registers used for some driver/switch manager operations.
|
||||
* *[asm/stdlib.asm](asm/stdlib.asm)*: Standard library and other miscellaneous utilities.
|
||||
* *[asm/init.asm](asm/init.asm)*: Sets up some required registers and other config.
|
8
asm/init.asm
Normal file
8
asm/init.asm
Normal file
|
@ -0,0 +1,8 @@
|
|||
; Initialization function
|
||||
|
||||
.constant rrcc_ENTRYPOINT @__init
|
||||
|
||||
__init:
|
||||
MOV rrcc_STACK_POINTER, 0 ; Reset Stack pointer to 0
|
||||
CALL @entrypoint ; Calls user-defined entrypoint
|
||||
END ; Stops execution if it ever returns
|
60
asm/stdlib.asm
Normal file
60
asm/stdlib.asm
Normal file
|
@ -0,0 +1,60 @@
|
|||
; Standard Library
|
||||
|
||||
.constant std_RETURN_VALUE MGMT_SCRATCH_0
|
||||
.constant RRET std_RETURN_VALUE ;Alias
|
||||
|
||||
; Ephemeral registers to be used within functions. These values may not be kept when calling other functions. They can be used when returning values if necessary.
|
||||
; Some std functions might restore these values.
|
||||
.constant std_EPHEMERAL_REGISTER_0 BSM_SCRATCH_START +0x1F0
|
||||
.constant std_EPHEMERAL_REGISTER_1 std_EPHEMERAL_REGISTER_0 +0x1
|
||||
.constant std_EPHEMERAL_REGISTER_2 std_EPHEMERAL_REGISTER_0 +0x2
|
||||
.constant std_EPHEMERAL_REGISTER_3 std_EPHEMERAL_REGISTER_0 +0x3
|
||||
.constant std_EPHEMERAL_REGISTER_4 std_EPHEMERAL_REGISTER_0 +0x4
|
||||
.constant std_EPHEMERAL_REGISTER_5 std_EPHEMERAL_REGISTER_0 +0x5
|
||||
.constant std_EPHEMERAL_REGISTER_6 std_EPHEMERAL_REGISTER_0 +0x6
|
||||
.constant std_EPHEMERAL_REGISTER_7 std_EPHEMERAL_REGISTER_0 +0x7
|
||||
.constant std_EPHEMERAL_REGISTER_8 std_EPHEMERAL_REGISTER_0 +0x8
|
||||
.constant std_EPHEMERAL_REGISTER_9 std_EPHEMERAL_REGISTER_0 +0x9
|
||||
.constant std_EPHEMERAL_REGISTER_A std_EPHEMERAL_REGISTER_0 +0xa
|
||||
.constant std_EPHEMERAL_REGISTER_B std_EPHEMERAL_REGISTER_0 +0xb
|
||||
.constant std_EPHEMERAL_REGISTER_C std_EPHEMERAL_REGISTER_0 +0xc
|
||||
.constant std_EPHEMERAL_REGISTER_D std_EPHEMERAL_REGISTER_0 +0xd
|
||||
.constant std_EPHEMERAL_REGISTER_E std_EPHEMERAL_REGISTER_0 +0xe
|
||||
.constant std_EPHEMERAL_REGISTER_F std_EPHEMERAL_REGISTER_0 +0xf
|
||||
; Abbreviations
|
||||
.constant R0 std_EPHEMERAL_REGISTER_0
|
||||
.constant R1 std_EPHEMERAL_REGISTER_1
|
||||
.constant R2 std_EPHEMERAL_REGISTER_2
|
||||
.constant R3 std_EPHEMERAL_REGISTER_3
|
||||
.constant R4 std_EPHEMERAL_REGISTER_4
|
||||
.constant R5 std_EPHEMERAL_REGISTER_5
|
||||
.constant R6 std_EPHEMERAL_REGISTER_6
|
||||
.constant R7 std_EPHEMERAL_REGISTER_7
|
||||
.constant R8 std_EPHEMERAL_REGISTER_8
|
||||
.constant R9 std_EPHEMERAL_REGISTER_9
|
||||
.constant RA std_EPHEMERAL_REGISTER_A
|
||||
.constant RB std_EPHEMERAL_REGISTER_B
|
||||
.constant RC std_EPHEMERAL_REGISTER_C
|
||||
.constant RD std_EPHEMERAL_REGISTER_D
|
||||
.constant RE std_EPHEMERAL_REGISTER_E
|
||||
.constant RF std_EPHEMERAL_REGISTER_F
|
||||
|
||||
; uint std_multiply(uint A, uint B). Return value on RRET
|
||||
; Uses simple addition
|
||||
; TODO: use add + shift
|
||||
.constant std_mul @std_multiply
|
||||
.constant std_multiply @std_multiply
|
||||
std_multiply:
|
||||
PUSH R0 ; Save old value of R0
|
||||
PUSH BSM_COUNTER_0 ; Save old value of counter
|
||||
POPP R0, 3 ; Get B
|
||||
POPP BSM_COUNTER_0, 4 ; Get A
|
||||
MOV RRET, 0
|
||||
JUMP @.loop ; Skip first iteration
|
||||
.multiply:
|
||||
ADD RRET, RRET, R0 ; Add B to itself A times
|
||||
.loop: LOOP @.multiply ; Check if 0, if not, decrease A and go back. Use COUNTER[0]
|
||||
POP BSM_COUNTER_0 ; Restore old value of counter
|
||||
POP R0 ; Restore old value of R0
|
||||
RET 2 ; Return and get rid of 2 parameters
|
||||
|
|
@ -36,18 +36,35 @@ void Assembler::assemble(uint32_t baseAddress, uint32_t imageSize) {
|
|||
|
||||
uint32_t freeOffsetLocation = baseAddress;
|
||||
|
||||
if(linker.getVariables().find("rrcc_ENTRYPOINT") == linker.getVariables().end()){
|
||||
throw std::runtime_error("rrcc_ENTRYPOINT is not defined");
|
||||
}
|
||||
|
||||
std::string entrypointName;
|
||||
|
||||
for(auto& t : linker.getVariables().at("rrcc_ENTRYPOINT")){
|
||||
if(t.getType() == Token::Type::CodeLabel){
|
||||
entrypointName = t.getTextValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(entrypointName.empty()){
|
||||
throw std::runtime_error("rrcc_ENTRYPOINT is not set");
|
||||
}
|
||||
|
||||
|
||||
if (placementMode == FunctionPlacementMode::PlaceAll) {
|
||||
for (auto &f : linker.getTree()) {
|
||||
if (f.label == "entrypoint") {
|
||||
if (f.label == entrypointName) {
|
||||
baseAddress = freeOffsetLocation;
|
||||
}
|
||||
freeOffsetLocation = placeFunction(freeOffsetLocation, f);
|
||||
}
|
||||
} else {
|
||||
auto entrypoint = getFunctionByLabel("entrypoint");
|
||||
auto entrypoint = getFunctionByLabel(entrypointName);
|
||||
if (entrypoint == nullptr) {
|
||||
throw std::runtime_error("Entrypoint function not found");
|
||||
throw std::runtime_error("Entrypoint function "+entrypointName+" not found");
|
||||
}
|
||||
|
||||
freeOffsetLocation = placeFunction(freeOffsetLocation, *entrypoint);
|
||||
|
|
|
@ -56,6 +56,7 @@ namespace Instruction {
|
|||
|
||||
addOperator("POP", 1, Stack::Pop::fromTokens);
|
||||
addOperator("POPI", 0, Stack::PopImm::fromTokens);
|
||||
addOperator("POPP", 1, Stack::PopPeek::fromTokens);
|
||||
|
||||
addOperator("CALL", 1, Call::fromTokens);
|
||||
addOperator("RET", 0, Ret::fromTokens);
|
||||
|
|
|
@ -81,9 +81,9 @@ namespace Instruction {
|
|||
return std::make_unique<Ret>();
|
||||
}
|
||||
|
||||
Ret::Ret() {
|
||||
instructions.push_back(std::make_unique<Stack::PopImm>(1));
|
||||
instructions.push_back(std::make_unique<Return>(AddressWithOffset{Stack::stackRegisterStart, Stack::stackOffsetRegister}));
|
||||
Ret::Ret(uint32_t count) {
|
||||
instructions.push_back(std::make_unique<Stack::PopImm>(count));
|
||||
instructions.push_back(std::make_unique<Return>(AddressWithOffset{Stack::stackRegisterStart + count - 1, Stack::stackOffsetRegister}));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace Instruction {
|
|||
std::vector<std::unique_ptr<Instruction>> instructions;
|
||||
public:
|
||||
|
||||
Ret();
|
||||
explicit Ret(uint32_t count = 1);
|
||||
|
||||
CommandOp getCommand() const override {
|
||||
return CommandOp::END;
|
||||
|
|
|
@ -78,6 +78,32 @@ namespace Instruction {
|
|||
return v;
|
||||
}
|
||||
|
||||
PopPeek::PopPeek(const AddressWithOffset &address, uint32_t offset, uint8_t count) {
|
||||
if (count > 4) {
|
||||
throw std::runtime_error("PopPeek count cannot be larger than 4 words at once");
|
||||
}
|
||||
instructions.push_back(
|
||||
std::make_unique<Copy>(address, AddressWithOffset{stackRegisterStart - count - offset, stackOffsetRegister}, count));
|
||||
}
|
||||
|
||||
std::vector<uint8_t> PopPeek::toBytes() const {
|
||||
std::vector<uint8_t> v;
|
||||
for (auto &i : instructions) {
|
||||
auto b = i->toBytes();
|
||||
v.insert(v.end(), b.begin(), b.end());
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<Instruction> PopPeek::fromTokens(const Instruction::Instruction::parseOperatorResult &op,
|
||||
const std::vector<Token> &tokens) {
|
||||
return std::make_unique<Stack::PopPeek>(
|
||||
AddressWithOffset{tokens.at(0).getNumericValue(), op.offset1},
|
||||
tokens.size() >= 2 ? tokens.at(1).getNumericValue() : 0,
|
||||
tokens.size() >= 3 ? tokens.at(2).getNumericValue() : 1);
|
||||
}
|
||||
|
||||
PopImm::PopImm(uint8_t count) {
|
||||
instructions.push_back(std::make_unique<CalcImm>(Calc::Operation::SUB, 0, stackOffsetRegisterAddress,
|
||||
stackOffsetRegisterAddress, count));
|
||||
|
|
|
@ -73,6 +73,23 @@ namespace Instruction {
|
|||
fromTokens(const Instruction::parseOperatorResult &op, const std::vector<Token> &tokens);
|
||||
};
|
||||
|
||||
class PopPeek : public Instruction {
|
||||
private:
|
||||
std::vector<std::unique_ptr<Instruction>> instructions;
|
||||
public:
|
||||
|
||||
explicit PopPeek(const AddressWithOffset &address, uint32_t offset = 0, uint8_t count = 1);
|
||||
|
||||
CommandOp getCommand() const override {
|
||||
return CommandOp::END;
|
||||
};
|
||||
|
||||
std::vector<uint8_t> toBytes() const override;
|
||||
|
||||
static std::unique_ptr<Instruction>
|
||||
fromTokens(const Instruction::parseOperatorResult &op, const std::vector<Token> &tokens);
|
||||
};
|
||||
|
||||
class PopImm : public Instruction {
|
||||
private:
|
||||
std::vector<std::unique_ptr<Instruction>> instructions;
|
||||
|
|
|
@ -18,7 +18,9 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
std::vector<EmbeddedResource> embeddedResources = {
|
||||
LOAD_RESOURCE(asm_registers_asm),
|
||||
LOAD_RESOURCE(asm_api_asm)
|
||||
LOAD_RESOURCE(asm_api_asm),
|
||||
LOAD_RESOURCE(asm_stdlib_asm),
|
||||
LOAD_RESOURCE(asm_init_asm)
|
||||
};
|
||||
|
||||
Instruction::Instruction::addDefaultOperators();
|
||||
|
|
Loading…
Reference in a new issue