{"id":24884166,"url":"https://github.com/spectrum4/spectrum4","last_synced_at":"2025-07-21T10:34:11.227Z","repository":{"id":45716035,"uuid":"154108859","full_name":"spectrum4/spectrum4","owner":"spectrum4","description":"A modern-day ZX Spectrum OS rewritten from scratch in ARM assembly (aarch64) to run natively on Raspberry Pi 400","archived":false,"fork":false,"pushed_at":"2025-07-18T03:43:24.000Z","size":9787,"stargazers_count":36,"open_issues_count":2,"forks_count":3,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-07-18T07:28:55.450Z","etag":null,"topics":["aarch64","arm64","assembly","bare-metal","kernel","raspberry-pi","retro","rpi4","tup","z80","zx-spectrum"],"latest_commit_sha":null,"homepage":"","language":"Assembly","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/spectrum4.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,"zenodo":null}},"created_at":"2018-10-22T08:18:33.000Z","updated_at":"2025-07-18T03:43:27.000Z","dependencies_parsed_at":"2023-10-15T14:48:08.380Z","dependency_job_id":"14acd41a-ff1a-4eeb-86ba-fc977324adc6","html_url":"https://github.com/spectrum4/spectrum4","commit_stats":{"total_commits":253,"total_committers":1,"mean_commits":253.0,"dds":0.0,"last_synced_commit":"33a5955320801c0718452190a889ebc37941d3c3"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/spectrum4/spectrum4","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spectrum4%2Fspectrum4","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spectrum4%2Fspectrum4/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spectrum4%2Fspectrum4/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spectrum4%2Fspectrum4/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/spectrum4","download_url":"https://codeload.github.com/spectrum4/spectrum4/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spectrum4%2Fspectrum4/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266285573,"owners_count":23905382,"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":["aarch64","arm64","assembly","bare-metal","kernel","raspberry-pi","retro","rpi4","tup","z80","zx-spectrum"],"created_at":"2025-02-01T14:19:38.023Z","updated_at":"2025-07-21T10:34:11.209Z","avatar_url":"https://github.com/spectrum4.png","language":"Assembly","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!--\nThis file is part of the Spectrum +4 Project.\nLicencing information can be found in the LICENCE file\n(C) 2021 Spectrum +4 Authors. All rights reserved.\n--\u003e\n\n# ZX Spectrum +4\n\nA modern-day ZX Spectrum OS rewritten from scratch in ARM assembly (aarch64) to\nrun natively on Raspberry Pi 400. Based on the Spectrum 128K.\n\nOriginally targetted at the Raspberry Pi 3 Model B, with the introduction of\nthe Raspberry Pi 400, the author decided to adapt the project to target the\nnewer model. The USB hardware is easier to work with, and requires support for\nonly a single keyboard.\n\nFor now, the code continues to work on a Raspberry Pi 3 Model B, however, the\nkeyboard interpretation routines will not work on this model when they are\nwritten. The unit tests are designed to run under QEMU in the CI, which only\nsupports the Raspberry Pi 3 Model B (`qemu-system-aarch64 -M raspi3b`). If at\nsome point QEMU starts supporting the Raspberry Pi 400 or Raspberry Pi 4 Model\nB, the CI may be adapted to use it, and support removed for the Raspberry Pi 3\nModel B.\n\nIn addition to the Raspberry Pi 400, it is likely (although not tested by the\nauthor) due to hardware similarity, that the ZX Spectrum +4 will also run on\nthe Raspberry Pi 4 Model B, together with the standard Raspberry Pi USB\nKeyboard.\n\nIf you are not familiar with the ZX Spectrum computer from the 1980's, there\nare some excellent emulators around, such as [Retro Virtual\nMachine](http://www.retrovirtualmachine.org/), and even some very good online\nemulators that you can run directly in your browser.\n\nFor more information about the history and development of this project, see\n\u003chttps://github.com/spectrum4/notes\u003e.\n\n__Please note this project is very much in its infancy.__\n\n__Only a handful of routines have been ported/implemented so far.__\n\n## Variations from the Spectrum 128K\n\nThe Spectrum +4 is intentionally incompatible with the original Spectrum. If\nyou wish to run original ZX Spectrum software, there are some excellent\nemulators available such as [Retro Virtual\nMachine](https://www.retrovirtualmachine.org/en/), or for the Raspberry Pi see\n[ZXBaremulator](http://zxmini.speccy.org/en/index.html), as well as new\n[compatible hardware](https://www.specnext.com/shop/).\n\nThe idea behind this project is to imagine what Sinclair/Amstrad might have\ndeveloped for their next Spectrum, if Raspberry Pi 400 hardware had been\navailable at the time, rather than to reproduce what they already had.\n\nIt is also an excuse for me to learn bare metal programming and aarch64\nassembly. :-)\n\nWith that in mind, the following sections outline the differences between\nSpectrum +4 and the original ZX Spectrum 128K.\n\n## Graphics\n\n![Screen loading demo](animated.gif)\n\nIn order to retain the spirit of the original Spectrum computers, the video\ndisplay preserves many of the original Spectrum principles:\n\n  * The original colour palette\n  * The original character cell restrictions\n    * Each character cell is limited to a single 3 bit paper and 3 bit ink\n      colour\n    * Each character cell may be `BRIGHT` or not\n    * Each character cell may `FLASH` or not\n  * A solid border colour around the edges of the display\n\nHowever, the screen geometry has changed a little:\n\n  * Each character cell is now 16x16 pixels, rather than 8x8 pixels\n  * The screen now is 108 character cells wide instead of 32\n  * The screen now is 60 character cells high instead of 24\n\nThe border thickness is equivalent to the original Spectrum 128K in terms of\nequivalent character cell counts:\n\n  * Left border: 6 characters wide\n  * Right border: 6 characters wide\n  * Top border: 8 characters high\n  * Bottom border: 7 characters high\n\nThis matches the original screen geometry (which had 8 pixels per character):\n\n  * \u003chttp://www.zxdesign.info/vidparam.shtml\u003e\n\nIn order to enforce the video restrictions, updates to the display file and\nattributes file explicitly call the `poke_address` routine, which syncs the\nVideoCore IV GPU firmware framebuffer with the display file and attributes\nfile. I believe it should be possible to trap memory writes directly to the\ndisplay file and attributes file, and call `poke_address` from the exception\nhandler. Some information about trapping memory writes is\n[here](https://www.cnblogs.com/pengdonglin137/p/14091950.html). This particular\nguide is focussed on EL2 handling of EL1 memory accesses, but the same\nprinciples should apply with EL1 handling of EL0 memory accesses. The MMU\nis enabled, and so are interrupts. At the moment the interrupt routine doesn't\ndo anything. It is fired by a timer.\n\nThe display file and attributes file differ from the Spectrum 128K as follows:\n\n  * Each vertical screen third is now 20 character cells high rather than 8\n  * Each cell now has 16 pixel rows instead of 8\n  * A single pixel row of a character cell now requires 2 bytes instead of 1\n\nThe mechanics of converting memory addresses to `(x, y)` coordinates is no\nlonger a matter of simple bit manipulation. This is a consequence of the\ndimensions no longer being powers of 2. However, sequencially updating bytes in\nthe display and attributes file simulates the original screen loading\nmechanics, which is nice to have preserved.\n\n## Memory\n\nThe Raspberry Pi 400 has 4GB RAM, which is considerably more than the Spectrum\n128K.  Using the 64 bit instruction set means that most of the memory paging\nroutines in the original Spectrum can be mostly ignored and don't require\ntranslation. It also means that there is much more space available for BASIC\nprograms, machine code routines, and RAM disk storage.\n\n  * Spectrum +4 is loaded at physical ARM address 0x00000000\n  * The RAM Disk is initially set to 256MB\n  * The HEAP is initially set to 256MB\n\n## Execution context\n\n  * Spectrum +4 runs at EL1\n  * MMU is enabled\n  * Kernel virtual addresses map 1:1 with physical addresses, but with upper 28\n    bits set (leaving a 36 bit adddress range)\n  * EL1 data cache is enabled\n  * EL1 instruction cache is enabled\n  * Timer interrupts configured and enabled, but keyboard routines not yet written\n\n## Code organisation\n\n  * All Spectrum +4 routines are written in aarch64 assembly (GNU assembler\n  syntax).\n  * The Spectrum +4 source code is under the `/src/spectrum4` directory.\n  * The build and test directives live in the various `Tup*` files scattered\n  throughout the repository (tup build system is used - see\n  [Building](#building))\n  * As much as possible, the naming of system variables and routines, and the\n  ordering of routines, match the disassembly in the\n  `src/spectrum128k/roms/romX.s` files.\n  * Each ported routine contains a comment giving the label of the associated\n  Spectrum 128K routine that it was ported from. The label is an `L` followed\n  by the 16 bit hexadecimal address of the original Spectrum 128K routine.\n\n## Building\n\nTo build/test everything, simply run `./tup-under-docker.sh`. This requires\nthat [`docker`](https://www.docker.com/) is installed on your system. It simply\ncalls [`tup`](http://gittup.org/tup/index.html) inside a docker container that\ncontains all required build/test dependencies. Run `./tup-under-docker.sh -h`\nto see additional options.\n\nIf you prefer to use a native toolchain, or cannot run docker containers on\nyour host then see [Building Without Docker](dev-setup/README.md).\n\n## Running\n\nAfter building using one of the methods above, the following distribution\nfiles/directories will be updated:\n\n  * Directory `src/spectrum4/dist` contains a debug and release version of\n    Spectrum +4. The debug version is the same as the release version, but\n    additionally logs debug messages to Mini UART, and performs a short demo on\n    start up.\n  * Directory `src/spectrum128k/tests` contains Spectrum 128K casette tape images\n    (*.tzx files) and casette tape audio samples (*.wav files) for running the\n    Spectrum 128K unit tests under a Spectrum 128K emulator (such as FUSE or\n    Retro Virtual Machine) or on a real Spectrum 128K machine.\n  * Directory `src/spectrum4/targets` contains Raspberry Pi kernel images for\n    running individual test suites, e.g. under QEMU, or on a real Raspberry Pi.\n\nIn order to run the debug and/or release builds of Spectrum +4 on an actual\nRaspbery Pi, either copy the contents of the given distribution directory to a\nformatted SD card, or serve the directory contents over TFTP to a suitably\nconfigured Raspberry Pi that has been configured to network boot. The\n[github.com/spectrum4/notes](https://github.com/spectrum4/notes#5-rpi-3b-bootloading)\nproject has some information about that type of setup, if you are interested.\n\nAlternatively, to run Spectrum +4 under QEMU instead of a real Raspberry Pi,\nrun something like:\n\n```bash\n$ qemu-system-aarch64 -full-screen -M raspi3b -kernel \\\nsrc/spectrum4/targets/debug.elf -serial null -serial stdio\n```\n\nAt the time of writing, `qemu-system-aarch64` does not have Rasperry Pi 4 Model\nB / Raspberry Pi 400 target.\n\nNote, __you will likely need QEMU version 5.2.0 or later__. Also note that the `.elf`\nfile is passed to the `-kernel` option, rather than the `.img` file, in order that\nQEMU loads the kernel at address 0x0 rather than 0x80000, which seems not to be\npossible when passing the `.img` file directly.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspectrum4%2Fspectrum4","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspectrum4%2Fspectrum4","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspectrum4%2Fspectrum4/lists"}