An experimental virtual CPU, built in Java.
JavaVCPU executes byte-sized instructions to work with its own paged memory and palette display. It is a small place to experiment with the pieces beneath a computer: registers, opcodes, jumps, memory pages, and pixels.
bytecode program ──► JavaVCPU ──► memory pages
│
└────────► 256 × 256 display
| JV-DOS shell | Highlighted source editor |
|---|---|
![]() |
![]() |
The complete screenshot gallery shows boot, help, directory, documents, images, music, program execution, graphics demos and Disk Workshop.
The default BIOS boots JV-DOS 1.3, implemented using the existing VCPU opcodes. It provides an editable command line, persistent named files, a source editor with highlighting, runnable JVS programs, COM bytecode loading, palette images, a document pager, and a four-voice music player. Type HELP or CODEHELP in the display window.
Click the JavaVCPU display window before typing.
Open Disk Workshop locally to import small text/source/binary files, convert images or MIDI clips, and download an updated storage.img. Stop the VM before replacing its disk, then restart. The tool preserves the BIOS and OS bytes. Format documentation and limits explain the linked files up to 61,200 bytes and media conversions.
Use VIEW FILE.TXT to page through documents, IMAGE FILE.IMG to display a palette image, and PLAY FILE.JMT to play imported MIDI-note streams. Arrow keys navigate documents; Esc closes a viewer or stops music. RUN also recognizes imported image/music types. Shift supplies punctuation, including symbols, braces and quotes; keypad keys work. SOUND OFF disables keyboard clicks.
Use BROWSE example.com/ or BROWSE http://localhost:8000/index.html for the guest HTTP text browser. URLs use lowercase letters by default; hold Shift for uppercase. Up/Down page through the result, Home returns to the top, and Esc exits or cancels a request. The browser requests HTTP/1.0, removes response headers and HTML tags, and keeps up to 60,000 bytes of text in RAM without writing to disk. It supports plain HTTP and custom ports. HTTPS, redirects, JavaScript, CSS layout, character entities, images, and clickable links are not supported; script/style contents may appear as text. Servers must close the response connection; chunked responses are not decoded. The system image updates automatically on restart and preserves user files.
On first launch, DiskInstaller writes the BIOS and MicroDOS bytecode image to storage.img. Later launches execute a small bootstrap program that reads the image through the storage instruction, writes it into virtual memory, and begins at its BIOS entry page.
JavaVCPU requires JDK 26.
./gradlew.bat buildThen run xyz.ignite4inferneo.Main from IntelliJ IDEA with JDK 26 selected. There is currently no Gradle run task.
| Part | What it does |
|---|---|
| CPU | Executes bytecode through eight general-purpose registers plus a program counter and active-page register. |
| Memory | Provides two banks of 256 pages of 256 bytes: 128 KiB in total. |
| Display | Renders a 256 × 256 palette framebuffer in an 800 × 800 Swing window. |
| Programs | Includes a POST boot flow, text rendering, a snowfall animation, and memory-page examples. |
Programs are byte arrays assembled with the opcode and register helpers:
static final byte[] PROGRAM_EXAMPLE = new byte[] {
OPCode.STORE.code(), 42, Registers.A.address(),
OPCode.OUTPUT.code(), Registers.A.address(),
OPCode.STOP.code()
};Add the bytecode to Programs, add a matching Program enum value and loader case, then select it in Main.main(). Jump targets are byte addresses, so include every opcode and operand when calculating them.
| Program | Demonstrates |
|---|---|
BIOS_POST |
The default BIOS POST and handoff to the resident monitor. |
DEMO_OS |
Legacy enum name for the resident JV-DOS 1.2 bytecode operating system. |
PERIPHERAL_DIAGNOSTICS |
Storage read/write, keyboard polling, audio control, multiplication, and increment. |
DISPLAY_HELLO_CPU |
Drawing HELLO CPU with graphics bytecode. |
SNOWFALL |
Pixel reads and writes for falling, accumulating snow. |
PAGED_MEMORY |
Independent values at the same address on different pages. |
LOOP_127_3 |
Register arithmetic and conditional looping. |
HELLO_CPU |
Building ASCII values with arithmetic and printing them. |
Memory and registers
JavaVCPU has 256 memory pages of 256 bytes each. PAGE selects the page used for instruction fetches and memory instructions; changing pages preserves register values. Page numbers, addresses, and register operands are interpreted as unsigned bytes. Arithmetic wraps when stored back into a register.
| Register | Index | Purpose |
|---|---|---|
| A–H | 0–7 | General-purpose byte registers |
| COUNTER | 8 | Next instruction address on the active page |
| PAGE | 9 | Active memory page |
Programs.load uploads a program and resets PAGE and COUNTER to zero. It replaces only the uploaded byte range; it does not clear the rest of memory.
Instruction set
Each instruction is one opcode byte followed by zero or more operands. In the table, r, a, b, and out are register indices; value and address are literal bytes. R[r] is a register value and M[address] is an address on the active page.
| Opcode | Instruction | Bytes | Behavior |
|---|---|---|---|
| 0 | ADD a, b, out |
4 | R[out] = R[a] + R[b] |
| 1 | SUB a, b, out |
4 | R[out] = R[a] - R[b] |
| 2 | STORE value, r |
3 | R[r] = value |
| 3 | JMP address |
2 | Set COUNTER to address |
| 4 | STOP |
1 | End execution and print timing information |
| 5 | OUTPUT r |
2 | Print the signed value of R[r] |
| 6 | COND_JUMP a, b, address |
4 | Jump when R[a] == R[b] |
| 7 | LOAD_MEM r, address |
3 | R[r] = M[address] |
| 8 | STORE_MEM r, address |
3 | M[address] = R[r] |
| 9 | CHANGE_PAGE r |
2 | Set PAGE = R[r] |
| 10 | CHANGE_PAGE_JUMP r, target |
3 | Set PAGE = R[r], then COUNTER = R[target] |
| 11 | CHANGE_PAGE_COND_JUMP r, a, b, address |
5 | On equality, select the page and jump |
| 12 | PUSH_GRA_MEM x, y, color |
4 | Write R[color] at (R[x], R[y]) |
| 13 | CLEAR_GRA |
1 | Fill the framebuffer with black |
| 14 | DISPLAY |
1 | Present the framebuffer and limit execution to roughly 30 frames/second |
| 15 | READ_GRA_MEM x, y, out |
4 | Store the palette color at (R[x], R[y]) in R[out] |
| 16 | READ_INPUT device, out |
3 | Read a device port into R[out] |
| 17 | OUTPUT_AUDIO voice, note, control |
4 | Configure an audio voice from registers |
| 18 | READ_BYTE_FROM_STORAGE x, y, z, out |
5 | Read storage byte (R[x], R[y], R[z]) into R[out] |
| 19 | WRITE_BYTE_TO_STORAGE x, y, z, value |
5 | Write R[value] to storage byte (R[x], R[y], R[z]) |
| 20 | MULTIPLY a, b, out |
4 | R[out] = R[a] * R[b] |
| 21 | INCREMENT_REGISTER r |
2 | Increment R[r] |
| 22 | STORE_MEM_ON_PAGE value, page, address |
4 | Memory[R[page]][R[address]] = R[value] |
Display and colors
Monitor stores a 256 × 256 framebuffer and uses nearest-neighbor scaling for an 800 × 800 Swing window. Call DISPLAY after drawing a frame.
PUSH_GRA_MEM and READ_GRA_MEM read their coordinates from registers. Valid coordinates are 0 through 255; coordinates are interpreted as unsigned bytes.
Colors use the low seven bits of a byte in RRGGGBB order:
| Bits | Channel | Levels |
|---|---|---|
| 6–5 | Red | 4 |
| 4–2 | Green | 8 |
| 1–0 | Blue | 4 |
The high bit is ignored on writes. 0b11_111_00 is yellow and 0b11_111_11 is white.
| File | Purpose |
|---|---|
Main.java |
CPU state, instruction dispatch, and implementations |
Memory.java |
Paged-memory storage |
Monitor.java |
Framebuffer access and Swing rendering |
OPCode.java |
Opcode values and instruction lengths |
Programs.java |
Built-in bytecode and its loader |
jvdos/JvDosImage.java |
Assembles the guest DOS kernel, editor, source interpreter, and media tools |
tools/disk-workshop/index.html |
Browser-local disk importer/editor and image/MIDI converters |
Registers.java |
Register indices |
JV-DOS 1.2 expands storage to 254 banks of 255 shared blocks. Use BANK, BANK +, and BANK - to inspect and change banks. The device remains 16 MiB; files can now use linked blocks up to 61,200 bytes when bank space permits; existing files stay in bank 2. The DOS assembler is now in xyz.ignite4inferneo.jvdos.
RAM now provides 131,072 eight-bit locations (128 KiB) through two 64 KiB banks. Legacy programs boot in bank 0. Opcodes 23–25 provide cross-bank jumps, reads and writes; see the instruction set. Storage remains separately addressed at 16 MiB.
JV-DOS 1.3 supports larger text/JVS/COM files, 16-bit editor cursors and longer music streams (255 events). ./gradlew storageRegression runs the headless RAM/filesystem checks without external test libraries.
The DOS prompt supports Up/Down history (16 commands, cleared on reboot) and Tab completion of command names and bank-local filenames. Repeated Tab cycles matches; EDIT retains arrow navigation and four-space Tab indentation.
Multiple 16 MiB disk images can be mounted with program arguments such as --disk=1=secondary.img; select one in DOS with DRIVE 1. Network opcodes 29/30 expose an asynchronous TCP controller over its own byte-addressed register bus, using the host?s internet connection. See Peripheral buses for the device protocol and a runnable guest network example.


