_ _ ___ _ _ _ | || | | _ \ / \ | \/ | | __ | | / | ^ | | __ | |_||_| |_\_\ |_|_| |_||_| THE HAND ROLLED ASSEMBLY MACHINE ================================ /// program like it's 1979 ///

lua & jit assembly & vram & lpeg ( gif coming soon! )
Screenshot 1
========================================

# what is hram

# top HRAM is a 1979-era computer simulator that lets you experience the pure joy of true lowlevel computer programming write and run real assembly from lua access the same memory in lua or asm use lpeg to more easily generate asm specs graphics :: 128x72, 8-bit screen colors :: red/green, 256 total memory :: 16kb, all pages exec footprint :: c, win32, d3d, 1.4mb ideal env for * learning low level programming * making retro style video games * learn x64 assembly the fun way * creating programming languages ======================================== # top (~~~~~~~~~~~~~~~~~~~~( ) ) ( download ( ) exe or zip ) ( ( )~~~~~~~~~~~~~~~~~~~~) source :: github repo platforms :: windows 10+ 64-bit only version :: v221 community :: r/hram-lua donate :: venmo / cashapp / stripe ========================================

# what can it do

# top [[ create assembly functions ]] asm(0x33000,100, MOV, {Reg, RAX}, {Reg, RCX}, INC, {Reg, RAX}, RET ) [[ call assembly functions ]] printf("%d\n", (0x33000)(3)) -- 4 [[ disassemble real code ]] printf("%s\n", dasm(0x33000,7)) -- 33000 mov rax, rcx -- 33003 inc rax -- 33006 ret [[ read memory from lua ]] printf("%d\n", (0x33000)[0]) -- 72 [[ read memory from assembly ]] asm(0x33000,100, MOV, {Reg, RAX}, {Mem, disp=0x33000, bytes=8 }, RET ) printf("%d\n", (0x33000)()) -- 72 ======================================== _ _ _ _ _ _ _ _ | \/ | / \ |\| | | | | / \ | | | __ | | ^ | | \ | | | | | ^ | | |_ |_||_| |_|_| |_|\| |___| |_|_| |___| ========================================

# getting started

# top 1. create %APPDATA%\hram\boot.lua 2. type print('hello world!') 3. start hram.exe to run your file congratulations! you ran your first hram program! typically you want to react to signals so you would define function signal() and check if the signal is a frame or mouse movement or key press etc to draw to screen, set screen bytes and toggle the blit interrupt flag so the system will blit next frame for extra speed, you can compile asm and call your asm functions from lua but this is optional and not needed and you can use hram without assembly for more information consult the manual below ========================================

# memory table

# top base addr :: 0x30000 total memory :: 16kb page size :: 4kb core memory :: 3 pages free memory :: 1 page addr size purpose ---------------------------------- 0x30000 2 HRAM version 0x30002 1 signal id 0x30003 1 signal arg 0x30004 1 interrupt flag 0x30005 1 pressed modkeys 0x30006 2 caret (hi=col lo=row) 0x30008 4 clock (freq ~10-20ms) 0x3000c 2 last mouse pos 0x3000e 2 [reserved] 0x30010 20 scankeys pressed 0x30030 d0 c-addresses 0x30100 2400 screen (128x72) 0x32500 900 font (4x6 x 16x6) 0x32e00 200 [reserved] 0x33000 1000 free (unused) memory c-addresses int aplusbtimes2(int a, int b) void togglefullscreen() void blitimmediately() [rest reserved] interrupt flag bits 1 blit next frame [rest reserved] extra memory if you need more than 4kb you can use screen memory as a temporary memory buffer then draw over it when done third party licenses are available at 0x33000 ========================================

# signal table

# top name id argument ------------------------------ frame 0 delta mousemove 1 n/a mousewheel 2 delta mousedown 3 button mouseup 4 button keydown 5 keycode keyup 6 keycode keychar 7 ascii code ========================================

# api reference

# top int[i] :: *((u8*)int + i) int[i]=n :: *((u8*)int + i)=n int(...) :: exec(int, ...) #int :: *(u64*)int language extensions to integer type [] gets or sets byte at addr+offset () calls the asm or c fn at address # returns uint64 at addr (for ptrs) signal() define as global to handle signals printf(str, ...) draws str:format(...) uses font sheet in user memory memcpy(dst, src, len) memcpy(dst, src) copy len bytes from src into dst in second form src is a lua string memset(addr, val, len) fill addr with val up to len strdup(addr) -> str return lua string at addr to \0 strndup(addr, len) -> str return lua string at addr to len asm(addr,len,...instrs)->int|[nil,str] writes <=len assembly bytes to addr returns byte after last one written on err, returns err, writes nothing instrs = (opcode, ...operands)+ operands are each tables as follows: { Reg, val, 'is4' } { Ptr, 'segment', 'offset' } { Imm, val, 'signed' } { Mmm, 'base', 'index', 'scale', 'disp', 'bytes' } bare args = sequential keys quot args = table keys, default=0 global constants: Reg, Mem, Ptr, Imm MOV, NUL, AND, JNBE, RET, ... RAX, RSI, XMM0, EFLAGS, ... dasm(addr, len) -> string disassemble code at addr up to len returns human readable asm string exec(addr, ...) -> int calls function at addr, passing args NOTE: for now, only int args are valid NOTE: for now, only accepts single arg lpeg parsing expression grammars for lua see official lpeg website for docs ========================================

# recipes

# top to compile and run assembly local myfn = 0x33000 local ok, err = asm(myfn,100, MOV, {Reg, RAX}, {Reg, RCX}, INC, {Reg, RAX}, RET ) if not ok then print(err) else print(dasm(myfn, ok-myfn)) print(myfn(3)) end clear screen to color memset(0x30100, 0x30, 128*72) draw dot at mouse local base = 0x30000 function signal() if base[1] == 1 then local x, y = base[0xc], base[0xd] local off = y * 128 + x base[0x100 + off] = 0xff base[4] = 1 end end print the time local base = 0x30000 print((base[0xb] << 24) | (base[0xa] << 16) | (base[0x9] << 8) | (base[0x8])) check if key is down function keydown(i) return (0x30010)[i//8]&(1<<(i%8))>0 end more coming soon ==================================== copyright (c) novo cantico llc, 2025