Compare commits
2 Commits
75e9c27dda
...
9233ca421b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9233ca421b | ||
|
|
9a88a859cf |
@@ -75,6 +75,7 @@ start:
|
|||||||
; 0x1000 ; memory address, following byte should be a register
|
; 0x1000 ; memory address, following byte should be a register
|
||||||
; 0x1000 ; not a register
|
; 0x1000 ; not a register
|
||||||
; - operator tokens followed by the wrong number of arguments
|
; - operator tokens followed by the wrong number of arguments
|
||||||
|
; TODO enforce this in `tokenise`
|
||||||
; 0x004F ; hlt, expects 0 arguments
|
; 0x004F ; hlt, expects 0 arguments
|
||||||
; 0x0000 ; rax, an argument
|
; 0x0000 ; rax, an argument
|
||||||
; - an undefined token is included, like 0x0051
|
; - an undefined token is included, like 0x0051
|
||||||
@@ -92,17 +93,6 @@ assemble:
|
|||||||
mov di, [rax * TOKEN_TABLE_ENTRY_SIZE + TOKEN_TABLE_ADDR] ; next tte
|
mov di, [rax * TOKEN_TABLE_ENTRY_SIZE + TOKEN_TABLE_ADDR] ; next tte
|
||||||
push rax
|
push rax
|
||||||
|
|
||||||
; di = next tte
|
|
||||||
call get_tte_type
|
|
||||||
; al = type of token
|
|
||||||
|
|
||||||
; on stack:
|
|
||||||
; rax = number of tokens processed
|
|
||||||
; rdi = number of tokens in table
|
|
||||||
cmp al, 0x01 ; check if next tte's type is an operator
|
|
||||||
je .operator ; if so, handle case of operator
|
|
||||||
jne .continue_operator ; if not, jump past the case
|
|
||||||
|
|
||||||
; di = tte of operator
|
; di = tte of operator
|
||||||
.operator: ; if next tte's type is an operator:
|
.operator: ; if next tte's type is an operator:
|
||||||
push rdi
|
push rdi
|
||||||
@@ -122,7 +112,9 @@ assemble:
|
|||||||
cmp al, 2 ; check if operator has two operands
|
cmp al, 2 ; check if operator has two operands
|
||||||
je .operator_2 ; if so, handle case of two operands
|
je .operator_2 ; if so, handle case of two operands
|
||||||
|
|
||||||
jmp .operator_with_args ; of not, handle case of some operands
|
jmp .unexpected_token ; TODO actually check operator type or not first
|
||||||
|
; if get_tte_typed_metadata happens to return 0, 1,
|
||||||
|
; or 2 on a non-operator, it doesn't get caught
|
||||||
|
|
||||||
; di = tte of operator
|
; di = tte of operator
|
||||||
.operator_0:
|
.operator_0:
|
||||||
@@ -138,7 +130,11 @@ assemble:
|
|||||||
call .output_byte
|
call .output_byte
|
||||||
pop rdi
|
pop rdi
|
||||||
|
|
||||||
jmp .continue
|
pop rax ; rax = number of tokens processed
|
||||||
|
pop rdi ; rdi = total number of tokens
|
||||||
|
inc rax
|
||||||
|
cmp rax, rdi
|
||||||
|
jmp .loop
|
||||||
|
|
||||||
; di = tte of operator
|
; di = tte of operator
|
||||||
.operator_1:
|
.operator_1:
|
||||||
@@ -188,9 +184,9 @@ assemble:
|
|||||||
.operator_1_memory_access:
|
.operator_1_memory_access:
|
||||||
push rsi
|
push rsi
|
||||||
mov rsi, .msg_operator_1_memory_access
|
mov rsi, .msg_operator_1_memory_access
|
||||||
call print.error
|
call print.debug
|
||||||
pop rsi
|
pop rsi
|
||||||
jmp halt
|
jmp .unsupported_memory_access
|
||||||
|
|
||||||
.operator_1_register:
|
.operator_1_register:
|
||||||
push rsi
|
push rsi
|
||||||
@@ -258,9 +254,9 @@ assemble:
|
|||||||
.operator_2_memory_access:
|
.operator_2_memory_access:
|
||||||
push rsi
|
push rsi
|
||||||
mov rsi, .msg_operator_2_memory_access
|
mov rsi, .msg_operator_2_memory_access
|
||||||
call print.error
|
call print.debug
|
||||||
pop rsi
|
pop rsi
|
||||||
jmp halt
|
jmp .unsupported_memory_access
|
||||||
|
|
||||||
.operator_2_register:
|
.operator_2_register:
|
||||||
push rsi
|
push rsi
|
||||||
@@ -303,9 +299,38 @@ assemble:
|
|||||||
.operator_2_register_memory_access:
|
.operator_2_register_memory_access:
|
||||||
push rsi
|
push rsi
|
||||||
mov rsi, .msg_operator_2_register_memory_access
|
mov rsi, .msg_operator_2_register_memory_access
|
||||||
call print.error
|
call print.debug
|
||||||
pop rsi
|
pop rsi
|
||||||
jmp halt
|
|
||||||
|
cmp di, 0x1000 ; check if token is addressing to a register
|
||||||
|
jne .unsupported_memory_access ; if not, unsupported :/
|
||||||
|
|
||||||
|
pop rax
|
||||||
|
pop rdi
|
||||||
|
inc rax
|
||||||
|
cmp rax, rdi
|
||||||
|
jge .break
|
||||||
|
push rdi
|
||||||
|
push rax
|
||||||
|
xor edi, edi
|
||||||
|
mov di, [rax * TOKEN_TABLE_ENTRY_SIZE + TOKEN_TABLE_ADDR] ; di = next tte
|
||||||
|
|
||||||
|
; si = `R/M` tte
|
||||||
|
; di = `reg` tte
|
||||||
|
push rsi
|
||||||
|
mov si, di
|
||||||
|
pop rdi
|
||||||
|
mov dl, 00b ; dl = mod bits
|
||||||
|
call get_ModRM
|
||||||
|
; al = Mod R/M byte
|
||||||
|
call .output_byte
|
||||||
|
|
||||||
|
pop rax ; rax = number of tokens processed
|
||||||
|
pop rdi ; rdi = total number of tokens
|
||||||
|
inc rax
|
||||||
|
cmp rax, rdi
|
||||||
|
jge .break
|
||||||
|
jmp .loop
|
||||||
|
|
||||||
.operator_2_register_register:
|
.operator_2_register_register:
|
||||||
push rsi
|
push rsi
|
||||||
@@ -315,6 +340,9 @@ assemble:
|
|||||||
|
|
||||||
; si = `R/M` tte
|
; si = `R/M` tte
|
||||||
; di = `reg` tte
|
; di = `reg` tte
|
||||||
|
push rsi
|
||||||
|
mov si, di
|
||||||
|
pop rdi
|
||||||
mov dl, 11b ; dl = mod bits
|
mov dl, 11b ; dl = mod bits
|
||||||
call get_ModRM
|
call get_ModRM
|
||||||
; al = Mod R/M byte
|
; al = Mod R/M byte
|
||||||
@@ -327,99 +355,18 @@ assemble:
|
|||||||
jge .break
|
jge .break
|
||||||
jmp .loop
|
jmp .loop
|
||||||
|
|
||||||
; di = tte of operator
|
|
||||||
.operator_with_args:
|
|
||||||
mov [.pending_operator_num_args], al ; save # args fttb
|
|
||||||
|
|
||||||
push rdi
|
|
||||||
; di = next tte
|
|
||||||
call get_opcode
|
|
||||||
; al = opcode
|
|
||||||
mov [.pending_operator_opcode], al ; save opcode fttb
|
|
||||||
pop rdi
|
|
||||||
|
|
||||||
jmp .continue
|
|
||||||
|
|
||||||
.continue_operator:
|
|
||||||
cmp al, 0x02 ; check if next tte's type is a register
|
|
||||||
je .register ; if so, handle case of register
|
|
||||||
jne .continue_register ; if not, jump past the case
|
|
||||||
|
|
||||||
; di MUST be a valid register tte
|
|
||||||
.register: ; if next tte's type is a register:
|
|
||||||
call .dec_num_args ; because we've found an argument, we need 1 fewer noch
|
|
||||||
|
|
||||||
cmp byte [.pending_operator_num_args], 1 ; check if this is 1st of 2 args
|
|
||||||
je .register_one_of_two ; if so, jump to handler
|
|
||||||
|
|
||||||
cmp byte [.pending_operator_num_args], 0 ; check if this is the last arg
|
|
||||||
je .register_last ; if so, jump to handler
|
|
||||||
; note: not necessarily the last
|
|
||||||
; of 2 args, it could also be the
|
|
||||||
; last of 1
|
|
||||||
|
|
||||||
; otherwise, discard the token, reset things, and keep going :/
|
|
||||||
push rsi
|
|
||||||
mov rsi, .warn_unexpected_register
|
|
||||||
call print.warn
|
|
||||||
pop rsi
|
|
||||||
call .reset_state
|
|
||||||
jmp .continue_register
|
|
||||||
|
|
||||||
.register_one_of_two: ; if it's the first of 2 arguments:
|
|
||||||
mov [.first_argument], di ; ax = tte
|
|
||||||
jmp .continue_register
|
|
||||||
|
|
||||||
.register_last: ; if it's the last argument:
|
|
||||||
; swap so the first argument sits in .first_argument
|
|
||||||
push rax
|
|
||||||
mov ax, di
|
|
||||||
mov di, [.first_argument]
|
|
||||||
mov [.first_argument], ax
|
|
||||||
pop rax
|
|
||||||
|
|
||||||
cmp di, UNRECOGNISED_TOKEN_ID ; check if the second argument is defined
|
|
||||||
jne .operator_finalise_2 ; if so, there are 2 arguments
|
|
||||||
; if not, there is just 1
|
|
||||||
|
|
||||||
.operator_finalise_1:
|
|
||||||
mov di, 0x0000 ; id of rax. reg bits 000b
|
|
||||||
|
|
||||||
.operator_finalise_2:
|
|
||||||
; TODO avoid swapping earlier and now :/
|
|
||||||
mov cx, di
|
|
||||||
mov di, [.first_argument]
|
|
||||||
mov si, cx
|
|
||||||
mov dl, 11b
|
|
||||||
call get_ModRM
|
|
||||||
; al = ModR/M byte
|
|
||||||
push rax
|
|
||||||
mov al, [.pending_operator_opcode]
|
|
||||||
call .output_byte ; output operator's opcode
|
|
||||||
pop rax
|
|
||||||
|
|
||||||
call .output_byte ; output ModR/M byte
|
|
||||||
|
|
||||||
call .reset_state ; reset all the state parts of this function
|
|
||||||
jmp .continue_register
|
|
||||||
|
|
||||||
.continue_register:
|
|
||||||
|
|
||||||
.continue:
|
|
||||||
pop rax ; rax = number of tokens processed
|
|
||||||
pop rdi ; rdi = total number of tokens
|
|
||||||
|
|
||||||
inc rax
|
|
||||||
cmp rax, rdi
|
|
||||||
jge .break ; at end of table, break
|
|
||||||
jmp .loop
|
|
||||||
|
|
||||||
.break:
|
.break:
|
||||||
ret
|
ret
|
||||||
|
|
||||||
; constants
|
.unexpected_token:
|
||||||
|
mov rsi, .msg_unexpected_token
|
||||||
|
call print.error
|
||||||
|
jmp halt
|
||||||
|
|
||||||
.warn_unexpected_register db "ignoring unexpected register", 0x0A, 0x00
|
.unsupported_memory_access:
|
||||||
|
mov rsi, .msg_unsupported_memory_access
|
||||||
|
call print.error
|
||||||
|
jmp halt
|
||||||
|
|
||||||
; procedures
|
; procedures
|
||||||
|
|
||||||
@@ -430,35 +377,11 @@ assemble:
|
|||||||
inc edx ; increment address
|
inc edx ; increment address
|
||||||
mov [.next_output_byte], edx ; put output byte's address
|
mov [.next_output_byte], edx ; put output byte's address
|
||||||
ret
|
ret
|
||||||
|
.next_output_byte dd OUTPUT_ADDR ; next empty byte in output
|
||||||
|
; TODO get rid of this sketchy bit of state
|
||||||
|
|
||||||
; runs dec on .pending_operator_num_args
|
.msg_unexpected_token db "unexpected token, aborting", 0x0A, 0x00
|
||||||
.dec_num_args:
|
.msg_unsupported_memory_access db "unsupported memory access, aborting", 0x0A, 0x00
|
||||||
push rax
|
|
||||||
mov al, [.pending_operator_num_args]
|
|
||||||
dec al
|
|
||||||
mov [.pending_operator_num_args], al
|
|
||||||
pop rax
|
|
||||||
ret
|
|
||||||
|
|
||||||
; resets sketchy memory-based state
|
|
||||||
; TODO put this state in an accumulator or something
|
|
||||||
.reset_state:
|
|
||||||
; I don't actually know if these `word` directives are needed
|
|
||||||
; TODO check that. I think they are, becasue Nasm doesn't record the size
|
|
||||||
; of labels?
|
|
||||||
mov word [.pending_operator_opcode], UNRECOGNISED_TOKEN_ID
|
|
||||||
mov [.pending_operator_num_args], 0x00
|
|
||||||
mov word [.first_argument], UNRECOGNISED_TOKEN_ID
|
|
||||||
ret
|
|
||||||
|
|
||||||
; state variables
|
|
||||||
|
|
||||||
.pending_operator_opcode db 0x00 ; the operator seeking args
|
|
||||||
.pending_operator_num_args db 0x00 ; # of args it takes
|
|
||||||
|
|
||||||
.first_argument dw UNRECOGNISED_TOKEN_ID ; first argument if there are two
|
|
||||||
|
|
||||||
.next_output_byte dd OUTPUT_ADDR ; next empty byte in output
|
|
||||||
.msg_operator_0 db "operator_0", 0x0A, 0x00
|
.msg_operator_0 db "operator_0", 0x0A, 0x00
|
||||||
.msg_operator_1 db "operator_1", 0x0A, 0x00
|
.msg_operator_1 db "operator_1", 0x0A, 0x00
|
||||||
.msg_operator_1_memory_access db "operator_1_memory_access", 0x0A, 0x00
|
.msg_operator_1_memory_access db "operator_1_memory_access", 0x0A, 0x00
|
||||||
@@ -1792,7 +1715,7 @@ opcodes:
|
|||||||
db 0x00 ; reserved
|
db 0x00 ; reserved
|
||||||
|
|
||||||
dw 0x0056 ; mov
|
dw 0x0056 ; mov
|
||||||
db 0x89
|
db 0x8B
|
||||||
db 0x00 ; reserved
|
db 0x00 ; reserved
|
||||||
|
|
||||||
dw 0x004F ; hlt
|
dw 0x004F ; hlt
|
||||||
@@ -1810,6 +1733,7 @@ program:
|
|||||||
db "xor eax, eax", 0x0A
|
db "xor eax, eax", 0x0A
|
||||||
db "inc rax ; inline comment", 0x0A
|
db "inc rax ; inline comment", 0x0A
|
||||||
db "; one line comment", 0x0A
|
db "; one line comment", 0x0A
|
||||||
|
db "mov rdx, [rax]", 0x0A
|
||||||
db "mov [rax], rdx", 0x0A
|
db "mov [rax], rdx", 0x0A
|
||||||
db "hlt", 0x0A ; TODO make it so it doesn't need to end with a newline; this
|
db "hlt", 0x0A ; TODO make it so it doesn't need to end with a newline; this
|
||||||
; would mean range checking members in operator/operand/com-
|
; would mean range checking members in operator/operand/com-
|
||||||
|
|||||||
Reference in New Issue
Block a user