⚠️ 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:

// Assembly Brainfuck interpreter // Alternative name: "ASSembly Brainfuck interpretER" // Compiles with 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