diff --git a/120allocate.subx b/120allocate.subx index 20595e64..c482ae07 100644 --- a/120allocate.subx +++ b/120allocate.subx @@ -879,7 +879,7 @@ zero-out: # start: (addr byte), size: int # curr/esi = start # i/ecx = 0 # while true - # if (i >= len) break + # if (i >= size) break # *curr = 0 # ++curr # ++i @@ -896,10 +896,10 @@ zero-out: # start: (addr byte), size: int 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi # var i/ecx: int = 0 31/xor 3/mod/direct 1/rm32/ecx . . . 1/r32/ecx . . # clear ecx - # edx = len + # edx = size 8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 2/r32/edx 0xc/disp8 . # copy *(ebp+12) to edx $zero-out:loop: - # if (i >= len) break + # if (i >= size) break 39/compare 3/mod/direct 1/rm32/ecx . . . 2/r32/edx . . # compare ecx with edx 7d/jump-if->= $zero-out:end/disp8 # *curr = 0 @@ -929,7 +929,7 @@ test-zero-out: 89/copy 3/mod/direct 1/rm32/ecx . . . 4/r32/esp . . # copy esp to ecx # zero-out(ecx, 3) # . . push args - 68/push 3/imm32/len + 68/push 3/imm32/size 51/push-ecx # . . call e8/call zero-out/disp32 diff --git a/308allocate-array.subx b/308allocate-array.subx index 2d3d1a9d..760b8090 100644 --- a/308allocate-array.subx +++ b/308allocate-array.subx @@ -1,5 +1,7 @@ # 2-arg version of allocate-array. +== code + allocate-array2: # ad: (addr allocation-descriptor), array-len: int, elem-size: int, out: (addr handle array _) # . prologue 55/push-ebp diff --git a/309stream.subx b/309stream.subx index 8e6d0fbf..84642def 100644 --- a/309stream.subx +++ b/309stream.subx @@ -1,6 +1,8 @@ # Some unsafe methods not intended to be used directly in SubX, only through # Mu after proper type-checking. +== code + stream-empty?: # s: (addr stream _) -> result/eax: boolean # . prologue 55/push-ebp diff --git a/310copy-bytes.subx b/310copy-bytes.subx new file mode 100644 index 00000000..f33388a9 --- /dev/null +++ b/310copy-bytes.subx @@ -0,0 +1,57 @@ +# Fill a region of memory with zeroes. + +== code + +copy-bytes: # src: (addr byte), dest: (addr byte), size: int + # pseudocode: + # curr-src/esi = src + # curr-dest/edi = dest + # i/ecx = 0 + # while true + # if (i >= size) break + # *curr-dest = *curr-src + # ++curr-src + # ++curr-dest + # ++i + # + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 56/push-esi + 57/push-edi + # curr-src/esi = src + 8b/-> *(ebp+8) 6/r32/esi + # curr-dest/edi = dest + 8b/-> *(ebp+0xc) 7/r32/edi + # var i/ecx: int = 0 + b9/copy-to-ecx 0/imm32 + # edx = size + 8b/-> *(ebp+0x10) 2/r32/edx + { + # if (i >= size) break + 39/compare %ecx 2/r32/edx + 7d/jump-if->= break/disp8 + # *curr-dest = *curr-src + 8a/byte-> *esi 0/r32/AL + 88/byte<- *edi 0/r32/AL + # update + 46/increment-esi + 47/increment-edi + 41/increment-ecx + eb/jump loop/disp8 + } +$copy-bytes:end: + # . restore registers + 5f/pop-to-edi + 5e/pop-to-esi + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return diff --git a/400.mu b/400.mu index 0bcf7e64..b1970f15 100644 --- a/400.mu +++ b/400.mu @@ -162,3 +162,5 @@ sig open filename: (addr array byte), write?: boolean, out: (addr handle buffere sig stream-empty? s: (addr stream _) -> result/eax: boolean sig stream-full? s: (addr stream _) -> result/eax: boolean + +sig copy-bytes src: (addr byte), dest: (addr byte), n: int diff --git a/405screen.mu b/405screen.mu index f7e04c53..8555b494 100644 --- a/405screen.mu +++ b/405screen.mu @@ -258,8 +258,10 @@ $print-grapheme:body: { var data-ah/eax: (addr handle array screen-cell) <- get screen-addr, data var data/eax: (addr array screen-cell) <- lookup *data-ah var offset/ecx: (offset screen-cell) <- compute-offset data, idx - var cell/eax: (addr screen-cell) <- index data, offset - var dest/eax: (addr grapheme) <- get cell, data + var dest-cell/ecx: (addr screen-cell) <- index data, offset + var src-cell/eax: (addr screen-cell) <- get screen-addr, curr-attributes + copy-object src-cell, dest-cell + var dest/eax: (addr grapheme) <- get dest-cell, data var c2/ecx: grapheme <- copy c #? print-grapheme-to-real-screen c2 #? print-string-to-real-screen "\n" @@ -315,6 +317,23 @@ fn screen-grapheme-at-idx screen-on-stack: (addr screen), idx-on-stack: int -> r result <- copy *src } +fn screen-color-at screen-on-stack: (addr screen), row: int, col: int -> result/eax: int { + var screen-addr/esi: (addr screen) <- copy screen-on-stack + var idx/ecx: int <- screen-cell-index screen-addr, row, col + result <- screen-color-at-idx screen-addr, idx +} + +fn screen-color-at-idx screen-on-stack: (addr screen), idx-on-stack: int -> result/eax: int { + var screen-addr/esi: (addr screen) <- copy screen-on-stack + var data-ah/eax: (addr handle array screen-cell) <- get screen-addr, data + var data/eax: (addr array screen-cell) <- lookup *data-ah + var idx/ecx: int <- copy idx-on-stack + var offset/ecx: (offset screen-cell) <- compute-offset data, idx + var cell/eax: (addr screen-cell) <- index data, offset + var src/eax: (addr int) <- get cell, color + result <- copy *src +} + fn print-code-point screen: (addr screen), c: code-point { var g/eax: grapheme <- to-grapheme c print-grapheme screen, g @@ -346,6 +365,11 @@ $reset-formatting:body: { { break-if-= # fake screen + var screen-addr/esi: (addr screen) <- copy screen + var dest/ecx: (addr screen-cell) <- get screen-addr, curr-attributes + var empty-cell: screen-cell + var empty-cell-addr/eax: (addr screen-cell) <- address empty-cell + copy-object empty-cell-addr, dest } } } @@ -361,6 +385,14 @@ $start-color:body: { { break-if-= # fake screen + var screen-addr/esi: (addr screen) <- copy screen + var attr/ecx: (addr screen-cell) <- get screen-addr, curr-attributes + var dest/edx: (addr int) <- get attr, color + var src/eax: int <- copy fg + copy-to *dest, src + var dest/edx: (addr int) <- get attr, background-color + var src/eax: int <- copy bg + copy-to *dest, src } } } @@ -376,6 +408,10 @@ $start-bold:body: { { break-if-= # fake screen + var screen-addr/esi: (addr screen) <- copy screen + var attr/ecx: (addr screen-cell) <- get screen-addr, curr-attributes + var dest/edx: (addr boolean) <- get attr, bold? + copy-to *dest, 1 } } } @@ -391,6 +427,10 @@ $start-underline:body: { { break-if-= # fake screen + var screen-addr/esi: (addr screen) <- copy screen + var attr/ecx: (addr screen-cell) <- get screen-addr, curr-attributes + var dest/edx: (addr boolean) <- get attr, underline? + copy-to *dest, 1 } } } @@ -406,6 +446,10 @@ $start-reverse-video:body: { { break-if-= # fake screen + var screen-addr/esi: (addr screen) <- copy screen + var attr/ecx: (addr screen-cell) <- get screen-addr, curr-attributes + var dest/edx: (addr boolean) <- get attr, reverse? + copy-to *dest, 1 } } } @@ -421,6 +465,10 @@ $start-blinking:body: { { break-if-= # fake screen + var screen-addr/esi: (addr screen) <- copy screen + var attr/ecx: (addr screen-cell) <- get screen-addr, curr-attributes + var dest/edx: (addr boolean) <- get attr, blink? + copy-to *dest, 1 } } } @@ -436,6 +484,9 @@ $hide-cursor:body: { { break-if-= # fake screen + var screen-addr/esi: (addr screen) <- copy screen + var hide?/ecx: (addr boolean) <- get screen-addr, cursor-hide? + copy-to *hide?, 1 } } } @@ -451,6 +502,9 @@ $show-cursor:body: { { break-if-= # fake screen + var screen-addr/esi: (addr screen) <- copy screen + var hide?/ecx: (addr boolean) <- get screen-addr, cursor-hide? + copy-to *hide?, 0 } } } @@ -479,14 +533,13 @@ fn check-screen-row-from screen-on-stack: (addr screen), row-idx: int, col-idx: var expected-grapheme/eax: grapheme <- read-grapheme e-addr var expected-grapheme2/eax: int <- copy expected-grapheme # compare graphemes - $check-screen-row:compare-graphemes: { + $check-screen-row-from:compare-graphemes: { # if expected-grapheme is space, null grapheme is also ok { compare expected-grapheme2, 0x20 break-if-!= compare g2, 0 - break-if-!= - break $check-screen-row:compare-graphemes + break-if-= $check-screen-row-from:compare-graphemes } check-ints-equal g2, expected-grapheme2, msg } @@ -497,10 +550,47 @@ fn check-screen-row-from screen-on-stack: (addr screen), row-idx: int, col-idx: # various variants by screen-cell attribute; spaces in the 'expected' data should not match the attribute -fn check-screen-row-in-color screen-on-stack: (addr screen), fg: color, row-idx: int, expected: (addr array byte), msg: (addr array byte) { +fn check-screen-row-in-color screen: (addr screen), fg: color, row-idx: int, expected: (addr array byte), msg: (addr array byte) { + check-screen-row-in-color-from screen, fg, row-idx, 1, expected, msg } fn check-screen-row-in-color-from screen-on-stack: (addr screen), fg: color, row-idx: int, col-idx: int, expected: (addr array byte), msg: (addr array byte) { + var screen/esi: (addr screen) <- copy screen-on-stack + var idx/ecx: int <- screen-cell-index screen, row-idx, col-idx + # compare 'expected' with the screen contents starting at 'idx', grapheme by grapheme + var e: (stream byte 0x100) + var e-addr/edx: (addr stream byte) <- address e + write e-addr, expected + { + var done?/eax: boolean <- stream-empty? e-addr + compare done?, 0 + break-if-!= + var g/eax: grapheme <- screen-grapheme-at-idx screen, idx + var g2/ebx: int <- copy g + var expected-grapheme/eax: grapheme <- read-grapheme e-addr + var expected-grapheme2/edx: int <- copy expected-grapheme + # compare graphemes + $check-screen-row-in-color-from:compare-graphemes: { + # if expected-grapheme is space, null grapheme is also ok + { + compare expected-grapheme2, 0x20 + break-if-!= + compare g2, 0 + break-if-= $check-screen-row-in-color-from:compare-graphemes + } + # if expected-grapheme is space, a different color is ok + { + compare expected-grapheme2, 0x20 + break-if-!= + var color/eax: int <- screen-color-at-idx screen, idx + compare color, fg + break-if-!= $check-screen-row-in-color-from:compare-graphemes + } + check-ints-equal g2, expected-grapheme2, msg + } + idx <- increment + loop + } } # background color is visible even for spaces, so 'expected' behaves as an array of booleans. @@ -704,7 +794,23 @@ fn test-check-screen-scrolls-on-overflow { check-screen-row-from screen, 5, 1, "b", "F - test-check-screen-scrolls-on-overflow/2" } +fn test-check-screen-color { + var screen-on-stack: screen + var screen/esi: (addr screen) <- address screen-on-stack + initialize-screen screen, 5, 4 + var c/eax: grapheme <- copy 0x61 # 'a' + print-grapheme screen, c + start-color screen, 1, 0 # foreground=1 + c <- copy 0x62 # 'b' + print-grapheme screen, c + start-color screen, 0, 0 # back to default + c <- copy 0x63 # 'c' + print-grapheme screen, c + check-screen-row-in-color screen, 0, 1, "a c", "F - test-check-screen-color" +} + #? fn main -> exit-status/ebx: int { +#? #? test-check-screen-color #? run-tests #? exit-status <- copy 0 #? } diff --git a/apps/mu b/apps/mu index f3c88e9c..2cf5d31c 100755 Binary files a/apps/mu and b/apps/mu differ diff --git a/apps/mu.subx b/apps/mu.subx index f673045a..1b68350f 100644 --- a/apps/mu.subx +++ b/apps/mu.subx @@ -12695,6 +12695,10 @@ has-primitive-name?: # stmt: (addr stmt) -> result/eax: boolean (string-equal? %esi "compute-offset") # => eax 3d/compare-eax-and 0/imm32/false 0f 85/jump-if-!= $has-primitive-name?:end/disp32 + # if (name == "copy-object") return true + (string-equal? %esi "copy-object") # => eax + 3d/compare-eax-and 0/imm32/false + 0f 85/jump-if-!= $has-primitive-name?:end/disp32 # if (name == "allocate") return true (string-equal? %esi "allocate") # => eax 3d/compare-eax-and 0/imm32/false @@ -12820,6 +12824,14 @@ check-mu-primitive: # stmt: (addr stmt), fn: (addr function), err: (addr buffer (check-mu-compute-offset-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) e9/jump $check-mu-primitive:end/disp32 } + # if (op == "copy-object") check-mu-copy-object-stmt + { + (string-equal? %ecx "copy-object") # => eax + 3d/compare-eax-and 0/imm32/false + 74/jump-if-= break/disp8 + (check-mu-copy-object-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14)) + e9/jump $check-mu-primitive:end/disp32 + } # if (op == "allocate") check-mu-allocate-stmt { (string-equal? %ecx "allocate") # => eax @@ -13786,6 +13798,18 @@ $check-mu-compute-offset-stmt:end: 5d/pop-to-ebp c3/return +check-mu-copy-object-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers +$check-mu-copy-object-stmt:end: + # . restore registers + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + check-mu-allocate-stmt: # stmt: (addr stmt), fn: (addr function), err: (addr buffered-file), ed: (addr exit-descriptor) # . prologue 55/push-ebp @@ -16039,6 +16063,15 @@ emit-subx-stmt: # out: (addr buffered-file), stmt: (addr stmt), primitives: (ad (translate-mu-allocate-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18)) e9/jump $emit-subx-stmt:end/disp32 } + # copy-object + { + # if (!string-equal?(stmt->operation, "copy-object")) break + (string-equal? %ecx "copy-object") # => eax + 3d/compare-eax-and 0/imm32 + 0f 84/jump-if-= break/disp32 + (translate-mu-copy-object-stmt *(ebp+8) *(ebp+0xc) *(ebp+0x14) *(ebp+0x18)) + e9/jump $emit-subx-stmt:end/disp32 + } # allocate array { # if (!string-equal?(stmt->operation, "populate")) break @@ -16810,6 +16843,34 @@ $translate-mu-get-stmt:end: 5d/pop-to-ebp c3/return +translate-mu-copy-object-stmt: # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + # + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "(copy-bytes") + # eax = stmt + 8b/-> *(ebp+0xc) 0/r32/eax + # var first-inout/eax: (addr stmt-var) = stmt->inouts[0] + (lookup *(eax+0xc) *(eax+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (emit-subx-call-operand *(ebp+8) %eax) + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + (emit-subx-call-operand *(ebp+8) %eax) + (write-buffered *(ebp+8) Space) + (addr-payload-size %eax *(ebp+0x10) *(ebp+0x14)) # => eax + (write-int32-hex-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) ")\n") +$translate-mu-copy-object-stmt:end: + # . restore registers + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + translate-mu-allocate-stmt: # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor) # . prologue 55/push-ebp