⚠️ Warning: This is a draft ⚠️
This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.
If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.
==x86_64 Assembly==
GAS Syntax for Linux. Called it "Brainkrieg" after Teen Girl Squad. Operating principle is a little like a multi-cycle processor. Uses a jump table. Fixed data memory block.
Implementation:
gcc -nostdlib brainkrieg.sx -o brainkrieg
// Usage: ./brainkrieg "filename"
// Return 0 if normal exit
#define SYS_READ $0
#define SYS_WRITE $1
#define SYS_OPEN $2
#define SYS_CLOSE $3
#define SYS_FSTAT $5
#define SYS_MMAP $9
#define SYS_MUNMAP $11
#define SYS_EXIT $60
// From experiments: #define FSIZEOFF 48 #define STATSIZE 144
// From Linux source: #define RDONLY $00 #define PROT_READ $0x1 #define MAP_PRIVATE $0x02 #define STDIN $0 #define STDOUT $1 #define STDERR $2
#define DEBUGMODE 0
.global _start .text
.macro ERRCHECK code cmpq $\code, %rax je fs_error .endm
/* Local stack notes: 0: int fd / #define STACKSIZE $4 _start: / Entry Point: */ // Open: movq RDONLY, %rsi // Filename ptr is on stack currently as argv[1]: cmpq $1, (%rsp) // if argc is 1, error jnz open_file jmp fs_error
open_file: movq 16(%rsp), %rdi // argc(8), argv0(8) => rsp+16. filename movq SYS_OPEN, %rax syscall ERRCHECK -1 subq STACKSIZE, %rsp // local stack movl %eax, (%rsp) // int fd = open(argv[1], RDONLY) // fstat to get filesize fstat: movq $statstruct, %rsi movl (%rsp), %edi // fd movq SYS_FSTAT, %rax syscall // fstat(fd, statstruct) ERRCHECK -1 // mmap - don't forget to munmap. mmap: movq $0, %r9 // offset movq (%rsp), %r8 // fd movq MAP_PRIVATE, %r10 movq PROT_READ, %rdx movq filesize, %rsi movq (%rsp), %rdi // vmemptr movq SYS_MMAP, %rax syscall ERRCHECK -1 // Set up machine: boot: movq %rax, head // head = mmap'd file start movq %rax, inst_ptr // inst_ptr = head addq filesize, %rax movq %rax, end // end = head+filesize movq $tape, data_ptr // data_ptr = tape xorq %rax, %rax /* Magic happens here: - Fetch symbol - Decode symbol - Execute opcode - Instruction out of range = halt - Data out of range = halt */ OS_start: fetch: movq inst_ptr, %rbx cmpq end, %rbx ja shutdown // End of code movzbq (%rbx), %rax incq %rbx movq %rbx, inst_ptr decode: #if DEBUGMODE movb %al, debugChar movq $1, %rdx movq $debugChar, %rsi movq STDERR, %rdi movq SYS_WRITE, %rax syscall ERRCHECK -1 movzbq debugChar, %rax #endif mov $branch_table, %rcx jmp *(%rcx,%rax,8) // execute: dp_left: cmpq $tape, data_ptr jz scram decq data_ptr jmp fetch dp_right: cmpq $endtape, data_ptr jz scram incq data_ptr jmp fetch dec_data: movq data_ptr, %rbx decb (%rbx) jmp fetch inc_data: movq data_ptr, %rbx incb (%rbx) jmp fetch out_data: movq $1, %rdx movq data_ptr, %rsi movq STDOUT, %rdi movq SYS_WRITE, %rax syscall ERRCHECK -1 jmp fetch in_data: movq $1, %rdx movq data_ptr, %rsi movq STDIN, %rdi movq SYS_READ, %rax syscall ERRCHECK -1 cmpb $'\n, (%rsi) je fetch movq %rax, junkChar jmp fetch brf: // branch if *dp=0 movq data_ptr, %rbx cmpb $0, (%rbx) jnz fetch matchfwd: movq inst_ptr, %rbx movb (%rbx), %al cmpb $'[, %al jne no_smph incq brack_smph cmpq end, %rbx je scram incq inst_ptr jmp matchfwd no_smph: // no semaphore needed cmpb $'], %al je check_smph cmpq end, %rbx je scram incq inst_ptr jmp matchfwd check_smph: // check if semaphore set cmpq $0, brack_smph jz donematch decq brack_smph cmpq end, %rbx je scram incq inst_ptr jmp matchfwd brb: // branch if *dp!=0 movq data_ptr, %rbx cmpb $0, (%rbx) jz fetch subq $2, inst_ptr // Branch taken, scan back. matchbwd: movq inst_ptr, %rbx movb (%rbx), %al cmpb $'], %al jne no_smph2 incq brack_smph cmpq head, %rbx je scram decq inst_ptr jmp matchbwd no_smph2: // no semaphore needed cmpb $'[, %al je check_smph2 cmpq head, %rbx je scram decq inst_ptr jmp matchbwd check_smph2: // check if semaphore set cmpq $0, brack_smph jz donematch2 decq brack_smph cmpq head, %rbx je scram decq inst_ptr jmp matchbwd donematch: incq inst_ptr donematch2: jmp fetch scram: // Memory breached movq $0x7f, err_val shutdown: // Consume rest of stdin if we used it. cmpb $0, junkChar jz skip_flush flush_stdin: movq SYS_READ, %rax movq STDIN, %rdi movq $junkChar, %rsi movq $1, %rdx syscall cmpq $0, %rax // EOF jz skip_flush cmpb $'\n, junkChar jne flush_stdin // munmap skip_flush: movq filesize, %rsi movq head, %rdi movq SYS_MUNMAP, %rax syscall // munmap(vmemptr, filesize) cmpq $-1, %rax je fs_error // close movl (%rsp), %edi movq SYS_CLOSE, %rax syscall // close(fd) ERRCHECK -1
exit: movq SYS_EXIT, %rax movzbq err_val, %rdi syscall
fs_error: movq SYS_EXIT, %rax movq $-1, %rdi syscall // exit(-1)
.data branch_table: .rept 43 .quad fetch .endr
.quad inc_data .quad in_data .quad dec_data .quad out_data .rept 13 .quad fetch .endr .quad dp_left .quad fetch .quad dp_right .rept 28 .quad fetch .endr .quad brf .quad fetch .quad brb .rept 162 .quad fetch .endr
.bss brack_smph: // Bracket matching semaphore .quad 0
junkChar: // Also used to check if input was used. .byte 0
#if DEBUGMODE debugChar: .byte 0 #endif
err_val: .byte 0
// fstat: statstruct: // This struct is 144 bytes. Only want size (+48) .zero FSIZEOFF filesize: // 8 bytes. .quad 0 .zero STATSIZE-FSIZEOFF+8
// Program: head: .quad 0 end: .quad 0 inst_ptr: .quad 0
// Data: data_ptr: .quad 0 tape: .zero (1<<20) endtape: .zero 1