{"id":19320217,"url":"https://github.com/widberg/kasm","last_synced_at":"2025-04-22T18:30:29.439Z","repository":{"id":136103760,"uuid":"298049917","full_name":"widberg/kasm","owner":"widberg","description":"A MIPS-like virtual machine and assembler.","archived":false,"fork":false,"pushed_at":"2021-06-11T05:30:03.000Z","size":3180,"stargazers_count":6,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-16T19:15:59.090Z","etag":null,"topics":["assembler","assembly","mips","programming-language","virtual-machine"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/widberg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-09-23T17:47:53.000Z","updated_at":"2022-08-23T08:13:13.000Z","dependencies_parsed_at":null,"dependency_job_id":"7036f33b-00a6-4c68-84ff-364bd65b5a01","html_url":"https://github.com/widberg/kasm","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/widberg%2Fkasm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/widberg%2Fkasm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/widberg%2Fkasm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/widberg%2Fkasm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/widberg","download_url":"https://codeload.github.com/widberg/kasm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250297078,"owners_count":21407147,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["assembler","assembly","mips","programming-language","virtual-machine"],"created_at":"2024-11-10T01:27:53.583Z","updated_at":"2025-04-22T18:30:29.428Z","avatar_url":"https://github.com/widberg.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# kasm\n\nA MIPS-like virtual machine, compiler, and assembler.\n\n## Compilers Targeting KASM\n\n* [Kiwi Language Compiler](https://github.com/litala123/kiwi-lang) by [litala123](https://github.com/litala123)\n\n## Getting Started\n\nThese instructions will get you a copy of the project up and running on your local machine for development and testing purposes.\n\n### Prerequisites\n\n* CMake \u003e= 3.2\n\n### Checkout\n\n```sh\ngit clone https://github.com/widberg/kasm.git\ncd kasm\n```\n\n### Build\n\n```sh\nmkdir build\ncd build\ncmake ..\ncmake --build .\n```\n\n## KASM Environment\n\n### Tools\n\n* kasm - Assembler\n  - `kasm asm source.kasm o.kexe`\n* kdsm - Disassembler\n  - `kasm dsm o.kexe source.kasm`\n* kvm - Virtual Machine\n  - `kasm vm o.kexe`\n* kdbg - Debugger\n* klang - K Structured Programming Language Compiler\n\n## kasm/kvm\n\n### Directives\n\n| Directive | Description |\n| --- | --- |\n| .text | Move the cursor to the first unwritten byte of the text segment |\n| .data | Move the cursor to the first unwritten byte of the data segment |\n| .word i | a\\[, i\\|a\\]... Align the cursor to the nearest word boundary and writes each immediate or memory direct address as a word to the data segment in sequence |\n| .word i | a:X Align the cursor to the nearest word boundary and writes the immediate or labeled address as a word to the data segment the specified number of times |\n| .byte i | a\\[, i\\|a\\]... Write each immediate or labeled address as a byte to the data segment in sequence |\n| .byte i | a:X Write the immediate or memory direct address as a byte to the data segment the specified number of times |\n| .align X | Align the cursor to the nearest 2^X address |\n| .ascii \"string\" | Write the characters of `string` to the data segment as bytes in sequence |\n| .asciiz \"string\" | Write the characters of `string` to the data segment as bytes in sequence followed by a null byte |\n| .space X | Move the cursor forward by X bytes |\n| .include \"file\" | Insert the contents of `file` into the input stream in place of this directive. If a relative path is used, the current working directory is searched first, then if no file was found, the directory containing the assembler executable is searched. |\n| .message \"msg\" | Print `msg` to the standard output stream |\n| .error \"msg\" | Print `msg` to the standard output stream and throw an assembler exception |\n| .dbg \"msg\" | Dummy directive to test assembler |\n| .dbgbp | In debug builds cause a debug breakpoint in the assembler |\n| .define IDENTIFIER XXXXX | Define an inline macro |\n| .macro IDENTIFIER([parameter0[, parameter1]...]) | Begin a macro function definition |\n| .end | End macro function definition |\n| IDENTIFIER([argument0[, argument1]...]) | Insert the contents of the macro body with parameter replacement into the input stream in place of this directive |\n\n### Registers\n\n| ID | Name | Conventional Purpose |\n| --- | --- | --- |\n| 0 | zero | Hard-wired to 0 |\n| 1 | at | Reserved for pseudo-instructions |\n| 2-3 | v0-v1 | Return values from functions |\n| 4-7 | a0-a3 | Arguments to functions |\n| 8-17 | t0-t9 | Temporary data |\n| 18-27 | s0-s9 | Saved registers |\n| 28 | gp | Global Area Pointer |\n| 29 | sp | Stack Pointer |\n| 30 | fp | Frame Pointer |\n| 31 | ra | Return Address |\n\n### Address Encoding\n\nInstructions are (1 word | 4 bytes | 32 bits) long.\n\nAddresses are stored inline with the instruction. Bits used for the address fields may not be used for the instruction fields.\n\n```text\n|------DDDDDDDDDDDDDDDDDDDDDDDDDD| Direct Address Absolute\n|----------------AAAAAAAAAAAAAAAA| Address Offset\n|-----------RRRRR----------------| Register\n```\n\n### Addressing Modes\n\n| Mode | Format | Effective Address |\n| --- | --- | --- |\n| Memory Direct | label | Address of label |\n| Register Indirect | ($s) | Contents of `$s` |\n| Immediate Offset | i($s) | Contents of `$s` + `i` |\n| Label Offset | label($s) | Contents of `$s` + address of label |\n| Label + Immediate | label+i | Address of label + `i` |\n| Label + Immediate Offset | label+i($s) | Address of label + `i` + contents of `$s` |\n\n### Instruction Encoding\n\nInstructions are (1 word | 4 bytes | 32 bits) long.\n\n```text\n|OOOOOO--------------------------| Opcode\n|------AAAAABBBBBCCCCC-----------| Register slots A, B, and C\n|----------------IIIIIIIIIIIIIIII| Immediate\n```\n\n### Instruction Set\n\n| KASM | Operation | Encoding |\n| --- | --- | --- |\n| add $d, $s, $t | $d = $s + $t; advancePC(); | 0000 00dd ddds ssss tttt t--- ---- ---- |\n| addi $d, $s, i | $d = $s + i; advancePC(); | 0000 01dd ddds ssss iiii iiii iiii iiii |\n| addiu $d, $s, i  | $d = $s + i; advancePc(); |  |\n| addu $d, $s, $t  | $d = $s + $t; advancePc(); |  |\n| and $d, $s, $t  | $d = $s \u0026 $t; advancePc(); |  |\n| andi $d, $s, i  | $d = $s \u0026 i; advancePc(); |  |\n| beq $f, $s, address | if ($f == $s) setPc(address); |  |\n| bgez $f, address  | if ($f \u003e= 0) setPc(address); |  |\n| bgezal $f, address  | if ($f \u003e= 0) { advancePc(); $ra = getPc(); setPc(address) }; |  |\n| bgtz $f, address  | if ($f \u003e 0) setPc(address); |  |\n| blez $f, address  | if ($f \u003c= 0) setPc(address); |  |\n| bltz $f, address  | if ($f \u003c 0) setPc(address); |  |\n| bltzal $f, address  | if ($f \u003c 0) { advancePc(); $ra = getPc(); setPc(address) }; |  |\n| bne $d, $f, address | if ($f != 0) setPc(address); |  |\n| div $f, $s  | lo = $f / $s; hi = $f % $s |  |\n| divu $f, $s  | lo = $f / $s; hi = $f % $s |  |\n| j address  | setPc(address); |  |\n| jal address  | advancePc(); $ra = getPc(); setPc(address); |  |\n| jalr $f, $s  | advancePc(); $s = getPc(); setPc($f); |  |\n| jr $f | setPc($f); |  |\n| lb $d, address  | $d = memory\\[address\\]; advancePc(); |  |\n| lui $d, i  | $d = i \u003c\u003c 16; advancePc(); |  |\n| lw $d, address  | $d = \\*(uint32_t*)\u0026memory\\[address\\]; advancePc(); |  |\n| mfhi $d  | $d = hi; advancePc(); |  |\n| mflo $d  | $d = lo; advancePc(); |  |\n| mult $f, $s  | lo = $f \\* $s; hi = ($f \\* $s) \u003e\u003e 32; advancePc(); |  |\n| multu $f, $s  | lo = $f \\* $s; hi = ($f \\* $s) \u003e\u003e 32; advancePc(); |  |\n| nor $d, $s, $t  | $d = ~($s \\| $t); advancePc(); |  |\n| or $d, $s, $t  | $d = $s \\| $t; advancePc(); |  |\n| ori $d, $s, i  | $d = $s \\| i; advancePc(); |  |\n| sb $f, address  | memory\\[address\\] = $f \u0026 0xFF; advancePc(); |  |\n| seq $d, $s, $t  | $d = $s == $t; advancePc(); |  |\n| sll $d, $s, i  | $d = $s \u003c\u003c i; advancePc(); |  |\n| sllv $d, $s, $t  | $d = $s \u003c\u003c $t; advancePc(); |  |\n| slt $d, $s, $t  | $d = $s \u003c $t; advancePc(); |  |\n| slti $d, $s, i  | $d = $s \u003c i; advancePc(); |  |\n| sltiu $d, $s, i  | $d = $s \u003c i; advancePc(); |  |\n| sltu $d, $s, $t  | $d = $s \u003c $t; advancePc(); |  |\n| sne $d, $s, $t  | $d = $s != $t; advancePc(); |  |\n| sra $d, $s, i  | $d = (signed)$s \u003e\u003e i; advancePc(); |  |\n| srl $d, $s, i  | $d = $s \u003e\u003e i; advancePc(); |  |\n| srlv $d, $s, $t  | $d = $s \u003e\u003e $t; advancePc(); |  |\n| sub $d, $s, $t  | $d = $s - $t; advancePc(); |  |\n| subu $d, $s, $t  | $d = $s - $t; advancePc(); |  |\n| sw $d, address  | \\*(uint32_t*)\u0026memory\\[address\\] = $f; advancePc(); |  |\n| sys | systemCall(); advancePc(); |  |\n| xor $d, $s, $t  | $d = $s ^ $t; advancePc(); |  |\n| xori $d, $s, i  | $d = $s ^ i; advancePc(); |  |\n\n### Pseudoinstruction Set\n\n| KASM | Operation |\n| --- | --- |\n| add $d, $s, i | addi $d, $s, i |\n| b address | beq $zero, $zero, address |\n| bal address | bgezal $zero, address |\n| beq $f, i, address | ori $at, $zero, i; beq $f, $at, address |\n| beqz $f, address | beq $f, $zero, address |\n| bge $f, $s, address | slt $at, $f, $s; beq $at, $zero, address |\n| bgt $f, $s, address | slt $at, $s, $f; bne $at, $zero, address |\n| bgtu $f, $s, address | sltu $at, $f, $s; beq $at, $zero, address |\n| ble $f, $s, address | slt $at, $s, $f; beq $at, $zero, address |\n| blt $f, $s, address | slt $at, $f, $s; beq $at, $zero, address |\n| bne $f, i, address | ori $at, $zero, i; bne $f, $at, address |\n| call address | jal address |\n| clr $d | or $d, $zero, $zero |\n| copy $d, $s | or $d, $s, $zero |\n| div $d, $s, $t | div $s, $t; mflo $d |\n| enter | addi $sp, $sp, -4; sw $ra, 0($sp); addi $sp, $sp,-4; sw $fp, 0($sp); or $fp, $sp, $zero |\n| jalr $f | jalr $f, $ra |\n| la $d, address | lui $d, address \u003e\u003e 16; ori $d, $d, address \u0026 0xFFFF |\n| li $d, i | lui $d, i \u003e\u003e 16; ori $d, $d, i \u0026 0xFFFF |\n| mult $d, $s, $t | mult $s, $t; mflo $d |\n| nop | sll $zero, $zero, 0 |\n| not $d, $t | nor $d, $t, $zero |\n| popb $f | lb $f, 0($sp); addi $sp, $sp, 1 |\n| popw $f | lw $f, 0($sp); addi $sp, $sp, 4 |\n| pushb $d | addi $sp, $sp, -1; sb $d, 0($sp)|\n| pushw $d | addi $sp, $sp, -4; sw $d, 0($sp) |\n| rem $d, $s, $t | div $s, $t; mfhi $d |\n| ret | or $sp, $fp, $zero; lw $fp, 0($sp); addi $sp, $sp, 4; lw $ra, 0($sp); addi $sp, $sp, 4; jr $ra |\n\n### System Calls\n\nSystem services are called by storing the service's code in the `$a0` register and executing the `sys` instruction. Some services require additional arguments to be executed; these arguments are stored in the `$ax` registers according to the table below. Some services return values; these return values can be accessed by reading them from the `$vx` registers according to the table below.\n\n| Code | Service | Arguments | Returns |\n| --- | --- | --- | --- |\n| 0 | exit | $a1 = exit code |  |\n| 1 | read_int |  | $a0 = word read |\n| 2 | write_int | $a0 = word to write |  |\n| 3 | read_char |  | $a0 = char read |\n| 4 | write_char | $a0 = char to write |  |\n| 5 | read_string | $a0 = buffer address, $a1 = buffer size |  |\n| 6 | write_string | $a0 = null terminated buffer address |  |\n| 7 | allocate | $a0 = size | $v0 = heap address |\n| 8 | deallocate | $a0 = heap address |  |\n| 9 | open_file | $a0 = file name buffer address, $a1 = mode | $v0 = file handle |\n| 10 | close_file | $a0 = file handle |  |\n| 11 | seek | $a0 = file handle, $a1 = distance, $a2 = mode |  |\n\n### Standard Macro Library\n\nThe KASM Standard Macro Library is located in `std.kasm`.\n\n## klang\n\n### Directives\n\nDirectives must appear at the beginning of a line, excluding whitespace characters and comments.\n\n| Directive | Description |\n| --- | --- |\n| %include \"file\" | Insert the contents of `file` into the input stream in place of this directive. If a relative path is used, the current working directory is searched first, then if no file was found, the directory containing the assembler executable is searched. |\n\n### Types\n\n| Name | Description |\n| --- | --- |\n| u8 | 1 byte unsigned integer |\n| u16 | 2 byte unsigned integer |\n| u32 | 4 byte unsigned integer |\n| s8 | 1 byte signed 2s compliment integer |\n| s16 | 2 byte signed 2s compliment integer |\n| s32 | 4 byte signed 2s compliment integer |\n| f32 | 4 byte IEEE-754 floating point number |\n| f64 | 8 byte IEEE-754 floating point number |\n\nPointer types are denoted by an asterisk, `*`, following a type name or `void`.\n\n### void\n\nWhen used as a function return type, the void keyword specifies that the function does not return a value. When used in the declaration of a pointer, void specifies that the pointer is \"universal.\"\n\n### Type Specifiers\n\n| Name | Description |\n| --- | --- |\n| const | The variable will not change after initialization |\n| static | The variable will be stored in the data segment and retain its value across function calls after initialization |\n\n### Expression Specifiers\n\n| Name | Description |\n| --- | --- |\n| comptime | The expression's value will be evaluated at compile time |\n| inline | Replaces function calls in the expression with the function definition |\n| sizeof | Evaluates to size of the expression's type at compile time |\n\n### Function Specifiers\n\n| Name | Description |\n| --- | --- |\n| inline | Replaces calls to the function with the function definition |\n\n### Inline KASM\n\nThe keyword `kasm` followed by an `{` will instruct the compiler to evaluate the proceeding text as if it were kasm. This will continue until the compiler encounters a `}` outside of a comment, string literal, or character literal.\n\n### Intrinsics\n\n| Name | Description |\n| --- | --- |\n| nullptr | Evaluates to a void pointer with the value 0 |\n| true | Evaluates to a u8 with the value 1 |\n| false | Evaluates to a u8 with the value 0 |\n\n### Operators\n\n### Control Structures\n\n#### if, if/else\n\n#### switch\n\n#### while, do/while\n\n#### for\n\n#### return\n\n#### Labeled Statement\n\n#### goto\n\n### Data Structures\n\n#### enum\n\n#### struct\n\n#### union\n\n### namespace\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwidberg%2Fkasm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwidberg%2Fkasm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwidberg%2Fkasm/lists"}