570 lines
12 KiB
NASM
570 lines
12 KiB
NASM
LOAD_ADDR equ 0x00010000 ; address this program is loaded at
|
|
|
|
TOKEN_TABLE_ADDR equ 0x00060000 ; address the token table is loaded at
|
|
TOKEN_TABLE_SIZE equ 0x1000 ; max length of table
|
|
|
|
TEST_ARENA_ADDR equ 0x00060000 ; address to run tests at
|
|
TEST_ARENA_SIZE equ 0x1000 ; maximum size tests can use
|
|
|
|
OUTPUT_ADDR equ 0x00070000 ; address of outputed binary
|
|
OUTPUT_SIZE equ 0x1000 ; max length of outputed binary
|
|
|
|
STACK_ADDR equ 0x00060000 ; address to put the 64-bit stack at
|
|
|
|
[bits 64]
|
|
[org LOAD_ADDR]
|
|
|
|
start:
|
|
mov rsp, STACK_ADDR ; we might need more stack space, let's just be safe
|
|
|
|
mov rsi, msg_welcome
|
|
call print
|
|
|
|
call run_tests
|
|
|
|
call clear_token_table
|
|
|
|
jmp halt
|
|
|
|
; ------------------------------------------------------------------------------
|
|
; tokenising
|
|
; ------------------------------------------------------------------------------
|
|
|
|
; ------------------------------------------------------------------------------
|
|
; copy_token
|
|
;
|
|
; description:
|
|
; copies a token from one spot in memory to another
|
|
;
|
|
; parameters:
|
|
; rdi -> start of buffer to be read
|
|
; rsi -> start of buffer to be written
|
|
;
|
|
; returned:
|
|
; rax -> last byte read
|
|
; rdx -> last byte written
|
|
; ------------------------------------------------------------------------------
|
|
|
|
copy_token:
|
|
.loop:
|
|
|
|
mov dl, [rdi] ; move bit to compare to current byte in read buffer
|
|
|
|
push rdi ; push incrementors to call elemb
|
|
push rsi ;
|
|
|
|
mov rdi, 8 ; length of terminator list
|
|
mov rsi, token_terminator_8 ; start of terminator list
|
|
; dl set before pushing rdi
|
|
call elemb
|
|
|
|
pop rsi ;
|
|
pop rdi ; pop incrementors after call
|
|
|
|
cmp rax, 1 ; check if the next character is a token terminator
|
|
je .break ; > if so, break the function
|
|
|
|
; rdi and rsi set from previous loop iteration
|
|
call copy_byte ; if not, copy the current byte in read buffer
|
|
|
|
inc rdi ; read pointer
|
|
inc rsi ; write pointer
|
|
|
|
jmp .loop
|
|
|
|
.break:
|
|
mov rax, rdi ; -> last byte read
|
|
mov rdx, rsi ; -> last byte written
|
|
ret
|
|
|
|
; ------------------------------------------------------------------------------
|
|
; copy_byte
|
|
;
|
|
; description:
|
|
; copies a byte from one spot in memory to another
|
|
;
|
|
; parameters:
|
|
; rdi -> word to be read
|
|
; rsi -> word to be written
|
|
;
|
|
; returned:
|
|
; al = byte that was read; the rest of rax is zeroed
|
|
; ------------------------------------------------------------------------------
|
|
|
|
copy_byte:
|
|
xor rax, rax ; zero out so it returns fine
|
|
mov al, [rdi]
|
|
mov [rsi], al
|
|
ret
|
|
|
|
; ------------------------------------------------------------------------------
|
|
; utilities
|
|
; ------------------------------------------------------------------------------
|
|
|
|
; ------------------------------------------------------------------------------
|
|
; print
|
|
;
|
|
; description:
|
|
; prints a null-terminated string
|
|
;
|
|
; parameters:
|
|
; rsi -> start of null-terminated string
|
|
; ------------------------------------------------------------------------------
|
|
|
|
print:
|
|
push rdx
|
|
mov rdx, 0x3F8
|
|
.loop:
|
|
mov al, [rsi]
|
|
test al, al
|
|
jz .done
|
|
out dx, al
|
|
inc rsi
|
|
jmp .loop
|
|
.done:
|
|
pop rdx
|
|
ret
|
|
|
|
; ------------------------------------------------------------------------------
|
|
; halt
|
|
;
|
|
; description:
|
|
; halts the program, silly :)
|
|
; ------------------------------------------------------------------------------
|
|
|
|
halt:
|
|
mov rsi, msg_halt
|
|
call print
|
|
hlt
|
|
jmp halt
|
|
|
|
; ------------------------------------------------------------------------------
|
|
; elemb
|
|
;
|
|
; description:
|
|
; checks if given byte is element of the specified list
|
|
;
|
|
; parameters:
|
|
; rdi = size of list
|
|
; rsi -> start of list
|
|
; dl = given byte
|
|
;
|
|
; returned:
|
|
; rax = 0: is not an element
|
|
; 1: is an element
|
|
; ------------------------------------------------------------------------------
|
|
|
|
elemb:
|
|
.loop
|
|
cmp rdi, 0 ; check if remaining length 0
|
|
je .not_found ; if so, break; dl not an element of list
|
|
|
|
mov al, [rsi]
|
|
cmp al, dl ; check if current byte in list is the desired byte
|
|
je .found ; if so, break; dl an element of list
|
|
|
|
inc rsi ; move to next byte
|
|
dec rdi ; and reduce remaining length
|
|
|
|
jmp .loop
|
|
|
|
.not_found
|
|
xor rax, rax ; return 0; dl not an element of list
|
|
ret
|
|
|
|
.found
|
|
xor rax, rax
|
|
mov rax, 1 ; return 1; dl an element of list
|
|
ret
|
|
|
|
.f db "found", 0x0D, 0x0A, 0x00
|
|
.nf db "not found", 0x0D, 0x0A, 0x00
|
|
|
|
; ------------------------------------------------------------------------------
|
|
; clear_token_table
|
|
;
|
|
; description:
|
|
; clears the token table as specified by TOKEN_TABLE_SIZE and TOKEN_TABLE_ADDR
|
|
; ------------------------------------------------------------------------------
|
|
|
|
clear_token_table:
|
|
xor rax, rax ; value to write
|
|
mov rcx, TOKEN_TABLE_SIZE / 4 ; number of double words
|
|
mov rdi, TOKEN_TABLE_ADDR ; address to start
|
|
rep stosd
|
|
ret
|
|
|
|
; ------------------------------------------------------------------------------
|
|
; clear_test_arena
|
|
;
|
|
; description:
|
|
; clears the test arena as specified by TEST_ARENA_SIZE and TEST_ARENA_ADDR
|
|
; ------------------------------------------------------------------------------
|
|
|
|
clear_test_arena:
|
|
xor rax, rax ; value to write
|
|
mov rcx, TOKEN_TABLE_SIZE / 4 ; number of double words
|
|
mov rdi, TOKEN_TABLE_ADDR ; address to start
|
|
rep stosd
|
|
ret
|
|
|
|
; ------------------------------------------------------------------------------
|
|
; tests
|
|
; ------------------------------------------------------------------------------
|
|
|
|
; ------------------------------------------------------------------------------
|
|
; run_tests
|
|
;
|
|
; description:
|
|
; runs all tests
|
|
; ------------------------------------------------------------------------------
|
|
|
|
run_tests:
|
|
mov rsi, .msg
|
|
call print
|
|
|
|
call clear_test_arena
|
|
call test_copy_byte
|
|
|
|
call clear_test_arena
|
|
call test_copy_token
|
|
|
|
call clear_test_arena
|
|
call test_elemb
|
|
|
|
ret
|
|
.msg db "running test suite...", 0x0D, 0x0A, 0x00
|
|
|
|
; ------------------------------------------------------------------------------
|
|
; test_copy_byte
|
|
;
|
|
; description:
|
|
; tests copy_byte described functionality
|
|
; ------------------------------------------------------------------------------
|
|
|
|
test_copy_byte:
|
|
mov rsi, .msg
|
|
call print
|
|
|
|
mov rdi, test_byte ; byte to be copied
|
|
mov rsi, TEST_ARENA_ADDR ; location of test
|
|
call copy_byte
|
|
|
|
mov cx, [rsi]
|
|
and ax, 0xFF ; only compare bottom byte
|
|
and cx, 0xFF
|
|
cmp ax, cx ; compare returned byte to copied byte
|
|
jne .fail
|
|
cmp al, [test_byte] ; compare returned byte to expected byte
|
|
jne .fail
|
|
|
|
.pass:
|
|
mov rsi, msg_pass
|
|
call print
|
|
ret
|
|
.fail:
|
|
mov rsi, msg_fail
|
|
call print
|
|
ret
|
|
.msg db "test_copy_byte...", 0x00
|
|
|
|
; ------------------------------------------------------------------------------
|
|
; test_copy_token
|
|
;
|
|
; description:
|
|
; tests copy_token described functionality
|
|
; ------------------------------------------------------------------------------
|
|
|
|
test_copy_token:
|
|
mov rsi, .msg
|
|
call print
|
|
|
|
; test case: space terminated
|
|
|
|
mov rdi, test_token_space ; read buffer
|
|
mov rsi, TEST_ARENA_ADDR ; write buffer
|
|
call copy_token
|
|
|
|
; check reported final indicies with the expected final indicies
|
|
cmp rax, test_token_space + 8 ; last byte read
|
|
jne .fail
|
|
cmp rdx, TEST_ARENA_ADDR + 8 ; last byte written
|
|
jne .fail
|
|
|
|
mov rsi, TEST_ARENA_ADDR
|
|
mov rcx, [rsi]
|
|
cmp rcx, [test_token_space] ; check if copied token matches expected token
|
|
jne .fail ; if not, fail
|
|
|
|
; test case: null terminated
|
|
|
|
mov rdi, test_token_null ; read buffer
|
|
mov rsi, TEST_ARENA_ADDR ; write buffer
|
|
call copy_token
|
|
|
|
; check reported final indicies with the expected final indicies
|
|
cmp rax, test_token_null + 8 ; last byte read
|
|
jne .fail
|
|
cmp rdx, TEST_ARENA_ADDR + 8 ; last byte written
|
|
jne .fail
|
|
|
|
mov rsi, TEST_ARENA_ADDR
|
|
mov rcx, [rsi]
|
|
cmp rcx, [test_token_null] ; check if copied token matches expected token
|
|
jne .fail ; if not, fail
|
|
|
|
.pass:
|
|
mov rsi, msg_pass
|
|
call print
|
|
ret
|
|
.fail:
|
|
mov rsi, msg_fail
|
|
call print
|
|
ret
|
|
.msg db "test_copy_token...", 0x00
|
|
|
|
; ------------------------------------------------------------------------------
|
|
; test_elemb
|
|
;
|
|
; description:
|
|
; tests elemb described functionality
|
|
; ------------------------------------------------------------------------------
|
|
|
|
test_elemb:
|
|
mov rsi, .msg
|
|
call print
|
|
|
|
; [0]
|
|
mov rdi, 5
|
|
mov rsi, test_elemb_5
|
|
mov dl, [test_elemb_5]
|
|
call elemb
|
|
cmp al, 1
|
|
jne .fail
|
|
|
|
; [n - 1]
|
|
mov rdi, 5
|
|
mov rsi, test_elemb_5
|
|
mov dl, [test_elemb_5 + 4]
|
|
call elemb
|
|
cmp al, 1
|
|
jne .fail
|
|
|
|
; [1]
|
|
mov rdi, 5
|
|
mov rsi, test_elemb_5
|
|
mov dl, [test_elemb_5 + 1]
|
|
call elemb
|
|
cmp al, 1
|
|
jne .fail
|
|
|
|
; not present
|
|
mov rdi, 5
|
|
mov rsi, test_elemb_5
|
|
mov dl, 0xDA
|
|
call elemb
|
|
cmp al, 0
|
|
jne .fail
|
|
|
|
; 0 length list
|
|
mov rdi, 0
|
|
mov rsi, test_elemb_0
|
|
mov dl, 0x34
|
|
call elemb
|
|
cmp al, 0
|
|
jne .fail
|
|
|
|
.pass:
|
|
mov rsi, msg_pass
|
|
call print
|
|
ret
|
|
.fail:
|
|
mov rsi, msg_fail
|
|
call print
|
|
ret
|
|
.msg db "test_elemb...", 0x00
|
|
|
|
; ------------------------------------------------------------------------------
|
|
; data
|
|
; ------------------------------------------------------------------------------
|
|
|
|
tokens:
|
|
.length2
|
|
db "r8"
|
|
dw 0x0008
|
|
db "r9"
|
|
dw 0x0009
|
|
db "ax"
|
|
dw 0x0020
|
|
db "bx"
|
|
dw 0x0021
|
|
db "cx"
|
|
dw 0x0022
|
|
db "dx"
|
|
dw 0x0023
|
|
db "si"
|
|
dw 0x0024
|
|
db "di"
|
|
dw 0x0025
|
|
db "sp"
|
|
dw 0x0026
|
|
db "bp"
|
|
dw 0x0027
|
|
db "al"
|
|
dw 0x0030
|
|
db "bl"
|
|
dw 0x0031
|
|
db "cl"
|
|
dw 0x0032
|
|
db "dl"
|
|
dw 0x0033
|
|
db "ah"
|
|
dw 0x0040
|
|
db "bh"
|
|
dw 0x0041
|
|
db "ch"
|
|
dw 0x0042
|
|
db "dh"
|
|
dw 0x0043
|
|
db "cs"
|
|
dw 0x0044
|
|
db "ds"
|
|
dw 0x0045
|
|
db "es"
|
|
dw 0x0046
|
|
db "fs"
|
|
dw 0x0047
|
|
db "gs"
|
|
dw 0x0048
|
|
db "ss"
|
|
dw 0x0049
|
|
.length3
|
|
db "rax"
|
|
dw 0x0000
|
|
db "rbx"
|
|
dw 0x0001
|
|
db "rcx"
|
|
dw 0x0002
|
|
db "rdx"
|
|
dw 0x0003
|
|
db "rsi"
|
|
dw 0x0004
|
|
db "rdi"
|
|
dw 0x0005
|
|
db "rsp"
|
|
dw 0x0006
|
|
db "rbp"
|
|
dw 0x0007
|
|
db "r10"
|
|
dw 0x000A
|
|
db "r11"
|
|
dw 0x000B
|
|
db "r12"
|
|
dw 0x000C
|
|
db "r13"
|
|
dw 0x000D
|
|
db "r14"
|
|
dw 0x000E
|
|
db "r15"
|
|
dw 0x000F
|
|
db "eax"
|
|
dw 0x0010
|
|
db "ebx"
|
|
dw 0x0011
|
|
db "ecx"
|
|
dw 0x0012
|
|
db "edx"
|
|
dw 0x0013
|
|
db "esi"
|
|
dw 0x0014
|
|
db "edi"
|
|
dw 0x0015
|
|
db "esp"
|
|
dw 0x0016
|
|
db "ebp"
|
|
dw 0x0017
|
|
db "r8d"
|
|
dw 0x0018
|
|
db "r9d"
|
|
dw 0x0019
|
|
db "r8w"
|
|
dw 0x0028
|
|
db "r9w"
|
|
dw 0x0029
|
|
db "sil"
|
|
dw 0x0034
|
|
db "dil"
|
|
dw 0x0035
|
|
db "spl"
|
|
dw 0x0036
|
|
db "bpl"
|
|
dw 0x0037
|
|
db "r8b"
|
|
dw 0x0038
|
|
db "r9b"
|
|
dw 0x0039
|
|
db "cr0"
|
|
dw 0x004A
|
|
db "cr2"
|
|
dw 0x004B
|
|
db "cr3"
|
|
dw 0x004C
|
|
db "cr4"
|
|
dw 0x004D
|
|
db "cr8"
|
|
dw 0x004E
|
|
.length4
|
|
db "r10d"
|
|
dw 0x001A
|
|
db "r11d"
|
|
dw 0x001B
|
|
db "r12d"
|
|
dw 0x001C
|
|
db "r13d"
|
|
dw 0x001D
|
|
db "r14d"
|
|
dw 0x001E
|
|
db "r15d"
|
|
dw 0x001F
|
|
db "r10w"
|
|
dw 0x002A
|
|
db "r11w"
|
|
dw 0x002B
|
|
db "r12w"
|
|
dw 0x002C
|
|
db "r13w"
|
|
dw 0x002D
|
|
db "r14w"
|
|
dw 0x002E
|
|
db "r15w"
|
|
dw 0x002F
|
|
db "r10b"
|
|
dw 0x003A
|
|
db "r11b"
|
|
dw 0x003B
|
|
db "r12b"
|
|
dw 0x003C
|
|
db "r13b"
|
|
dw 0x003D
|
|
db "r14b"
|
|
dw 0x003E
|
|
db "r15b"
|
|
dw 0x003F
|
|
.length5
|
|
.end
|
|
|
|
msg_welcome db "Welcome to Twasm", 0x0D, 0x0A, 0x00
|
|
msg_halt db "halted.", 0x0D, 0x0A, 0x00
|
|
msg_pass db "passed.", 0x0D, 0x0A, 0x00
|
|
msg_fail db "failed.", 0x0D, 0x0A, 0x00
|
|
|
|
test_byte db "Q" ; unterminated, just a byte chillin
|
|
test_token_null db "TestTokn", 0x00 ; followed by null terminator. Quad word
|
|
test_token_space db "TestTokn " ; followed by space. Quad word
|
|
test_elemb_0
|
|
test_elemb_5 db 0x54, 0x00, 0x21, 0x20, 0x34
|
|
|
|
token_terminator_8 db 0x00, " ", 0x0A, 0x0D, 0x00, 0x00, 0x00, 0x00
|
|
|
|
debug_string db "debug_string", 0x0D, 0x0A, 0x00
|