Skip to content

Commit c0ea694

Browse files
PEEK and POKE variants
1 parent 8eca555 commit c0ea694

File tree

10 files changed

+342
-23
lines changed

10 files changed

+342
-23
lines changed

include/basic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,4 @@
4848
#include "basic/process.h"
4949
#include "basic/reflection.h"
5050
#include "basic/datetime.h"
51+
#include "basic/peekpoke.h"

include/basic/peekpoke.h

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* @file basic/peekpoke.h
3+
* @brief Functions related to BASIC PEEK and POKE functions
4+
*/
5+
#pragma once
6+
#include <kernel.h>
7+
8+
/**
9+
* Read one byte from the given memory address.
10+
*
11+
* @param ctx BASIC context
12+
* @return Value read as integer, or 0 with error set if invalid
13+
*/
14+
int64_t basic_peek(struct basic_ctx *ctx);
15+
16+
/**
17+
* Read one 16-bit word from the given memory address.
18+
*
19+
* @param ctx BASIC context
20+
* @return Value read as integer, or 0 with error set if invalid
21+
*/
22+
int64_t basic_peekw(struct basic_ctx *ctx);
23+
24+
/**
25+
* Read one 32-bit double word from the given memory address.
26+
*
27+
* @param ctx BASIC context
28+
* @return Value read as integer, or 0 with error set if invalid
29+
*/
30+
int64_t basic_peekd(struct basic_ctx *ctx);
31+
32+
/**
33+
* Read one 64-bit quad word from the given memory address.
34+
*
35+
* @param ctx BASIC context
36+
* @return Value read as integer, or 0 with error set if invalid
37+
*/
38+
int64_t basic_peekq(struct basic_ctx *ctx);
39+
40+
/**
41+
* Store one byte at the given memory address.
42+
*
43+
* @param ctx BASIC context
44+
*/
45+
void poke_statement(struct basic_ctx *ctx);
46+
47+
/**
48+
* Store one 16-bit word at the given memory address.
49+
*
50+
* @param ctx BASIC context
51+
*/
52+
void pokew_statement(struct basic_ctx *ctx);
53+
54+
/**
55+
* Store one 32-bit double word at the given memory address.
56+
*
57+
* @param ctx BASIC context
58+
*/
59+
void poked_statement(struct basic_ctx *ctx);
60+
61+
/**
62+
* Store one 64-bit quad word at the given memory address.
63+
*
64+
* @param ctx BASIC context
65+
*/
66+
void pokeq_statement(struct basic_ctx *ctx);

include/basic/tokenizer.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@
124124
T(DIM) \
125125
T(REDIM) \
126126
T(PUSH) \
127+
T(POKE) \
128+
T(POKEW) \
129+
T(POKED) \
130+
T(POKEQ) \
127131
T(POP) \
128132
T(LOCAL) \
129133
T(CHDIR) \
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
DEF PROCmouse
2+
__MOUSE_X = GRAPHICS_WIDTH / 2
3+
__MOUSE_Y = GRAPHICS_HEIGHT / 2
4+
__MOUSE_LMB = FALSE
5+
__MOUSE_RMB = FALSE
6+
__MOUSE_MMB = FALSE
7+
UDPBIND "127.0.0.1", 14502 + PID
8+
ENDPROC
9+
10+
DEF PROCmouse_done
11+
UDPUNBIND "127.0.0.1", 14502 + PID
12+
ENDPROC
13+
14+
DEF PROCfetch_mouse
15+
UDPWRITE "127.0.0.1", 14502 + PID, 14501, "GET"
16+
PACKET$ = UDPREAD$(14502 + PID)
17+
IF PACKET$ <> "" THEN
18+
X$ = TOKENIZE$(PACKET$, " ")
19+
Y$ = TOKENIZE$(PACKET$, " ")
20+
M$ = TOKENIZE$(PACKET$, " ")
21+
__MOUSE_X = VAL(X$)
22+
__MOUSE_Y = VAL(Y$)
23+
__MOUSE_BUTTONS = VAL(M$)
24+
__MOUSE_LMB = BITAND(__MOUSE_BUTTONS, 1)
25+
__MOUSE_RMB = BITSHR(BITAND(__MOUSE_BUTTONS, 2), 1)
26+
__MOUSE_MMB = BITSHR(BITAND(__MOUSE_BUTTONS, 4), 2)
27+
ENDIF
28+
ENDPROC
29+
30+
DEF FNmouse_x
31+
=__MOUSE_X
32+
33+
DEF FNmouse_y
34+
=__MOUSE_Y
35+
36+
DEF FNmouse_lmb
37+
=__MOUSE_LMB
38+
39+
DEF FNmouse_rmb
40+
=__MOUSE_RMB
41+
42+
DEF FNmouse_mmb
43+
=__MOUSE_MMB

os/programs/mousetest.rrbasic

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,19 @@
11
CLS
2+
LIBRARY LIB$ + "/mouse"
23
SPRITELOAD cursor,"/images/cursor.png"
3-
UDPBIND "127.0.0.1", 9999
4-
X = GRAPHICS_WIDTH / 2
5-
Y = GRAPHICS_HEIGHT / 2
6-
PLOT cursor, X, Y
4+
X = 0
5+
Y = 0
76
REPEAT
8-
CURSOR 0, 0
9-
UDPWRITE "127.0.0.1", 9999, 14501, "GET"
10-
PACKET$ = UDPREAD$(9999)
11-
IF PACKET$ <> "" THEN
12-
PRINT PACKET$
13-
X$ = TOKENIZE$(PACKET$, " ")
14-
Y$ = TOKENIZE$(PACKET$, " ")
15-
M$ = TOKENIZE$(PACKET$, " ")
16-
NEW_X = VAL(X$)
17-
NEW_Y = VAL(Y$)
18-
IF NEW_X <> X OR NEW_Y <> Y THEN
19-
GCOL 0
20-
RECTANGLE X, Y, X + 32, Y + 45
21-
M = VAL(M$)
22-
X = NEW_X
23-
Y = NEW_Y
24-
PLOT cursor, X, Y
25-
ENDIF
7+
PROCfetch_mouse()
8+
NEW_X = FNmouse_x()
9+
NEW_Y = FNmouse_y()
10+
IF NEW_X <> X OR NEW_Y <> Y THEN
11+
GCOL 0
12+
RECTANGLE X, Y, X + 32, Y + 45
13+
X = NEW_X
14+
Y = NEW_Y
15+
PLOT cursor, X, Y
2616
ENDIF
2717
UNTIL INKEY$ <> ""
28-
UDPUNBIND "127.0.0.1", 9999
18+
PROCmouse_done()
19+
END

src/basic/function.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ struct basic_int_fn builtin_int[] =
8080
{ basic_bitshr, "BITSHR" },
8181
{ basic_bitrol, "BITROL" },
8282
{ basic_bitror, "BITROR" },
83+
{ basic_peekq, "PEEKQ" },
84+
{ basic_peekd, "PEEKD" },
85+
{ basic_peekw, "PEEKW" },
86+
{ basic_peek, "PEEK" },
8387
{ NULL, NULL },
8488
};
8589

src/basic/peekpoke.c

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
#include <kernel.h>
2+
#include <stdint.h>
3+
#include <stdbool.h>
4+
5+
extern volatile struct limine_memmap_request memory_map_request;
6+
7+
static inline bool span_overflows(uint64_t addr, uint64_t width) {
8+
if (width == 0) {
9+
return true;
10+
}
11+
uint64_t end = addr + width - 1;
12+
return end < addr;
13+
}
14+
15+
static inline bool type_readable(uint64_t t) {
16+
return t == LIMINE_MEMMAP_USABLE
17+
|| t == LIMINE_MEMMAP_ACPI_NVS
18+
|| t == LIMINE_MEMMAP_ACPI_RECLAIMABLE
19+
|| t == LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE
20+
|| t == LIMINE_MEMMAP_FRAMEBUFFER
21+
|| t == LIMINE_MEMMAP_KERNEL_AND_MODULES;
22+
}
23+
24+
static inline bool type_writable(uint64_t t) {
25+
return t == LIMINE_MEMMAP_USABLE
26+
|| t == LIMINE_MEMMAP_ACPI_RECLAIMABLE
27+
|| t == LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE
28+
|| t == LIMINE_MEMMAP_FRAMEBUFFER;
29+
}
30+
31+
static inline bool address_valid_span(uint64_t addr, uint64_t width, bool for_write) {
32+
if (addr < 0x1000 || span_overflows(addr, width)) {
33+
return false;
34+
}
35+
36+
const uint64_t end = addr + width - 1;
37+
uint64_t cursor = addr;
38+
39+
const struct limine_memmap_response *resp = memory_map_request.response;
40+
if (!resp || resp->entry_count == 0 || !resp->entries) {
41+
return false;
42+
}
43+
44+
while (cursor <= end) {
45+
const struct limine_memmap_entry *hit = NULL;
46+
47+
for (uint64_t i = 0; i < resp->entry_count; ++i) {
48+
const struct limine_memmap_entry *e = resp->entries[i];
49+
const uint64_t e_base = e->base;
50+
const uint64_t e_end = e->base + e->length - 1;
51+
if (cursor >= e_base && cursor <= e_end) {
52+
const bool ok = for_write ? type_writable(e->type) : type_readable(e->type);
53+
if (ok) {
54+
hit = e;
55+
}
56+
break;
57+
}
58+
}
59+
if (!hit) {
60+
return false;
61+
}
62+
63+
const uint64_t hit_end = hit->base + hit->length - 1;
64+
if (hit_end >= end) {
65+
return true;
66+
}
67+
cursor = hit_end + 1;
68+
}
69+
return true;
70+
}
71+
72+
static inline bool address_valid_read(uint64_t addr, int8_t width) {
73+
return address_valid_span(addr, width, false);
74+
}
75+
76+
static inline bool address_valid_write(uint64_t addr, int8_t width) {
77+
return address_valid_span(addr, width, true);
78+
}
79+
80+
/* ---- BASIC PEEK wrappers (error message unchanged) ---- */
81+
82+
int64_t basic_peek(struct basic_ctx *ctx)
83+
{
84+
PARAMS_START;
85+
PARAMS_GET_ITEM(BIP_INT);
86+
uint64_t addr = (uint64_t)intval;
87+
PARAMS_END("PEEK", 0);
88+
89+
if (!address_valid_read(addr, 1)) {
90+
tokenizer_error_printf(ctx, "Bad Address at &%016lx", addr);
91+
return 0;
92+
}
93+
uint8_t v = *(volatile uint8_t *)(uintptr_t)addr;
94+
return (int64_t)v;
95+
}
96+
97+
int64_t basic_peekw(struct basic_ctx *ctx)
98+
{
99+
PARAMS_START;
100+
PARAMS_GET_ITEM(BIP_INT);
101+
uint64_t addr = (uint64_t)intval;
102+
PARAMS_END("PEEKW", 0);
103+
104+
if (!address_valid_read(addr, 2)) {
105+
tokenizer_error_printf(ctx, "Bad Address at &%016lx", addr);
106+
return 0;
107+
}
108+
uint16_t v = *(volatile uint16_t *)(uintptr_t)addr;
109+
return (int64_t)v;
110+
}
111+
112+
int64_t basic_peekd(struct basic_ctx *ctx)
113+
{
114+
PARAMS_START;
115+
PARAMS_GET_ITEM(BIP_INT);
116+
uint64_t addr = (uint64_t)intval;
117+
PARAMS_END("PEEKD", 0);
118+
119+
if (!address_valid_read(addr, 4)) {
120+
tokenizer_error_printf(ctx, "Bad Address at &%016lx", addr);
121+
return 0;
122+
}
123+
uint32_t v = *(volatile uint32_t *)(uintptr_t)addr;
124+
return (int64_t)v;
125+
}
126+
127+
int64_t basic_peekq(struct basic_ctx *ctx)
128+
{
129+
PARAMS_START;
130+
PARAMS_GET_ITEM(BIP_INT);
131+
uint64_t addr = (uint64_t)intval;
132+
PARAMS_END("PEEKQ", 0);
133+
134+
if (!address_valid_read(addr, 8)) {
135+
tokenizer_error_printf(ctx, "Bad Address at &%016lx", addr);
136+
return 0;
137+
}
138+
uint64_t v = *(volatile uint64_t *)(uintptr_t)addr;
139+
return (int64_t)v;
140+
}
141+
142+
void poke_statement(struct basic_ctx* ctx) {
143+
accept_or_return(POKE, ctx);
144+
int64_t addr = expr(ctx);
145+
accept_or_return(COMMA, ctx);
146+
int64_t val = expr(ctx);
147+
accept_or_return(NEWLINE, ctx);
148+
149+
if (!address_valid_write((uint64_t)addr, 1)) {
150+
tokenizer_error_printf(ctx, "Bad Address at &%016lx", (uint64_t)addr);
151+
return;
152+
}
153+
*(volatile uint8_t *)(uintptr_t)addr = (uint8_t)val;
154+
}
155+
156+
void pokew_statement(struct basic_ctx* ctx) {
157+
accept_or_return(POKEW, ctx);
158+
int64_t addr = expr(ctx);
159+
accept_or_return(COMMA, ctx);
160+
int64_t val = expr(ctx);
161+
accept_or_return(NEWLINE, ctx);
162+
163+
if (!address_valid_write((uint64_t)addr, 2)) {
164+
tokenizer_error_printf(ctx, "Bad Address at &%016lx", (uint64_t)addr);
165+
return;
166+
}
167+
*(volatile uint16_t *)(uintptr_t)addr = (uint16_t)val;
168+
}
169+
170+
void poked_statement(struct basic_ctx* ctx) {
171+
accept_or_return(POKED, ctx);
172+
int64_t addr = expr(ctx);
173+
accept_or_return(COMMA, ctx);
174+
int64_t val = expr(ctx);
175+
accept_or_return(NEWLINE, ctx);
176+
177+
if (!address_valid_write((uint64_t)addr, 4)) {
178+
tokenizer_error_printf(ctx, "Bad Address at &%016lx", (uint64_t)addr);
179+
return;
180+
}
181+
*(volatile uint32_t *)(uintptr_t)addr = (uint32_t)val;
182+
}
183+
184+
void pokeq_statement(struct basic_ctx* ctx) {
185+
accept_or_return(POKEQ, ctx);
186+
int64_t addr = expr(ctx);
187+
accept_or_return(COMMA, ctx);
188+
int64_t val = expr(ctx);
189+
accept_or_return(NEWLINE, ctx);
190+
191+
if (!address_valid_write((uint64_t)addr, 8)) {
192+
tokenizer_error_printf(ctx, "Bad Address at &%016lx", (uint64_t)addr);
193+
return;
194+
}
195+
*(volatile uint64_t *)(uintptr_t)addr = (uint64_t)val;
196+
}

src/basic/sockets.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ static void basic_udp_handle_packet(uint32_t src_ip, uint16_t src_port, uint16_t
250250
if (!opaque) {
251251
return;
252252
}
253+
dprintf("basic_udp_handle_packet %u\n", dst_port);
253254
queued_udp_packet* packet = buddy_malloc(ctx->allocator, sizeof(queued_udp_packet));
254255
char ip[MAX_STRINGLEN];
255256
src_ip = ntohl(src_ip);
@@ -345,6 +346,7 @@ char* basic_udpread(struct basic_ctx* ctx) {
345346
lock_spinlock_irq(&udp_read_lock, &flags);
346347
queued_udp_packet* queue = udp_packets[port];
347348
if (queue) {
349+
dprintf("non empty queue");
348350
ctx->last_packet = *queue;
349351
if (queue == udp_list_tail[port]) {
350352
/* This packet is the tail packet */

0 commit comments

Comments
 (0)