From c80481de768fdd7b7cdf0d89c6e53523d0e96f1e Mon Sep 17 00:00:00 2001 From: zongor Date: Sat, 25 Oct 2025 21:39:13 -0700 Subject: [PATCH] Update devices to use file descriptor rather than handel. Create REFRESH syscall --- docs/favicon.ico | Bin 305684 -> 305664 bytes docs/undar.png | Bin 1802 -> 7936 bytes docs/undar.svg | 14 ++++---- src/arch/linux/devices.c | 10 ++++-- src/arch/linux/devices.h | 1 + src/arch/linux/main.c | 10 ++++-- src/tools/assembler.c | 2 ++ src/vm/opcodes.h | 4 ++- src/vm/vm.c | 71 +++++++++++++++++++++++++-------------- test/paint-bw.asm.lisp | 18 ++++------ test/paint.asm.lisp | 24 ++++++------- test/paint.ul | 26 +++++--------- test/simple.asm.lisp | 2 +- test/simple.ul | 6 ++-- test/window.asm.lisp | 27 ++++++--------- 15 files changed, 114 insertions(+), 101 deletions(-) diff --git a/docs/favicon.ico b/docs/favicon.ico index 1bfaf27ed5467381c049f8e30946b5850e912ebd..7a815a889f1cf0270deb727e6b5eb4d01b7bb25f 100644 GIT binary patch literal 305664 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 literal 305684 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 XH%2G@%zMtVM3=B@qeNBl2u|z=YC3En diff --git a/docs/undar.png b/docs/undar.png index 40cd8073e79d426fa11a8f10727603f74acc8a7a..cb50d0bed2ac6b31424ee6d787ace2b1fb19a7aa 100644 GIT binary patch literal 7936 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 IoUyv|A9s5&oB#j- literal 1802 zcmZ{kc{JPU8pnUA##+_I(rMCGtJ)wUf)=rrCM2ZxqFf>=Mnfu5iMbK%hEl`SPA1N|=bm%_nCG15{hs%Ezn|y*?|c7>BU(}Jm>d8A zigp+qXR*fZwah;8iGh-(#BwqK}s+58j zCo}PbBms-I0f4I1(+KfRmV)u50)W=Ry_U!fc2XA)K{PuDTaZvr?Fa;FugSR}?`5E>jVf)vMg6oL7 z4U%WJZjuku8<%ZKDY7ic$pd=36b+$w!-wqrQo`$|Y6?$svRA)K5tW^yPz&Az8*A9H zwE_XEgUT474s5OJo;+f`k8bQjzJ zzL38nG54YK^z!=J4is&WEHvOu^A%*jjPs1Gz_Dau=`)2Ps{qblCcZ5^W8rw^Dp5yX zJ3^N3t2xEUBFysC1MOb>WS_Ao~ydVwSTb!l^CpUO5#9f-fJEkuV-snn_uXN zzCYlRd;l>QY{}_#dGfKnccLbv8V=I?g*yZpiKvZYNG~3|TdqF=C`EV^n`4%DH>2!FpLTUmev*EN;gmm{*l)p>xOU3JS~aoz-_doStx2=8$aLk$Sg@^_ISc8@^cI6nT(-MC>j2UX5{d^x~j|NL`zZEvTjB5&*x4 zo%xae@;0Z=8T;jC(X<={=%!?CtG8)DqXS%g>1n3c1ldl!tEFZo)0+`AKbm%_3QCw2 z+aS{gRdEgrA@lM=<;G`)Ht$xz7wVU$(3*_yGueUuqsv0f>z!Jm`}acC>07g4bSW2A z9L?UvI>_oXPH`2U%xpFocAZoUSH=RSHY#Ej#Pt)-e^p6FpIhWZs&1xKabRTJA|^z( zt)*s&10K<9&c6bG7dhxFg__%(>gk_ksrkK7+?29z>@lk80J|uEsFuqd=Z_@izh5SK^&u;goqp8`JrVovZMB8cz)Dw&O8x6khC|iH zZ);H}s6HE0&B5MR^3&52sywAEJf){A(5QazJa()gCZ<`mBPeNYFEj}l>BPHRnZ^~B zJ0t3DsXT3(TC16?MaP#^4?>mcz{#C+WjV!-Iv=x6Od=P)z;V=yJMVwcX2_cX595WA z%5KUaX1iNifstZ*c~}OEv;?p#N?Qd&q^Z25x^2UoL=ZqI1nofb%y%!oU~UZ@e`w%#K;!cqmS;}C4~dZ?Z#%?CdY7p3E7ZKlr) zp_kr>He#pdm;ZIOS!LIMfK^cW(Tvh}5IFM$W4<-)0c%J1lr9lv8esJ!Gu+fXO}_r1 zuO!RkzoC*KaC6r%EB;v8R%#^TI*@P{m%YU41#9DyU4ujBu;!PwMX?0w-7f8puXSyd zytO~@b(cU(g#Ro)Sh;}@T~I#iKJ{(XtELwl9~c~eO%Wpg!E#p8rH(lu$eS7}6l8p$LeoFo>ce#rNLK{h!~kxBL}k+9&<5Nd!wg#-%=4}7#}c1&yn>}(xvo?83e F`5Vv-H&*}v diff --git a/docs/undar.svg b/docs/undar.svg index a54757f..4e34255 100644 --- a/docs/undar.svg +++ b/docs/undar.svg @@ -8,7 +8,7 @@ version="1.1" id="svg1" inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)" - sodipodi:docname="undâr.svg" + sodipodi:docname="undar.svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" @@ -24,9 +24,9 @@ inkscape:deskcolor="#d1d1d1" inkscape:document-units="mm" showguides="false" - inkscape:zoom="10.504938" - inkscape:cx="69.062756" - inkscape:cy="50.880831" + inkscape:zoom="5.252469" + inkscape:cx="31.413798" + inkscape:cy="77.392175" inkscape:window-width="1939" inkscape:window-height="932" inkscape:window-x="0" @@ -40,16 +40,16 @@ inkscape:groupmode="layer" id="layer1"> diff --git a/src/arch/linux/devices.c b/src/arch/linux/devices.c index fb85cb8..4d667b1 100644 --- a/src/arch/linux/devices.c +++ b/src/arch/linux/devices.c @@ -140,10 +140,14 @@ i32 mouse_open(void *data, u32 mode, u32 handle, u8 *buffer, u32 size) { } i32 mouse_read(void *data, u8 *buffer, u32 size) { - MouseDeviceData *mouse_data = (MouseDeviceData *)data; + USED(data); + USED(buffer); + USED(size); + return -1; +} - if (size < 12) - return -1; +i32 mouse_refresh(void *data, u8 *buffer) { + MouseDeviceData *mouse_data = (MouseDeviceData *)data; u8 *info = (u8 *)buffer; memcpy(&info[4], &mouse_data->x, sizeof(u32)); diff --git a/src/arch/linux/devices.h b/src/arch/linux/devices.h index b252c03..d0a5549 100644 --- a/src/arch/linux/devices.h +++ b/src/arch/linux/devices.h @@ -52,6 +52,7 @@ i32 screen_ioctl(void *data, u32 cmd, const u8 *buffer); i32 mouse_open(void *data, u32 mode, u32 handle, u8 *buffer, u32 size); i32 mouse_read(void *data, u8 *buffer, u32 size); +i32 mouse_refresh(void *data, u8 *buffer); i32 mouse_write(void *data, const u8 *buffer, u32 size); i32 mouse_close(void *data); diff --git a/src/arch/linux/main.c b/src/arch/linux/main.c index 9e52f93..8bcfe9a 100644 --- a/src/arch/linux/main.c +++ b/src/arch/linux/main.c @@ -15,19 +15,22 @@ static DeviceOps screen_ops = {.open = screen_open, .read = screen_read, .write = screen_write, .close = screen_close, - .ioctl = screen_ioctl}; + .ioctl = screen_ioctl, + .refresh = nil}; static DeviceOps mouse_ops = {.open = mouse_open, .read = mouse_read, .write = mouse_write, .close = mouse_close, - .ioctl = nil}; + .ioctl = nil, + .refresh = mouse_refresh}; static DeviceOps keyboard_ops = {.open = keyboard_open, .read = keyboard_read, .write = keyboard_write, .close = keyboard_close, - .ioctl = nil}; + .ioctl = nil, + .refresh = nil}; static DeviceOps console_device_ops = { .open = console_open, @@ -35,6 +38,7 @@ static DeviceOps console_device_ops = { .write = console_write, .close = console_close, .ioctl = console_ioctl, + .refresh = nil }; static ScreenDeviceData screen_data = {0}; diff --git a/src/tools/assembler.c b/src/tools/assembler.c index d7005cb..e528283 100644 --- a/src/tools/assembler.c +++ b/src/tools/assembler.c @@ -721,6 +721,8 @@ void process_code_expr(VM *vm, SymbolTable *table, ExprNode *node) { syscall_id = SYSCALL_DEVICE_CLOSE; else if (strcmp(syscall_name, "IOCTL") == 0) syscall_id = SYSCALL_DEVICE_IOCTL; + else if (strcmp(syscall_name, "REFRESH") == 0) + syscall_id = SYSCALL_DEVICE_REFRESH; emit_u32(vm, syscall_id); diff --git a/src/vm/opcodes.h b/src/vm/opcodes.h index 4b5da65..e3c038b 100644 --- a/src/vm/opcodes.h +++ b/src/vm/opcodes.h @@ -103,7 +103,8 @@ typedef enum { SYSCALL_DEVICE_READ, SYSCALL_DEVICE_WRITE, SYSCALL_DEVICE_CLOSE, - SYSCALL_DEVICE_IOCTL + SYSCALL_DEVICE_IOCTL, + SYSCALL_DEVICE_REFRESH } SyscallID; typedef struct device_ops_s { @@ -113,6 +114,7 @@ typedef struct device_ops_s { i32 (*close)(void *device_data); i32 (*ioctl)(void *device_data, u32 cmd, const u8 *buffer); /* optional control */ + i32 (*refresh)(void *device_data, u8 *buffer); } DeviceOps; #define DEVICE_TYPE_MAX_LENGTH 16 /* 15 chars + null terminator */ diff --git a/src/vm/vm.c b/src/vm/vm.c index 50701f2..a511262 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -556,7 +556,7 @@ bool step_vm(VM *vm) { switch (syscall_id) { case SYSCALL_DEVICE_OPEN: { Device *dev; - u32 path_ptr, mode, buffer_ptr; + u32 path_ptr, mode, device_ptr; u8 path_reg, mode_reg, dest_reg; dest_reg = read_u8(vm, code, vm->pc); vm->pc++; @@ -571,14 +571,14 @@ bool step_vm(VM *vm) { if (dev) { if (dev->ops->open) { /* return device plex to user */ - buffer_ptr = vm->mp; - frame->registers[dest_reg] = buffer_ptr; + device_ptr = vm->mp; + frame->registers[dest_reg] = device_ptr; /* malloc size for device */ - write_u32(vm, memory, buffer_ptr, dev->size); + write_u32(vm, memory, device_ptr, dev->size); vm->mp += (dev->size + 4); /* set flag from user */ vm->flag = dev->ops->open(dev->data, mode, dev->handle, - &vm->memory[buffer_ptr + 4], dev->size); + &vm->memory[device_ptr + 4], dev->size); } else { vm->flag = 1; /* success, no open needed */ } @@ -591,25 +591,23 @@ bool step_vm(VM *vm) { case SYSCALL_DEVICE_READ: { Device *dev; - u32 handle, buffer_ptr, size; - u16 handle_reg, buffer_reg, size_reg; - handle_reg = read_u8(vm, code, vm->pc); + u32 device_ptr, buffer_ptr, size; + u8 device_reg, buffer_reg, size_reg, handle; + device_reg = read_u8(vm, code, vm->pc); vm->pc++; buffer_reg = read_u8(vm, code, vm->pc); vm->pc++; size_reg = read_u8(vm, code, vm->pc); vm->pc++; - dest = read_u8(vm, code, vm->pc); - vm->pc++; - handle = frame->registers[handle_reg]; /* path pointer */ + device_ptr = frame->registers[device_reg]; /* device pointer */ + buffer_ptr = frame->registers[buffer_reg]; size = frame->registers[size_reg]; /* size */ - buffer_ptr = frame->registers[dest]; + handle = vm->memory[device_ptr + 4]; /* get device handle */ dev = &vm->devices[handle]; if (dev && dev->ops->read) { vm->flag = dev->ops->read(dev->data, &vm->memory[buffer_ptr + 4], size); - frame->registers[buffer_reg] = buffer_ptr; } else { vm->flag = 0; } @@ -617,21 +615,42 @@ bool step_vm(VM *vm) { return true; } + case SYSCALL_DEVICE_REFRESH: { + Device *dev; + u32 handle, device_ptr; + u8 device_reg; + device_reg = read_u8(vm, code, vm->pc); + vm->pc++; + + device_ptr = frame->registers[device_reg]; /* device pointer */ + handle = vm->memory[device_ptr + 4]; /* get device handle */ + dev = &vm->devices[handle]; + if (dev && dev->ops->refresh) { + vm->flag = dev->ops->refresh(dev->data, &vm->memory[device_ptr + 4]); + } else { + vm->flag = 0; + } + + return true; + } + + case SYSCALL_DEVICE_WRITE: { Device *dev; - u32 handle, buffer_ptr, size; - u16 handle_reg, buffer_reg, size_reg; - handle_reg = read_u8(vm, code, vm->pc); + u32 handle, buffer_ptr, size, device_ptr; + u8 device_reg, buffer_reg, size_reg; + device_reg = read_u8(vm, code, vm->pc); vm->pc++; buffer_reg = read_u8(vm, code, vm->pc); vm->pc++; size_reg = read_u8(vm, code, vm->pc); vm->pc++; - handle = frame->registers[handle_reg]; /* R0: path pointer */ + device_ptr = frame->registers[device_reg]; /* device pointer */ buffer_ptr = frame->registers[buffer_reg]; /* R1: buffer pointer */ size = frame->registers[size_reg]; /* R2: size */ + handle = vm->memory[device_ptr + 4]; /* get device handle */ dev = &vm->devices[handle]; if (dev && dev->ops->write) { vm->flag = dev->ops->write( @@ -645,13 +664,14 @@ bool step_vm(VM *vm) { case SYSCALL_DEVICE_CLOSE: { Device *dev; - u32 handle; - u8 handle_reg; - handle_reg = read_u8(vm, code, vm->pc); + u32 handle, device_ptr; + u8 device_reg; + device_reg = read_u8(vm, code, vm->pc); vm->pc++; - handle = frame->registers[handle_reg]; /* R0: path pointer */ + device_ptr = frame->registers[device_reg]; /* device pointer */ + handle = vm->memory[device_ptr + 4]; /* get device handle */ dev = &vm->devices[handle]; if (dev && dev->ops->close) { i32 result = dev->ops->close(dev->data); @@ -665,19 +685,20 @@ bool step_vm(VM *vm) { case SYSCALL_DEVICE_IOCTL: { Device *dev; - u32 handle, args_ptr, cmd; - u8 handle_reg, cmd_reg, args_ptr_reg; - handle_reg = read_u8(vm, code, vm->pc); + u32 handle, args_ptr, cmd, device_ptr; + u8 device_reg, cmd_reg, args_ptr_reg; + device_reg = read_u8(vm, code, vm->pc); vm->pc++; cmd_reg = read_u8(vm, code, vm->pc); vm->pc++; args_ptr_reg = read_u8(vm, code, vm->pc); vm->pc++; - handle = frame->registers[handle_reg]; /* R0: device path */ + device_ptr = frame->registers[device_reg]; /* device pointer */ cmd = frame->registers[cmd_reg]; /* R1: ioctl command */ args_ptr = frame->registers[args_ptr_reg]; /* R2: args pointer */ + handle = vm->memory[device_ptr + 4]; /* get device handle */ dev = &vm->devices[handle]; if (dev && dev->ops && dev->ops->ioctl) { i32 result = dev->ops->ioctl(dev->data, cmd, &vm->memory[args_ptr]); diff --git a/test/paint-bw.asm.lisp b/test/paint-bw.asm.lisp index 4c45753..92b5785 100644 --- a/test/paint-bw.asm.lisp +++ b/test/paint-bw.asm.lisp @@ -4,20 +4,17 @@ ; use load immediate because it is a pointer to a string, not a value (load-immediate $0 &screen-namespace) (load-immediate $11 0) - (syscall OPEN $18 $0 $11) ; open(out Plex screen, in namespace, in flags) + (syscall OPEN $0 $18 $11) ; open(out Plex screen, in namespace, in flags) - (load-offset-32 $0 $18 4) ; load handle - (load-offset-32 $20 $18 8) ; load width - (load-offset-32 $22 $18 12) ; load size + (load-offset-32 $20 $0 8) ; load width + (load-offset-32 $22 $0 12) ; load size (load-immediate $1 16) ; offset for screen buffer - (add-nat $21 $18 $1) + (add-nat $21 $0 $1) ; open mouse (load-immediate $16 &mouse-namespace) (syscall OPEN $15 $16 $11) ; open(out Plex mouse, in namespace, in flags) - (load-offset-32 $16 $15 4) ; load handle - ; outline_swatch(screen, BLACK, 1, 1); (load-absolute-32 $1 &BLACK) (load-immediate $12 1) @@ -33,16 +30,15 @@ ; screen.draw(); (syscall WRITE $0 $21 $22) - (load-immediate $3 16) (label draw-loop ; load mouse click data - (syscall READ $16 $2 $3 $15) + (syscall REFRESH $15) (load-offset-8 $9 $15 16) ; load btn1 pressed (jump-eq-nat &draw-loop $9 $11) - (load-offset-32 $7 $2 8) ; load x - (load-offset-32 $8 $2 12) ; load y + (load-offset-32 $7 $15 8) ; load x + (load-offset-32 $8 $15 12) ; load y (load-immediate $14 20) ; box size diff --git a/test/paint.asm.lisp b/test/paint.asm.lisp index 44c617d..8e96811 100644 --- a/test/paint.asm.lisp +++ b/test/paint.asm.lisp @@ -4,20 +4,17 @@ ; use load immediate because it is a pointer to a string, not a value (load-immediate $0 &screen-namespace) (load-immediate $11 0) - (syscall OPEN $18 $0 $11) ; Screen screen = open(namespace, flags) + (syscall OPEN $0 $0 $11) ; Screen screen = open(namespace, flags) - (load-offset-32 $0 $18 4) ; load handle - (load-offset-32 $20 $18 8) ; load width - (load-offset-32 $22 $18 12) ; load size - (load-immediate $1 16) ; offset for screen buffer - (add-nat $21 $18 $1) + (load-offset-32 $20 $0 8) ; load width + (load-offset-32 $22 $0 12) ; load size + (load-immediate $1 16) ; pointer offset for screen buffer + (add-nat $21 $0 $1) ; open mouse (load-immediate $16 &mouse-namespace) (syscall OPEN $15 $16 $11) ; Mouse mouse = open(namespace, flags) - (load-offset-32 $16 $15 4) ; load handle - ; outline_swatch(screen, BLACK, 1, 1); (load-absolute-32 $1 &BLACK) (load-immediate $12 1) @@ -73,16 +70,15 @@ ; screen.draw(); (syscall WRITE $0 $21 $22) - (load-immediate $3 16) (label draw-loop ; load mouse click data - (syscall READ $16 $2 $3 $15) + (syscall REFRESH $15) (load-offset-8 $9 $15 16) ; load btn1 pressed (jump-eq-nat &draw-loop $9 $11) - (load-offset-32 $7 $2 8) ; load x - (load-offset-32 $8 $2 12) ; load y + (load-offset-32 $7 $15 8) ; load x + (load-offset-32 $8 $15 12) ; load y (load-immediate $14 20) ; box size @@ -229,8 +225,8 @@ (return nil))) (data (label screen-namespace "/dev/screen/0") - (label mouse-namespace "/dev/mouse/0") - (label SELECTED-COLOR 255) + (label mouse-namespace "/dev/mouse/0") + (label SELECTED-COLOR 255) (label BLACK 0) (label WHITE 255) (label CHARCOAL 36) diff --git a/test/paint.ul b/test/paint.ul index f6b936e..0bf6aa8 100644 --- a/test/paint.ul +++ b/test/paint.ul @@ -1,8 +1,6 @@ /** * Constants */ -const str screen_namespace = "/dev/screen/0"; -const str mouse_namespace = "/dev/mouse/0"; const byte BLACK = 0; const byte WHITE = 255; const byte DARK_GRAY = 73; @@ -22,8 +20,10 @@ plex Screen implements Device { nat buffer_size; byte[] screen_buffer; - init(str namespace) { - this.handle = open(namespace); + draw() { + unsafe { + write(this.handle, &this.screen_buffer, this.buffer_size); + } } } @@ -35,29 +35,21 @@ plex Mouse implements Device { bool right; bool middle; bool btn4; - nat size; - - init(str namespace) { - this.handle = open(namespace); - } } /** * Main function */ function main() { - Screen screen(screen_namespace); - screen.open(0); - - Mouse mouse(mouse_namespace); - mouse.open(0); + Screen screen = open("/dev/screen/0", 0); + Mouse mouse = open("/dev/mouse/0", 0); outline_swatch(screen, BLACK, 1, 1); outline_swatch(screen, WHITE, 21, 1); screen.draw(); loop { - mouse.read(); + mouse.refresh(); if (not mouse.left) continue; int box_size = 20; @@ -98,7 +90,7 @@ function set_color(int box_size, int bx, int by, int mx, int my, byte color) { /** * Draw a color box with a grey outline, if selected use a darker color */ -function outline_swatch(ref Device screen, byte color, int x, int y) { +function outline_swatch(Device screen, byte color, int x, int y) { byte bg_color = GRAY; if (selected_color == color) { bg_color = DARK_GRAY; @@ -112,7 +104,7 @@ function outline_swatch(ref Device screen, byte color, int x, int y) { /** * Draw a rectangle */ -function rectangle(ref Device screen, byte color, int x, int y, int width, int height) { +function rectangle(Device screen, byte color, int x, int y, int width, int height) { // we need unsafe because we are using `ptr` and `memset` directly // unsafe takes the guardrails off and allows you to access/modify memory directly unsafe { diff --git a/test/simple.asm.lisp b/test/simple.asm.lisp index 8aed424..6562d0b 100644 --- a/test/simple.asm.lisp +++ b/test/simple.asm.lisp @@ -11,7 +11,7 @@ (load-immediate $11 0) (syscall OPEN $1 $1 $11) (load-immediate $3 &new-line) - (load-offset-32 $7 $1 4) ; load handle + (load-offset-32 $7 $1 4) ; load handle (string-length $2 $0) (syscall WRITE $7 $0 $2) (string-length $4 $3) diff --git a/test/simple.ul b/test/simple.ul index 5b26383..ff59272 100644 --- a/test/simple.ul +++ b/test/simple.ul @@ -2,12 +2,14 @@ * Constants */ const str nl = "\n"; +const real x = 1.0; +const real y = 1.0; plex Terminal { nat handle; init() { - handle = open("/dev/term/0", 0); + this.handle = open("/dev/term/0", 0); } } @@ -15,7 +17,7 @@ plex Terminal { * Main function */ function main() { - pln((1 + 2).str); + pln((x + y).str); } /** diff --git a/test/window.asm.lisp b/test/window.asm.lisp index 5b2c0e5..5246bab 100644 --- a/test/window.asm.lisp +++ b/test/window.asm.lisp @@ -2,26 +2,24 @@ (label main ; Open screen ; use load immediate because it is a pointer to a string, not a value - (load-immediate $0 &screen-namespace) - (syscall OPEN $18 $0 $11) ; open(out Plex screen, in namespace, in flags) - - (load-offset-32 $0 $18 4) ; load handle + (load-immediate $18 &screen-namespace) + (syscall OPEN $0 $18 $11) ; open(out Plex screen, in namespace, in flags) (nat-to-string $5 $0) (call &pln ($5) nil) - (load-offset-32 $20 $18 8) ; load width + (load-offset-32 $20 $0 8) ; load width (nat-to-string $5 $20) (call &pln ($5) nil) - (load-offset-32 $22 $18 12) ; load size + (load-offset-32 $22 $0 12) ; load size (nat-to-string $5 $22) (call &pln ($5) nil) (load-immediate $1 16) ; offset for screen buffer - (add-nat $21 $18 $1) + (add-nat $21 $0 $1) (nat-to-string $5 $21) (call &pln ($5) nil) @@ -30,21 +28,17 @@ (load-immediate $16 &mouse-namespace) (syscall OPEN $15 $16 $11) ; open(out Plex mouse, in namespace, in flags) - (load-offset-32 $16 $15 4) ; load handle - (syscall WRITE $0 $21 $22) ; redraw - (load-immediate $3 16) (label draw-loop ; load mouse click data - (syscall READ $16 $2 $3 $15) - + (syscall REFRESH $15) (load-offset-8 $9 $15 16) ; load btn1 pressed (jump-eq-nat &draw-loop $9 $11) - (load-offset-32 $7 $2 8) ; load x - (load-offset-32 $8 $2 12) ; load y + (load-offset-32 $7 $15 8) ; load x + (load-offset-32 $8 $15 12) ; load y ; Compute start address: y*width + x (mul-nat $30 $8 $20) ; $15 = y * width @@ -64,11 +58,10 @@ (load-immediate $11 0) (syscall OPEN $1 $1 $11) (load-immediate $3 &new-line) - (load-offset-32 $7 $1 4) ; load handle (string-length $2 $0) - (syscall WRITE $7 $0 $2) + (syscall WRITE $1 $0 $2) (string-length $4 $3) - (syscall WRITE $7 $3 $4) + (syscall WRITE $1 $3 $4) (return nil))) (data (label screen-namespace "/dev/screen/0")