https://github.com/JanNeuendorf/SVC16 Skip to content Navigation Menu Toggle navigation Sign in * Product + GitHub Copilot Write better code with AI + Security Find and fix vulnerabilities + Actions Automate any workflow + Codespaces Instant dev environments + Issues Plan and track work + Code Review Manage code changes + Discussions Collaborate outside of code + Code Search Find more, search less Explore + All features + Documentation + GitHub Skills + Blog * Solutions By company size + Enterprises + Small and medium teams + Startups By use case + DevSecOps + DevOps + CI/CD + View all use cases By industry + Healthcare + Financial services + Manufacturing + Government + View all industries View all solutions * Resources Topics + AI + DevOps + Security + Software Development + View all Explore + Learning Pathways + White papers, Ebooks, Webinars + Customer Stories + Partners + Executive Insights * Open Source + GitHub Sponsors Fund open source developers + The ReadME Project GitHub community articles Repositories + Topics + Trending + Collections * Enterprise + Enterprise platform AI-powered developer platform Available add-ons + Advanced Security Enterprise-grade security features + GitHub Copilot Enterprise-grade AI features + Premium Support Enterprise-grade 24/7 support * Pricing Search or jump to... Search code, repositories, users, issues, pull requests... Search [ ] Clear Search syntax tips Provide feedback We read every piece of feedback, and take your input very seriously. [ ] [ ] Include my email address so I can be contacted Cancel Submit feedback Saved searches Use saved searches to filter your results more quickly Name [ ] Query [ ] To see all available qualifiers, see our documentation. Cancel Create saved search Sign in Sign up Reseting focus You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session. Dismiss alert {{ message }} JanNeuendorf / SVC16 Public * Notifications You must be signed in to change notification settings * Fork 2 * Star 124 Simplest Virtual Computer License MIT license 124 stars 2 forks Branches Tags Activity Star Notifications You must be signed in to change notification settings * Code * Issues 0 * Pull requests 0 * Discussions * Actions * Security * Insights Additional navigation options * Code * Issues * Pull requests * Discussions * Actions * Security * Insights JanNeuendorf/SVC16 main BranchesTags [ ] Go to file Code Folders and files Name Name Last commit Last commit message date Latest commit History 20 Commits examples examples src src .gitignore .gitignore Cargo.lock Cargo.lock Cargo.toml Cargo.toml LICENSE LICENSE README.md README.md colors_scaled.png colors_scaled.png logo.png logo.png logo_alpha.png logo_alpha.png sketch.svg sketch.svg View all files Repository files navigation * README * MIT license The Simplest Virtual Computer (16 bit) Logo This is the specification for an extremely simple "virtual computer" that can be emulated. The goal in one word is simplicity. It should be simple to understand every instruction, to write machine code that runs on it, and to write a compiler for it. The instruction set and the design in general are in no way meant to resemble something that would make sense in real hardware. It is also not intended to be as simple and elegant as it could possibly be. This repo contains an emulator to run games or programs. It can be installed with cargo: cargo install --git https://github.com/JanNeuendorf/SVC16 You can then run a program from the cli: svc16 /path/to/my_rom.svc16 Use --help to see some basic options. I do not want to provide an assembler, any kind of compiler or even any ideas about things like call conventions. The idea is that you have to build that yourself. You can play a game from the example folder to get an idea of what can be built. Logo Quick Overview [?][?] Warning: Until there are specifications with version 1.0, there could be breaking changes. No Registers There are no CPU registers, just one chunk of memory. Values can be loaded from every memory address and written to every memory address. Everything is an unsigned 16-bit integer Everything is represented as a (le) unsigned 16-bit integer. That includes numbers, addresses, colors, the instruction pointer and the input. Booleans are represented as u16 values as well: 0 for false and >0 for true. (1 when written as a boolean.) Wrapping Arithmetic All numerical operations that will appear in the instructions are wrapping operations. Division by zero crashes the program. No Magic Numbers The main memory contains one valid address for every u16. The screen-buffer is the same size as the memory and there is one pixel for every u16. No Fluff There are as few features as possible. That means limited input, no sound, no variable display size etc. It also means that there are no accelerators or tricks to help with performance. Setup Here is a sketch of all components of the virtual computer: [sketch] Instruction pointer The instruction pointer represents an address in main memory. It starts as zero. Then, it is manipulated by the instructions. All operations performed on the instruction pointer are wrapping. Screen The screen has a resolution of $256*256=2^{16}$ pixels. The color of each pixel is represented with 16-bits using RGB565. The coordinate $ (x,y)$ of the screen maps to the index $256y+x$ in the screen-buffer. The coordinate $(0,0)$ is in the upper left-hand corner. Changes to the screen-buffer are not reflected on the screen until the system is synchronized. Input The only supported inputs are the mouse position and the left and right mouse keys. On synchronization the input on the last frame is loaded into the input-buffer. The position code is the index of the pixel, the mouse is currently on. The key code is given by left_mouse+2*right_mouse. So it can have the values 0 1 2 or 3. There is no guarantee that the inputs are synced on the next frame. Before the first synchronization, the input codes are zero. Synchronization When the console executes the Sync instruction, the screen-buffer is drawn to the screen. It is not cleared. The input-buffer is updated. The system will be put to sleep until the beginning of the next frame. The targeted timing is 30fps. There is a hard limit of 3000000 instructions per frame. This means that if the Sync command has not be called for 3000000 instructions, it will be performed automatically. CPU All instructions are 4 values long. A value is, of course, a u16. The instructions have the form opcode arg1 arg2 arg3. In the following table, all instructions are listed. @arg1 refers to the value at the memory address arg1. If the opcode is greater than 15, the system will abort. If one of the three arguments is not used, it can be set to any value, but it can not be omitted. When the instruction pointer advances, it does so by four positions. Opcode Name Advances Effect 0 Set yes @arg1=arg2 1 GoTo if if(not @arg3){inst_ptr=@arg1+arg2} skipped 2 Skip if if(not @arg3){inst_ptr=inst_ptr+4*arg1-4*arg2} skipped 3 Add yes @arg3=(@arg1+@arg2) 4 Sub yes @arg3=(@arg1-@arg2) 5 Mul yes @arg3=(@arg1*@arg2) 6 Div yes @arg3=(@arg1/@arg2) 7 Cmp yes @arg3=(@arg1<@arg2) as unsigned 8 Deref yes @arg2=@(@arg1+arg3) 9 Ref yes @(@arg1+arg3)=@arg2 10 Inst yes @arg1=inst_ptr 11 Print yes Writes color=@arg1 to index=@arg2 of screen-buffer. 12 Read yes Copies index=@arg1 of screen-buffer to @arg2 13 Band yes @arg3=@arg1&@arg2 14 Xor yes @arg3=@arg1^@arg2 15 Sync yes Puts @arg1=position_code, @arg2=key_code and synchronizes in that order Constructing a Program A program is really just the initial state of the main memory. There is no distinction between memory that contains instructions and memory that contains some other asset. The initial state is loaded from a binary file that is read as containing the (le) u16 values in order. The maximum size is $2*2^{16}=$ bytes ($\approx$ 131.1kB). It can be shorter, in which case the end is padded with zeroes. The computer will begin by executing the instruction at index 0. Example A simple example would be to print all $2^{16}$ possible colors to the screen. We make our lives easier, by mapping each index of the screen-buffer to the color which is encoded with the index. Here, we use the names of the opcodes instead of their numbers. Set 501 1 0 // Write the value 1 to address 501 Set 502 65535 0 // Write the largest possible value to 502 Print 500 500 0 // Display color=@500 at screen-index=@500 Add 500 501 500 // Increment the color/screen-index Cmp 500 502 503 // See if we are not at the max number Xor 503 501 503 // Negate it Skip 0 4 503 // Unless we are at the max number, go back 4 instructions Sync 0 0 0 // Sync GoTo 0 0 0 // Repeat to keep the window open We could rely on the fact that the value at index 500 starts at zero and we did not have to initialize it. To build a program that we can execute, we could use python: import struct code = [ 0, 501, 1, 0, #Opcodes replaced with numbers 0, 502, 65535, 0, 11, 500, 500, 0, # ... ] with open("all_colors.svc16", "wb") as f: for value in code: f.write(struct.pack("