src/main.c— entry point and demo program installation.src/utils/— logging and interactive startup configuration.src/rm/— Real Machine: CPU, memory, interrupts, timer, disk, channel device, IO facade.src/vm/— Virtual Machine: VM CPU, VM memory, VM/channel glue, VM lifecycle.include/— shared constants, structs, and opcode/interrupt definitions.asm/— placeholders (empty) for startup/interrupt/context-switch assembly.Makefile— builds intobin/rmvm, with objects inbuild/.NUL,rm_test,README.md— empty placeholders at the root.
- Word/register size: 16-bit;
REG_COUNT = 8general registers. - Physical memory:
MEMORY_SIZE = 512words, split into:- User space:
0..255(USER_MEMORY_START/END). - Supervisor space:
256..511(SUPERVISOR_MEMORY_START/END). - Any address outside these ranges raises
PI_INVALID_ADDRESS.
- User space:
- VM memory:
VM_MEMORY_SIZE = 0xFFbytes, independent of physical memory layout. - CPU modes:
MODE_USERandMODE_SUPERVISOR. Supervisor gates privileged ops and supervisor memory access. - Timer:
TICK_LIMIT = 10simulated ticks before raising a timer interrupt. - Flags:
FLAG_ZERO,FLAG_NEGATIVE,FLAG_OVERFLOW,FLAG_CARRYshare the singleSFfield. - Interrupt codes:
- Program interrupts (PI): invalid opcode/address/register, div-by-zero, privilege violation, overflow.
- System interrupts (SI): read/write/halt/sys requests.
- Timer interrupts (TI):
TI_EXPIREDwhen the counter hits its limit.
main()(src/main.c) callsgenerateConfig()to select logging behavior before any logging occurs.initRealMachine()(src/rm/rm.c) zeros physical memory, initializes CPU registers and flags, zeroes disk, and primes the IO channel.- Demo program is written directly into
physicalMemory.cells[0..3]as raw instruction words; CPU mode is set to supervisor,ICis reset. execCycle()(src/rm/cpu.c) loops:fetch→decode→executeuntil an interrupt is latched.- On interrupt,
handleInterrupts()logs/clears PI/SI/TI;SI_HALTends the loop, stopping the CPU. - VM creation is not currently wired into
main; VM paths run only whencreateVM()is called manually by another component.
CPU(include/registers.h): instruction counterIC, eight general registersR[], status flagsSF, privilegeMODE, interrupt latchesPI/SI/TI, page-table pointerPTR.Memory(include/memory.h): 512-word array. Accessors (read,write) enforce region + privilege rules;readUser/writeUserandreadSupervisor/writeSupervisorbypass checks for channel ops.HardDisk(include/disk.h): 128 sectors × 16 bytes;busy,ready,interruptFlag, andheadtrack device state.ChannelDevice(include/channel_device.h): describes a transfer using selectorsST(source type) andDT(destination type), basesSB/DB,COUNT,OFFSET,DATA, andbusy.Timer(include/timer.h): simple counter withlimit,active, andinterruptFlag.
initCPU: resets registers, flags, sets supervisor mode, clears interrupts, setsPTRtoPTR_START.fetch: reads a word fromphysicalMemoryatIC(respecting privilege rules), incrementsIC, stops on address faults.decode: unpacks[15:12]=opcode,[11:9]=regA,[8:7]=mode,[6:0]=operand(orregBfor ALU ops,addrfor jumps). Validation setsPIon any illegal opcode/register/address/mode.execute: semantics by opcode (all operate onrealCPUandphysicalMemory):LOAD: immediate, direct, or double-indirect.STORE: direct or double-indirect.ADD/SUB/MUL/DIV/CMP: register-register ALU with flag updates; overflow/div-zero set PI.JMP/JZ/JNZ: direct/indirect/double-indirect control flow;JZ/JNZtestFLAG_ZERO.READ/WRITE/HALT: supervisor-only; user attempts raisePI_INVALID_OPCODE; on success set SI.NOP/SYS:SYSsetsSI_SYS;NOPdoes nothing.
execCycle: loops fetch/decode/execute while no interrupts are latched; ticks a software timer (TICK_LIMIT); exits whenhandleInterruptsreturns 0 (halt).handleInterrupts: prints SI/PI/TI conditions, clears them, and terminates whenSI_HALTis set.
- Supervisor-only addresses (
>=256) raisePI_INVALID_ADDRESSwhen accessed in user mode. - No paging/translation is active despite
PTRexisting; addresses are direct. - Helper accessors without privilege checks are used only by the channel layer to avoid recursive faults.
raiseProgramInterrupt,raiseTimerInterrupt,raiseSystemInterruptsetrealCPU.PI/TI/SIrespectively (with bounds checks).hasPendingInterruptis a quick “is anything latched?” helper;clearAllInterruptszeros all latches.
initTimerarms a timer withlimit;tickTimerincrements and setsinterruptFlagat limit, then rolls over to 0.checkTimerInterruptreturns true once per limit interval;resetTimerclears both counter and flag.
- Sector-level API:
readDisk/writeDiskcopy full 16-byte sectors, togglebusy, and setinterruptFlagto signal completion. diskReadWordis a convenience: returns the first 16-bit word of a sector (used by channel transfers).simulateDiskInterruptclears the disk’sinterruptFlag; no asynchronous signaling is present.
ChannelDeviceselectors (include/channel_device.h):- Sources:
CH_SRC_USER_MEM,CH_SRC_SUPER_MEM,CH_SRC_DISK,CH_SRC_IO,CH_SRC_CPU_REG. - Destinations:
CH_DST_USER_MEM,CH_DST_SUPER_MEM,CH_DST_DISK,CH_DST_IO,CH_DST_CPU_REG.
- Sources:
channelXCHG(src/rm/channel_device.c) behavior:- User→Supervisor: copy
COUNTwords from user to supervisor addresses. - User→IO: print each user word as hex; set
cpu->SI = SI_WRITE. - Supervisor→User: copy
COUNTwords from supervisor to user addresses. - Disk→Supervisor: copy
COUNTwords viadiskReadWord; setcpu->SI = SI_READ. - IO→CPU register: prompt stdin, store hex word into
cpu->R[0]; setcpu->SI = SI_READ. - Invalid
STsetscpu->PI = PI_INVALID_ADDRESS;busywraps the entire transfer.
- User→Supervisor: copy
- IO facade (
src/rm/io.c):IOinitinitializes a static channel + disk (and zeroes disk contents).IOread: configures disk→supervisor transfer and raisesSI_READon success.IOwrite: configures supervisor→disk transfer and raisesSI_WRITEon success.IOcheckInterrupts: clearsrealCPU.SIwhen the channel is idle (polling hook for schedulers).
- Structures:
VirtualMachine(src/vm/vm.h): holds aChannel*,VM_MEMORY*, andVM_CPU*.VM_CPU(include/registers.h): 8 general registers,PC,SF,DS/CS,PTR,SI.VM_MEMORY(src/vm/vm_memory.h): flat byte buffer ofVM_MEMORY_SIZE.
- VM lifecycle (
src/vm/vm.c):createVM(channel): allocatesVirtualMachine; initializes VM memory/CPU; reads one disk sector through the provided channel into supervisor memory; copies that sector into VM memory; callsrunOperations(vm)immediately.- No scheduler integration yet; execution is synchronous and blocking.
VMinitMemoryis currently broken: it uses an uninitialized pointer; it must allocate (e.g.,calloc(1, sizeof(VM_MEMORY))) beforememset.loadProgramwrites anInstruction[]into consecutive 9-byte slots until it encountersOP_HALT; returns 1 on overflow beyondVM_MEMORY_SIZE.stuffInstruction(unused helper) decodes a 16-bit word intoInstructionfields and validates opcode/register/mode limits.
- Instruction storage (per 9-byte slot):
[0] opcode [1] regA [2] regB [3] mode [4] operand high byte [5] operand low byte [6] raw high byte [7] raw low byte [8] length (always 9 in current code) fetchgrabs a 9-byte frame atPC; out-of-bounds setsPI_INVALID_ADDRESSand aborts.- Addressing in
runOperations:LOADsources: immediate operand; absolute memory word; register value; register+displacement.STOREdestinations: absolute memory; register+displacement.ADD/SUB/MUL/DIV/CMPare register-register; flags come fromsf_setplus carry/overflow bits when relevant.JMP/JZ/JNZsetPCtooperand * 9so the operand indexes instructions, not bytes.READ/WRITE/SYS/HALTraise system interrupts via RM helpers and return to caller.
- Memory helpers:
vm_mem_read16/vm_mem_write16enforce bounds and operate on byte-packed words.sf_setsets zero/negative; carry/overflow are added explicitly by arithmetic handlers.
Channelembeds aChannelDeviceplus bookkeeping:dst_base: supervisor memory base where disk sectors land (defaultSUPERVISOR_MEMORY_START).last_buffer/last_qword_count: cache of most recent transfer, freed on next read.
readChannel: configures disk→supervisor transfer, copiesDISK_SECTOR_SIZEbytes into a heap buffer (asuint64_t[]), caches, returns pointer.writeChannel: writes cached buffer back to disk via supervisor→disk transfer. Fails if no cached buffer exists.
- RM opcodes (16-bit words):
HALT: supervisor-only; setsSI_HALT.LOAD/STORE: honor addressing mode; invalid mode raisesPI_INVALID_OPCODE.ADD/SUB/MUL/DIV/CMP: operate onR[regA]andR[regB]; overflow/div-zero latch PI.JMP/JZ/JNZ: operand is word address; indirect forms reread memory.READ/WRITE: supervisor-only; setSI_READ/SI_WRITE.NOP,SYS:SYSsetsSI_SYS.
- VM opcodes (9-byte frames):
- Same logical set, but all operands/addresses are byte-based; jumps multiply operand by 9 to land on instruction boundaries.
- System calls and HALT abort the VM loop after raising SI in the RM.
_logroutes throughlogFuncPtr, defaulting to stdout.g_fnameholds the current log filename (max 16 chars).generateConfig()prompt options:- stdout only
- custom file only (prompts for name; rejects names longer than 16 or containing spaces/newlines)
- default file only (
default_log.log) - stdout + default file
- stdout + custom file (prompts for name)
- Invalid selection or invalid file name falls back to the default file and logs an error via
_log. main()callsgenerateConfigbefore any other logging to ensure_loghas a destination.
- Installs four instruction words directly into
physicalMemory:0x1001:LOAD R0, #1(immediate)0x2002:LOAD R1, #2(immediate)0x3001:ADD R0, R10x0000:HALT
- Puts CPU into supervisor mode to allow HALT, zeroes
IC, and runsexecCycle()untilSI_HALTstops the loop. Demonstrates fetch/decode/execute and interrupt handling.
- Build:
make→bin/rmvm; intermediates inbuild/;make cleanpurges both. - Runtime: binary prompts for logging mode, initializes RM hardware emulation, runs the demo.
- Debug aids:
cpu.cprints each fetch ([DEBUG] Fetch @...) and interrupt handling messages.channel_device.clogs each transfer with source/destination selectors and counts.io.clogs disk read/write completion and raised interrupts.
- VM memory initialization bug:
VMinitMemorydereferences an uninitialized pointer; must allocate before use or every VM instantiation will crash. - VM is not integrated into
mainor any scheduler; creating a VM must be done manually by new code. - Interrupt handling is minimal: SI_READ/SI_WRITE are only logged; timer and disk interrupt flags are not surfaced to higher-level schedulers or handlers.
IOinitreinitializes the disk (zeroing storage); calling it after writing data wipes the disk image.- Channel transfers assume full-sector moves; partial-length or offset transfers are unsupported.
- Privilege enforcement only covers memory and certain opcodes; no paging/translation yet despite
PTRfield. - Assembly stubs in
asm/are empty placeholders; no boot or context-switch code is active.