Custom CPU Architecture and emulator for that architecture made for fun!
You need GNU make and a compiler that supports C11 at minimum installed. GCC and Clang work. Run make release
and the compiled binary should be in the build folder. In addition, you want lua installed to use the assembler script.
$ # create a program
$ vi my-program.turbine
$ # assemble it
$ ./scripts/assembler.lua my-program.turbine my-program.asm
$ # run it
$ ./build/turbine my-program.asm
- 16-bit processor
- Single-threaded
- 0x10000 bytes of memory
- Little-endian
ra
-> General Purpose Registerrb
-> General Purpose Registerrc
-> General Purpose Registerrd
-> General Purpose Registerre
-> General Purpose Registerrsp
-> Stack Pointerrbp
-> Base Pointerrpc
-> Instruction Pointerrac
-> Accumulatorrfl
-> Status Register
0x0
-> Console0x1 - 0xFFFF
-> RAM
0x0
->LOAD [reg flag] [mem addr]
0x1
->DUMP [reg flag] [mem addr]
0x2
->MOVE [reg flag] [reg flag]
*0x3
->LDD [reg flag] [data]
0x4
->PUSH [reg flag]
0x5
->POP [reg flag]
0x6
->ADD [reg flag] [reg flag]
**0x7
->ADC [reg flag] [reg flag]
**0x8
->SUB [reg flag] [reg flag]
**0x9
->SBB [reg flag] [reg flag]
**0xA
->NOT [reg flag]
**0xB
->OR [reg flag] [reg flag]
**0xC
->AND [reg flag] [reg flag]
**0xD
->CMP [reg flag] [reg flag]
0xE
->JUMP [status flag] [mem addr]
0xF
->HLT
*Two byte and one byte instructions do the same for this. This instruction also moves from register 1 to register 2
**These instructions save the result to the accumulator
- When passing in data with a command that uses a register flag, be wary of the amount of bytes that you type in.
- If it has
TWO_BYTES
attached to it, type in two different bytes in little-endian order. Messing this up can mean that a command can be interpreted as data and stuff gets messed up. - Please don't try to manually bit fiddle to build binaries! Use the assembly script I wrote in lua.
- Calling convention: Push arguments to stack
- Turbine doesn't take in the .turbine files! It takes in the .asm files which you get by first assembling the files using the script in ./scripts/assembler.lua
0x0
->RA_BYTE
-> 1 byte to register A0x1
->RA_TWO_BYTES
-> 2 bytes to register A0x2
->RB_BYTE
-> 1 byte to register B0x3
->RB_TWO_BYTES
-> 2 bytes to register B0x4
->RC_BYTE
-> 1 byte to register C0x5
->RC_TWO_BYTES
-> 2 bytes to register C0x6
->RD_BYTE
-> 1 byte to register D0x7
->RD_TWO_BYTES
-> 2 bytes to register D0x8
->RE_BYTE
-> 1 byte to register E0x9
->RE_TWO_BYTES
-> 2 bytes to register E0xa
->STACK_PTR
-> 2 bytes to stack pointer0xb
->BASE_PTR
-> 2 bytes to base pointer0xc
->ACCUMULATOR_BYTE
-> 1 byte to accumulator0xd
->ACCUMULATOR_TWO_BYTE
-> 2 byte to accumulator0xe
->STATUS
-> Status flag(1 byte) to status register
0x0
->CMP_EQUAL_TO
-> WhenCMP
finds both registers equal to each other0x1
->CMP_GREATER_THAN
-> WhenCMP
finds register a greater than b0x2
->CMP_LESS_THAN
-> WhenCMP
finds register a less than b0x3
->ADD_CARRY
-> WhenADC
orADD
set a carry flag0x4
->ADD_NO_CARRY
-> WhenADC
orADD
don't set a carry flag0x5
->SUB_BORROW
-> WhenSBB
orSUB
set a carry flag0x6
->SUB_NO_BORROW
-> WhenSBB
orSUB
don't set a carry flag