Implemented POPP stack peeking op. Start stdlib.asm and init
All checks were successful
continuous-integration/drone/push Build is passing

- implement std_multiply
This commit is contained in:
DataHoarder 2021-01-02 06:08:37 +01:00
parent 7d541611dd
commit bb8df3aae2
11 changed files with 145 additions and 9 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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