mirror of
https://github.com/irmen/prog8.git
synced 2024-12-25 23:29:55 +00:00
added sys.memcmp
This commit is contained in:
parent
a82f211f9a
commit
570b574b93
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 {{
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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!)
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user