mirror of
https://gitlab.os-k.eu/os-k-team/kvisc.git
synced 2023-08-25 14:05:46 +02:00
printf! :D
This commit is contained in:
parent
dbafbdb6e8
commit
149bf5b7e0
76
as/k-as.py
76
as/k-as.py
@ -106,7 +106,7 @@ def do_includes(fi):
|
|||||||
global inc_depth
|
global inc_depth
|
||||||
for _, line in enumerate(fi):
|
for _, line in enumerate(fi):
|
||||||
line = line.rstrip()
|
line = line.rstrip()
|
||||||
tok = line.split(' ', 1)
|
tok = line.split(None, 1)
|
||||||
|
|
||||||
if len(tok) == 0:
|
if len(tok) == 0:
|
||||||
continue
|
continue
|
||||||
@ -143,6 +143,8 @@ def do_includes(fi):
|
|||||||
else:
|
else:
|
||||||
source.write("{}\n".format(line))
|
source.write("{}\n".format(line))
|
||||||
|
|
||||||
|
inc_depth -= 1
|
||||||
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -302,6 +304,8 @@ def parse_preproc(line):
|
|||||||
return
|
return
|
||||||
|
|
||||||
print("Unrecognized directive: {}".format(line))
|
print("Unrecognized directive: {}".format(line))
|
||||||
|
leave()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -378,7 +382,7 @@ def parse_instr(line):
|
|||||||
if line == None or len(line) == 0:
|
if line == None or len(line) == 0:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
tok = line.split(' ', 1)
|
tok = line.split(None, 1)
|
||||||
|
|
||||||
instr = tok[0].strip()
|
instr = tok[0].strip()
|
||||||
|
|
||||||
@ -440,6 +444,11 @@ def parse_instr(line):
|
|||||||
if len(fts) != 0:
|
if len(fts) != 0:
|
||||||
fts += ' '
|
fts += ' '
|
||||||
|
|
||||||
|
# preprocessor
|
||||||
|
if word in pdefs:
|
||||||
|
word = pdefs[word]
|
||||||
|
# Fall through
|
||||||
|
|
||||||
# memory length prefixes
|
# memory length prefixes
|
||||||
if len(word) > 2 and '[' in word:
|
if len(word) > 2 and '[' in word:
|
||||||
if word[0] in 'bwlq':
|
if word[0] in 'bwlq':
|
||||||
@ -460,6 +469,11 @@ def parse_instr(line):
|
|||||||
assert(word[-1] == ']')
|
assert(word[-1] == ']')
|
||||||
word = word[1:-1]
|
word = word[1:-1]
|
||||||
|
|
||||||
|
# preprocessor, again
|
||||||
|
if word in pdefs:
|
||||||
|
word = pdefs[word]
|
||||||
|
# Fall through
|
||||||
|
|
||||||
#
|
#
|
||||||
# Make sure we got an access length prefix
|
# Make sure we got an access length prefix
|
||||||
#
|
#
|
||||||
@ -470,11 +484,16 @@ def parse_instr(line):
|
|||||||
|
|
||||||
instr_name += "_m"
|
instr_name += "_m"
|
||||||
|
|
||||||
|
# cheap way of getting [reg - imm] to work
|
||||||
|
word = word.replace('-', '+ -')
|
||||||
|
|
||||||
|
# remove every spaces!
|
||||||
|
word = word.replace(' ', '')
|
||||||
|
|
||||||
#
|
#
|
||||||
# Offsets
|
# Offsets
|
||||||
#
|
#
|
||||||
if '+' in word:
|
if '+' in word:
|
||||||
|
|
||||||
reg1 = "inv"
|
reg1 = "inv"
|
||||||
reg2 = "inv"
|
reg2 = "inv"
|
||||||
imm1 = '1'
|
imm1 = '1'
|
||||||
@ -544,7 +563,7 @@ def parse_instr(line):
|
|||||||
# Update fts and instr_args
|
# Update fts and instr_args
|
||||||
#
|
#
|
||||||
|
|
||||||
instr_args += "{}:{} ".format(reg2.strip(), reg1.strip())
|
instr_args += "{}:{} ".format(reg2, reg1)
|
||||||
size += 2
|
size += 2
|
||||||
|
|
||||||
if imm1 == '1':
|
if imm1 == '1':
|
||||||
@ -562,37 +581,6 @@ def parse_instr(line):
|
|||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
"""
|
|
||||||
# +2 for A_OFF, +2 for offset, +2 for regoff, +2 for register
|
|
||||||
size += 2 + 2 + 2 + 2
|
|
||||||
instr_args += "off "
|
|
||||||
|
|
||||||
assert(len(word) > 3)
|
|
||||||
|
|
||||||
regoff = "inv"
|
|
||||||
|
|
||||||
# [reg+off] or [reg+regoff]
|
|
||||||
if len(word.split('+')) == 2:
|
|
||||||
reg, off = word.split('+', 1)
|
|
||||||
|
|
||||||
if not is_number(off):
|
|
||||||
regoff = off
|
|
||||||
off = '0'
|
|
||||||
|
|
||||||
# [reg+regoff+off]
|
|
||||||
else:
|
|
||||||
assert(len(word.split('+')) == 3)
|
|
||||||
reg, regoff, off = word.split('+', 2)
|
|
||||||
|
|
||||||
off = off.strip()
|
|
||||||
reg = reg.strip()
|
|
||||||
regoff = regoff.strip()
|
|
||||||
|
|
||||||
instr_args += "{} {} {}".format(off, regoff, reg)
|
|
||||||
|
|
||||||
continue
|
|
||||||
"""
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# [imm64] or [reg]
|
# [imm64] or [reg]
|
||||||
#
|
#
|
||||||
@ -600,11 +588,15 @@ def parse_instr(line):
|
|||||||
fellthrough = True
|
fellthrough = True
|
||||||
# FALLTHROUGH
|
# FALLTHROUGH
|
||||||
|
|
||||||
# preprocessor
|
# preprocessor, yet again
|
||||||
if word in pdefs:
|
if word in pdefs:
|
||||||
word = pdefs[word]
|
word = pdefs[word]
|
||||||
# Fall through
|
# Fall through
|
||||||
|
|
||||||
|
# characters 'c'
|
||||||
|
if len(word) == 3 and word[0] == word[-1] == "'":
|
||||||
|
word = str(ord(word[1]))
|
||||||
|
|
||||||
# for now every immediate is 64-bit
|
# for now every immediate is 64-bit
|
||||||
if is_number(word):
|
if is_number(word):
|
||||||
# +8 for immediate
|
# +8 for immediate
|
||||||
@ -656,8 +648,8 @@ def parse_instr(line):
|
|||||||
# Compute FT1 and FT2
|
# Compute FT1 and FT2
|
||||||
#
|
#
|
||||||
if ' ' in fts:
|
if ' ' in fts:
|
||||||
assert(len(fts.split(' ')) == 2)
|
assert(len(fts.split()) == 2)
|
||||||
ft1, ft2 = fts.split(' ')
|
ft1, ft2 = fts.split()
|
||||||
|
|
||||||
w2 |= get_fts_mask(ft1, line) << 5
|
w2 |= get_fts_mask(ft1, line) << 5
|
||||||
w2 |= get_fts_mask(ft2, line)
|
w2 |= get_fts_mask(ft2, line)
|
||||||
@ -690,7 +682,8 @@ def gentext():
|
|||||||
data_start += (8 - data_start % 8)
|
data_start += (8 - data_start % 8)
|
||||||
|
|
||||||
for _, line in enumerate(instrs):
|
for _, line in enumerate(instrs):
|
||||||
tok = line.strip().split(' ')
|
tok = line.strip().split()
|
||||||
|
#print(tok)
|
||||||
|
|
||||||
for word in tok:
|
for word in tok:
|
||||||
if len(word) == 0:
|
if len(word) == 0:
|
||||||
@ -702,6 +695,11 @@ def gentext():
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
if ':' in word:
|
if ':' in word:
|
||||||
|
if len(word.split(':')) < 2:
|
||||||
|
print("Stray ':' in line: {}".format(line))
|
||||||
|
leave()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
reg2, reg1 = word.split(':', 1)
|
reg2, reg1 = word.split(':', 1)
|
||||||
idx1 = pregs.index(reg1)
|
idx1 = pregs.index(reg1)
|
||||||
idx2 = pregs.index(reg2)
|
idx2 = pregs.index(reg2)
|
||||||
|
38
ka/ABI
38
ka/ABI
@ -75,8 +75,9 @@ of the flags in the FLG register.
|
|||||||
Passing parameters is done using the following registers, in that order:
|
Passing parameters is done using the following registers, in that order:
|
||||||
ax0-ax7, lx0-lx7
|
ax0-ax7, lx0-lx7
|
||||||
|
|
||||||
The stack is never used for argument passing. If you need to pass large
|
The stack is never used for argument passing, except for variadic functions,
|
||||||
structures of data, pass their address in an appropriate register.
|
cf the next section. If you need to pass large structures of data, pass
|
||||||
|
their address in an appropriate register.
|
||||||
|
|
||||||
Return values are passed in 'rax'. If the return value does not fit
|
Return values are passed in 'rax'. If the return value does not fit
|
||||||
and require more registers, use the following registers, in that order:
|
and require more registers, use the following registers, in that order:
|
||||||
@ -84,14 +85,41 @@ and require more registers, use the following registers, in that order:
|
|||||||
|
|
||||||
The following registers are volatile; the calling function cannot assume
|
The following registers are volatile; the calling function cannot assume
|
||||||
that they will be left unmodified by the called function:
|
that they will be left unmodified by the called function:
|
||||||
rax, rcx, rdx, rsi, rdi, lx0-lx7, ax0-ax7
|
rax, rcx, rdx, rsx, lx0-lx7, ax0-ax7
|
||||||
|
|
||||||
The following registers are nonvolatile; the called function must preserve them:
|
The following registers are nonvolatile; the called function must preserve them:
|
||||||
rbp, rsp, rbx, rsx, rbi, nx0-nx7
|
rbx, rsi, rdi, rbi, nx0-nx7, rbp, rsp
|
||||||
|
|
||||||
#------------------------------------------------------------------------------#
|
#------------------------------------------------------------------------------#
|
||||||
|
|
||||||
3. SPECIAL REGISTERS
|
3. VARIADIC FUNCTIONS
|
||||||
|
|
||||||
|
To call a variadic function, do this:
|
||||||
|
sub rsp, nargs * 8
|
||||||
|
mov [rsp], arg0
|
||||||
|
...
|
||||||
|
...
|
||||||
|
...
|
||||||
|
mov [rsp+(N*8)], argN
|
||||||
|
call variadic_func
|
||||||
|
add rsp, nargs * 8
|
||||||
|
|
||||||
|
To the variadic function, argN can be accessed the following way:
|
||||||
|
mov reg, [rbp + N*8 + 16]
|
||||||
|
|
||||||
|
For instance:
|
||||||
|
mov rax, [rbp + 16] ; arg1
|
||||||
|
mov rdx, [rbp + 24] ; arg2
|
||||||
|
|
||||||
|
It is recommended to use the reg+reg*imm16+imm16 memory format:
|
||||||
|
mov rax, [rbp + rcx * 8 + 16] ; accesses arg#rcx
|
||||||
|
|
||||||
|
The 'va_list' type can be regarded as a pointer to the
|
||||||
|
variadic function's rbp+16
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------#
|
||||||
|
|
||||||
|
4. SPECIAL REGISTERS
|
||||||
|
|
||||||
The 'inv' register cannot be referenced by machine code except when specified
|
The 'inv' register cannot be referenced by machine code except when specified
|
||||||
as an offset register in the [reg+reg(*/+...)] memory formats; in these case,
|
as an offset register in the [reg+reg(*/+...)] memory formats; in these case,
|
||||||
|
236
ka/crt/fmt/_doprnt.k
Normal file
236
ka/crt/fmt/_doprnt.k
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
; The OS/K Team licenses this file to you under the MIT license.
|
||||||
|
; See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
_doprnt_test:
|
||||||
|
mov ax0, .fmt
|
||||||
|
sub rsp, 128
|
||||||
|
mov q[rsp+40], 0x7FE
|
||||||
|
mov q[rsp+32], -2
|
||||||
|
mov q[rsp+24], 666
|
||||||
|
mov q[rsp+16], 0x112233DDAA6677BB
|
||||||
|
mov q[rsp+8], 'K'
|
||||||
|
mov q[rsp], .str
|
||||||
|
call printf
|
||||||
|
add rsp, 128
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
.fmt = "%% Hello World %s - %c - %p - %d - %d - %b"
|
||||||
|
.str = "(cc)"
|
||||||
|
|
||||||
|
;
|
||||||
|
; typedef int (*PUTC)(int ch)
|
||||||
|
; int _doprnt(PUTC putc, int n, const char *fmt, va_list ap)
|
||||||
|
;
|
||||||
|
_doprnt:
|
||||||
|
enter 8
|
||||||
|
mov q[rbp-8], rbx
|
||||||
|
mov q[rbp-16], nx0
|
||||||
|
mov q[rbp-24], nx1
|
||||||
|
mov q[rbp-32], nx2
|
||||||
|
mov q[rbp-40], rdi
|
||||||
|
mov q[rbp-48], rsi
|
||||||
|
mov q[rbp-56], nx3
|
||||||
|
|
||||||
|
mov rbx, ax2 ; fmt
|
||||||
|
mov nx3, ax0 ; putc
|
||||||
|
mov nx0, ax1 ; n
|
||||||
|
xor nx1, nx1 ; return value
|
||||||
|
xor nx2, nx2 ; index in va_list
|
||||||
|
mov rsi, ax3 ; ap
|
||||||
|
|
||||||
|
.main_loop:
|
||||||
|
; find '%' or null-terminator
|
||||||
|
mov rcx, STRLEN_MAX
|
||||||
|
mov rdi, rbx
|
||||||
|
scasb.rep.nz rdi, '%'
|
||||||
|
|
||||||
|
.print_regular:
|
||||||
|
; everything below rdi is a regular character; print it
|
||||||
|
cmp rbx, rdi
|
||||||
|
j.z .check_modf
|
||||||
|
|
||||||
|
mov ax0, b[rbx]
|
||||||
|
call .doput
|
||||||
|
|
||||||
|
inc rbx
|
||||||
|
jmp .print_regular
|
||||||
|
|
||||||
|
.check_modf:
|
||||||
|
; did we find a '%' ?
|
||||||
|
cmp b[rbx], '%'
|
||||||
|
j.nz .epilogue ; no, we found fmt's null-terminator; we're done
|
||||||
|
|
||||||
|
; we did find a modifier / '%'
|
||||||
|
mov rax, b[rbx+1]
|
||||||
|
add rbx, 2
|
||||||
|
|
||||||
|
cmp rax, 's'
|
||||||
|
j.z .modf_s
|
||||||
|
cmp rax, 'c'
|
||||||
|
j.z .modf_c
|
||||||
|
cmp rax, 'p'
|
||||||
|
j.z .modf_p
|
||||||
|
cmp rax, 'x'
|
||||||
|
j.z .modf_x
|
||||||
|
cmp rax, 'u'
|
||||||
|
j.z .modf_u
|
||||||
|
cmp rax, 'd'
|
||||||
|
j.z .modf_d
|
||||||
|
cmp rax, 'o'
|
||||||
|
j.z .modf_o
|
||||||
|
cmp rax, 'b'
|
||||||
|
j.z .modf_b
|
||||||
|
cmp rax, '%'
|
||||||
|
j.z .modf_percent
|
||||||
|
; unrecognized
|
||||||
|
jmp .bad_modifier
|
||||||
|
|
||||||
|
.modf_s:
|
||||||
|
; get string address
|
||||||
|
mov rdi, q[rsi + nx2 * 8]
|
||||||
|
inc nx2
|
||||||
|
|
||||||
|
test rdi, rdi
|
||||||
|
j.z .nullstring
|
||||||
|
|
||||||
|
.print_string:
|
||||||
|
mov ax0, b[rdi]
|
||||||
|
test ax0, ax0
|
||||||
|
j.z .main_loop
|
||||||
|
|
||||||
|
inc rdi
|
||||||
|
call .doput
|
||||||
|
jmp .print_string
|
||||||
|
|
||||||
|
.modf_c:
|
||||||
|
mov ax0, q[rsi + nx2 * 8]
|
||||||
|
inc nx2
|
||||||
|
call .doput
|
||||||
|
jmp .main_loop
|
||||||
|
|
||||||
|
.modf_p:
|
||||||
|
mov ax0, '0'
|
||||||
|
call .doput
|
||||||
|
mov ax0, 'x'
|
||||||
|
call .doput
|
||||||
|
; Fallthrough
|
||||||
|
|
||||||
|
.modf_x:
|
||||||
|
mov ax2, 16
|
||||||
|
mov ax3, 1
|
||||||
|
jmp .print_number
|
||||||
|
|
||||||
|
.modf_u:
|
||||||
|
mov ax2, 10
|
||||||
|
mov ax3, 1
|
||||||
|
jmp .print_number
|
||||||
|
|
||||||
|
.modf_d:
|
||||||
|
mov ax2, 10
|
||||||
|
xor ax3, ax3
|
||||||
|
jmp .print_number
|
||||||
|
|
||||||
|
.modf_o:
|
||||||
|
mov ax2, 8
|
||||||
|
mov ax3, 1
|
||||||
|
jmp .print_number
|
||||||
|
|
||||||
|
.modf_b:
|
||||||
|
mov ax2, 2
|
||||||
|
mov ax3, 1
|
||||||
|
jmp .print_number
|
||||||
|
|
||||||
|
.print_number:
|
||||||
|
; allocate itoa convertion buffer
|
||||||
|
sub rsp, 80
|
||||||
|
mov rdi, rsp
|
||||||
|
|
||||||
|
; assume modifier already set up ax2 and ax3
|
||||||
|
mov ax0, rsp
|
||||||
|
mov ax1, q[rsi + nx2 * 8]
|
||||||
|
inc nx2
|
||||||
|
call _itoa
|
||||||
|
|
||||||
|
.print_itoa_buf:
|
||||||
|
mov ax0, b[rdi]
|
||||||
|
test ax0, ax0
|
||||||
|
add.z rsp, 80
|
||||||
|
j.z .main_loop
|
||||||
|
|
||||||
|
inc rdi
|
||||||
|
call .doput
|
||||||
|
jmp .print_itoa_buf
|
||||||
|
|
||||||
|
.modf_percent:
|
||||||
|
mov ax0, '%'
|
||||||
|
call .doput
|
||||||
|
jmp .main_loop
|
||||||
|
|
||||||
|
.bad_modifier:
|
||||||
|
; print "%?" to clearly indicate that something is wrong
|
||||||
|
mov ax0, '$'
|
||||||
|
call .doput
|
||||||
|
|
||||||
|
mov ax0, '?'
|
||||||
|
call .doput
|
||||||
|
|
||||||
|
jmp .main_loop
|
||||||
|
|
||||||
|
.nullstring:
|
||||||
|
; %s was passed a NULL
|
||||||
|
mov ax0, '('
|
||||||
|
call .doput
|
||||||
|
|
||||||
|
mov ax0, 'n'
|
||||||
|
call .doput
|
||||||
|
|
||||||
|
mov ax0, 'u'
|
||||||
|
call .doput
|
||||||
|
|
||||||
|
mov ax0, 'l'
|
||||||
|
call .doput
|
||||||
|
|
||||||
|
mov ax0, 'l'
|
||||||
|
call .doput
|
||||||
|
|
||||||
|
mov ax0, ')'
|
||||||
|
call .doput
|
||||||
|
|
||||||
|
jmp .main_loop
|
||||||
|
|
||||||
|
.epilogue:
|
||||||
|
mov rax, nx1
|
||||||
|
mov rbx, q[rbp-8]
|
||||||
|
mov nx0, q[rbp-16]
|
||||||
|
mov nx1, q[rbp-24]
|
||||||
|
mov nx2, q[rbp-32]
|
||||||
|
mov rdi, q[rbp-40]
|
||||||
|
mov rsi, q[rbp-48]
|
||||||
|
mov nx3, q[rbp-56]
|
||||||
|
leave
|
||||||
|
ret
|
||||||
|
;
|
||||||
|
; prints ax0
|
||||||
|
;
|
||||||
|
.doput:
|
||||||
|
; update print count
|
||||||
|
inc nx1
|
||||||
|
|
||||||
|
; if n==0, don't print
|
||||||
|
; we follow the C convention that sprintf()-like functions
|
||||||
|
; should return the number of characters that would have
|
||||||
|
; been printed/written if 'n' were big enough
|
||||||
|
test nx0, nx0
|
||||||
|
ret.z
|
||||||
|
|
||||||
|
; if n>0, decrement n and print
|
||||||
|
dec nx0
|
||||||
|
call nx3
|
||||||
|
|
||||||
|
; did putc fail?
|
||||||
|
cmp rax, 0
|
||||||
|
xor.nz nx0, nx0 ; yes, so artificially set n=0
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
@ -2,4 +2,6 @@
|
|||||||
; See the LICENSE file in the project root for more information.
|
; See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
include "crt/fmt/itoa.k"
|
include "crt/fmt/itoa.k"
|
||||||
|
include "crt/fmt/_doprnt.k"
|
||||||
|
include "crt/fmt/printf.k"
|
||||||
|
|
||||||
|
@ -2,9 +2,21 @@
|
|||||||
; See the LICENSE file in the project root for more information.
|
; See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
;
|
;
|
||||||
; char *_itoa(char *buf, int num, int base, int unsi)
|
; wrappers
|
||||||
;
|
;
|
||||||
; Acts as itoa if unsi == 0, as utoa otherwise
|
|
||||||
|
itoa:
|
||||||
|
mov ax3, 0
|
||||||
|
jmp _itoa
|
||||||
|
|
||||||
|
utoa:
|
||||||
|
mov ax3, 1
|
||||||
|
jmp _itoa
|
||||||
|
|
||||||
|
;
|
||||||
|
; void _itoa(char *buf, int num, int base, int unsi)
|
||||||
|
;
|
||||||
|
; Behaves as itoa if unsi == 0, as utoa otherwise
|
||||||
;
|
;
|
||||||
_itoa:
|
_itoa:
|
||||||
mov rax, ax0
|
mov rax, ax0
|
||||||
@ -46,11 +58,11 @@ _itoa:
|
|||||||
cmp lx1, 9 ; lx1 > 9 ?
|
cmp lx1, 9 ; lx1 > 9 ?
|
||||||
jmp.a .nondec
|
jmp.a .nondec
|
||||||
|
|
||||||
add lx1, 48 ; '0'
|
add lx1, '0'
|
||||||
jmp .next
|
jmp .next
|
||||||
|
|
||||||
.nondec:
|
.nondec:
|
||||||
add lx1, 87 ; 'a' - 10
|
add lx1, 55 ; 'A' - 10
|
||||||
|
|
||||||
.next:
|
.next:
|
||||||
mov b[ax0], lx1
|
mov b[ax0], lx1
|
||||||
@ -62,7 +74,7 @@ _itoa:
|
|||||||
; add minus flag, null-terminate and reverse
|
; add minus flag, null-terminate and reverse
|
||||||
.fini:
|
.fini:
|
||||||
cmp lx0, -1
|
cmp lx0, -1
|
||||||
mov.z b[ax0], 45 ; '-'
|
mov.z b[ax0], '-'
|
||||||
inc.z ax0
|
inc.z ax0
|
||||||
|
|
||||||
mov b[ax0], 0
|
mov b[ax0], 0
|
||||||
@ -86,15 +98,3 @@ _itoa:
|
|||||||
mov b[ax0+1], 0
|
mov b[ax0+1], 0
|
||||||
ret
|
ret
|
||||||
|
|
||||||
;
|
|
||||||
; wrappers
|
|
||||||
;
|
|
||||||
|
|
||||||
itoa:
|
|
||||||
mov ax3, 0
|
|
||||||
jmp _itoa
|
|
||||||
|
|
||||||
utoa:
|
|
||||||
mov ax3, 1
|
|
||||||
jmp _itoa
|
|
||||||
|
|
||||||
|
@ -2,15 +2,28 @@
|
|||||||
; See the LICENSE file in the project root for more information.
|
; See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
;
|
;
|
||||||
; Max amount of characters that print() will print
|
; int putc(int ch)
|
||||||
;
|
;
|
||||||
v_print_max := 0xFF
|
putc:
|
||||||
|
prn ax0
|
||||||
|
xor rax, rax
|
||||||
|
ret
|
||||||
|
|
||||||
|
;
|
||||||
|
; int printf(const char *fmt, ...)
|
||||||
|
;
|
||||||
|
printf:
|
||||||
|
mov ax2, ax0
|
||||||
|
mov ax0, putc
|
||||||
|
mov ax1, STRLEN_MAX
|
||||||
|
lea ax3, b[rsp+8]
|
||||||
|
jmp _doprnt
|
||||||
|
|
||||||
;
|
;
|
||||||
; Print a string
|
; Print a string
|
||||||
;
|
;
|
||||||
print:
|
print:
|
||||||
mov rcx, v_print_max
|
mov rcx, STRLEN_MAX
|
||||||
|
|
||||||
.1:
|
.1:
|
||||||
test b[ax0], b[ax0]
|
test b[ax0], b[ax0]
|
@ -5,14 +5,22 @@
|
|||||||
; char *strchrnul(const char *str, int ch)
|
; char *strchrnul(const char *str, int ch)
|
||||||
;
|
;
|
||||||
strchrnul:
|
strchrnul:
|
||||||
|
mov rcx, STRLEN_MAX
|
||||||
|
scasb.rep.nz ax0, ax1
|
||||||
|
|
||||||
|
mov rax, ax0
|
||||||
ret
|
ret
|
||||||
|
|
||||||
;
|
;
|
||||||
; char *strchr(const char *str, int ch)
|
; char *strchr(const char *str, int ch)
|
||||||
;
|
;
|
||||||
strchr:
|
strchr:
|
||||||
call strchrnul
|
mov rcx, STRLEN_MAX
|
||||||
test b[rax], b[rax]
|
scasb.rep.nz ax0, ax1
|
||||||
mov.z rax, 0
|
|
||||||
|
cmp b[ax0], 0
|
||||||
|
xor.z rax, rax
|
||||||
|
ret.z
|
||||||
|
|
||||||
|
mov rax, ax0
|
||||||
ret
|
ret
|
||||||
|
@ -17,7 +17,7 @@ strrev:
|
|||||||
; go to str's end, just before
|
; go to str's end, just before
|
||||||
; the null terminator
|
; the null terminator
|
||||||
mov rcx, STRLEN_MAX
|
mov rcx, STRLEN_MAX
|
||||||
scazsb.rep.nz ax1
|
scasb.rep.nz ax1, 0
|
||||||
dec ax1
|
dec ax1
|
||||||
|
|
||||||
.2:
|
.2:
|
||||||
@ -48,7 +48,7 @@ strrev2:
|
|||||||
; go to str's end, just before
|
; go to str's end, just before
|
||||||
; the null terminator
|
; the null terminator
|
||||||
mov rcx, STRLEN_MAX
|
mov rcx, STRLEN_MAX
|
||||||
scazsb.rep.nz ax1
|
scasb.rep.nz ax1, 0
|
||||||
dec ax1
|
dec ax1
|
||||||
|
|
||||||
; increase ax0 while decreasing ax1, performing exchanges
|
; increase ax0 while decreasing ax1, performing exchanges
|
||||||
|
1
ka/dos.k
1
ka/dos.k
@ -25,7 +25,6 @@ include "inc/regs.k"
|
|||||||
;
|
;
|
||||||
include "crt/err/errno.k"
|
include "crt/err/errno.k"
|
||||||
include "crt/fmt/format.k"
|
include "crt/fmt/format.k"
|
||||||
include "crt/prn/print.k"
|
|
||||||
include "crt/str/string.k"
|
include "crt/str/string.k"
|
||||||
|
|
||||||
;
|
;
|
||||||
|
34
ka/main.k
34
ka/main.k
@ -5,17 +5,28 @@
|
|||||||
; Main function
|
; Main function
|
||||||
;
|
;
|
||||||
main:
|
main:
|
||||||
call showoff
|
call _doprnt_test
|
||||||
ret
|
ret
|
||||||
|
|
||||||
showoff:
|
showoff:
|
||||||
call ramdev_test
|
call ramdev_test
|
||||||
call bswap_test
|
call bswap_test
|
||||||
call itoa_test
|
call itoa_test
|
||||||
|
prn 10
|
||||||
call str_test
|
call str_test
|
||||||
call movzx_test
|
call movzx_test
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
strchr_test:
|
||||||
|
mov rax, 0
|
||||||
|
mov ax0, .str
|
||||||
|
mov ax1, 33
|
||||||
|
call strchr
|
||||||
|
prn b[rax]
|
||||||
|
ret
|
||||||
|
|
||||||
|
.str = "Hello World!"
|
||||||
|
|
||||||
bswap_test:
|
bswap_test:
|
||||||
mov rdx, 0x1122334455667788
|
mov rdx, 0x1122334455667788
|
||||||
bswap rax, rdx
|
bswap rax, rdx
|
||||||
@ -35,25 +46,6 @@ ramdev_test:
|
|||||||
call MEM.GetMemSize
|
call MEM.GetMemSize
|
||||||
ret
|
ret
|
||||||
|
|
||||||
stosb_test:
|
|
||||||
mov rcx, 11
|
|
||||||
mov rax, 33
|
|
||||||
mov rdi, .buf
|
|
||||||
mov rsi, .buf
|
|
||||||
stosb.rep
|
|
||||||
|
|
||||||
mov rbx, rdi
|
|
||||||
sub rbx, rsi
|
|
||||||
|
|
||||||
mov ax0, .buf
|
|
||||||
mov ax1, 12
|
|
||||||
call print_n
|
|
||||||
|
|
||||||
ret
|
|
||||||
|
|
||||||
.str1 = "Hello World!\n"
|
|
||||||
.buf = [32]
|
|
||||||
|
|
||||||
movzx_test:
|
movzx_test:
|
||||||
enter 1
|
enter 1
|
||||||
|
|
||||||
@ -139,7 +131,7 @@ str_test:
|
|||||||
call strcmp
|
call strcmp
|
||||||
mov rsx, rax
|
mov rsx, rax
|
||||||
|
|
||||||
mov ax0, .msg
|
mov ax0, .buf2
|
||||||
call strlen
|
call strlen
|
||||||
|
|
||||||
ret
|
ret
|
||||||
|
157
vm/in/INSTRS
157
vm/in/INSTRS
@ -316,6 +316,20 @@ xchg rm rim
|
|||||||
#
|
#
|
||||||
cmpxchg rm rim
|
cmpxchg rm rim
|
||||||
|
|
||||||
|
#
|
||||||
|
# Load argument #N (LDARG)
|
||||||
|
#
|
||||||
|
# IF ($2 < 8) THEN
|
||||||
|
# $1 = AX$2
|
||||||
|
# ELSE
|
||||||
|
# $1 = LX($2-8)
|
||||||
|
# FI
|
||||||
|
#
|
||||||
|
# Throws:
|
||||||
|
# #ILL if $2 ≥ 16
|
||||||
|
#
|
||||||
|
ldarg rm rim
|
||||||
|
|
||||||
#---------------------------------------------------------------------------#
|
#---------------------------------------------------------------------------#
|
||||||
# Stack manipulation instructions #
|
# Stack manipulation instructions #
|
||||||
#---------------------------------------------------------------------------#
|
#---------------------------------------------------------------------------#
|
||||||
@ -359,7 +373,7 @@ leave
|
|||||||
#
|
#
|
||||||
# Store value into string (STOSx)
|
# Store value into string (STOSx)
|
||||||
#
|
#
|
||||||
# [%str] = $val
|
# [%1] = $2
|
||||||
# IF (DF == 0) THEN
|
# IF (DF == 0) THEN
|
||||||
# %str = %str + sizeof(x)
|
# %str = %str + sizeof(x)
|
||||||
# ELSE
|
# ELSE
|
||||||
@ -370,14 +384,15 @@ leave
|
|||||||
# When one parameter is given, %str = RDI and $val = $1
|
# When one parameter is given, %str = RDI and $val = $1
|
||||||
# When two parameters are given, %str = $1 and $val = $2
|
# When two parameters are given, %str = $1 and $val = $2
|
||||||
#
|
#
|
||||||
stosb
|
|
||||||
stosb rim
|
|
||||||
stosb r rim
|
stosb r rim
|
||||||
|
stosw r rim
|
||||||
|
stosl r rim
|
||||||
|
stosq r rim
|
||||||
|
|
||||||
#
|
#
|
||||||
# Load value from string (LODSx)
|
# Load value from string (LODSx)
|
||||||
#
|
#
|
||||||
# %dest = [%str]
|
# $1 = [%2]
|
||||||
# IF (DF == 0) THEN
|
# IF (DF == 0) THEN
|
||||||
# %str = %str + sizeof(x)
|
# %str = %str + sizeof(x)
|
||||||
# ELSE
|
# ELSE
|
||||||
@ -387,176 +402,92 @@ stosb r rim
|
|||||||
# Preserves CF, OF and SF
|
# Preserves CF, OF and SF
|
||||||
# Sets ZF according to the loaded value
|
# Sets ZF according to the loaded value
|
||||||
#
|
#
|
||||||
# When no parameters are given, %dest = RAX and %str = RSI
|
|
||||||
# When one parameter is given, %dest = $1 and %str = RSI
|
|
||||||
# When two parameters are given, %dest = $1 and %str = $2
|
|
||||||
#
|
|
||||||
lodsb
|
|
||||||
lodsb r
|
|
||||||
lodsb r r
|
lodsb r r
|
||||||
lodsw
|
|
||||||
lodsw r
|
|
||||||
lodsw r r
|
lodsw r r
|
||||||
lodsl
|
|
||||||
lodsl r
|
|
||||||
lodsl r r
|
lodsl r r
|
||||||
lodsq
|
|
||||||
lodsq r
|
|
||||||
lodsq r r
|
lodsq r r
|
||||||
|
|
||||||
#
|
#
|
||||||
# Scan string for a particular value (SCASx)
|
# Scan string for a particular value (SCASx)
|
||||||
#
|
#
|
||||||
# CMP([%str], $val)
|
# CMP([%1], $2)
|
||||||
#
|
#
|
||||||
|
# IF ([%1] == 0) THEN
|
||||||
|
# ZF = 1
|
||||||
|
# ELIF (ZF == 0) THEN
|
||||||
# IF (DF == 0) THEN
|
# IF (DF == 0) THEN
|
||||||
# %str = %str + sizeof(x)
|
# %1 = %1 + sizeof(x)
|
||||||
# ELSE
|
# ELSE
|
||||||
# %str = %str - sizeof(x)
|
# %1 = %1 - sizeof(x)
|
||||||
|
# FI
|
||||||
# FI
|
# FI
|
||||||
#
|
#
|
||||||
# Sets CF, OF, ZF and SF according to the result of the comparison
|
# Sets CF, OF and SF according to the result of the comparison
|
||||||
|
# Sets ZF according to whether [%1] and $2 are equal, OR if [%1] is null
|
||||||
#
|
#
|
||||||
# When no parameters are given, %str = RDI and $val = RAX
|
# Notes:
|
||||||
# When one parameter is given, %str = RDI and $val = $1
|
# - Does not move past the value when found
|
||||||
# When two parameters are given, %str = $1 and $val = $2
|
# - 'SCASB.REP.NZ reg ch' is a short 'strchnul()'
|
||||||
#
|
#
|
||||||
# Note that SCASx moves in the string no matter whether the value
|
|
||||||
# was found or not; therefore when the value *is* found, it will
|
|
||||||
# be sizeof(x) bytes below the current value of %str
|
|
||||||
#
|
|
||||||
scasb
|
|
||||||
scasb rim
|
|
||||||
scasb r rim
|
scasb r rim
|
||||||
scasw
|
|
||||||
scasw rim
|
|
||||||
scasw r rim
|
scasw r rim
|
||||||
scasl
|
|
||||||
scasl rim
|
|
||||||
scasl r rim
|
scasl r rim
|
||||||
scasq
|
|
||||||
scasq rim
|
|
||||||
scasq r rim
|
scasq r rim
|
||||||
|
|
||||||
#
|
|
||||||
# Scan string for null terminator (SCAZSx)
|
|
||||||
#
|
|
||||||
# CMP([%str], 0)
|
|
||||||
#
|
|
||||||
# IF (ZF == 0)
|
|
||||||
# IF (DF == 0) THEN
|
|
||||||
# %str = %str + sizeof(x)
|
|
||||||
# ELSE
|
|
||||||
# %str = %str - sizeof(x)
|
|
||||||
# FI
|
|
||||||
# FI
|
|
||||||
#
|
|
||||||
# Sets CF, OF, ZF and SF according to the result of the comparison
|
|
||||||
#
|
|
||||||
# When no parameters are given, %str = RDI and $val = RAX
|
|
||||||
# When one parameter is given, %str = RDI and $val = $1
|
|
||||||
# When two parameters are given, %str = $1 and $val = $2
|
|
||||||
#
|
|
||||||
# Unlike SCASx, this instruction does NOT move forward after
|
|
||||||
# finding what it was looking for. The instruction:
|
|
||||||
# REP.NZ SCAZSx %str
|
|
||||||
# serves as a much faster shorthand for
|
|
||||||
# REP.NZ SCASx %str
|
|
||||||
# DEC %str
|
|
||||||
#
|
|
||||||
scazsb
|
|
||||||
scazsb r
|
|
||||||
scazsw
|
|
||||||
scazsw r
|
|
||||||
scazsl
|
|
||||||
scazsl r
|
|
||||||
scazsq
|
|
||||||
scazsq r
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Compare bytes in strings (CMPSx)
|
# Compare bytes in strings (CMPSx)
|
||||||
#
|
#
|
||||||
# CMP([%str1], [%str2])
|
# CMP([%1], [%2])
|
||||||
#
|
#
|
||||||
# IF (DF == 0) THEN
|
# IF (DF == 0) THEN
|
||||||
# %str1 = %str1 + sizeof(x)
|
# %1 = %1 + sizeof(x)
|
||||||
# %str2 = %str2 + sizeof(x)
|
# %2 = %2 + sizeof(x)
|
||||||
# ELSE
|
# ELSE
|
||||||
# %str1 = %str1 - sizeof(x)
|
# %1 = %1 - sizeof(x)
|
||||||
# %str2 = %str2 - sizeof(x)
|
# %2 = %2 - sizeof(x)
|
||||||
# FI
|
# FI
|
||||||
#
|
#
|
||||||
# Sets CF, OF, ZF and SF according to the result of the comparison
|
# Sets CF, OF, ZF and SF according to the result of the comparison
|
||||||
#
|
#
|
||||||
# When no parameters are given, %str1 = RDI and %str2 = RSI
|
# Moves past the compared values in any case!
|
||||||
# When one parameter is given, %str1 = RDI and %str2 = $1
|
|
||||||
# When two parameters are given, %str1 = $1 and %str2 = $2
|
|
||||||
#
|
#
|
||||||
cmpsb
|
|
||||||
cmpsb r
|
|
||||||
cmpsb r r
|
cmpsb r r
|
||||||
cmpsw
|
|
||||||
cmpsw r
|
|
||||||
cmpsw r r
|
cmpsw r r
|
||||||
cmpsl
|
|
||||||
cmpsl r
|
|
||||||
cmpsl r r
|
cmpsl r r
|
||||||
cmpsq
|
|
||||||
cmpsq r
|
|
||||||
cmpsq r r
|
cmpsq r r
|
||||||
|
|
||||||
#
|
#
|
||||||
# Safe compare bytes in strings (CMPZSx)
|
# Safe compare bytes in strings (CMPZSx)
|
||||||
#
|
#
|
||||||
# Behaves precisely like CMPSx, except in the following case:
|
# Behaves precisely like CMPSx, except in the following case:
|
||||||
# - If both [%str1] and [%str2] are zero, clears ZF (indicating NOT EQUAL)
|
# - If both [%1] and [%2] are zero, clears ZF (indicating NOT EQUAL)
|
||||||
#
|
#
|
||||||
# This prevents 'REP.Z CMPZSx' from looping infinitely when both strings
|
# This prevents 'CMPZSx.REP.Z' from looping infinitely when both strings
|
||||||
# have the exact same content; this allows for short strcmp's
|
# have the exact same content; this allows for short strcmp's
|
||||||
#
|
#
|
||||||
cmpzsb
|
|
||||||
cmpzsb r
|
|
||||||
cmpzsb r r
|
cmpzsb r r
|
||||||
cmpzsw
|
|
||||||
cmpzsw r
|
|
||||||
cmpzsw r r
|
cmpzsw r r
|
||||||
cmpzsl
|
|
||||||
cmpzsl r
|
|
||||||
cmpzsl r r
|
cmpzsl r r
|
||||||
cmpzsq
|
|
||||||
cmpzsq r
|
|
||||||
cmpzsq r r
|
cmpzsq r r
|
||||||
|
|
||||||
#
|
#
|
||||||
# Move value from string to string (MOVSx)
|
# Move value from string to string (MOVSx)
|
||||||
#
|
#
|
||||||
# [%str1] = [%str2]
|
# [%1] = [%1]
|
||||||
# IF (DF == 0) THEN
|
# IF (DF == 0) THEN
|
||||||
# %str1 = %str1 + sizeof(x)
|
# %1 = %1 + sizeof(x)
|
||||||
# %str2 = %str2 + sizeof(x)
|
# %2 = %2 + sizeof(x)
|
||||||
# ELSE
|
# ELSE
|
||||||
# %str1 = %str1 - sizeof(x)
|
# %1 = %1 - sizeof(x)
|
||||||
# %str2 = %str2 - sizeof(x)
|
# %2 = %2 - sizeof(x)
|
||||||
# FI
|
# FI
|
||||||
#
|
#
|
||||||
# Preserves CF, OF and SF
|
# Preserves CF, OF and SF
|
||||||
# Sets ZF according to the moved value
|
# Sets ZF according to the moved value
|
||||||
#
|
#
|
||||||
# When no parameters are given, %str1 = RDI and %str2 = RSI
|
|
||||||
# When one parameter is given, %str1 = RDI and %str2 = $1
|
|
||||||
# When two parameters are given, %str1 = $1 and %str2 = $2
|
|
||||||
#
|
|
||||||
movsb
|
|
||||||
movsb r
|
|
||||||
movsb r r
|
movsb r r
|
||||||
movsw
|
|
||||||
movsw r
|
|
||||||
movsw r r
|
movsw r r
|
||||||
movsl
|
|
||||||
movsl r
|
|
||||||
movsl r r
|
movsl r r
|
||||||
movsq
|
|
||||||
movsq r
|
|
||||||
movsq r r
|
movsq r r
|
||||||
|
|
||||||
#---------------------------------------------------------------------------#
|
#---------------------------------------------------------------------------#
|
||||||
|
16
vm/in/mov.c
16
vm/in/mov.c
@ -51,6 +51,21 @@ IMPL_OUT;
|
|||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
//----------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
IMPL_START_2(ldarg)
|
||||||
|
{
|
||||||
|
if (v2 < 8)
|
||||||
|
v1 = R(AX0 + v2);
|
||||||
|
|
||||||
|
else if (v2 < 16)
|
||||||
|
v1 = R(LX0 + v2 - 8);
|
||||||
|
|
||||||
|
else
|
||||||
|
_except(ctx, E_ILL, "ldarg: value out of range: %lu", v1);
|
||||||
|
}
|
||||||
|
IMPL_OUT;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------//
|
||||||
|
|
||||||
IMPL_START_1(gco)
|
IMPL_START_1(gco)
|
||||||
{
|
{
|
||||||
v1 = cr1;
|
v1 = cr1;
|
||||||
@ -63,4 +78,5 @@ IMPL_START_1(gcd)
|
|||||||
}
|
}
|
||||||
IMPL_OUT;
|
IMPL_OUT;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
189
vm/in/string.c
189
vm/in/string.c
@ -15,28 +15,11 @@
|
|||||||
|
|
||||||
static void stos_impl(ctx_t *ctx, acc_t *p1, acc_t *p2, uint len)
|
static void stos_impl(ctx_t *ctx, acc_t *p1, acc_t *p2, uint len)
|
||||||
{
|
{
|
||||||
ulong reg, val;
|
|
||||||
|
|
||||||
if (p2) {
|
|
||||||
DECV(v2, p2);
|
DECV(v2, p2);
|
||||||
reg = p1->reg;
|
|
||||||
val = v2;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (p1) {
|
writemem(ctx, v2, R(p1->reg), len);
|
||||||
DECV(v1, p1);
|
|
||||||
reg = RDI;
|
|
||||||
val = v1;
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
STR_MOVE(p1->reg, len);
|
||||||
reg = RDI;
|
|
||||||
val = rax;
|
|
||||||
}
|
|
||||||
|
|
||||||
writemem(ctx, val, R(reg), len);
|
|
||||||
|
|
||||||
STR_MOVE(reg, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IMPL_START_0(stosb)
|
IMPL_START_0(stosb)
|
||||||
@ -67,28 +50,11 @@ IMPL_END;
|
|||||||
|
|
||||||
static void lods_impl(ctx_t *ctx, acc_t *p1, acc_t *p2, uint len)
|
static void lods_impl(ctx_t *ctx, acc_t *p1, acc_t *p2, uint len)
|
||||||
{
|
{
|
||||||
ulong reg1, reg2;
|
R(p1->reg) = readmem(ctx, R(p2->reg), len);
|
||||||
|
|
||||||
if (p2) {
|
flg = (R(p1->reg) == 0 ? flg|ZF : flg&~ZF);
|
||||||
reg1 = p1->reg;
|
|
||||||
reg2 = p2->reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (p1) {
|
STR_MOVE(p2->reg, len);
|
||||||
reg1 = p1->reg;
|
|
||||||
reg2 = RSI;
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
reg1 = RAX;
|
|
||||||
reg2 = RSI;
|
|
||||||
}
|
|
||||||
|
|
||||||
R(reg1) = readmem(ctx, R(reg2), len);
|
|
||||||
|
|
||||||
flg = (R(reg1) == 0 ? flg|ZF : flg&~ZF);
|
|
||||||
|
|
||||||
STR_MOVE(reg2, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IMPL_START_0(lodsb)
|
IMPL_START_0(lodsb)
|
||||||
@ -119,29 +85,18 @@ IMPL_END;
|
|||||||
|
|
||||||
static void scas_impl(ctx_t *ctx, acc_t *p1, acc_t *p2, uint len)
|
static void scas_impl(ctx_t *ctx, acc_t *p1, acc_t *p2, uint len)
|
||||||
{
|
{
|
||||||
ulong reg, val;
|
|
||||||
|
|
||||||
if (p2) {
|
|
||||||
DECV(v2, p2);
|
DECV(v2, p2);
|
||||||
reg = p1->reg;
|
|
||||||
val = v2;
|
ulong x = readmem(ctx, R(p1->reg), len);
|
||||||
|
COMPARE(x, v2);
|
||||||
|
|
||||||
|
if (x == 0) {
|
||||||
|
flg |= ZF;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (p1) {
|
else if (!(flg&ZF)) {
|
||||||
DECV(v1, p1);
|
STR_MOVE(p1->reg, len);
|
||||||
reg = RDI;
|
|
||||||
val = v1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
|
||||||
reg = RDI;
|
|
||||||
val = rax;
|
|
||||||
}
|
|
||||||
|
|
||||||
ulong x = readmem(ctx, R(reg), len);
|
|
||||||
COMPARE(x, val);
|
|
||||||
|
|
||||||
STR_MOVE(reg, len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IMPL_START_0(scasb)
|
IMPL_START_0(scasb)
|
||||||
@ -170,75 +125,15 @@ IMPL_END;
|
|||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
//----------------------------------------------------------------------------//
|
||||||
|
|
||||||
static void scazs_impl(ctx_t *ctx, acc_t *p1, uint len)
|
|
||||||
{
|
|
||||||
ulong reg;
|
|
||||||
|
|
||||||
if (p1)
|
|
||||||
reg = p1->reg;
|
|
||||||
else
|
|
||||||
reg = RDI;
|
|
||||||
|
|
||||||
ulong x = readmem(ctx, R(reg), len);
|
|
||||||
COMPARE(x, 0);
|
|
||||||
|
|
||||||
if (!(flg&ZF)) {
|
|
||||||
STR_MOVE(reg, len);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IMPL_START_0(scazsb)
|
|
||||||
{
|
|
||||||
scazs_impl(ctx, p1, 1);
|
|
||||||
}
|
|
||||||
IMPL_END;
|
|
||||||
|
|
||||||
IMPL_START_0(scazsw)
|
|
||||||
{
|
|
||||||
scazs_impl(ctx, p1, 2);
|
|
||||||
}
|
|
||||||
IMPL_END;
|
|
||||||
|
|
||||||
IMPL_START_0(scazsl)
|
|
||||||
{
|
|
||||||
scazs_impl(ctx, p1, 4);
|
|
||||||
}
|
|
||||||
IMPL_END;
|
|
||||||
|
|
||||||
IMPL_START_0(scazsq)
|
|
||||||
{
|
|
||||||
scazs_impl(ctx, p1, 8);
|
|
||||||
}
|
|
||||||
IMPL_END;
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------//
|
|
||||||
|
|
||||||
static void cmps_impl(ctx_t *ctx, acc_t *p1, acc_t *p2, uint len)
|
static void cmps_impl(ctx_t *ctx, acc_t *p1, acc_t *p2, uint len)
|
||||||
{
|
{
|
||||||
ulong reg1, reg2;
|
ulong x1 = readmem(ctx, R(p1->reg), len);
|
||||||
|
ulong x2 = readmem(ctx, R(p2->reg), len);
|
||||||
if (p2) {
|
|
||||||
reg1 = p1->reg;
|
|
||||||
reg2 = p2->reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (p1) {
|
|
||||||
reg1 = RDI;
|
|
||||||
reg2 = p1->reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
reg1 = RDI;
|
|
||||||
reg2 = RSI;
|
|
||||||
}
|
|
||||||
|
|
||||||
ulong x1 = readmem(ctx, R(reg1), len);
|
|
||||||
ulong x2 = readmem(ctx, R(reg2), len);
|
|
||||||
|
|
||||||
COMPARE(x1, x2);
|
COMPARE(x1, x2);
|
||||||
|
|
||||||
STR_MOVE(reg1, len);
|
STR_MOVE(p1->reg, len);
|
||||||
STR_MOVE(reg2, len);
|
STR_MOVE(p2->reg, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
IMPL_START_0(cmpsb)
|
IMPL_START_0(cmpsb)
|
||||||
@ -269,33 +164,16 @@ IMPL_END;
|
|||||||
|
|
||||||
static void cmpzs_impl(ctx_t *ctx, acc_t *p1, acc_t *p2, uint len)
|
static void cmpzs_impl(ctx_t *ctx, acc_t *p1, acc_t *p2, uint len)
|
||||||
{
|
{
|
||||||
ulong reg1, reg2;
|
ulong x1 = readmem(ctx, R(p1->reg), len);
|
||||||
|
ulong x2 = readmem(ctx, R(p2->reg), len);
|
||||||
if (p2) {
|
|
||||||
reg1 = p1->reg;
|
|
||||||
reg2 = p2->reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (p1) {
|
|
||||||
reg1 = RDI;
|
|
||||||
reg2 = p1->reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
reg1 = RDI;
|
|
||||||
reg2 = RSI;
|
|
||||||
}
|
|
||||||
|
|
||||||
ulong x1 = readmem(ctx, R(reg1), len);
|
|
||||||
ulong x2 = readmem(ctx, R(reg2), len);
|
|
||||||
|
|
||||||
COMPARE(x1, x2);
|
COMPARE(x1, x2);
|
||||||
|
|
||||||
if (!x1 && !x2)
|
if (!x1 && !x2)
|
||||||
flg &= ~ZF;
|
flg &= ~ZF;
|
||||||
|
|
||||||
STR_MOVE(reg1, len);
|
STR_MOVE(p1->reg, len);
|
||||||
STR_MOVE(reg2, len);
|
STR_MOVE(p2->reg, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
IMPL_START_0(cmpzsb)
|
IMPL_START_0(cmpzsb)
|
||||||
@ -326,30 +204,13 @@ IMPL_END;
|
|||||||
|
|
||||||
static void movs_impl(ctx_t *ctx, acc_t *p1, acc_t *p2, uint len)
|
static void movs_impl(ctx_t *ctx, acc_t *p1, acc_t *p2, uint len)
|
||||||
{
|
{
|
||||||
ulong reg1, reg2;
|
ulong x = readmem(ctx, R(p2->reg), len);
|
||||||
|
writemem(ctx, x, R(p1->reg), len);
|
||||||
if (p2) {
|
|
||||||
reg1 = p1->reg;
|
|
||||||
reg2 = p2->reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (p1) {
|
|
||||||
reg1 = RDI;
|
|
||||||
reg2 = p1->reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
reg1 = RDI;
|
|
||||||
reg2 = RSI;
|
|
||||||
}
|
|
||||||
|
|
||||||
ulong x = readmem(ctx, R(reg2), len);
|
|
||||||
writemem(ctx, x, R(reg1), len);
|
|
||||||
|
|
||||||
flg = (x == 0 ? flg|ZF : flg&~ZF);
|
flg = (x == 0 ? flg|ZF : flg&~ZF);
|
||||||
|
|
||||||
STR_MOVE(reg1, len);
|
STR_MOVE(p1->reg, len);
|
||||||
STR_MOVE(reg2, len);
|
STR_MOVE(p2->reg, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
IMPL_START_0(movsb)
|
IMPL_START_0(movsb)
|
||||||
|
298
vm/pc/decd.c
298
vm/pc/decd.c
@ -4,7 +4,7 @@
|
|||||||
#include <pc/arch.h>
|
#include <pc/arch.h>
|
||||||
|
|
||||||
//
|
//
|
||||||
// Imperatively read the "DECD" file before reading this code
|
// Read the "DECD" file before reading this code
|
||||||
//
|
//
|
||||||
|
|
||||||
static void check_param_type(ctx_t *ctx, instr_t *in, uint prm, uchar fmt)
|
static void check_param_type(ctx_t *ctx, instr_t *in, uint prm, uchar fmt)
|
||||||
@ -26,113 +26,6 @@ static void check_param_type(ctx_t *ctx, instr_t *in, uint prm, uchar fmt)
|
|||||||
"fmt=0x%x prm=0x%x", in->full, fmt, prm);
|
"fmt=0x%x prm=0x%x", in->full, fmt, prm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void decode(ctx_t *ctx)
|
|
||||||
{
|
|
||||||
char *illmsg;
|
|
||||||
|
|
||||||
instr_t *in;
|
|
||||||
|
|
||||||
acc_t p1 = { 0 };
|
|
||||||
acc_t p2 = { 0 };
|
|
||||||
|
|
||||||
bool rep = 0;
|
|
||||||
uint cond = 0;
|
|
||||||
bool lock, nomore;
|
|
||||||
|
|
||||||
ushort w1, w2;
|
|
||||||
uchar f1 = 0, f2 = 0;
|
|
||||||
|
|
||||||
ulong pc = rip;
|
|
||||||
|
|
||||||
// Instruction counter
|
|
||||||
R(RX0)++;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Process the first word of the instruction
|
|
||||||
//
|
|
||||||
w1 = ctx->get(ctx);
|
|
||||||
|
|
||||||
// Extract first word flags
|
|
||||||
|
|
||||||
lock = !!(w1 & PREF_LOCK);
|
|
||||||
nomore = !!(w1 & PREF_NOMORE);
|
|
||||||
|
|
||||||
w1 &= ~(PREF_LOCK|PREF_NOMORE);
|
|
||||||
|
|
||||||
// Find instruction
|
|
||||||
|
|
||||||
if (w1 >= NINSTRS)
|
|
||||||
{
|
|
||||||
illmsg = "No such INSTR";
|
|
||||||
goto ill;
|
|
||||||
}
|
|
||||||
|
|
||||||
in = &ctx->i[w1];
|
|
||||||
|
|
||||||
if (nomore)
|
|
||||||
goto skip_w2;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Process second word
|
|
||||||
//
|
|
||||||
|
|
||||||
w2 = ctx->get(ctx);
|
|
||||||
|
|
||||||
// REP and COND
|
|
||||||
rep = !!(w2 & PREF_REP);
|
|
||||||
cond = (w2 & BITS_COND) >> COND_SHIFT;
|
|
||||||
|
|
||||||
// F1 and F2
|
|
||||||
f1 = (w2 >> F1_SHIFT) & Fx_MASK;
|
|
||||||
f2 = w2 & Fx_MASK;
|
|
||||||
|
|
||||||
skip_w2:
|
|
||||||
|
|
||||||
//
|
|
||||||
// Deal with operand 1
|
|
||||||
//
|
|
||||||
|
|
||||||
if (in->prm1 == NOPRM)
|
|
||||||
{
|
|
||||||
if (f1 || f2)
|
|
||||||
{
|
|
||||||
illmsg = "FT1 and/or FT2 filled for 0-param INSTR";
|
|
||||||
goto ill;
|
|
||||||
}
|
|
||||||
|
|
||||||
exec_instr(ctx, in, NULL, NULL, lock, rep, cond, pc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
check_param_type(ctx, in, in->prm1, f1);
|
|
||||||
extract_param(ctx, &p1, f1);
|
|
||||||
|
|
||||||
//
|
|
||||||
// Deal with operand 2
|
|
||||||
//
|
|
||||||
|
|
||||||
if (in->prm2 == NOPRM)
|
|
||||||
{
|
|
||||||
if (f2)
|
|
||||||
{
|
|
||||||
illmsg = "FT2 filled for 1-param INSTR";
|
|
||||||
goto ill;
|
|
||||||
}
|
|
||||||
|
|
||||||
exec_instr(ctx, in, &p1, NULL, lock, rep, cond, pc);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
check_param_type(ctx, in, in->prm2, f2);
|
|
||||||
extract_param(ctx, &p2, f2);
|
|
||||||
|
|
||||||
exec_instr(ctx, in, &p1, &p2, lock, rep, cond, pc);
|
|
||||||
return;
|
|
||||||
|
|
||||||
ill:
|
|
||||||
_except(ctx, E_ILL, illmsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Verify that access to a certain register is legal
|
// Verify that access to a certain register is legal
|
||||||
//
|
//
|
||||||
@ -251,119 +144,110 @@ void extract_param(ctx_t *ctx, acc_t *p, uchar fmt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool eval_cond(ctx_t *ctx, uint cond)
|
void decode(ctx_t *ctx)
|
||||||
{
|
{
|
||||||
bool neg = cond & (1 << 4);
|
char *illmsg;
|
||||||
bool ok;
|
|
||||||
|
|
||||||
cond &= ~(1 << 4);
|
instr_t *in;
|
||||||
|
|
||||||
switch (cond)
|
acc_t p1 = { 0 };
|
||||||
|
acc_t p2 = { 0 };
|
||||||
|
|
||||||
|
bool rep = 0;
|
||||||
|
uint cond = 0;
|
||||||
|
bool lock, nomore;
|
||||||
|
|
||||||
|
ushort w1, w2;
|
||||||
|
uchar f1 = 0, f2 = 0;
|
||||||
|
|
||||||
|
ulong pc = rip;
|
||||||
|
|
||||||
|
// Instruction counter
|
||||||
|
R(RX0)++;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Process the first word of the instruction
|
||||||
|
//
|
||||||
|
w1 = ctx->get(ctx);
|
||||||
|
|
||||||
|
// Extract first word flags
|
||||||
|
|
||||||
|
lock = !!(w1 & PREF_LOCK);
|
||||||
|
nomore = !!(w1 & PREF_NOMORE);
|
||||||
|
|
||||||
|
w1 &= ~(PREF_LOCK|PREF_NOMORE);
|
||||||
|
|
||||||
|
// Find instruction
|
||||||
|
|
||||||
|
if (w1 >= NINSTRS)
|
||||||
{
|
{
|
||||||
case CD_NONE: ok = 1; break;
|
illmsg = "No such INSTR";
|
||||||
|
goto ill;
|
||||||
case CD_C: ok = flg&CF; break;
|
|
||||||
case CD_O: ok = flg&OF; break;
|
|
||||||
case CD_Z: ok = flg&ZF; break;
|
|
||||||
case CD_S: ok = flg&SF; break;
|
|
||||||
case CD_P: ok = flg&PF; break;
|
|
||||||
|
|
||||||
case CD_A: ok = !(flg&CF || flg&ZF); break;
|
|
||||||
case CD_AE: ok = !(flg&CF); break;
|
|
||||||
|
|
||||||
case CD_B: ok = flg&CF; break;
|
|
||||||
case CD_BE: ok = flg&CF || flg&ZF; break;
|
|
||||||
|
|
||||||
case CD_G: ok = !(flg&ZF) && (!(flg&SF) == !(flg&OF)); break;
|
|
||||||
case CD_GE: ok = !(flg&SF) == !(flg&OF); break;
|
|
||||||
|
|
||||||
case CD_L: ok = !(flg&SF) != !(flg&OF); break;
|
|
||||||
case CD_LE: ok = flg&ZF || (!(flg&SF) != !(flg&OF)); break;
|
|
||||||
|
|
||||||
case CD_CXZ: ok = !rcx; break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
_except(ctx, E_ILL, "Invalid COND value: 0x%x", (neg?cond|(1<<4):cond));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return neg ? !ok : !!ok;
|
in = &ctx->i[w1];
|
||||||
|
|
||||||
|
if (nomore)
|
||||||
|
goto skip_w2;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Process second word
|
||||||
|
//
|
||||||
|
|
||||||
|
w2 = ctx->get(ctx);
|
||||||
|
|
||||||
|
// REP and COND
|
||||||
|
rep = !!(w2 & PREF_REP);
|
||||||
|
cond = (w2 & BITS_COND) >> COND_SHIFT;
|
||||||
|
|
||||||
|
// F1 and F2
|
||||||
|
f1 = (w2 >> F1_SHIFT) & Fx_MASK;
|
||||||
|
f2 = w2 & Fx_MASK;
|
||||||
|
|
||||||
|
skip_w2:
|
||||||
|
|
||||||
|
//
|
||||||
|
// Deal with operand 1
|
||||||
|
//
|
||||||
|
|
||||||
|
if (in->prm1 == NOPRM)
|
||||||
|
{
|
||||||
|
if (f1 || f2)
|
||||||
|
{
|
||||||
|
illmsg = "FT1 and/or FT2 filled for 0-param INSTR";
|
||||||
|
goto ill;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exec_instr(ctx, in, NULL, NULL, lock, rep, cond, pc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
check_param_type(ctx, in, in->prm1, f1);
|
||||||
|
extract_param(ctx, &p1, f1);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Executes an instruction
|
// Deal with operand 2
|
||||||
//
|
//
|
||||||
void exec_instr(ctx_t *ctx,
|
|
||||||
instr_t *in,
|
if (in->prm2 == NOPRM)
|
||||||
acc_t *p1,
|
|
||||||
acc_t *p2,
|
|
||||||
bool lock,
|
|
||||||
bool rep,
|
|
||||||
uint cond,
|
|
||||||
ulong pc)
|
|
||||||
{
|
{
|
||||||
bool out;
|
if (f2)
|
||||||
ulong r1 = 0, r2 = 0;
|
{
|
||||||
|
illmsg = "FT2 filled for 1-param INSTR";
|
||||||
|
goto ill;
|
||||||
|
}
|
||||||
|
|
||||||
// Debugging
|
exec_instr(ctx, in, &p1, NULL, lock, rep, cond, pc);
|
||||||
dump_instr(ctx, in, p1, p2, lock, rep, cond, pc);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
check_param_type(ctx, in, in->prm2, f2);
|
||||||
// For REPs we evaluate the condition AFTER running the instruction,
|
extract_param(ctx, &p2, f2);
|
||||||
// in a do ... while(cond) fashion
|
|
||||||
//
|
exec_instr(ctx, in, &p1, &p2, lock, rep, cond, pc);
|
||||||
if (!rep && !eval_cond(ctx, cond))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
do_rep:
|
ill:
|
||||||
|
_except(ctx, E_ILL, illmsg);
|
||||||
out = in->func(ctx, p1, p2, &r1, &r2);
|
|
||||||
|
|
||||||
if (out)
|
|
||||||
{
|
|
||||||
if (p1->type == A_REG)
|
|
||||||
R(p1->reg) = r1;
|
|
||||||
|
|
||||||
else if (p1->type == A_IMM64)
|
|
||||||
_except(ctx, E_ACC, "Trying to output to an IMM64");
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
assert(ACC_IS_MEM(p1));
|
|
||||||
writemem(ctx, r1, p1->addr, p1->mlen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out == 2)
|
|
||||||
{
|
|
||||||
if (p2->type == A_REG)
|
|
||||||
R(p2->reg) = r2;
|
|
||||||
|
|
||||||
else if (p2->type == A_IMM64)
|
|
||||||
_except(ctx, E_ACC, "Trying to output to an IMM64");
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
assert(ACC_IS_MEM(p2));
|
|
||||||
writemem(ctx, r2, p2->addr, p2->mlen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rep)
|
|
||||||
{
|
|
||||||
// RCX remains untouched when condition fails
|
|
||||||
if (!eval_cond(ctx, cond))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (rcx > 0)
|
|
||||||
rcx--;
|
|
||||||
|
|
||||||
if (rcx == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Show that we're REP'ing
|
|
||||||
dump_instr(ctx, in, p1, p2, lock, rep, cond, pc);
|
|
||||||
|
|
||||||
goto do_rep;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,8 +78,11 @@ void dump_instr(ctx_t *ctx,
|
|||||||
log("%s", cond_suffixes[cond]);
|
log("%s", cond_suffixes[cond]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rep && cond != CD_CXZ)
|
if (!rep
|
||||||
log("\t\t");
|
#if _ATT_STYLE == 1
|
||||||
|
&& cond != CD_CXZ
|
||||||
|
#endif
|
||||||
|
) log("\t\t");
|
||||||
|
|
||||||
else
|
else
|
||||||
log("\t");
|
log("\t");
|
||||||
|
121
vm/pc/exec.c
Normal file
121
vm/pc/exec.c
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
// The OS/K Team licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
#include <pc/arch.h>
|
||||||
|
|
||||||
|
static bool eval_cond(ctx_t *ctx, uint cond)
|
||||||
|
{
|
||||||
|
bool neg = cond & (1 << 4);
|
||||||
|
bool ok;
|
||||||
|
|
||||||
|
cond &= ~(1 << 4);
|
||||||
|
|
||||||
|
switch (cond)
|
||||||
|
{
|
||||||
|
case CD_NONE: ok = 1; break;
|
||||||
|
|
||||||
|
case CD_C: ok = flg&CF; break;
|
||||||
|
case CD_O: ok = flg&OF; break;
|
||||||
|
case CD_Z: ok = flg&ZF; break;
|
||||||
|
case CD_S: ok = flg&SF; break;
|
||||||
|
case CD_P: ok = flg&PF; break;
|
||||||
|
|
||||||
|
case CD_A: ok = !(flg&CF || flg&ZF); break;
|
||||||
|
case CD_AE: ok = !(flg&CF); break;
|
||||||
|
|
||||||
|
case CD_B: ok = flg&CF; break;
|
||||||
|
case CD_BE: ok = flg&CF || flg&ZF; break;
|
||||||
|
|
||||||
|
case CD_G: ok = !(flg&ZF) && (!(flg&SF) == !(flg&OF)); break;
|
||||||
|
case CD_GE: ok = !(flg&SF) == !(flg&OF); break;
|
||||||
|
|
||||||
|
case CD_L: ok = !(flg&SF) != !(flg&OF); break;
|
||||||
|
case CD_LE: ok = flg&ZF || (!(flg&SF) != !(flg&OF)); break;
|
||||||
|
|
||||||
|
case CD_CXZ: ok = !rcx; break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
_except(ctx, E_ILL, "Invalid COND value: 0x%x", (neg?cond|(1<<4):cond));
|
||||||
|
}
|
||||||
|
|
||||||
|
return neg ? !ok : !!ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Executes an instruction
|
||||||
|
//
|
||||||
|
void exec_instr(ctx_t *ctx,
|
||||||
|
instr_t *in,
|
||||||
|
acc_t *p1,
|
||||||
|
acc_t *p2,
|
||||||
|
bool lock,
|
||||||
|
bool rep,
|
||||||
|
uint cond,
|
||||||
|
ulong pc)
|
||||||
|
{
|
||||||
|
bool out;
|
||||||
|
ulong r1 = 0, r2 = 0;
|
||||||
|
|
||||||
|
// Debugging
|
||||||
|
dump_instr(ctx, in, p1, p2, lock, rep, cond, pc);
|
||||||
|
|
||||||
|
//
|
||||||
|
// For REPs we evaluate the condition AFTER running the instruction,
|
||||||
|
// in a do ... while(cond) fashion
|
||||||
|
//
|
||||||
|
if (!rep && !eval_cond(ctx, cond))
|
||||||
|
return;
|
||||||
|
|
||||||
|
do_rep:
|
||||||
|
|
||||||
|
out = in->func(ctx, p1, p2, &r1, &r2);
|
||||||
|
|
||||||
|
if (out)
|
||||||
|
{
|
||||||
|
if (p1->type == A_REG)
|
||||||
|
R(p1->reg) = r1;
|
||||||
|
|
||||||
|
else if (p1->type == A_IMM64)
|
||||||
|
_except(ctx, E_ACC, "Trying to output to an IMM64");
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(ACC_IS_MEM(p1));
|
||||||
|
writemem(ctx, r1, p1->addr, p1->mlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out == 2)
|
||||||
|
{
|
||||||
|
if (p2->type == A_REG)
|
||||||
|
R(p2->reg) = r2;
|
||||||
|
|
||||||
|
else if (p2->type == A_IMM64)
|
||||||
|
_except(ctx, E_ACC, "Trying to output to an IMM64");
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(ACC_IS_MEM(p2));
|
||||||
|
writemem(ctx, r2, p2->addr, p2->mlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rep)
|
||||||
|
{
|
||||||
|
// RCX remains untouched when condition fails
|
||||||
|
if (!eval_cond(ctx, cond))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (rcx > 0)
|
||||||
|
rcx--;
|
||||||
|
|
||||||
|
if (rcx == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Show that we're REP'ing
|
||||||
|
dump_instr(ctx, in, p1, p2, lock, rep, cond, pc);
|
||||||
|
|
||||||
|
goto do_rep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user