Last active
October 31, 2024 15:33
-
-
Save Liebranca/5e5e9678a17dd847618ec98ed4d41780 to your computer and use it in GitHub Desktop.
D&D dice set in flat assembler
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; to compile: fasm dice.asm roll | |
; to run: ./roll 1d20 2d4 4d6 etc. | |
; | |
; --- * --- * --- | |
; info | |
format ELF64 executable 3; | |
entry _start; | |
define VERSION v0.00.6a; | |
define AUTHOR IBN-3DILA; | |
; --- * --- * --- | |
; utils | |
macro list_range dst,cnt { | |
local ok; | |
dst equ; | |
rept cnt idex \{ | |
ok equ 1; | |
match any,dst \\{ | |
dst equ dst,idex; | |
ok equ 0; | |
\\} | |
match =1,ok \\{ | |
dst equ idex; | |
\\} | |
\}; | |
}; | |
macro _mkstrtab name,[elem] { | |
common name#_SRC: | |
forward match any , elem \{ | |
.n\#any\#: db \`any,$0A,0; | |
.n\#any\#_len=$-.n\#any; | |
\}; | |
common name#: | |
forward match any , elem \{ | |
dw name#_SRC.n\#any-name#_SRC; | |
dw name#_SRC.n\#any\#_len; | |
\}; | |
}; | |
macro mkstrtab name,cnt { | |
local dst; | |
list_range dst,cnt; | |
match list,dst \{ | |
_mkstrtab name,list; | |
\}; | |
}; | |
; --- * --- * --- | |
; ROM | |
segment readable; | |
DICETAB: | |
.d4 dq RPG.Dice_d4; | |
.d6 dq RPG.Dice_d6; | |
.d8 dq RPG.Dice_d8; | |
.d10 dq RPG.Dice_d10; | |
.d12 dq RPG.Dice_d12; | |
.d20 dq RPG.Dice_d20; | |
.d100 dq RPG.Dice_d100; | |
mkstrtab NUMTAB,100; | |
EOL db $0A; | |
errme db 'SNAFU',$0A; | |
errme.len=$-errme; | |
; --- * --- * --- | |
; GBL | |
segment readable writeable; | |
FOUT.sz=$100; | |
FOUT: | |
.ptr dw $00; | |
.buff db FOUT.sz dup $00 | |
; --- * --- * --- | |
; EXE | |
segment readable executable; | |
align $10; | |
; --- * --- * --- | |
; generate random byte | |
RPG.Dice_xlamp: | |
mov rdx,rax | |
RPG.Dice_xlamp_anon@127: | |
rept 7 { | |
ror rdx,8 | |
xor rax,rdx | |
} | |
xor rdx,rdx; | |
and rax,$FF | |
ret | |
RPG.Dice_prng: | |
rdtsc | |
shl rdx,32 | |
or rax,rdx | |
call RPG.Dice_xlamp | |
ret | |
; --- * --- * --- | |
; ^map to diceroll! | |
RPG.Dice_d4: | |
call RPG.Dice_prng | |
and al,3 | |
ret | |
RPG.Dice_d6: | |
call RPG.Dice_prng | |
mov rdi,rax | |
mov rax,683 | |
imul rax,rdi | |
shr rax,12 | |
lea rax,[rax*2] | |
lea rax,[rax+rax*2] | |
sub rdi,rax | |
mov rax,rdi | |
ret | |
RPG.Dice_d8: | |
call RPG.Dice_prng | |
and rax,7 | |
ret | |
RPG.Dice_d10: | |
call RPG.Dice_prng | |
mov rdi,rax | |
mov rax,410 | |
imul rax,rdi | |
shr rax,12 | |
lea rax,[rax*2] | |
lea rax,[rax+rax*4] | |
sub rdi,rax | |
mov rax,rdi | |
ret | |
RPG.Dice_d12: | |
call RPG.Dice_prng | |
mov rdi,rax | |
mov rax,342 | |
imul rax,rdi | |
shr rax,12 | |
lea rax,[rax+rax*2] | |
lea rax,[rax*4] | |
sub rdi,rax | |
mov rax,rdi | |
ret | |
RPG.Dice_d20: | |
call RPG.Dice_prng | |
mov rdi,rax | |
mov rax,205 | |
imul rax,rdi | |
shr rax,12 | |
lea rax,[rax*4] | |
lea eax,[rax+rax*4] | |
sub rdi,rax | |
mov rax,rdi | |
ret | |
RPG.Dice_d100: | |
call RPG.Dice_prng | |
mov rdi,rax | |
mov rax,41 | |
imul rax,rdi | |
shr rax,12 | |
mov rdx,100 | |
imul rax,rdx | |
sub rdi,rax | |
mov rax,rdi | |
ret | |
; --- * --- * --- | |
; entry point | |
_start: | |
; get argc | |
push rbp; | |
mov rbp,rsp; | |
sub rsp,$08; | |
; setup counter | |
define PENDING rbp+$08; | |
define NEXT rbp-$08; | |
mov rax,qword [rbp+$08]; | |
dec rax; | |
mov qword [PENDING],rax; | |
mov qword [NEXT],$18; | |
; --- * --- * --- | |
; roll next dice! | |
.get_next: | |
; get counter | |
mov rax,qword [PENDING]; | |
test rax,rax; | |
jz .skip; | |
dec qword [PENDING]; | |
; get idex | |
mov rax,qword [NEXT]; | |
add qword [NEXT],$08; | |
mov rax,qword [rbp+rax]; | |
; read input string | |
mov r15b,byte [rax]; | |
mov r14d,dword [rax+1]; | |
; get number of copies to roll! | |
mov al,$30; | |
mov dl,$37; | |
cmp r15b,$39; | |
cmovg eax,edx; | |
sub r15b,al; | |
; ^match string to dice! | |
cmp r14w,word $3464; | |
cmovz r14,qword [DICETAB.d4]; | |
cmp r14w,word $3664; | |
cmovz r14,qword [DICETAB.d6]; | |
cmp r14w,word $3864; | |
cmovz r14,qword [DICETAB.d8]; | |
cmp r14d,dword $303164; | |
cmovz r14,qword [DICETAB.d10]; | |
cmp r14d,dword $323164; | |
cmovz r14,qword [DICETAB.d12]; | |
cmp r14d,dword $00303264; | |
cmovz r14,qword [DICETAB.d20]; | |
cmp r14w,word $2564; | |
cmovz r14,qword [DICETAB.d100]; | |
; --- * --- * --- | |
; roll dice N times! | |
.reroll: | |
call r14; | |
cmp al,$64; | |
jge .error; | |
; ^load string repr from table | |
xor rdi,rdi; | |
xor rsi,rsi; | |
lea rax,[NUMTAB+rax*4]; | |
mov di,word [rax]; | |
mov si,word [rax+2]; | |
add rdi,NUMTAB_SRC; | |
call FOUT.write; | |
; manage iter | |
dec r15b; | |
test r15b,r15b; | |
jnz .reroll; | |
jmp .get_next; | |
; --- * --- * --- | |
; cleanup and give | |
.skip: | |
call FOUT.flush; | |
leave; | |
mov rax,60; | |
syscall; | |
; --- * --- * --- | |
; d'oh! | |
.error: | |
; ^write repr to stdout | |
mov rdi,1; | |
mov rsi,errme; | |
mov rdx,errme.len; | |
mov rax,1; | |
syscall; | |
; exit | |
mov rdi,1; | |
mov rax,60; | |
syscall; | |
; --- * --- * --- | |
; writes to static mem | |
FOUT.write: | |
; point to buffer+offset | |
xor rax,rax; | |
mov ax,word [FOUT.ptr]; | |
add rax,FOUT.buff; | |
; read str -> write at ptr | |
mov rdx,qword [rdi]; | |
mov qword [rax],rdx; | |
; update ptr and give | |
add word [FOUT.ptr],si; | |
ret; | |
; --- * --- * --- | |
; ^outputs buffer to stdout | |
FOUT.flush: | |
; point to buffer | |
xor rdx,rdx; | |
lea rsi,[FOUT.buff]; | |
mov dx,word [FOUT.ptr]; | |
; flush and give | |
mov rdi,$01; | |
mov rax,$01; | |
syscall; | |
ret; | |
; --- * --- * --- |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment