added sys.memcmp

This commit is contained in:
Irmen de Jong 2024-10-28 00:41:26 +01:00
parent a82f211f9a
commit 570b574b93
10 changed files with 384 additions and 20 deletions

View File

@ -177,6 +177,65 @@ _longcopy
}}
}
asmsub memcmp(uword address1 @R0, uword address2 @R1, uword size @AY) -> byte @A {
; Compares two blocks of memory
; Returns -1 (255), 0 or 1, meaning: block 1 sorts before, equal or after block 2.
%asm {{
sta P8ZP_SCRATCH_REG ; lsb(size)
sty P8ZP_SCRATCH_B1 ; msb(size)
lda cx16.r0
ldy cx16.r0+1
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda cx16.r1
ldy cx16.r1+1
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
ldx P8ZP_SCRATCH_B1
beq _no_msb_size
_loop_msb_size
ldy #0
- lda (P8ZP_SCRATCH_W1),y
cmp (P8ZP_SCRATCH_W2),y
bcs +
lda #-1
rts
+ beq +
lda #1
rts
+ iny
bne -
inc P8ZP_SCRATCH_W1+1
inc P8ZP_SCRATCH_W2+1
dec P8ZP_SCRATCH_B1 ; msb(size) -= 1
dex
bne _loop_msb_size
_no_msb_size
lda P8ZP_SCRATCH_REG ; lsb(size)
bne +
rts
+ ldy #0
- lda (P8ZP_SCRATCH_W1),y
cmp (P8ZP_SCRATCH_W2),y
bcs +
lda #-1
rts
+ beq +
lda #1
rts
+ iny
cpy P8ZP_SCRATCH_REG ; lsb(size)
bne -
lda #0
rts
}}
}
inline asmsub read_flags() -> ubyte @A {
%asm {{
php

View File

@ -726,6 +726,65 @@ _longcopy
}}
}
asmsub memcmp(uword address1 @R0, uword address2 @R1, uword size @AY) -> byte @A {
; Compares two blocks of memory
; Returns -1 (255), 0 or 1, meaning: block 1 sorts before, equal or after block 2.
%asm {{
sta P8ZP_SCRATCH_REG ; lsb(size)
sty P8ZP_SCRATCH_B1 ; msb(size)
lda cx16.r0
ldy cx16.r0+1
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda cx16.r1
ldy cx16.r1+1
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
ldx P8ZP_SCRATCH_B1
beq _no_msb_size
_loop_msb_size
ldy #0
- lda (P8ZP_SCRATCH_W1),y
cmp (P8ZP_SCRATCH_W2),y
bcs +
lda #-1
rts
+ beq +
lda #1
rts
+ iny
bne -
inc P8ZP_SCRATCH_W1+1
inc P8ZP_SCRATCH_W2+1
dec P8ZP_SCRATCH_B1 ; msb(size) -= 1
dex
bne _loop_msb_size
_no_msb_size
lda P8ZP_SCRATCH_REG ; lsb(size)
bne +
rts
+ ldy #0
- lda (P8ZP_SCRATCH_W1),y
cmp (P8ZP_SCRATCH_W2),y
bcs +
lda #-1
rts
+ beq +
lda #1
rts
+ iny
cpy P8ZP_SCRATCH_REG ; lsb(size)
bne -
lda #0
rts
}}
}
inline asmsub read_flags() -> ubyte @A {
%asm {{
php

View File

@ -725,6 +725,65 @@ _longcopy
}}
}
asmsub memcmp(uword address1 @R0, uword address2 @R1, uword size @AY) -> byte @A {
; Compares two blocks of memory
; Returns -1 (255), 0 or 1, meaning: block 1 sorts before, equal or after block 2.
%asm {{
sta P8ZP_SCRATCH_REG ; lsb(size)
sty P8ZP_SCRATCH_B1 ; msb(size)
lda cx16.r0
ldy cx16.r0+1
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda cx16.r1
ldy cx16.r1+1
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
ldx P8ZP_SCRATCH_B1
beq _no_msb_size
_loop_msb_size
ldy #0
- lda (P8ZP_SCRATCH_W1),y
cmp (P8ZP_SCRATCH_W2),y
bcs +
lda #-1
rts
+ beq +
lda #1
rts
+ iny
bne -
inc P8ZP_SCRATCH_W1+1
inc P8ZP_SCRATCH_W2+1
dec P8ZP_SCRATCH_B1 ; msb(size) -= 1
dex
bne _loop_msb_size
_no_msb_size
lda P8ZP_SCRATCH_REG ; lsb(size)
bne +
rts
+ ldy #0
- lda (P8ZP_SCRATCH_W1),y
cmp (P8ZP_SCRATCH_W2),y
bcs +
lda #-1
rts
+ beq +
lda #1
rts
+ iny
cpy P8ZP_SCRATCH_REG ; lsb(size)
bne -
lda #0
rts
}}
}
inline asmsub read_flags() -> ubyte @A {
%asm {{
php

View File

@ -1703,6 +1703,56 @@ _longcopy
}}
}
asmsub memcmp(uword address1 @R0, uword address2 @R1, uword size @AY) -> byte @A {
; Compares two blocks of memory
; Returns -1 (255), 0 or 1, meaning: block 1 sorts before, equal or after block 2.
%asm {{
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
ldx P8ZP_SCRATCH_W1+1
beq _no_msb_size
_loop_msb_size
ldy #0
- lda (cx16.r0),y
cmp (cx16.r1),y
bcs +
lda #-1
rts
+ beq +
lda #1
rts
+ iny
bne -
inc cx16.r0+1
inc cx16.r1+1
dec P8ZP_SCRATCH_W1+1
dex
bne _loop_msb_size
_no_msb_size
lda P8ZP_SCRATCH_W1
bne +
rts
+ ldy #0
- lda (cx16.r0),y
cmp (cx16.r1),y
bcs +
lda #-1
rts
+ beq +
lda #1
rts
+ iny
cpy P8ZP_SCRATCH_W1
bne -
lda #0
rts
}}
}
inline asmsub read_flags() -> ubyte @A {
%asm {{
php

View File

@ -279,6 +279,65 @@ _longcopy
}}
}
asmsub memcmp(uword address1 @R0, uword address2 @R1, uword size @AY) -> byte @A {
; Compares two blocks of memory
; Returns -1 (255), 0 or 1, meaning: block 1 sorts before, equal or after block 2.
%asm {{
sta P8ZP_SCRATCH_REG ; lsb(size)
sty P8ZP_SCRATCH_B1 ; msb(size)
lda cx16.r0
ldy cx16.r0+1
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
lda cx16.r1
ldy cx16.r1+1
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
ldx P8ZP_SCRATCH_B1
beq _no_msb_size
_loop_msb_size
ldy #0
- lda (P8ZP_SCRATCH_W1),y
cmp (P8ZP_SCRATCH_W2),y
bcs +
lda #-1
rts
+ beq +
lda #1
rts
+ iny
bne -
inc P8ZP_SCRATCH_W1+1
inc P8ZP_SCRATCH_W2+1
dec P8ZP_SCRATCH_B1 ; msb(size) -= 1
dex
bne _loop_msb_size
_no_msb_size
lda P8ZP_SCRATCH_REG ; lsb(size)
bne +
rts
+ ldy #0
- lda (P8ZP_SCRATCH_W1),y
cmp (P8ZP_SCRATCH_W2),y
bcs +
lda #-1
rts
+ beq +
lda #1
rts
+ iny
cpy P8ZP_SCRATCH_REG ; lsb(size)
bne -
lda #0
rts
}}
}
inline asmsub read_flags() -> ubyte @A {
%asm {{
php

View File

@ -73,6 +73,18 @@ sys {
}}
}
sub memcmp(uword address1, uword address2, uword size) -> byte {
; Compares two blocks of memory of up to 65535 bytes in size
; Returns -1 (255), 0 or 1, meaning: block 1 sorts before, equal or after block 2.
%ir {{
loadm.w r65533,sys.memcmp.address1
loadm.w r65534,sys.memcmp.address2
loadm.w r65535,sys.memcmp.size
syscall 47 (r65533.w, r65534.w, r65535.w) : r0.b
returnr.b r0
}}
}
sub exit(ubyte returnvalue) {
; -- immediately exit the program with a return code in the A register
%ir {{

View File

@ -296,6 +296,10 @@ sys (part of syslib)
Efficiently set a part of memory to the given (u)word value.
But the most efficient will always be to write a specialized fill routine in assembly yourself!
``memcmp (address1, address2, size)``
Compares two blocks of memory of up to 65535 bytes in size.
Returns -1 (255), 0 or 1, meaning: block 1 sorts before, equal or after block 2.
``read_flags () -> ubyte``
Returns the current value of the CPU status register.

View File

@ -3,6 +3,9 @@ TODO
- check benchmark score vs previous version
- writing a 'txt' block in user program suddenly spews out all textio unused reference warnings because of the %option merge promotion going on. Merging should probably be handled differently
Improve register load order in subroutine call args assignments:
in certain situations, the "wrong" order of evaluation of function call arguments is done which results
in overwriting registers that already got their value, which requires a lot of stack juggling (especially on plain 6502 cpu!)

View File

@ -1,18 +1,61 @@
%import textio
%import string
%option no_sysinit
%zeropage basicsafe
main {
sub start() {
alias prn = txt.print_ub
alias spc = txt.spc
alias nl = txt.nl
str name1 = "alfred"
str name2 = "aldrik"
str name3 = "aldrik"
prn(10)
spc()
prn(20)
spc()
prn(30)
nl()
uword block1 = memory("block1", 1000, 0)
uword block2 = memory("block2", 1000, 0)
uword block3 = memory("block3", 1000, 0)
sys.memset(block1, 1000, 0)
sys.memset(block2, 1000, 0)
sys.memset(block3, 1000, 0)
void string.copy(name1, block1+900)
void string.copy(name2, block2+900)
void string.copy(name3, block3+900)
txt.print_b(string.compare(name1, name2))
txt.spc()
txt.print_b(string.compare(name2, name3))
txt.spc()
txt.print_b(string.compare(name2, name1))
txt.nl()
txt.print_b(sys.memcmp(name1, name2, len(name1)))
txt.spc()
txt.print_b(sys.memcmp(name2, name3, len(name1)))
txt.spc()
txt.print_b(sys.memcmp(name2, name1, len(name1)))
txt.nl()
txt.nl()
name1[1] = 0
name2[1] = 0
name3[1] = 0
txt.print_b(string.compare(name1, name2))
txt.spc()
txt.print_b(string.compare(name2, name3))
txt.spc()
txt.print_b(string.compare(name2, name1))
txt.nl()
txt.print_b(sys.memcmp(name1, name2, len(name1)))
txt.spc()
txt.print_b(sys.memcmp(name2, name3, len(name1)))
txt.spc()
txt.print_b(sys.memcmp(name2, name1, len(name1)))
txt.nl()
txt.print_b(sys.memcmp(block1, block2, 1000))
txt.spc()
txt.print_b(sys.memcmp(block2, block3, 1000))
txt.spc()
txt.print_b(sys.memcmp(block2, block1, 1000))
txt.nl()
}
}

View File

@ -50,16 +50,14 @@ SYSCALLS:
37 = memset
38 = memsetw
39 = stringcopy
40 = ...unused...
41 = ...unused...
42 = memcopy_small
43 = load
44 = load_raw
45 = save
46 = delete
47 = rename
48 = directory
49 = getconsolesize
40 = load
41 = load_raw
42 = save
43 = delete
44 = rename
45 = directory
46 = getconsolesize
47 = memcmp
*/
enum class Syscall {
@ -109,7 +107,8 @@ enum class Syscall {
DELETE,
RENAME,
DIRECTORY,
GETGONSOLESIZE
GETGONSOLESIZE,
MEMCMP
;
companion object {
@ -271,6 +270,23 @@ object SysCalls {
else
returnValue(callspec.returns.single(), 1, vm)
}
Syscall.MEMCMP -> {
val (firstV, secondV, sizeV) = getArgValues(callspec.arguments, vm)
var firstAddr = (firstV as UShort).toInt()
var secondAddr = (secondV as UShort).toInt()
var size = (sizeV as UShort).toInt()
while(size>0) {
val comparison = vm.memory.getUB(firstAddr).compareTo(vm.memory.getUB(secondAddr))
if(comparison<0)
return returnValue(callspec.returns.single(), -1, vm)
else if(comparison>0)
return returnValue(callspec.returns.single(), 1, vm)
firstAddr++
secondAddr++
size--
}
return returnValue(callspec.returns.single(), 0, vm)
}
Syscall.RNDFSEED -> {
val seed = getArgValues(callspec.arguments, vm).single() as Double
if(seed>0) // always use negative seed, this mimics the behavior on CBM machines