Hi all,
I'm working toward a specs freeze for the uxn core right now and I
wanted to have your opinion on something that hasn't been implemented
the same throughout the various emulators. While Varvara handles the
erroring, the core itself is what communicates that error. The halting
is out of the scope of the specs freeze, but the error codes aren't.
I was wondering if you had any suggestion or opinion on this little
bit of documentation:
Errors occur when a program behaves badly. There are four known error
types, and each one has an error code. Errors are indicated with the
address where it occurred, and the stack which caused it. For example,
an underflow in the return stack, will be reported as "Return Stack
Underflow, at #0000".
01 Underflow: Occurs when an opcode is trying to pop an item from
an empty stack.
02 Overflow: Occurs when an opcode is trying to push an item to a
full stack.
03 Division By Zero: Occurs when the DIV opcode is done on a value of zero.
04 Busy: Occurs when the BRK opcode is triggered and the stack is not empty.
Let me know what you think :)
cheers!
On Sun, Jun 12, 2022 at 09:57:53 -0700, Devine Lu Linvega wrote:
> While Varvara handles the erroring, the core itself is what> communicates that error. The halting is out of the scope of the specs> freeze, but the error codes aren't.
Are you suggesting to standardise the error codes which should be
printed by an emulator? Or might these by reported in some way, maybe by
the System vector?
As for the actual values, they're fine, but I don't see a huge point in
standardising them if they are only to be printed with an accompanying
message.
phoebos
Yes, I just want to make sure that error code 01, for example, is the
same number across each emulator so if the program requires to know
what error occurred they can reliably use that number to print the
right error :)
On 6/12/22, phoebos <ben@bvnf.space> wrote:
> On Sun, Jun 12, 2022 at 09:57:53 -0700, Devine Lu Linvega wrote:>> While Varvara handles the erroring, the core itself is what>> communicates that error. The halting is out of the scope of the specs>> freeze, but the error codes aren't.>> Are you suggesting to standardise the error codes which should be> printed by an emulator? Or might these by reported in some way, maybe by> the System vector?>> As for the actual values, they're fine, but I don't see a huge point in> standardising them if they are only to be printed with an accompanying> message.>> phoebos>
> 04 Busy: Occurs when the BRK opcode is triggered and the stack is not empty.
That last one, I think, is a bad idea: it would make it impossible
to handle events while inside some task doing arbitrary processing.
Currently it is possible to force event handling by issuing a BRK
with suitable vectors set to ensure returning back (think of it as
a system-level continuation passing style situation, or a an
async-style scenario with user code and event-loop processing running
as coroutines).
Enforcing empty stacks has no real use, I'd say, than saving the
programmer from doing stupid mistakes, something that should always
be done with much care, as you will never be able to anticipate
with what clever tricks future programmers may come up with. Since
one is already, when programming uxn, at such a low level, it would
make sense to be lenient with respect to the machine state (just
as CPUs are), otherwise you create constraints for no objective
reason. This is somewhat related to the enforced event-loop timeout
currently implemented in SDL uxn - there is no real technical reason
for such behaviour, just a subjective one.
felix
It's pretty hard to predict which vector will fire next, enough that I
feel like, even for passing data across vectors - there are better
safer ways. I'm not particularly attached to this, but here's how I
see it:
Errors are typically handled by the emulator unless the System/vector
is set, so that means that for most non-esoteric applications, this
will raise an error, and cover mistakes for most people that are in
the code.
But errors CAN be handled in uxn, if you wanted to make an application
that would make use of this in some way, your application will very
likely be esoteric enough that you'll have set stacks to be
visible/writable and at the same time, can decide to handle this error
or not.
It will save a lot of headache for most people, and for niche strange
applications and repls and things, people can decide to handle the
error and not display it. Here's an example of how specific error
handling could be done:
https://git.sr.ht/~rabbits/uxn5/tree/main/item/etc/tests.tal#L305> This is somewhat related to the enforced event-loop timeout
currently implemented in SDL uxn - there is no real technical reason
for such behaviour, just a subjective one.
What do you mean an enforced event loop? What would be an alternative
to this way of doing things, evaluate once? I'd love to hear more
about this.
On 6/12/22, felix.winkelmann@bevuta.com <felix.winkelmann@bevuta.com> wrote:
>> 04 Busy: Occurs when the BRK opcode is triggered and the stack is not>> empty.>> That last one, I think, is a bad idea: it would make it impossible> to handle events while inside some task doing arbitrary processing.>> Currently it is possible to force event handling by issuing a BRK> with suitable vectors set to ensure returning back (think of it as> a system-level continuation passing style situation, or a an> async-style scenario with user code and event-loop processing running> as coroutines).>> Enforcing empty stacks has no real use, I'd say, than saving the> programmer from doing stupid mistakes, something that should always> be done with much care, as you will never be able to anticipate> with what clever tricks future programmers may come up with. Since> one is already, when programming uxn, at such a low level, it would> make sense to be lenient with respect to the machine state (just> as CPUs are), otherwise you create constraints for no objective> reason. This is somewhat related to the enforced event-loop timeout> currently implemented in SDL uxn - there is no real technical reason> for such behaviour, just a subjective one.>>> felix>>
On Sun, Jun 12, 2022 at 09:38:57PM +0200, felix.winkelmann@bevuta.com wrote:
> That last one, I think, is a bad idea: it would make it impossible> to handle events while inside some task doing arbitrary processing.
For the purposes of freezing the spec I don't think it matters whether
we decide to enforce this (or not enforce it, or make it optional). We
only need to decide what error code to reserve (if any).
We have 256 possible error codes to use, so the big question is
whether implementors are willing to standardize on a set of numbers,
even if some may never be used.
My vote would be to standardize on Devine's proposal with two extra
parts:
- error code 0x00 (0) is unused.
- error codes 0x01 - 0x04 (1-4) are as Devine suggests.
- error codes 0x05 - 0x76 (5-126) should be reserved for future standards.
- error code 0x7f (127) should signal an unknown error.
- error codes 0x80 - 0xff (128-255) should be left open for extension
and experimentation by emulator authors or for other private uses.
Maybe this sounds too bureaucratic but since we have 256 values we
might as well explain what they mean now and in the future.
-- Erik
Oh!
In the case of an unknown error code, in bicycle for instance, if uxn
evaluates the System/vector without an error being set(#00), it's what
i consider an unknown error, I think we might not need another number
for this.
> It's pretty hard to predict which vector will fire next, enough that I> feel like, even for passing data across vectors - there are better> safer ways. I'm not particularly attached to this, but here's how I> see it:> > Errors are typically handled by the emulator unless the System/vector> is set, so that means that for most non-esoteric applications, this> will raise an error, and cover mistakes for most people that are in> the code.
Ah, nice, I didn't know of the fact that this allows user-level
error handling.
> > But errors CAN be handled in uxn, if you wanted to make an application> that would make use of this in some way, your application will very> likely be esoteric enough that you'll have set stacks to be> visible/writable and at the same time, can decide to handle this error> or not.
The problem I see here is that you define some arbitrary situation
as an error, because it may use the system's facilities in some
particular fashion (whether that's "esoteric" depends on the what
the user intends, though, not on your taste - and I'm not saying
this to slight you in any way, I hope this is obvious). Overflow,
underflow and div/0 are clearly situations that exceed machine
limitations, but "business" isn't. It forces a particular programming
model on the user, which, I think, should not be done. Uxn is at a
level deeper than a programming language - let the user decide how
to take advantage of it's features and don't add unnecessary
constraints.
Thinking about it, it would be just as easy to perform the business
check manually, in user code, if one is so inclined. There are
countless situations where you can fight with unbalanced stacks,
the BRK is just one of them.
> > It will save a lot of headache for most people, and for niche strange> applications and repls and things, people can decide to handle the> error and not display it. Here's an example of how specific error> handling could be done:> > https://git.sr.ht/~rabbits/uxn5/tree/main/item/etc/tests.tal#L305
From the little experience I have so far, this didn't cause me
any headaches (many other things did!), but it will prevent
certain errors, that's true. But again, what you declare to be
an error is, for example in my current project, totally fine
and actually necessary.
> > > This is somewhat related to the enforced event-loop timeout> currently implemented in SDL uxn - there is no real technical reason> for such behaviour, just a subjective one.> > What do you mean an enforced event loop? What would be an alternative> to this way of doing things, evaluate once? I'd love to hear more> about this.
I mean the timeout caused by throwing an error when the event loop
has not been called inside a certain time limit:
https://git.sr.ht/~rabbits/uxn/tree/main/item/src/uxn.c#L45
Currently I work around this by making my vectors aware of this
and calling BRK, continuing (with the original stacks) once
a vector fires. The program is a Forth REPL, so it may not be
possible to estimate before the execution how long some
evaluation may take. Calling a user-level routine to do the
BRK dance above at least allows me to continue processing.
It's slow and ugly, but it works.
I suggest just dropping the check, or issue a warning on stderr,
or allow overiding the check by a commandline option (the proper
place, IMHO) or environment variable or programming interface. This
is another case where some perceived model of using the machine is
enforced to catch one particular kind of user-level error, that,
in fact, may be intended or simply unavoidable.
Uxn is your baby, and I totally understand that you want to
make life easier for the user by preventing certain errors,
so it is not on me to insist on the existence or absence of
certain features. I just want to emphasize that any constraint
you introduce in the code the machine is able to execute should
have a true technical reason, be it undefined behaviour or
because some limit is exceeded. An event-loop timeout or
a tidy stack on BRK have not.
felix
> An example of an actual application catching errors, is Varvara's Bicycle.> > https://git.sr.ht/~rabbits/drifblim/tree/main/item/src/bicycle.tal#L204
This uses the stack-mapping feature, right? Is this intended
to be a fixed part of varvara or just experimental? I'd love
to be able to write portable code, and currently SDL uxn is
my emulator of choice, since it seems to be the "canonical"
one on UNIX systems and seems to work a bit better than uxn11.
It's a pity that one has to sacrifice 512 bytes just to be"
able to manipulate the stack pointers, though...
felix
> I mean the timeout caused by throwing an error when the event loop
has not been called inside a certain time limit:
Oh! Yes, I think I'd like this removed too, I've never implemented it
in uxn11, and on the raspberry pi it makes using uxn-sdl applications
almost impossible since every little lag fills the stack is garbage.
For example, scrolling across a large file in Left will instantly make
it throw all sorts of errors.
I see what you mean about the err4 and I think I agree, this shouldn't
be handled in uxn-space altogether, it could be a varvara thing, or
even a userspace thing, but definitely not within uxnspace, and so
does not warrant its own errcode.
> This uses the stack-mapping feature, right? Is this intended
to be a fixed part of varvara or just experimental? I'd love
to be able to write portable code, and currently SDL uxn is
my emulator of choice, since it seems to be the "canonical"
one on UNIX systems and seems to work a bit better than uxn11.
It's just experimental, it allows anyone to experiment with uxn,
without having to modify the c stuff too much. Alderwick has been
working on something like it but which swaps memory instead of
overwriting it like in uxn11, it's a bit more complex, I wouldn't be
able to explain it.
Uxnsdl is the reference implementation, varvara doesn't really have
anything like a frozen state, it's more like a per-device basis. And
timing, error handling, it's all over the place while we figure out
what works and what doesn't.
I realize that you want to write portable code, but uxn/varvara are
very young projects, and there are many rough edges still, anything
beyond the opcodes, the screen, mouse/keyboard, is somewhat up in the
air. But this is why we made this mailing list :)
I've noodled around with this this afternoon and catching busy stacks
on break in userspace/per-application is pretty cumbersome and
invasive.
So what I did was this, a typical debug query:
#02 .System/debug DEO
And thereafter, the uxn11 emulator is printing a warning(not errorring),
when it is breaking on non-empty stack. It's non-intrusive,
varvara-space defined and straight-forward. I've grown used to this
little safeguard and I'd like to keep it in, this might be the way.
I'll spend a few more days with this to test it out :)
> I've noodled around with this this afternoon and catching busy stacks> on break in userspace/per-application is pretty cumbersome and> invasive.> > So what I did was this, a typical debug query:> > #02 .System/debug DEO> > And thereafter, the uxn11 emulator is printing a warning(not errorring),> when it is breaking on non-empty stack. It's non-intrusive,
So the debug DEO enables this warning?
> varvara-space defined and straight-forward. I've grown used to this> little safeguard and I'd like to keep it in, this might be the way.> > I'll spend a few more days with this to test it out :)
A warning on stderr would be fine, I think, as long as execution
proceeds as normal.
felix
On Sun, Jun 12, 2022 at 02:05:42PM -0700, Devine Lu Linvega wrote:
>> I mean the timeout caused by throwing an error when the event loop>> has not been called inside a certain time limit:>>Oh! Yes, I think I'd like this removed too, I've never implemented it>in uxn11, and on the raspberry pi it makes using uxn-sdl applications>almost impossible since every little lag fills the stack is garbage.
I've been working on vsync support lately, but on reading this it's
clear that the execution timeouts aren't working. I've disabled them
with
https://git.sr.ht/~rabbits/uxn/commit/fb030288f941615df5bfa2a2fbaf6a075b8ab6ca
.
Ultimately I think it would be nice to be able to catch overlong loops
in a REPL, but this functionality shouldn't be enabled by default — this
is why I say “for now” in the above commit message, because some of the
reserved bytes described in
https://lists.sr.ht/~rabbits/uxn/%3C20220604142148.1299.43328%40mail.envs.net%3E#%3C20220607152847.k6slek6bzwbbnns6@mutt%3E
can be used to switch execution timeouts back on when the
special-purpose Uxntal program needs it for a REPL or to single-step
code.
Best wishes,
Andy
Hi,
On 12/06/2022 20:38, felix.winkelmann@bevuta.com wrote:
>> 04 Busy: Occurs when the BRK opcode is triggered and the stack is not empty.> That last one, I think, is a bad idea: it would make it impossible> to handle events while inside some task doing arbitrary processing.
Yes I agree, this would break the AI player of the game I implemented:
it runs in the frame vector with a yield/continue thing using BRK
to amortize calculations over time, and assumes the non-empty stack
is preserved between yields/continues.
Warnings printed to stderr would be bad too, unless there was rate limiting
(e.g. print warning at most once per launch by default,
which tells how to enable repeated printing explicitly).
Claude
Since, it turns there is an actual use to keep stacks across vectors
like you demonstrated, and also Claude contacted me about this
off-list to tell me they also used it, then forget about error4
altogether, there's nothing stopping you to just lead things in the
stacks :)
I found a way that I liked to work around this as well, the reason why
I was even considering error4 was that I tend to rely on this to tell
me if I have leaks.
Without having to change much at all, I figured that if I don't print
the stack content when they are empty, and leave a #01 .System/debug
DEO at the end of each vector in the programs I'm writing, the effect
is the same.
https://git.sr.ht/~rabbits/uxn11/tree/main/item/src/devices/system.c#L35
So forget about this error4 thing, I shall not mention it again :)
Thanks for catching this one, maybe I might also try to write programs
that keep content in stacks across vectors!
Have a nice one.
On 6/13/22, felix.winkelmann@bevuta.com <felix.winkelmann@bevuta.com> wrote:
>> I've noodled around with this this afternoon and catching busy stacks>> on break in userspace/per-application is pretty cumbersome and>> invasive.>>>> So what I did was this, a typical debug query:>>>> #02 .System/debug DEO>>>> And thereafter, the uxn11 emulator is printing a warning(not errorring),>> when it is breaking on non-empty stack. It's non-intrusive,>> So the debug DEO enables this warning?>>> varvara-space defined and straight-forward. I've grown used to this>> little safeguard and I'd like to keep it in, this might be the way.>>>> I'll spend a few more days with this to test it out :)>> A warning on stderr would be fine, I think, as long as execution> proceeds as normal.>>> felix>>