From 47b26774309e3a2b317f0de7adc93227d5d38aaf Mon Sep 17 00:00:00 2001 From: julianb0 Date: Sun, 16 Jun 2019 21:17:56 +0200 Subject: [PATCH] rep --- Makefile | 2 +- as/k-as.py | 33 ++++++++++++++++----------------- ka/crt/str/strcmp.k | 2 +- ka/crt/str/strcpy.k | 4 ++-- ka/crt/str/strlen.k | 2 +- ka/crt/str/strrev.k | 14 ++++++-------- ka/main.k | 5 ++--- vm/in/INSTRS | 35 ++++++++++++++++++++++++++++++++++- vm/in/string.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 106 insertions(+), 34 deletions(-) diff --git a/Makefile b/Makefile index 2105f2b..82c324b 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ all: kas kpc: @cd vm && make --no-print-directory verbose=no -kas: kpc as/k-as.py as/regs.lst as/ +kas: kpc as/regs.lst as/k-as.py @cp vm/in/instrs.lst as DOSK = $(shell find ka -name '*.k') diff --git a/as/k-as.py b/as/k-as.py index 425caa2..25bc874 100755 --- a/as/k-as.py +++ b/as/k-as.py @@ -394,26 +394,25 @@ def parse_instr(line): # Word 2 (rep|cond|ft1|ft2) w2 = 0 - if '.' in instr: - w2 |= get_cond_mask(instr.split('.', 1)[1], line) - instr = instr.split('.', 1)[0] + if len(instr) > 2 and '.' in instr: + instr, suf = instr.split('.', 1) + + if len(instr) == 0: + print("Missing instruction name before suffixes: {}".format(line)) - else: - instr = instr + if len(suf) > 2 and suf[:3] == "rep": + if len(suf) > 3: + suf = suf[3:] - if instr == "rep": - if params == None: - print("Missing instruction after rep prefix: {}".format(line)) - leave() - sys.exit(1) + if len(suf) > 0 and suf[0] == '.': + suf = suf[1:] + else: + suf = '' - w2 |= 0x8000 # 16th bit - - if len(params.split(' ', 1)) == 2: - instr, params = params.split(' ', 1) - else: - instr = params.split(' ', 1)[0] - params = None + w2 |= 0x8000 # REP + + if len(suf) > 0: + w2 |= get_cond_mask(suf, line) instr_name = instr instr_args = '' diff --git a/ka/crt/str/strcmp.k b/ka/crt/str/strcmp.k index 404545d..f33de41 100644 --- a/ka/crt/str/strcmp.k +++ b/ka/crt/str/strcmp.k @@ -21,7 +21,7 @@ strncmp: mov.cxz rax, 0 ret.cxz - rep.e cmpzsb ax0, ax1 + cmpzsb.rep.e ax0, ax1 mov rax, b[ax0] sub rax, b[ax1] diff --git a/ka/crt/str/strcpy.k b/ka/crt/str/strcpy.k index a9feeeb..80730a6 100644 --- a/ka/crt/str/strcpy.k +++ b/ka/crt/str/strcpy.k @@ -15,7 +15,7 @@ strncpy: mov rcx, ax2 ret.cxz - rep.nz movsb ax0, ax1 + movsb.rep.nz ax0, ax1 ret @@ -29,7 +29,7 @@ strnzcpy: dec rcx jmp.cxz .1 - rep.nz movsb ax0, ax1 + movsb.rep.nz ax0, ax1 .1: mov b[ax0], 0 diff --git a/ka/crt/str/strlen.k b/ka/crt/str/strlen.k index 2b0ddd0..b3af334 100644 --- a/ka/crt/str/strlen.k +++ b/ka/crt/str/strlen.k @@ -6,7 +6,7 @@ ; strnlen: mov rcx, ax1 - rep.nz scasb ax0, 0 + scasb.rep.nz ax0, 0 mov rax, ax1 sub rax, rcx diff --git a/ka/crt/str/strrev.k b/ka/crt/str/strrev.k index d2e98a0..b2602ae 100644 --- a/ka/crt/str/strrev.k +++ b/ka/crt/str/strrev.k @@ -16,10 +16,9 @@ strrev: ; go to str's end, just before ; the null terminator -.1: - test b[ax1+1], b[ax1+1] - inc.nz ax1 - jmp.nz .1 + mov rcx, STRLEN_MAX + scazsb.rep.nz ax1 + dec ax1 .2: ; copy, going backward though str @@ -48,10 +47,9 @@ strrev2: ; go to str's end, just before ; the null terminator -.1: - test b[ax1+1], b[ax1+1] - inc.nz ax1 - jmp.nz .1 + mov rcx, STRLEN_MAX + scazsb.rep.nz ax1 + dec ax1 ; increase ax0 while decreasing ax1, performing exchanges .2: diff --git a/ka/main.k b/ka/main.k index c101643..5400d9a 100644 --- a/ka/main.k +++ b/ka/main.k @@ -5,7 +5,7 @@ ; Main function ; main: - call showoff + call itoa_test ret showoff: @@ -35,12 +35,11 @@ ramdev_test: ret stosb_test: - cld mov rcx, 11 mov rax, 33 mov rdi, .buf mov rsi, .buf - rep stosb + stosb.rep mov rbx, rdi sub rbx, rsi diff --git a/vm/in/INSTRS b/vm/in/INSTRS index c21fe09..abc15ba 100644 --- a/vm/in/INSTRS +++ b/vm/in/INSTRS @@ -412,10 +412,43 @@ lodsb r r # When one parameter is given, %str = RDI and $val = $1 # When two parameters are given, %str = $1 and $val = $2 # +# 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 +# +# 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 + # # Compare bytes in strings (CMPSx) # @@ -445,7 +478,7 @@ cmpsb r r # Behaves precisely like CMPSx, except in the following case: # - If both [%str1] and [%str2] are zero, clears ZF (indicating NOT EQUAL) # -# This prevents 'rep.e cmpsb' from looping infinitely when both strings +# This prevents 'REP.Z CMPZSx' from looping infinitely when both strings # have the exact same content; this allows for short strcmp's # cmpzsb diff --git a/vm/in/string.c b/vm/in/string.c index 51b682f..74a1ea6 100644 --- a/vm/in/string.c +++ b/vm/in/string.c @@ -170,6 +170,49 @@ 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) { ulong reg1, reg2;