{"id":23478019,"url":"https://github.com/owl-from-hogvarts/csa-lab3","last_synced_at":"2026-05-19T07:09:54.775Z","repository":{"id":238749704,"uuid":"797433438","full_name":"owl-from-hogvarts/csa-lab3","owner":"owl-from-hogvarts","description":"Self-made assembler and Accumulator CPU","archived":false,"fork":false,"pushed_at":"2024-05-13T09:54:28.000Z","size":464,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-14T03:17:08.836Z","etag":null,"topics":["assembly","cpu","emulator"],"latest_commit_sha":null,"homepage":"","language":"Rust","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/owl-from-hogvarts.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":"2024-05-07T20:29:51.000Z","updated_at":"2025-08-29T00:52:09.000Z","dependencies_parsed_at":"2024-05-13T10:56:21.858Z","dependency_job_id":null,"html_url":"https://github.com/owl-from-hogvarts/csa-lab3","commit_stats":null,"previous_names":["owl-from-hogvarts/csa-lab3"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/owl-from-hogvarts/csa-lab3","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/owl-from-hogvarts%2Fcsa-lab3","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/owl-from-hogvarts%2Fcsa-lab3/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/owl-from-hogvarts%2Fcsa-lab3/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/owl-from-hogvarts%2Fcsa-lab3/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/owl-from-hogvarts","download_url":"https://codeload.github.com/owl-from-hogvarts/csa-lab3/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/owl-from-hogvarts%2Fcsa-lab3/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33205678,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-18T09:27:30.708Z","status":"online","status_checked_at":"2026-05-19T02:00:06.763Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["assembly","cpu","emulator"],"created_at":"2024-12-24T18:44:06.563Z","updated_at":"2026-05-19T07:09:54.737Z","avatar_url":"https://github.com/owl-from-hogvarts.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\n# Thanks\n\nSpecial thanks to [Zerumi Coder](https://github.com/zerumi) whose purest soul helped me on this long journey! The Guy who supported me on every tricky junction of the long night road. The Guy, who lit the way for me, who has enlighten me! \n\nThank you, Zerumi!\n\nThanks to [Lannee](https://github.com/lannee) the Great, who supported the Magnificent Order of Rust!\n\nThanks to [Local Piper](https://github.com/localPiper/) the Funniest, who didn't let me give up! His majesty supported me with marvelous jokes!\n\nThanks to all other fellow comrades who stood with me, who fought bravely, who has won this battle!\n\n# Variant\n\n- Тернавский Константин Евгеньевич. P3206\n\n```\nasm | acc | neum | mc -\u003e hw | tick -\u003e instr | struct | stream | port | pstr | prob2 | cache\n```\n\n- Базовый вариант\n\n## Transcript\n\n- assembler\n- accumulator\n- Von Neumann (same memory for commands and data)\n- Microcode\n- accurate up to tick\n- code is stored as High-Level structure\n- Stream IO (no interrupts)\n- IO devices addressed by ports. Separate IO instruction\n- Pascal strings (length + content)\n- Prob 2. Even Fibonacci numbers\n- Cache (***not implemented***)\n\n# Table of content\n\n- [Thanks](#thanks)\n- [Variant](#variant)\n  - [Transcript](#transcript)\n- [Table of content](#table-of-content)\n- [Language](#language)\n  - [Syntax](#syntax)\n  - [Semantics](#semantics)\n  - [Literals](#literals)\n  - [Argument types](#argument-types)\n  - [Assembler directives](#assembler-directives)\n- [ISA](#isa)\n  - [Instruction format](#instruction-format)\n  - [Instruction pipeline](#instruction-pipeline)\n  - [Operand types](#operand-types)\n- [Memory](#memory)\n- [CPU Architecture](#cpu-architecture)\n  - [Data path](#data-path)\n    - [Registers](#registers)\n    - [ALU](#alu)\n  - [Control unit](#control-unit)\n- [Stats](#stats)\n\n\n# Language\n\n## Syntax\n\n\u003e `number` is 16-bit number\n\u003e `number(n)` is n-bits number\n\nAssembly:\n```ebnf\nprogram ::= lines\n\nlines ::= line | line lines\n\nline ::= new_line | statement new_line\n\nstatement ::= item | label item\n\nlabel ::= word \":\"\n\nitem ::= empty | command | directive\n\n// command names are matched case-insensitive\ncommand ::= command_none\n          | command_address\n          | command_immediate\n          | command_port\n\ncommand_none ::= \"inc\" \n               | \"shift_left\"\n               | \"shift_right\"\n               | \"nop\"\n               | \"halt\"\n\ncommand_address ::= opcode_address address\n\nopcode_address ::= \"load\"\n                 | \"store\"\n                 | \"add\"\n                 | \"and\"\n                 | \"cmp\"\n                 | \"jzc\"\n                 | \"jzs\"\n                 | \"jz\" // alias for jzs\n                 | \"jcc\"\n                 | \"jcs\"\n                 | \"jc\" // alias for jcs\n                 | \"jump\"\n\naddress ::= address_relative \n          | address_absolute\n          | address_indirect\n\n\naddress_relative ::= actual_address\n\naddress_absolute ::= \"!\" actual_address\n\naddress_indirect ::= \"(\" actual_address  \")\"\n\nactual_address ::= word | number\n\ncommand_immediate ::= \"andi\" number\n\ncommand_port ::= opcode_port port\n\nopcode_port ::= \"in\" | \"out\"\n\nport ::= number(8)\n\n// supports numbers:\n// decimal: 145, 0001\n// hex: 0xaf\n// bin: 0b010101\nnumber ::= \"^(?P\u003cprefix\u003e0[xb])?(?P\u003cnumber\u003e[\\dabcdef_]+)\"\n\ndirective ::= directive_word | directive_org\n\ndirective_word ::= \"word\" word_arguments\n\nword_arguments ::= word_argument | word_argument word_arguments\n\nword_argument ::= number(32) | label\n\ndirective_org ::= \"org\" number\n\n```\n\n\u003e Note: space symbols are not considered and are skipped\n\u003e Space symbols are defined as following set: \" \"\n\n## Semantics\n\n- strategy of computation: *sequential*\n- label's scope: *global*\n\n## Literals\n\nFor number endian see [Memory](#memory) section.\n\n\u003e We use notion of number types similar to rust's one:  \n\u003e first letter says the type and affects sign extension:\n\u003e - `u` no sign extension happens. Value treated as **U**nsigned\n\u003e\n\u003e The letter is followed by a number. The number signifies amount of bits\n\u003e available to represent a number.\n\u003e\n\u003e Examples:\n\u003e - `u32` - 32-bit unsigned number\n\u003e - `u16` - 16-bit unsigned number\n\nAll literals are numbers with different range of values. All numbers have the same syntax. Range is determined based on usage context: command's argument type defines literal meaning. For details see command's argument types table.\n\nNumber literals support following prefixes:\n- `0x` - for *hex* numbers\n- `0b` - for *binary* numbers\n\nExample:\n```\ndecimal: 145, 0001\nhex: 0xaf\nbin: 0b010101\n```\n\n\n\u003chr\u003e\n\nNumbers without prefix are treated as *decimals*.\n\nNumbers *may* contain any amount of `_` at any point after prefix (or anywhere if there is no prefix):\n\nExample:\n\n- `4000`\n- `4_000`\n- `4_____000`\n- `___4_000___`\n- `0x____fa0`\n\nare all mean `4000` decimal value.\n\n\n\n## Argument types\n\n- `none` - command requires no arguments. Placing anything would result into error.\n- `port` - command requires single number which denotes IO device's address. Number is treated as `u8`\n- `immediate` - command requires single number. Number is treated as `u16`\n- `label` - special argument type. It requires single word. Word is a sequence of unicode letters. It may contain any number of `_` in any position. Used within composite type `address` and with [`word` directive](#assembler-directives).\n- `address` - composite type. see notes and table below\n- There are other types. They are special and used in conjunction with [Assembly directives](#assembler-directives)\n\n`Address` type is either number treated as `u16` or label. Address allows modifiers to switch addressing mode. \n\nIn the following table, strings enclosed with `\"\"` means literal characters present in source code. `|` means *alternative*. `()` are used to *group items*.\n\nThat is `\"!\" (u16 | label)` means exclamation mark followed by either number literal or label where number literal is interpreted as 16-bit unsigned number\n\nEach addressing in this table corresponds to appropriate [addressing mode of CPU](#addressing-modes-argument-types).\n\n\u003ctable\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eMode\u003c/td\u003e\n      \u003ctd\u003eSyntax\u003c/td\u003e\n      \u003ctd\u003eExample\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eRelative\u003c/td\u003e\n      \u003ctd\u003e\u003ccode\u003eu16 | label\u003c/code\u003e\u003c/td\u003e\n      \u003ctd\u003e\u003cpre\u003eload 0x55\u003cbr\u003eload 145\u003cbr\u003eload some_label\u003c/pre\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eAbsolute\u003c/td\u003e\n      \u003ctd\u003e\u003ccode\u003e\"!\" (u16 | label)\u003c/code\u003e\u003c/td\u003e\n      \u003ctd\u003e\u003cpre\u003estore !0x55\u003cbr\u003estore !some_label\u003c/pre\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eIndirect\u003c/td\u003e\n      \u003ctd\u003e\u003ccode\u003e\"(\" u16 | label \")\"\u003c/code\u003e\u003c/td\u003e\n      \u003ctd\u003e\u003cpre\u003eload (some_label_ptr)\u003cbr\u003eload (0x55)\u003c/pre\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\n## Assembler directives\n\n- `data` - special argument type used with assembler directive `word`. It requires *one or **more** numbers* each seperated with at least one space. Each number is treated as `u32`. That is, although, value `0xff` perfectly fits into one byte, `word 0xff` occupies whole [memory cell](). *Notice, that no sign extension takes place! Value is placed as is*: \n  `0x00_00_00_ff`\n\nAssembler directives are not represented in CPU's memory. They are special commands intended to assist you write assembly code. \n\n\u003ctable\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003ctd\u003eDirective\u003c/td\u003e\n      \u003ctd style=\"width: 25%;\"\u003eAllowed argument types\u003c/td\u003e\n      \u003ctd\u003eComment\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\u003ccode\u003eword\u003c/code\u003e\u003c/td\u003e\n      \u003ctd\u003e\u003ccode\u003edata | label\u003c/code\u003e\u003c/td\u003e\n      \u003ctd\u003eplaces numbers into memory as is. can be used with labels to make pointers. I.e. \u003ccode\u003eword some_label\u003c/code\u003e places an address and \u003ci\u003eNOT the content at the address\u003c/i\u003e which \u003ccode\u003esome_labels\u003c/code\u003e refers to.\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003ctd\u003e\u003ccode\u003eorg\u003c/code\u003e\u003c/td\u003e\n      \u003ctd\u003e\u003ccode\u003eu16\u003c/code\u003e\u003c/td\u003e\n      \u003ctd\u003einstructs assembler where to place next code item \n       (be it a raw value or a command) into cell with address ADDRESS.\n       Subsequent code items will be placed after ADDRESS one by one\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\n\nExample:\n\n```asm\norg 0x04f\nVAR1: word 0x45a9 0xff\nadd 0xf\ncmp VAR1\n```\nHere `0x0000_45a9` will be placed in memory as is at address `0x04f`; `0x0000_00ff` at `0x0050`. `add 0xf` at `0x0051` and so on\n\n# ISA\n\nThis section describes opcodes and operand type suggested for use with them. \n\nNotice, that every command may theoretically work with every operand type except `none` operand type, though that has not been tested and may lead to undefined behaviour.\n\nProviding `none` operand type for command which requires any other type results in CPU panicking.\n\nCommands which suggest `none` operand type will simply ignore any operand, although operand fetch would still be executed. So that you *can* but you *should not* specify any operand type except `none` for commands which except `none`.\n\nFor this table let's introduce notion of special operand type `operand`. It *requires* operand type to be any of `Relative|Indirect|Immediate|Absolute`. Notice that `none` is ***forbidden*** for this speical type.\n\n```\nIN          immediate    - read data from IO device\nOUT         immediate    - write data to IO device\n\nLOAD        operand - load value into accumulator\nSTORE       operand - store value from accumulator into memory cell\n\nADD         operand - well... add a number?\nINC         none    - add 1 to accumulator\n\n// (to check for even values by applying 0x1 mask)\nAND         operand\nCMP         operand - subtract number from accumulator without \n                      storing result anywhere. Sets status flags.\n                      Useful for branching\nSHIFT_LEFT  none\nSHIFT_RIGHT none\n\nJZC         operand - Jump if Zero Clear\nJZS         operand - Jump if Zero Set\nJCC         operand - Jump if Carry Clear\nJCS         operand - Jump if Carry Set\nJUMP        operand - Unconditional jump\n\nNOP         none    - does nothing\nHALT        none    - Stops the simulation\n```\n\nAssembler supports variants of some instructions with immediate argument. Namely:\n```\nAND -\u003e ANDI // useful for masking\n```\n\nFor more, please, see [syntax](#syntax) section.\n\n## Instruction format\n\nEvery instruction occupies exactly one [memory cell](#memory).\n\nAll instruction if would be represented in binary has following format:\n\n\u003ctable\u003e\n    \u003cthead\u003e\n        \u003ctr\u003e\n            \u003cth\u003eopcode\u003c/th\u003e\n            \u003cth\u003eargument type\u003c/th\u003e\n            \u003cth\u003eargument\u003c/th\u003e\n        \u003c/tr\u003e\n    \u003c/thead\u003e\n    \u003ctbody\u003e\n        \u003ctr\u003e\n            \u003ctd\u003e1 byte\u003c/td\u003e\n            \u003ctd align=\"center\"\u003e1 byte\u003c/td\u003e\n            \u003ctd\u003e2 bytes\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd colspan=3 align=\"center\" \u003e4 bytes\u003c/td\u003e\n        \u003c/tr\u003e\n    \u003c/tbody\u003e\n\u003c/table\u003e\n\n\n## Instruction pipeline\n\n1) Instruction fetch\n   1) fetches instruction from memory to cmd register\n2) operand decode\n   1) determines type of operand\n   2) load operand\n3) execution\n   1) determines microinstruction number by opcode\n   2) execute instruction\n\n## Operand types\n\n```\n- None: jumps straight to command execution\n- Absolute: operand -\u003e address -\u003e [mem] -\u003e data\n- Relative: pc + operand -\u003e address -\u003e [mem] -\u003e data\n- Indirect: pc + operand -\u003e address -\u003e [mem] -\u003e data -\u003e address -\u003e data\n- Immediate: operand -\u003e data\n\n```\n\n# Memory\n\nThis CPU uses von Neumann memory model: both data and code are stored in the same memory. \n\n\u003e You neither can interpret data as instruction nor instruction as data though: limitation of current implementation.\n\nMemory consists of `2**16` memory cells. Each memory cell holds either a single 32-bit *big-endian* number *without* sign extension or an instruction.\n\nThe whole memory is addressable by `u16` address on per memory cell basis. That is by referring to `0x0000` you can fetch an `u32` number or an instruction.\n\nAddress space starts from ***zero***.\n\n| address  | content       |\n| -------- | ------------- |\n| `0x0000` | `0x0000_00ff` |\n| `0x0001` | `0xdead_beaf` |\n| ...      | ...           |\n| `0xffff` | `0x0000_0000` |\n\n# CPU Architecture\n\n## Data path\n\n### Registers\n\nRegisters support either `u32` or `u16` values. If you attempt to write `u32` value into `u16`-capable destination (that is either register or ALU) then sixteen most-significant bits are silently discarded.\n\nIf you attempt to write `u16` value into `u32`-capable destination, then value is zero-extended to 32 bits.\n\n\u003e *Notice that NO sign-extension takes place!*\n\n\u003chr\u003e\n\n- accumulator (`u32`) (least-significant byte is connected to IO)\n- data (connected to memory) (MemoryItem: `u32` | [`Command`](./isa/src/lib.rs))\n- status (zero, carry)\n- address (`u16`)\n- program counter (`u16`)\n- cmd(opcode, opcode_type, arg: `u16`)\n\n### ALU\n\nALU operates on two `u32` values, outputting `u32` result and optionally setting `status` register with `zero` and `carry` flags.\n\n![](./images/data_path.svg)\n\n## Control unit\n\n![](./images/control_unit.svg)\n\n\n# Stats\n\n```\n|           Full name             | alg            | loc | bytes | instr | exec_instr | tick |                                            variant                                             |\n|Тернавский Константин Евгеньевич | hello_world    | 35  | -     | 13    | 105        | 647  | asm     | acc | neum | mc -\u003e hw | tick -\u003e instr | struct | stream | port | pstr | prob2 | cache|\n|Тернавский Константин Евгеньевич | hello_username | 168 | -     | 81    | 434        | 2706 | asm     | acc | neum | mc -\u003e hw | tick -\u003e instr | struct | stream | port | pstr | prob2 | cache|\n|Тернавский Константин Евгеньевич | prob2          | 137 | -     | 48    | 630        | 3896 | asm     | acc | neum | mc -\u003e hw | tick -\u003e instr | struct | stream | port | pstr | prob2 | cache|\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fowl-from-hogvarts%2Fcsa-lab3","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fowl-from-hogvarts%2Fcsa-lab3","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fowl-from-hogvarts%2Fcsa-lab3/lists"}