Matrix Brandy V1.23.0 released
I have today released version 1.23.0 of Matrix Brandy.
Changes include:
- System: Add '-tek' (or -t) option to enable Tek graphics for 'tbrandy' on compatible platforms. Equivalent to issuing SYS"Brandy_TekEnabled",1
- System: Strict mode can now be set programmatically with SYS"Brandy_Strict".
- System: Strip quotes from filenames in *LOAD and *SAVE
- System: Implemented OSWORDs 1 and 2
- System: Fix file name bug in OSFILE.
- System: Filename translation between RISC OS and Linux for OPENIN, OPENOUT and OPENUP.
- System: Added "-nofull" command line option, to disable switching into full-screen mode (for questionable hardware, e.g. Poulsbo chipsets)
- System: Do not hang on text build startup when console doesn't handle the ANSI sequence to report the cursor location (e.g. Minix3 console), instead time out after 0.5 seconds.
- MOS: *Refresh, *WinTitle and *FullScreen are now recognised on RISC OS builds, but do nothing. (Previously, they raised a "Not Found" error.) This is to allow programs written targeting other platforms a better chance to run correctly under RISC OS without further modification.
- MOS: OSBYTEs 42-44 deprecated, use 163,2-4 instead.
- BASIC: LOCAL with no parameters now does nothing (as per Acorn) instead of reporting an error. This new behaviour is in place on a DEFAULT_IGNORE build unless -strict is set, or if -ignore is set. This can also be toggled at runtime with SYS"Brandy_Strict".
- BASIC: If Strict option is set, warnings are handled as fatal errors if a program is running.
- BASIC: Limit the recursion depth of RUN.
- BASIC: Don't choke if a numeric DATA element contains a comma (e.g. multi-dimensional array member or FN call)
- BASIC: Clear variable stubs if a DIM fails, and after CLEAR HIMEM.
- BASIC: Indirection with floats containing addresses > 32 bits now work.
- BASIC: Print a warning if a conversion from int64 to float loses precision.
- BASIC: Fix bugs in Exponent format number printing. Graphics: Fixed multiple problems with VDU24, RECTANGLE FILL, MOUSE and the plot_pixel() primitive, primarily to do with the oddball MODE 22. Thanks to Michael Fairbank for identifying and assisting with fixing this.
- Graphics: Fixed a cursor placement bug for VDU31 (PRINT TAB(x,y)) in VDU 5 mode.
As of this release, the git repository master branch will track releases. Development will be found in the dev-main branch.
Downloads are available, as usual, from the website.
Changes include:
- System: Add '-tek' (or -t) option to enable Tek graphics for 'tbrandy' on compatible platforms. Equivalent to issuing SYS"Brandy_TekEnabled",1
- System: Strict mode can now be set programmatically with SYS"Brandy_Strict".
- System: Strip quotes from filenames in *LOAD and *SAVE
- System: Implemented OSWORDs 1 and 2
- System: Fix file name bug in OSFILE.
- System: Filename translation between RISC OS and Linux for OPENIN, OPENOUT and OPENUP.
- System: Added "-nofull" command line option, to disable switching into full-screen mode (for questionable hardware, e.g. Poulsbo chipsets)
- System: Do not hang on text build startup when console doesn't handle the ANSI sequence to report the cursor location (e.g. Minix3 console), instead time out after 0.5 seconds.
- MOS: *Refresh, *WinTitle and *FullScreen are now recognised on RISC OS builds, but do nothing. (Previously, they raised a "Not Found" error.) This is to allow programs written targeting other platforms a better chance to run correctly under RISC OS without further modification.
- MOS: OSBYTEs 42-44 deprecated, use 163,2-4 instead.
- BASIC: LOCAL with no parameters now does nothing (as per Acorn) instead of reporting an error. This new behaviour is in place on a DEFAULT_IGNORE build unless -strict is set, or if -ignore is set. This can also be toggled at runtime with SYS"Brandy_Strict".
- BASIC: If Strict option is set, warnings are handled as fatal errors if a program is running.
- BASIC: Limit the recursion depth of RUN.
- BASIC: Don't choke if a numeric DATA element contains a comma (e.g. multi-dimensional array member or FN call)
- BASIC: Clear variable stubs if a DIM fails, and after CLEAR HIMEM.
- BASIC: Indirection with floats containing addresses > 32 bits now work.
- BASIC: Print a warning if a conversion from int64 to float loses precision.
- BASIC: Fix bugs in Exponent format number printing. Graphics: Fixed multiple problems with VDU24, RECTANGLE FILL, MOUSE and the plot_pixel() primitive, primarily to do with the oddball MODE 22. Thanks to Michael Fairbank for identifying and assisting with fixing this.
- Graphics: Fixed a cursor placement bug for VDU31 (PRINT TAB(x,y)) in VDU 5 mode.
As of this release, the git repository master branch will track releases. Development will be found in the dev-main branch.
Downloads are available, as usual, from the website.
1
Comments
-
-
This is as a result of RUN calling a function in the C code, and a program that calls RUN could exhaust the C stack if called recursively.0
-
-
No, it's just the way it works in the C code, that RUN is implemented as a C function that is called, thus it's called like a PROC rather than a GOTO in the C layer. So, if a program calls RUN within itself it can lead to C stack exhaustion or the process running out of memory, so I set a recursion limit to prevent it crashing the interpreter.0
-
RUN is implemented as a C function that is called, thus it's called like a PROC rather than a GOTO in the C layer. So, if a program calls RUN within itself it can lead to C stack exhaustion or the process running out of memory
If RUN is somehow different from CLEAR : GOTO and CHAIN I feel I must be missing something fundamental, which is rather worrying because it might mean that my interpreters are affected in a similar way without me ever realising it! Running this code doesn't cause any obvious issue in my coded-in-C interpreter:A% += 1 PRINT A% RUN
0 -
I'll have to take a closer look at this, it's code inherited from upstream that I haven't had to touch (beside tracking the recursion level). The limit is pretty high, 512 levels, and a program that refuses that much is likely to have gone wrong.
The issue is also likely to affect CHAIN, again I need to take a closer look.
Edit: Recurses, not refuses. Autocorrupt, typing on my phone.0 -
The limit is pretty high, 512 levels, and a program that refuses that much is likely to have gone wrong.
ON MOVE IF @msg% = 5 RUN ELSE RETURN : REM Resize
If CHAIN is also affected, in the context of an IDE which uses CHAIN to run the 'spawned' programs (my touchide.bbc is like that) there is no limit to the number of CHAINs one might get in a 'session'.0 -
While I am still to look at CHAIN, RUN is now resolved - it now uses setjmp/longjmp if the program is running to reset the C stack if RUN is called while a program is running. This ought to mean the repetition depth is unlimited. (After all, it isn't actual recursion as a program can't return from a RUN.)0
-
RUN is now resolved - it now uses setjmp/longjmp if the program is running to reset the C stack if RUN is called while a program is running.
* Except perhaps for RUN also clearing the BASIC stack.0 -
I looked at that approach, but GOTO <nonexistent line number> causes an error (as it does on the BBC, I think the Spectrum jumps to the next valid line). So if the "program running" flag is set, a RUN does a longjmp() back to the initialisation point, which also resets the stack - so a program constantly calling RUN won't cause the stack to grow.
I've been doing more work on the stack issues though, recursion of FN causes both the BASIC stack AND the C stack to grow, so I've changed the threading model a bit because pthreads allows me to set a custom stack size for a thread, and the artificial threading limit is based on a function of the supplied stack size (itself based on workspace size). Surprisingly this even works on Minix.0 -
I looked at that approach, but GOTO <nonexistent line number> causes an error (as it does on the BBCI've been doing more work on the stack issues though, recursion of FN causes both the BASIC stack AND the C stack to grow
In general I always follow the recommendation of Raymond Chen, the famous Microsoft blogger and Windows expert, who says you shouldn't attempt to trap running out of memory but rather you should let the program crash. It's safer and it's faster.
The nature of BBC BASIC is that you can crash the interpreter using BASIC code. That's not a fault that needs to be corrected. Spend your valuable time adding new features and fixing real bugs!
0 -
It's not a RUN in an FN, more like something contrived like this:
10 A%=0 20 PRINT FNr 30 END 100 DEFFNr 110 A%=A%+1 120 PRINT A% 130 =FNr
When the C stack is breached, you get a segmentation fault error, so I've been trying to prevent this. Of course it's not 100% possible to block this, I've been looking to see how I can deal with the stack and set a sensible recursion limit based on the stack size (which is now a known value).
An error will happen, what I am trying to avoid is the interpreter crashing out.0 -
It's not a RUN in an FN, more like something contrived like this:When the C stack is breached, you get a segmentation fault error, so I've been trying to prevent this.
For most of its history it has been impossible to protect BBC BASIC from crashing as a result of !<random address> or USR(<random address>) etc. and everybody accepts that as a price worth paying for the benefits of those low-level features.
You seem to be trying to leverage the hardware memory management features of modern CPUs to avoid those crashes, but in my opinion your efforts are misguided. Those same hardware features already mean that the crash just takes out one process, not the entire machine, so is harmless.
0 -
This is Raymond Chen's original article, in which he mentions stack growth.
Incidentally I'm not sure what the default stack size is for 64-bit GCC and Clang builds, do you know (it used to be a few megabytes for 32-bit builds I think)? It's usually possible to override that with a linker flag, but I don't do that in any of my builds.0 -
In Linux, the stack limit tends to be set with 'ulimit -s'.
However, pthreads allow you to set thread attributes including the thread stack size. Ever since I went multi-threaded I had the interpreter in a separate thread to the display (which must be the top level in SDL 1.2), I just switched from using SDL's threading functions to pthreads - which actually simplified the code as I needed pthreads for the text-mode builds anyway. Thus, by a bit of trial and error I've got a stack size that is related to the workspace size. Previously, especially in Windows I was getting a FN recursion limit barely bigger than I was seeing in HIBASIC 4.30 on the BBC Master, despite a workspace size of 64MBytes, versus the Master's 45.5K in HIBASIC! Even ARM BBC BASIC VI was giving me around 27000 in the default 640K workspace. Now I am getting a depth of about 100,000 in the 64MB workspace size. Matrix Brandy is clearly not as efficient as the ARM or 6502 BASICs in their use of BASIC workspace, when I tweak the algorithm to give way more stack than is needed (so the BASIC workspace is exhausted first), a 640K workspace gives me a recursion depth of just 1487, and with 46K workspace(!) I get only 105. The Master got about 1800.
RISC OS was the odd one out here, as I'm not using a threading model as I don't need to worry about graphics updates or the centisecond timer (as RISC OS provides both of these in a directly compatible fashion). The stack, at least on the UnixLib build grows as needed, but has a hard limit when the process size reaches the WimpSlot maximum of 28640K. So I've worked out the limit there and hardcoded a cap that's a bit below that, but of course on a machine with not so much memory it's still possible to crash it.0 -
I just switched from using SDL's threading functions to pthreads
Stack size has never been an issue for any of my programs, and nor has anybody else ever reported it being so. I can't imagine any reasonable circumstances when a recursion depth of several thousands, let alone tens of thousands, would be required.
When running on the Raspberry Pi Pico, with a total RAM (for everything) of only about 256 Kbytes, the limit is much smaller but again that has rarely been an issue. Only my Sudoku solver program has been known to run out of stack on that platform.
0 -
Richard_Russell wrote: »Some (e.g. Android and iOS) may well have relatively small limits imposed at run-time because of the nature of the OS.
0 -
That's a similar approach my code takes - if the stack can be increased, great. If it can't, oh well, we'll just make do with what we have.0
-
Richard_Russell wrote: »the maximum recursion depth remains at a few hundred.
0 -
I'm not sure if a flood fill counts as useful...
5REM>FFbasic 10MODE 19: REM 640x512 version of MODE 1 15O%=2: REM Pixel interval, set to 4 for MODE 1 20FOR X%=0 TO 1280 STEP (O%*2) 30MOVE X%,0: DRAW X%,1280 40MOVE 0,X%: DRAW 1280,X% 50NEXT 60GCOL 0,1 70GCOL 0,131 80PLOT &85,0,0 85WAIT 100 90GCOL0,2 100PROCfill(640,512) 110PRINT"Max depth: ";M%;" Depth at end: ";D% 120END 200DEFPROCfill(x%,y%) 210OFF 220D%=0:M%=0 230C%=POINT(x%,y%) 240PROCfill2(x%,y%) 250ON 260ENDPROC 270DEFPROCfill2(x%,y%) 280IF x%<0 OR y%<0 OR x%>1279 OR y%>1023 THEN D%-=1: ENDPROC 290POINT x%,y% 300D%+=1 310IFD%>M% THEN M%=D% 320IF POINT(x%-O%,y%)=C% PROCfill2(x%-O%,y%) 330IF POINT(x%,y%-O%)=C% PROCfill2(x%,y%-O%) 340IF POINT(x%+O%,y%)=C% PROCfill2(x%+O%,y%) 350IF POINT(x%,y%+O%)=C% PROCfill2(x%,y%+O%) 360D%-=1 370ENDPROC
0 -
I'm not sure if a flood fill counts as useful...
https://codeheir.com/2022/08/21/comparing-flood-fill-algorithms-in-javascript/if the stack can be increased, great. If it can't, oh well, we'll just make do with what we have.
My reasoning is this. If, for example, one wants to develop an Android app in BBC BASIC the development is likely to be done on a Windows or MacOS desktop, and only when the code has been thoroughly tested in that environment will it be tried on Android.
The last thing you want to discover at that late stage is that the algorithm you chose needs a stack greater than is available in Android! Far better to discover that earlier, when testing on the PC, so you change your approach then.0 -
I'm not sure if a flood fill counts as useful...
Generally speaking if the C stack is the limiting factor the likelihood is that the code can be rejigged to use a PROC with a RETURNed parameter rather than an FN. Here's a comparison I made using BBCSDL:PRINT FNr(0) END DEF FNr(A%) PRINT A% A% += 1 = FNr(A%)
Bombed out after 575 recursions because of C stack overflow.PROCr(A%) : PRINT A% END DEF PROCr(RETURN A%) PRINT A% A% += 1 PROCr(A%) ENDPROC
Bombed out after 466,000 recursions because of BASIC stack overflow.
0 -
Richard_Russell wrote: »I'm not sure if a flood fill counts as useful...
https://codeheir.com/2022/08/21/comparing-flood-fill-algorithms-in-javascript/
I guess my first step would be to try to implement some of these in BASIC, then once I fully understand how they work, port them to C to improve the PLOT &85 handler.0 -
Conversely, while slow, the Master's internal fill can fill that pattern
I've never implemented them fully (particularly in respect of the way they are supposed to move the graphics cursor) but I expect you do, in which case you should be able to make a respectable flood fill using them; I think you'll find it's the 'span' algorithm at the Javascript link.
The span algorithm performed the best of the bunch in those comparative tests, so it seems Acorn made a good choice of fill primitives in the BBC Micro. I can't say that I've ever seen a BASIC flood fill using those primitives, but it's what they were intended for.0