Skip to content

Commit

Permalink
Support ram wraparound
Browse files Browse the repository at this point in the history
  • Loading branch information
remko committed Nov 1, 2023
1 parent 2b9c688 commit 95ccd78
Show file tree
Hide file tree
Showing 4 changed files with 249 additions and 122 deletions.
85 changes: 55 additions & 30 deletions scripts/emuwasm.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ const instructions = [
(local.set $t (#T))
(local.set $n (#N))
(#set 2 -2)
(i32.store8 (i32.add (i32.const 0x10200) (local.get $t)) (local.get $n))
(i32.store8 offset=0x10200 (local.get $t) (local.get $n))
(call $deo (local.get $t) (local.get $n))
`,
],
Expand Down Expand Up @@ -288,7 +288,7 @@ const instructions = [
`
(local.set $t (#T))
(#set 0 -1)
(if (local.get $t) (then (local.set $pc (i32.add (i32.const 2) (i32.add (local.get $pc) (#signedswap (i32.load16_u (local.get $pc))))))) (else (local.set $pc (i32.add (local.get $pc) (i32.const 2)))))
(if (local.get $t) (then (local.set $pc (i32.add (i32.const 2) (i32.add (local.get $pc) (#peek16s (local.get $pc)))))) (else (local.set $pc (i32.add (local.get $pc) (i32.const 2)))))
`,
],
[
Expand Down Expand Up @@ -432,50 +432,53 @@ const instructions = [
`
(local.set $t (#T))
(#set 1 1)
(#T2^! (i32.load16_u (local.get $t)))
(#T2<zmem! (local.get $t))
`,
],
[
"STZ2",
`
(local.set $t (#T))
(local.set $n (#H2^))
(local.set $n (#N))
(local.set $l (#L))
(#set 3 -3)
(i32.store16 (local.get $t) (local.get $n))
(#poke2z (local.get $t) (local.get $l) (local.get $n))
`,
],
[
"LDR2",
`
(local.set $t (#Ts))
(#set 1 1)
(#T2^! (i32.load16_u (i32.add (local.get $pc) (local.get $t))))
(#T2<meme! (i32.add (local.get $pc) (local.get $t)))
`,
],
[
"STR2",
`
(local.set $t (#Ts))
(local.set $n (#H2^))
(local.set $n (#N))
(local.set $l (#L))
(#set 3 -3)
(i32.store16 (i32.add (local.get $pc) (local.get $t)) (local.get $n))
(#poke2e (i32.add (local.get $pc) (local.get $t)) (local.get $l) (local.get $n))
`,
],
[
"LDA2",
`
(local.set $t (#T2))
(#set 2 0)
(#T2^! (i32.load16_u (local.get $t)))
(#T2<mem! (local.get $t))
`,
],
[
"STA2",
`
(local.set $t (#T2))
(local.set $n (#N2^))
(local.set $n (#L))
(local.set $l (#X))
(#set 4 -4)
(i32.store16 (local.get $t) (local.get $n))
(#poke2 (local.get $t) (local.get $l) (local.get $n))
`,
],
[
Expand All @@ -494,10 +497,10 @@ const instructions = [
(local.set $n (#N))
(local.set $l (#L))
(#set 3 -3)
(i32.store8 (i32.add (i32.const 0x10200) (local.get $t)) (local.get $l))
(i32.store8 offset=0x10200 (local.get $t) (local.get $l))
(call $deo (local.get $t) (local.get $l))
(i32.store8 (i32.add (i32.const 0x10201) (local.get $t)) (local.get $n))
(call $deo (i32.add (local.get $t) (i32.const 1)) (local.get $n))
(i32.store8 offset=0x10200 (local.tee $t (i32.and (i32.add (local.get $t) (i32.const 1)) (i32.const 0xff))) (local.get $n))
(call $deo (local.get $t) (local.get $n))
`,
],
[
Expand Down Expand Up @@ -575,7 +578,7 @@ const instructions = [
[
"JMI",
`
(local.set $pc (i32.add (i32.const 2) (i32.add (local.get $pc) (#signedswap (i32.load16_u (local.get $pc))))))
(local.set $pc (i32.add (i32.const 2) (i32.add (local.get $pc) (#peek16s (local.get $pc)))))
`,
],
["INCr", null],
Expand Down Expand Up @@ -614,7 +617,7 @@ const instructions = [
`
(#set 0 2)
(#T2! (local.tee $n (i32.add (local.get $pc) (i32.const 2))))
(local.set $pc (i32.add (local.get $n) (#signedswap (i32.load16_u (local.get $pc)))))
(local.set $pc (i32.add (local.get $n) (#peek16s (local.get $pc))))
`,
],
["INC2r", null],
Expand Down Expand Up @@ -691,7 +694,7 @@ const instructions = [
"LIT2",
`
(#set 0 2)
(#T2^! (i32.load16_u (local.get $pc)))
(#T2<mem! (local.get $pc))
(local.set $pc (i32.add (local.get $pc) (i32.const 2)))
`,
],
Expand Down Expand Up @@ -804,7 +807,7 @@ function generate() {
(local $n i32)
(local $l i32)
(local $val i32)
(local $signedswap_val i32)
(local $mval i32)
(if (i32.eqz (local.get $pc)) (then (return)))
(if (i32.load8_u (i32.const 0x1020f)) (then (return)))
Expand Down Expand Up @@ -855,14 +858,29 @@ function generate() {

const macros = [
[
"signedswap",
`(i32.shr_s (i32.or (i32.shl (i32.and (local.tee $signedswap_val #1) (i32.const 0xff)) (i32.const 24)) (i32.shl (i32.and (local.get $signedswap_val) (i32.const 0xff00)) (i32.const 8))) (i32.const 16))`,
"peek16s",
`(i32.or (i32.shr_s (i32.shl (i32.load8_u #1) (i32.const 24)) (i32.const 16)) (i32.load8_u (i32.and (i32.add #1 (i32.const 1)) (i32.const 0xffff))))`,
],
[
"poke2",
`(i32.store8 #1 #2) (i32.store8 (i32.and (i32.add #1 (i32.const 1)) (i32.const 0xffff)) #3)`,
],
// with an expression address
[
"poke2e",
`(i32.store8 (local.tee $mval (i32.and #1 (i32.const 0xffff))) #2) (i32.store8 (i32.and (i32.add (local.get $mval) (i32.const 1)) (i32.const 0xffff)) #3)`,
],
// zero-page (not wrapping)
[
"poke2z",
`(i32.store8 #1 #2) (i32.store8 (i32.add #1 (i32.const 1)) #3)`,
],
];
for (const [regname, regidx] of [
["T", 0],
["N", 2],
["L", 4],
["X", 6],
["H", 1],
]) {
let reg = regname;
Expand All @@ -879,24 +897,31 @@ function generate() {
})) (i32.const 0xff)) (i32.shr_u (local.get $val) (i32.const 8)))`,
],
[
// Store short endianness-swapped
reg + "2^!",
// Copy from memory
reg + "2<mem!",
`(i32.store8 offset=${offset} (i32.and (i32.add (local.get $${stack}p) (i32.const ${
regidx + 1
})) (i32.const 0xff)) (i32.and (local.tee $val #1) (i32.const 0xff))) (i32.store8 offset=${offset} (i32.and (i32.add (local.get $${stack}p) (i32.const ${regidx})) (i32.const 0xff)) (i32.shr_u (local.get $val) (i32.const 8)))`,
})) (i32.const 0xff)) (i32.load8_u #1)) (i32.store8 offset=${offset} (i32.and (i32.add (local.get $${stack}p) (i32.const ${regidx})) (i32.const 0xff)) (i32.load8_u (i32.and (i32.add #1 (i32.const 1)) (i32.const 0xffff))))`,
],
[
reg + "2",
`(i32.or (i32.load8_u offset=${offset} (i32.and (i32.add (local.get $${stack}p) (i32.const ${regidx})) (i32.const 0xff))) (i32.shl (i32.load8_u offset=${offset} (i32.and (i32.add (local.get $${stack}p) (i32.const ${
// Copy from zero-page memory
reg + "2<zmem!",
`(i32.store8 offset=${offset} (i32.and (i32.add (local.get $${stack}p) (i32.const ${
regidx + 1
})) (i32.const 0xff))) (i32.const 8)))`,
})) (i32.const 0xff)) (i32.load8_u #1)) (i32.store8 offset=${offset} (i32.and (i32.add (local.get $${stack}p) (i32.const ${regidx})) (i32.const 0xff)) (i32.load8_u (i32.add #1 (i32.const 1))))`,
],
// Load endianness-swapped
[
reg + "2^",
`(i32.or (i32.shl (i32.load8_u offset=${offset} (i32.and (i32.add (local.get $${stack}p) (i32.const ${regidx})) (i32.const 0xff))) (i32.const 8)) (i32.load8_u offset=${offset} (i32.and (i32.add (local.get $${stack}p) (i32.const ${
// Copy from memory (with expression)
reg + "2<meme!",
`(i32.store8 offset=${offset} (i32.and (i32.add (local.get $${stack}p) (i32.const ${
regidx + 1
})) (i32.const 0xff))))`,
})) (i32.const 0xff)) (i32.load8_u (local.tee $mval #1))) (i32.store8 offset=${offset} (i32.and (i32.add (local.get $${stack}p) (i32.const ${regidx})) (i32.const 0xff)) (i32.load8_u (i32.and (i32.add (local.get $mval) (i32.const 1)) (i32.const 0xffff))))`,
],
[
reg + "2",
`(i32.or (i32.load8_u offset=${offset} (i32.and (i32.add (local.get $${stack}p) (i32.const ${regidx})) (i32.const 0xff))) (i32.shl (i32.load8_u offset=${offset} (i32.and (i32.add (local.get $${stack}p) (i32.const ${
regidx + 1
})) (i32.const 0xff))) (i32.const 8)))`,
],
...(regidx % 2 === 0
? [
Expand Down
100 changes: 80 additions & 20 deletions src/tests/opctest.tal
Original file line number Diff line number Diff line change
@@ -1,32 +1,36 @@
( Opcode Tester )
( Source: https://git.sr.ht/~rabbits/uxn-utils/tree/main/item/cli/opctest/opctest.tal )

|0013

@Zeropage &byte $1 &short $2

|0100

@on-reset ( -> )

( part 1
> LIT2: Puts a short on the stack
> #18 DEO: Write a letter in terminal )
> LIT: Puts a byte on the stack
> #18 DEO: Write a letter in terminal
> ;meta: Push short
> #06 DEO: Write to metadata ports )

LIT2 "kO #18 DEO #18 DEO #0a18 DEO
[ LIT2 "kO ] #18 DEO #18 DEO #0a18 DEO
;meta #06 DEO2

( part 2
> LITr: Put a byte on return stack
> LIT: Puts a byte on the stack
> STH: Move a byte from working stack to return stack
> STH2r: Move a short from return stack to working stack )

LITr "k LIT "O STH STH2r #18 DEO #18 DEO #0a18 DEO
[ LITr "k ] [ LIT "O ] STH STH2r #18 DEO #18 DEO #0a18 DEO

( part 3
> LIT2r: Put a short on return stack
> DUP: Duplicate byte
> ADDr: Add bytes on return stack )

LIT2r "k 4d #01 DUP STH ADDr STH ADDr STH2r #18 DEO #18 DEO #0a18 DEO
[ LIT2r "k 4d ] #01 DUP STH ADDr STH ADDr STH2r #18 DEO #18 DEO #0a18 DEO

( part 4
> JSI: Subroutine to relative absolute address
Expand All @@ -47,25 +51,74 @@
> LDA2k: Non-destructive load short from absolute address
> STA2: Store short at absolute address )

LIT2r 0000
[ LIT2r 0000 ]
;tests/end ;tests
&l
run-test STH ADDr
run-test [ LITr 00 ] STH ADD2r
INC2 INC2 GTH2k ?&l
POP2 POP2
STH2r ;Dict/done pstr
STH2r ;tests/end ;tests SUB2 #01 SFT2
EQU2 ;Dict/opctests test-part

( Part 7
> Testing that stacks are circular and wrapping
> Storing 12 at -1 and 34 at 0 )

POP #12 #34 ADD #46 EQU STH
POP #1234 ADD #46 EQU STH
POP2 #1111 #2222 ADD2 #3333 EQU2
STHr AND STHr AND
;Dict/stack-wrap test-part

( Part 8
> Testing RAM wrapping
> Storing 12 in 0xffff, and 34 in 0x0000 )

#1234 #ffff STA2
#ffff LDA #0000 LDA ADD #46 EQU
#ffff LDA2 ADD #46 EQU
AND ;Dict/ram-wrap test-part

( halt )
( Part 9
> Testing that zero-page is not wrapping )

#010f DEO
#1234 #ff STZ2
#ff LDZ #0100 LDA ADD #46 EQU
;Dict/zp-wrap test-part

( Part 10
> Testing that device page is wrapping
> TODO )

( end )

[ LIT &fail 80 ]
DUP #80 EQU ;Dict/result test-part
#0f DEO

#0a18 DEO
#010e DEO

BRK

@meta 00
( name ) "Opctest 0a
( details ) "A 20 "Testing 20 "Program 0a
( author ) "By 20 "Devine 20 "Lu 20 "Linvega 0a
( date ) "31 20 "Oct 20 "2023 $2

@test-part ( f name* -- )
pstr ?{
#01 ;on-reset/fail STA
;Dict/failed !pstr }
;Dict/passed !pstr

@run-test ( addr* -- addr* f )

LDA2k JSR2 DUP ?&pass
;Dict/failed pstr
[ LIT2 &name $2 ] pstr #0a18 DEO JMP2r
;Dict/missed pstr
[ LIT2 &name $2 ] pstr/ #0a18 DEO
#01 ;on-reset/fail STA JMP2r
&pass

JMP2r
Expand All @@ -78,8 +131,9 @@ JMP2r

@pstr ( str* -- )

LDAk ?&w POP2 JMP2r
&w LDAk #18 DEO INC2 LDAk ?&w
&w ( -- )
LDAk #18 DEO
INC2 & LDAk ?&w
POP2

JMP2r
Expand Down Expand Up @@ -166,7 +220,7 @@ JMP2r
&d #00 #ff EQU [ #00 ] EQU JMP2r
&e #f801 #f801 EQU2 [ #01 ] EQU JMP2r
&f #01f8 #01f8 EQU2 [ #01 ] EQU JMP2r
&g #f801 #01f8 EQU2 [ #00 ] EQU JMP2r ( HERE )
&g #f801 #01f8 EQU2 [ #00 ] EQU JMP2r
&h #01f8 #f801 EQU2 [ #00 ] EQU JMP2r
@op-neq ;Dict/neq !set
&a #f8 #f8 NEQ [ #00 ] EQU JMP2r
Expand Down Expand Up @@ -349,21 +403,27 @@ JMP2r

@special ( routine* -- f )

( test the stack order )
( test that the stack order is LIFO )
DUP2 STH2kr EQU2
ROT ROT DUP2r STHr STHr SWP EQU2 AND

JMP2r

@routine ( a b -- c ) ADD JMP2r
@subroutine ( -- ) LIT2 "kO #18 DEO #18 DEO #0a18 DEO JMP2r
@subroutine ( -- ) [ LIT2 "kO ] #18 DEO #18 DEO #0a18 DEO JMP2r
@Absolute &byte $1 &short $2
@phex ( short* -- ) SWP phex/b &b ( byte -- ) DUP #04 SFT phex/c &c ( char -- ) #0f AND DUP #09 GTH #27 MUL ADD #30 ADD #18 DEO JMP2r

@Dict [
&ok "Ok $1
&done "Tests 20 "Complete. 0a $1
&failed "-- 20 "failed: 20 $1
&opctests "Opcodes $1
&stack-wrap "Stack-wrap $1
&ram-wrap "RAM-wrap $1
&zp-wrap "Zeropage-wrap $1
&result "Result: $1
&passed 20 "passed! 0a $1
&missed "Opcode 20 "Failed 20 "-- 20 $1
&failed 20 "failed. 0a $1
&equ "EQU $1 &neq "NEQ $1 &gth "GTH $1 &lth "LTH $1
&add "ADD $1 &sub "SUB $1 &mul "MUL $1 &div "DIV $1
&inc "INC $1 &pop "POP $1 &dup "DUP $1 &nip "NIP $1
Expand Down
Loading

0 comments on commit 95ccd78

Please sign in to comment.