{"id":16696095,"url":"https://github.com/clord/mips-cpu-simulator","last_synced_at":"2025-09-08T14:43:18.544Z","repository":{"id":1442895,"uuid":"1673269","full_name":"clord/MIPS-CPU-Simulator","owner":"clord","description":"This is a mips simulator I wrote once to help my understanding of pipelines, branch prediction, assembly language, and more.","archived":false,"fork":false,"pushed_at":"2019-12-03T21:17:05.000Z","size":47,"stargazers_count":65,"open_issues_count":0,"forks_count":14,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-08-03T20:50:03.975Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C++","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/clord.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}},"created_at":"2011-04-27T23:16:50.000Z","updated_at":"2024-12-26T22:23:13.000Z","dependencies_parsed_at":"2022-07-29T13:39:06.484Z","dependency_job_id":null,"html_url":"https://github.com/clord/MIPS-CPU-Simulator","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/clord/MIPS-CPU-Simulator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clord%2FMIPS-CPU-Simulator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clord%2FMIPS-CPU-Simulator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clord%2FMIPS-CPU-Simulator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clord%2FMIPS-CPU-Simulator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/clord","download_url":"https://codeload.github.com/clord/MIPS-CPU-Simulator/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clord%2FMIPS-CPU-Simulator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274201191,"owners_count":25240225,"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","status":"online","status_checked_at":"2025-09-08T02:00:09.813Z","response_time":121,"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":[],"created_at":"2024-10-12T17:25:57.102Z","updated_at":"2025-09-08T14:43:18.470Z","avatar_url":"https://github.com/clord.png","language":"C++","funding_links":["https://www.buymeacoffee.com/clord"],"categories":[],"sub_categories":[],"readme":"## Introduction\n\nThis project simulates the execution of a subset of a 32-bit five-stage [MIPS][4] CPU Pipeline\ndescribed in “Computer Organization and Design (COD)” by Patterson \u0026 Hennessy.\n\nThe code is based on a class project from my university days, in which we built from the ground\nup this simulator and assembler. In that class, the various parts were split up such that the whole\npackage never really came into existence. I came across the various labs in my backup and decided\nto finish up the project, and add a very small smattering of cleanup and experience into the mix.\n\n\u003ca class=\"bmc-button\" target=\"_blank\" href=\"https://www.buymeacoffee.com/clord\"\u003e\u003cimg src=\"https://cdn.buymeacoffee.com/buttons/bmc-new-btn-logo.svg\" alt=\"Buy me a coffee\"\u003e\u003cspan style=\"margin-left:15px;font-size:19px !important;\"\u003eBuy me a coffee\u003c/span\u003e\u003c/a\u003e\n\n## Usage\n\nExtract the package and type `make`. Realize your build environment needs massaging, go off and fix\nthis-and-that. Tweak `CC` and `CCC`. Figure out how to install Yacc and Bison. Try `make` again.\nThis will then construct the assembler `rasm` and the simulator `ssim`.\nThere is an additional shell script called `regs` that does assembly and simulation in one step.\nThe assembler `rasm` responds to the following command switches:\n\n* `-f sourcefile` – assemble ASCII assembly code from file (required)\n* `-t textstreamfile` – override default destination and output binary `.text` to specified file\n* `-d datastreamfile` – override default destination and output binary `.data` to specified file\n\nThe simulator `rsim` responds to the following command switches:\n\n* `-t textstreamfile` – load memory segment .text with the contents of a binary file (required)\n* `-d datastreamfile` – load memory segment .data with contents of a binary file\n* `-v` – very verbose CPU. Will echo every instruction, and the associated program counter.\n* `-m` – collect memory statistics and display a summary after the CPU terminates.\n   * Place after `-f`/`-t` in order to not report on the loading the files into memory.\n   * Place before one or both in order to include that activity in the report.\n\n\n## Implementation Notes\n\nThe [instruction pipeline][3] implementation is mostly contained in `stages.{c,h}`. I’ve tried to follow\nthe basic design of the COD MIPS pipeline. This means [control signals][9] and [latches][1] are simulated.\n\nAs a result, much of the semantics used to describe the five-stage MIPS CPU in COD is\ntransferable directly to the simulator, accelerating development. Unfortunately, all\nof this extra simulacrum means lower performance and a larger code-base.\n\nI suggest that reader or contributor follow along with COD as I did.\n\n\n### Simulating Combinatorical Circuits\n\nSimulating asynchronous behaviour using the sequential machine exposed by C is a\nsomewhat tricky task. The order in which various actions occur is deterministic, so\nthe relative order of execution is important. I’ve tackled this problem by running through the\npipeline three times per clock, once for execution of the stages, once to resolve\nhazards, and one last time to simulate the action of latches being clocked (or shifted)\nforward.\n\nThe precise order of execution is sometimes important. The best example is in the\nresolution of the two read-after-write hazards. These occurs at each writable media,\ni.e. memory and register. The memory read stage might attempt to read from an address\nthat was written in the same clock cycle. This places certain constraints on the order\nof execution of the various stages. Having reorderable execute stages is the reason I\ndecoupled hazard/shift logic from execution.\n\nTiming issues like this can occur; but I was surprised to find that most of the time\nsequential order does not matter as much as with regular C code. This order-independent code\nhappens whenever a latch is involved. Significant reordering of any one of the stages is\npossible, as long as the latches get the same values in the end. It would be interesting to\nimplement the latches with atomic operations and break the pipeline up across an SMP machine.\n\nThe most interesting feature of this design is the virtual latch. A latch is a device which\npreserves its output, and can atomically and simultaneously change the output to the input on a clock pulse.\nThere is no such construct exposed to high level programming languages. The way my code simulates\nthis is to have a “left” and a “right” edge of each stage. When the shift signal occurs, all of the\nright-hand edges are transferred to the left edge of the next stage.\n\n\n### Hazards\n\n#### Forwarding\n\nThe forwarding logic has to handle four different hazard situations corresponding to four dependency situations:\n\n1. Execute-Decode for `Rs`: The result of the execute stage’s right latch is required by the decode stage’s right latch for register `Rs`.\n2. Memory-Decode for `Rs`: The result of the memory stage’s right latch is required by the decode stage’s right latch for register `Rs`.\n3. Execute-Decode for `Rt`: The result of the execute stage’s right latch is required by the decode stage’s right latch for register `Rt`.\n4. Memory-Decode for `Rt`: The result of the memory stage’s right latch is required by the decode stage’s right latch for register `Rt`.\n\n#### Pipeline bubble for `lw`\n\nIn the five-stage pipeline, there is a potential issue with loading from memory.\nThe problem is that data comes out of memory one stage after the ALU result is computed,\nbut `lw` looks like an r-type instruction.\nThus, the forwarding logic can not successfully attach to the memory result:\nit forwards the calculated address from the ALU.\n\nThe solution I pursued was to bubble the pipeline by one stage whenever the result of a `lw` is needed by\nthe very next instruction. This bubble allows the normal forwarding logic to handle the situation correctly.\nThe previous instruction had to be re-issued, so I backed up the program counter by one instruction.\n\n\n#### Branch Bubbles\n\nBranch miss-predicts are somewhat easier to resolve. I use a very simple [branch predictor][2] (it predicts not-taken every\ntime.) This will ensure that mis-predicts occur with some frequency.\nIf a branch miss-prediction is detected (`mispredict = (prediction != branch_taken)`); then the two previous\nstages can be abandoned, creating a pipeline bubble. The program counter adjustment mentioned in the previous section\nis not required for the “all-not-taken” predictor. This may or may not be the case if a more successful\npredictor is to be used (I have not approached the problem for this project).\n\n\n## System Memory\n\nIn the original design, memory for the system was simulated with several mmap segments mapped into the simulator’s process,\nrepresenting the simulated .text, .data, etc. Each was a memory map with only a subset of the segment’s true space. Access outside\nthe subsets led to hardware faults being thrown (i.e., a C++ exception and an aborted simulator)\n\nThe original design did this because it had to fit a 32-bit address space into a 32-bit host process.\nThus each memory mapped segment is smaller than the real MIPS equivalent — although they should be sufficient for almost all programs.\n\nIn the version I am checking into GitHub, the entire 32-bit address space is mapped, and I require that you build on\na 64-bit machine with a 64-bit C runtime.\n\nIn either case, the operating system will lazily map pages as the simulator touches memory.\n\n## The Assembler\n\nThe assembler takes an ASCII MIPS [assembly file][6] and produces a binary representation that is executable\nby the simulator. Currently, the assembler will generate separate `.t` (text) and `.d` (data) files, which should be loaded\ninto the correct segment on the simulator by the user. See the usage section for more details.\n\nMy assembler parses and lexes with [Bison][8] and [Flex][7]. I made this choice in university, and it reflected the tools I was using\nto build a Pascal compiler at the same time for a different class. Using a grammar to express an assembly language led to certain\nadvantages as the course content changed, and even now all these years later it lets me make changes with ease.\n\nI’d like to take a moment to express my admiration for the MIPS assembly text format. It’s so much more sane than other assembly languages\nI’ve dealt with in my career since university.\n\n\n### Instruction Encoding\n\nIn the interest of avoiding a [complicated fetch stage][5], I use a simple structure — eight bytes for each instruction, aligned at 8 bytes.\nIn order, there is a one-byte opcode, a two-byte operand field, a byte of padding, and space for a four-byte immediate. I leave the\nendiness up to the host compiler, meaning that the object files are not portable between simulators and assemblers compiled for different\nhost architectures.\n\nI’d rather spend my time building the simulator than coming up with a clever binary packing. It would be really\ncool if someone managed to make this thing binary-compatible with a real MIPS chip, but my goal here is gain some\nunderstanding of CPU design.\n\n\n[1]: http://en.wikipedia.org/wiki/Flip-flop_(electronics)\n[2]: http://en.wikipedia.org/wiki/Branch_predictor\n[3]: http://en.wikipedia.org/wiki/Instruction_pipeline\n[4]: http://en.wikipedia.org/wiki/MIPS_architecture\n[5]: http://wiki.osdev.org/X86_Instruction_Encoding\n[6]: http://en.wikipedia.org/wiki/Assembly_language\n[7]: http://en.wikipedia.org/wiki/Flex_lexical_analyser\n[8]: http://en.wikipedia.org/wiki/GNU_bison\n[9]: http://www.d.umn.edu/~gshute/spimsal/new/control-signal-summary.xhtml\n\n\n\n\n\n# License\n\nThe MIT License\n\nCopyright (c) 2006 Christopher Lord\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclord%2Fmips-cpu-simulator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fclord%2Fmips-cpu-simulator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclord%2Fmips-cpu-simulator/lists"}