{"id":26798177,"url":"https://github.com/krzys9876/z80_sim_scala","last_synced_at":"2025-03-29T19:17:18.980Z","repository":{"id":42495504,"uuid":"475656524","full_name":"krzys9876/z80_sim_scala","owner":"krzys9876","description":"Z80-based system simulator written in scala","archived":false,"fork":false,"pushed_at":"2023-05-03T13:54:12.000Z","size":781,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2023-05-03T15:28:02.779Z","etag":null,"topics":["functional-programming","immutability","scala","simulator","z80","z80-assembler","z80-emulator"],"latest_commit_sha":null,"homepage":"","language":"Scala","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/krzys9876.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":"2022-03-29T23:54:04.000Z","updated_at":"2023-05-03T15:28:02.779Z","dependencies_parsed_at":"2022-08-22T15:00:54.747Z","dependency_job_id":null,"html_url":"https://github.com/krzys9876/z80_sim_scala","commit_stats":null,"previous_names":[],"tags_count":null,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krzys9876%2Fz80_sim_scala","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krzys9876%2Fz80_sim_scala/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krzys9876%2Fz80_sim_scala/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/krzys9876%2Fz80_sim_scala/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/krzys9876","download_url":"https://codeload.github.com/krzys9876/z80_sim_scala/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246230504,"owners_count":20744349,"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":["functional-programming","immutability","scala","simulator","z80","z80-assembler","z80-emulator"],"created_at":"2025-03-29T19:17:18.142Z","updated_at":"2025-03-29T19:17:18.972Z","avatar_url":"https://github.com/krzys9876.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Scala based Z80 CPU/System simulator #\n\nYou might be thinking why would anybody write such a useless project. The obvious answer is: **for fun**.\n\nStill it is a great learning tool for **Scala**, **functional programming**, **immutability** and **refactoring**.\n\n## Background ##\n\nI love retro-computing. I know Z80 quite well, some time ago I built a ZX Spectrum-like homebrew computer.\nI learned Z80 assembler quite well and tweaked some publicly available ROMs to suit my needs.\n\nI used different tools and simulators to make it easier. \nBut one thing was always missing - a simulator that I could easily modify myself, with simple I/O.\n\n### Why Scala ###\n\nI use Scala at work, and I am still exploring useful functional patterns. \nI thought that it would be great to have simple side project to exercise handling application state in immutable fashion.  \n\nAnd here it is :slightly_smiling_face:\n\n## Current state of the project ##\n\n### Instruction set ###\n\n\u003cimg src=\"https://img.shields.io/badge/Load%208--bit-Done-green.svg\"/\u003e\u003c/a\u003e\n\u003cimg src=\"https://img.shields.io/badge/Load%2016--bit-Done-green.svg\"/\u003e\u003c/a\u003e\n\u003cimg src=\"https://img.shields.io/badge/Exchange-Done-green.svg\"/\u003e\u003c/a\u003e\n\u003cimg src=\"https://img.shields.io/badge/Block%20transfer-Done-green.svg\"/\u003e\u003c/a\u003e\n\u003cimg src=\"https://img.shields.io/badge/8--bit%20arithmetic-Done-green.svg\"/\u003e\u003c/a\u003e\n\n\u003cimg src=\"https://img.shields.io/badge/16--bit%20arithmetic-Done-green.svg\"/\u003e\u003c/a\u003e\n\u003cimg src=\"https://img.shields.io/badge/Control%20incl. INT-Done-green.svg\"/\u003e\u003c/a\u003e\n\u003cimg src=\"https://img.shields.io/badge/Rotate%20and%20shift-Done-green.svg\"/\u003e\u003c/a\u003e\n\n\u003cimg src=\"https://img.shields.io/badge/Bit%20manipulation-Done-green.svg\"/\u003e\u003c/a\u003e\n\u003cimg src=\"https://img.shields.io/badge/Jump%20call%20return-Done-green.svg\"/\u003e\u003c/a\u003e\n\u003cimg src=\"https://img.shields.io/badge/Input%20and%20output-Done-green.svg\"/\u003e\u003c/a\u003e \n\n### Skipped instructions ###\nI will not use non-maskable interrupts so I do not need \u003ccode\u003eRETN\u003c/code\u003e.\n\nMost of IO operations except for: \u003ccode\u003e IN A,(n) IN A,(C) OUT (n),A OUT (C),r\u003c/code\u003e.\nActually I did not see many uses of other IOs, \nso it is not a great loss anyway.\n\n## The goal ##\n\nI thought that to be able to run **1978 Microsoft Basic** would be a good target for this fun project.\n(If you've never used old Basic you should try it and for a moment feel like a kid in 70's and 80's!)\n\nIt seemed difficult since assembler programs leave no room for errors in handling operations. \n\nAfter extensive refactoring effort and (hopefully) necessary simplifications \nI was able to debug errors and run the most trivial Basic program, which was:\n\n    10 FOR I=1 TO 10\n    20 PRINT I;\" \";I^2;\" \";I^3\n    30 NEXT I\n\nI remember well that the power operator (^) in Basic was really slow, therefore I deliberately used it to check for performance.\n\n## Performance ##\n\nThe whole code initially needed ~40 seconds to complete and ~0.5 million steps (11th gen i5) - without initial memory test, \nwhich I skip by entering \"65536\" at start of the Basic interpreter.\n\nProfiler showed that most of the program time was spent looking up opcodes in various list (from OpCodes). \nAfter removing most of the lookup operations the reference program took ~4 seconds to complete - 10x improvement. \n\nAnother optimization was to replace costly map handling in register file. After replacing it with just vals\n(which added some complexity to the code) the reference program finishes in \u003c3 seconds. \nThis highly depends on whether it is run from IntelliJ or directly from command prompt.\n\nI've added tracking of T cycles throughout the program, so it is possible to compare timings to actual Z80 performance @ 3.6864MHz. \nThat's the clock speed I use in my Z80 projects as it allows serial communication @ 57600 / 115200.\n\nThe best I could normally get for a reference program (and others) was ~50-75%. However, for the **arithmetic.txt** \nprogram (see _input-files_ folder - no loops, just calculations) the ratio once peeked as high as almost 250%. \nNote that extensive use of console may degrade performance due to scrolling.\n\n![demo](z80_sim_sample.gif)\n\n## How much faster are mutable collections? ##\n\nThe initial idea was to use purely immutable data structures, including array/vector for the memory.\nI verified the performance several times with _visualvm_ and the results were clear - the application spent ~50% of time\nto manipulate the memory and another ~10% for registers. So why not test the mutable memory and registers for comparison?\n\nI used native java array (to avoid boxing of integer values) and the same mutable-like interface (every function\nreturns an instance of the memory, which in case of mutable memory is just the same instance\nevery time). The boost in performance was quite substantial - for **arithmetic2.txt** it was x2 - x3 (from ~80%-100% to even ~200-400% or more).\n\n## Run sample programs ##\n\nIn the main project directory you will find the _run.bat_ script with some examples. \nThe parameters are:\n\n     --mode           : batch (no user interaction)/\n                        interactive (use console to interact with the program and Esc to break execution))\n     --hex-file       : the ROM file to run\n    [--basic-file]    : a file with Basic proram, \n                        actually this is just to simulate user input\n    [--steps-m]       : steps to be executed in millions (real number) or -1 for infinity\n    [--memory-type]   : fast/slow (default: fast)\n    [--register-type] : fast/slow (default: fast)\n    [--interrupts]    : true/false (default: true) - should the program use interrupts to read user input\n\n## Copyright notice ##\n\nNascom/Microsoft Basic 4.7 is copyright of Microsoft. See also: [http://www.nascomhomepage.com/](http://www.nascomhomepage.com/)\n\nModifications to original source are copyright of Grant Searle. You cannot use it for commercial purposes. See: [http://searle.wales/](http://searle.wales/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkrzys9876%2Fz80_sim_scala","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkrzys9876%2Fz80_sim_scala","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkrzys9876%2Fz80_sim_scala/lists"}