{"id":17250650,"url":"https://github.com/statusfailed/riscv-macroassembler","last_synced_at":"2026-07-03T09:03:41.946Z","repository":{"id":145120145,"uuid":"342046289","full_name":"statusfailed/riscv-macroassembler","owner":"statusfailed","description":null,"archived":false,"fork":false,"pushed_at":"2024-07-08T14:10:24.000Z","size":17,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-01-31T08:18:53.100Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/statusfailed.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2021-02-24T21:55:19.000Z","updated_at":"2024-07-08T14:10:28.000Z","dependencies_parsed_at":null,"dependency_job_id":"1de5c7d9-6f79-45f2-a444-5431859751fc","html_url":"https://github.com/statusfailed/riscv-macroassembler","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/statusfailed%2Friscv-macroassembler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/statusfailed%2Friscv-macroassembler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/statusfailed%2Friscv-macroassembler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/statusfailed%2Friscv-macroassembler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/statusfailed","download_url":"https://codeload.github.com/statusfailed/riscv-macroassembler/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245605709,"owners_count":20643030,"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":[],"created_at":"2024-10-15T06:49:15.125Z","updated_at":"2026-07-03T09:03:41.906Z","avatar_url":"https://github.com/statusfailed.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RISC-V Macroassembler\n\nThis toy project is an assembler for RISC-V that requires only a Python 3\ninterpreter, and doesn't have any external dependencies like gcc.\n\nIt can produce a binary file of RISC-V instructions, but doesn't wrap them in a\nformat like ELF.\n\nNote that this code is not finished, and currently supports very few instructions.\nSee [`DESIGN.md`](./DESIGN.md) for implementation details.\n\n# Usage\n\nSee [`example.py`](./example.py) for example usage.\nThis file generates a \"Hello, World\" program which can run in\n[QEMU](https://www.qemu.org/) under the `virt` RISC-V machine.\nYou can run it as follows.\n\nFirst, encode some instructions and write them to `out.bin`:\n\n    $ python3 example.py out.bin\n\nRun `out.bin` on a QEMU `virt` machine using the following command:\n\n    $ qemu-system-riscv64 -nographic -machine virt -bios out.bin\n    Hello, World!\n\nAt this point the QEMU machine will appear to hang; you can bring up a QEMU\nprompt and quit using `C-a c`:\n\n    QEMU 9.0.1 monitor - type 'help' for more information\n    (qemu) quit\n\n\nFinally, if you have a RISC-V-aware objdump, you can disassemble the contents of\n`out.bin`:\n\n    $ riscv64-linux-gnu-objdump -b binary --architecture=riscv -D out.bin\n      0000000000000000 \u003c.data\u003e:\n     0:   00100093                li      ra,1\n     4:   01c09093                slli    ra,ra,0x1c\n     8:   04800113                li      sp,72\n     c:   00208023                sb      sp,0(ra)\n    10:   06500113                li      sp,101\n    14:   00208023                sb      sp,0(ra)\n    18:   06c00113                li      sp,108\n    (...snip...)\n\n# Running on `sifive_u`\n\nRunning on `sifive_u` is a little different: the UART address is at\n`0x10010000`, and we have to write in word-sized chunks.\nRun as below, and remember you can use `C-a c` to bring up the console and quit.\n\n    $ ./sifive_example.py out.bin\n    $ qemu-system-riscv64 -nographic -M sifive_u -bios out.bin\n    Hello, World!\n    QEMU 9.0.1 monitor - type 'help' for more information\n    (qemu) quit\n\n## Notes on `sifive_u`\n\nThe `sifive_u` machine is a little different to `virt`, and so the program\ngenerated in `sifive_example.py` has some differences.\nMost importantly, the UART is now at `0x10010000`, and we have to write\nword-sized chunks to this address.\nIf we only write chars, you can get errors by running with this command:\n\n    qemu-system-riscv64 -nographic -M sifive_u -bios out.bin -d guest_errors,unimp,pcall -D qemu.log\n\nExit using `C-a c quit` and then `head -n 1 qemu.log`:\n\n    Invalid write at addr 0x0, size 1, region 'riscv.sifive.uart', reason: invalid size (min:4 max:4)\n\nWriting a full word [0x0, 0x0, 0x0, c] for each character c *almost* works; you\nget output like this:\n\n    HHeelllloo,,  WWoorrlldd!\n    !\n\nThis is because `sifive_u` has 2 cores, and they both write to the UART!\nSo we have to add an instruction to check our **hardware thread ID** (`hart id`),\nthen only print if the ID is `0`.\nTo do that, we have the following prelude:\n\n    \u003eriscv64-linux-gnu-objdump -b binary --architecture=riscv -M numeric -D out.bin\n    ...\n    0000000000000000 \u003c.data\u003e:\n       0:   f14020f3                csrr    x1,mhartid\n       4:   fe009ee3                bnez    x1,0x0\n\nThis reads the `mhartid` status register into x1, then if x1 is nonzero will go\ninto a busy-wait loop.\n\n# Debugging\n\nInstall a RISC-V-compatible gdb, e.g. on arch:\n\n    pacman -S riscv64-linux-gnu-gdb\n\nRun QEMU in debug mode:\n\n    qemu-system-riscv64 -nographic -M sifive_u -bios out.bin -s -S\n\nConnect to gdb:\n\n    riscv64-linux-gnu-gdb\n\nRun this in gdb:\n\n    target remote :1234\n    layout asm\n\nIf you want to skip the bootloader(?) and go straight to your code from\n`out.bin`, you can also run\n\n    b *0x80000000\n    c\n\nInstead of typing this all out, you can also just do this:\n\n    riscv64-linux-gnu-gdb -x start.gdb\n\n# TODO\n\n- [ ] `Instruction.where`\n- [ ] `make_instruction` helper\n- [ ] Generate instruction encodings using [riscv-opcodes](https://github.com/riscv/riscv-opcodes)\n\n# References\n\n- [RISC-V ISA Reference](https://github.com/riscv/riscv-isa-manual/releases/download/Ratified-IMAFDQC/riscv-spec-20191213.pdf)\n    - See Chapter 24 for a table of instruction encodings\n- [RISC-V Privileged Architecture](https://riscv.org/wp-content/uploads/2017/05/riscv-privileged-v1.10.pdf)\n    - Note that the numeric value of `mhartid` and other status registers can be\n      found in `Table 2.3`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstatusfailed%2Friscv-macroassembler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstatusfailed%2Friscv-macroassembler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstatusfailed%2Friscv-macroassembler/lists"}