Shop OBEX P1 Docs P2 Docs Learn Events
A retromachine Basic interpreter [beta] - Page 3 — Parallax Forums

A retromachine Basic interpreter [beta]

13567

Comments

  • I usually time an empty loop and deduct the looping overhead, to get an idea of command processing time (courtesy of @JonnyMac :) )

    Craig

  • pik33pik33 Posts: 2,387

    Now it is fast enough to do this:

  • Yeah that's nice @pik33. How many FPS are you getting?

    Horizontal lines do really benefit from the PSRAM block fills.

  • pik33pik33 Posts: 2,387

    2 frames per screen, 25 fps. I think 50 fps is possible when compiled: this is the interpreter loop that itself eats several microseconds. Then the Atari Basic style "plot, then draw" needs 2 PSRAM access per line. I have to add setpoint command or something like this, that sets the starting point without plotting on it, or make 4 parameters version of draw. The current version of the interpreter doesn't allow variable numbers of parameters.

  • roglohrogloh Posts: 5,837
    edited 2023-08-10 07:03

    By the way, my PSRAM driver code also has some line drawing acceleration built in as an optional feature for drawing non-horizontal lines. You just need to setup a memory request list item and the driver will draw it for you. I think it supports 8,16,32bpp modes (but not 1/2/4bpp at the moment). It may be useful to couple it to your BASIC to speed up those operations as well if you were not already using it. You probably just have to do some bounds checking before you set it up as it assumes the start/end addresses are correct and just does the operation, so if you pass garbage it could fill forever or overwrite areas outside the screen. See the gfxLine API in memory.spin2. These arguments might seem a little strange as it is optimized for the driver not for the user:

    PUB gfxLine(dstAddr, dstPitch, xoffset, yoffset, pattern, listPtr, datasize) : r | req, m, list, dx, dy

    • dstAddr is the starting pixel address in PSRAM (lower addressed co-ordinate of line)
    • dstPitch is the spacing in bytes between two lines
    • xoffset is the X pixel offset between the start and end x co-ordinates
    • yoffset is the Y pixel offset between the start and end y co-ordinates
    • pattern is the fill data (colour)
    • listPtr is your own listItem buffer if you want to chain a bunch of requests together and issue later (or 0 to use the built in buffer and issue immediately)
    • datasize is the number of bytes per pixels (1,2,4)

    You should also to pass in the F_EXPANSION bitmask flag when you start the memory driver so it includes this optional graphics acceleration feature which runs from HUBRAM and is therefore potentially susceptible to lock up if other COGs ever overwrite its code memory (unlike the remainder of the driver which runs from COGRAM and so will(?) never crash).

    Here was some code making use of it...bpp and stride, screenbuf, xmax, ymax etc were other global variables based on screen size and bit depth and window address.

    ' line drawing methods
    
    PUB line(x1, y1, x2, y2, colour)
        if xmax +< x1 or xmax +< x2 or ymax +< y2 or ymax +< y2 ' prevent lines that exceed dimensions
            return
        if y1 == y2 ' optimization for horizontal lines
            horizLine(x1, x2, y1, colour)
        elseif bpp>4
            mem.gfxLine(screenbuf + x1<<(bpp>>4) + stride*y1, stride, x2-x1, y2-y1, colour, 0, bpp>>3)
        else
            lowBppLine(x1, y1, x2, y2, colour)
    
  • pik33pik33 Posts: 2,387

    Interesting thing.... I have no such procedure in 16-bit wrapper but I have it for 4 bit. Maybe they are the same :) and I can transplant it. My line procedure, as it is now, checks if it is horizontal, then draws it fast, else draws it pixel by pixel using putpixel, that's much slower.

    Drivers I am currenty using are now old, both drivers and wrappers, but they are modified to do the list without polling other cogs between list entries. Maybe it is time to switch to the current version of the driver and check, for example, if I can use a (16 bit?) PSRAM soldered to non-PSRAM Edge at clk/3...

    Another hack I did was to move the mailbox to $7FF00. This allows to inplement brun command that can load and run any P2 binary from inside Basic. It loads it to the PSRAM, then moves to HUB, so If there is a mailbox somewhere in the middle, it cannot work. Having the mailbox on the top allows to fill near full HUB RAM with the binary code.

  • @pik33 said:
    Interesting thing.... I have no such procedure in 16-bit wrapper but I have it for 4 bit. Maybe they are the same :) and I can transplant it. My line procedure, as it is now, checks if it is horizontal, then draws it fast, else draws it pixel by pixel using putpixel, that's much slower.

    Yeah they should be the same, maybe I just forgot to include it in that version. I have that many drivers now with all these variants, hard to keep track of it all.

    Drivers I am currenty using are now old, both drivers and wrappers, but they are modified to do the list without polling other cogs between list entries. Maybe it is time to switch to the current version of the driver and check, for example, if I can use a (16 bit?) PSRAM soldered to non-PSRAM Edge at clk/3...

    I think those timing hacks were mainly for Wuerfel_21 when we had multiple device fanout like Rayman's large boards have.

    Another hack I did was to move the mailbox to $7FF00. This allows to inplement brun command that can load and run any P2 binary from inside Basic. It loads it to the PSRAM, then moves to HUB, so If there is a mailbox somewhere in the middle, it cannot work. Having the mailbox on the top allows to fill near full HUB RAM with the binary code.

    Sounds useful. An almost zero footprint mailbox would be nice for that sort of thing. :smile:

  • pik33pik33 Posts: 2,387

    That thing doesn't work after transplanting. Maybe the driver used is too old. I have now to check what I used here and replace it with something that's not that old :) .

  • roglohrogloh Posts: 5,837
    edited 2023-08-10 09:03

    I do see the GFX expansion code present in rev 0.9b PSRAM 16 bit COG driver code but you probably just need to modify the wrapper flags which right now are just defaulting to zero in psram.spin2.

        ' optional FLAGS for driver
        FLAGS = 0
    
  • pik33pik33 Posts: 2,387
    edited 2023-08-10 12:38

    (Deleted 0.16 as this binary seems to be useless... the bug has to be found and fixed first)


    I do see the GFX expansion code present in rev 0.9b PSRAM 16 bit COG driver code but you probably just need to modify the wrapper flags which right now are just defaulting to zero in psram.spin2.

    Flags set to $10000000, still no line. I will try this later.

  • pik33pik33 Posts: 2,387
    edited 2023-08-10 13:49

    That 0.16 seems to be working now. Removing one bug caused another one to hit hard, generating all kinds of strange behavior when a command without arguments was placed in the middle of the line like this:

    120 j=j+1 : waitvbl : goto 110

    The bug caused thiswaitvbl to be treated as as an "empty line" and make the interpreter to call "delete_line" instead of "compile_line"

  • pik33pik33 Posts: 2,387

    When I tried something with floats, I encountered that assigning to float variables didn't work well... it copied the 32bit encoded float to the integer as is. The result was not what I wanted and expected... so I updated it. Then I realized that making type conversion on the fly while assigning - instead or generating error messages - costs near nothing. So now any type of a variable can be assigned to anything else.

    10 c$="3.456789"
    20 v!=c$
    30 print v!
    

    The printed result is now 3.4568. The precision is awful, this Basic needs proper floats... 8bit Atari was better than that (it used 6 bytes long BCD encoded floats)
    The conversion is done "on the fly" and that means functions like str$ and val are no more needed in the interpreter.

    The example that beeps the C major scale now works. Notice slowing down when the interpreter has to scroll the screen up while printing.

  • pik33pik33 Posts: 2,387

    Plot test time reduced to about 16 seconds. About the same time with 1000000 for-add-next loops. With plot loop, compiled-to-interpreted speed is about 8:1. Much better than 35:1 where I started.

    Before heavy thinking about how to make goto fully functional, I added, for fun, "ink", "paper" and "font"
    Ink sets the color for print, paper sets the background color. Font sets a font family (0: PC type, 1 ST type)

    This means I can switch to "another nostalgic look" with several commands... font 0 : ink 22 : paper 0 : cls and I have the "amber PC" look instead of Atari.

  • For an interpreter, the performance is already quite astounding.

    How does compiled Spin2 compare with interpreted Spin2, I wonder?

    Craig

  • pik33pik33 Posts: 2,387
    edited 2023-08-11 12:47
    con
    _clkfreq=220000000
    
    pub test11()  | i,j,a
    
    
    i:=getct()
    a:=0
    repeat j from 0 to 1000000
      a:=a+1
    i:=getct()-i
    debug(udec(a),udec(i))
    

    2_000_000 clocks with Flexprop, 192_000_000 with Propeller Tool.
    And about 5_400_000_000 with my interpreter :(

    Flexprop compiled rep there. 1000000 adds - rep add #1. So 2 clocks per add, 2 clocks per loop. Fastest possible thing.


    The interpreter got a new "fun type" command: mode. That changes the look and feel of it at one command

    Also, I found typing

    load "test.bas"

    annoying, with these "" string delimiters. So now I can type load test.bas and it will do this instead of "error 30: string expected"

  • pik33pik33 Posts: 2,387

    Mode, new load syntax and some random music :)

  • pik33pik33 Posts: 2,387

    0.17. Alpha stage now reached.

    - proper GOTO that can be written at any time
    - new commands: "paper", "ink", "font" and "mode"
    - "load", "save" and "brun" file names can be written without ""
    - only ctrl-c is now used to break the program
    
  • pik33pik33 Posts: 2,387

    How to make a string more permanent in FlexBasic?

    I have a "disappearing strings" in the interpreter. The cause of the problem is simple:

    • the interpreter analyses the line and finds the string
    • then the string became the part of compiled_line
    • the compiled_line is then written to the PSRAM, but there is no actual string in PSRAM, as the string variable is only a pointer
    • the proces continues with the next line, then the flexspin thinks the string is no longer needed and reuses the memory for something else. The pointer in PSRAM is now invalid and the interpreter displays garbage

    What I need is to make the string permanent in the hub until the interpreter got a 'new' command. A table of strings to make Flexprop think the string is still in use, or even save them in the PSRAM.

  • @pik33 said:
    Mode, new load syntax and some random music :)

    OMG I now feel 40 years younger. I think I would have been basically doing this sometime around 1983. :smile:

  • pik33pik33 Posts: 2,387
    edited 2023-08-12 06:16

    OMG I now feel 40 years younger.

    That's one of purposes of this interpreter :)

  • @pik33 said:
    How to make a string more permanent in FlexBasic?

    I have a "disappearing strings" in the interpreter. The cause of the problem is simple:

    • the interpreter analyses the line and finds the string
    • then the string became the part of compiled_line
    • the compiled_line is then written to the PSRAM, but there is no actual string in PSRAM, as the string variable is only a pointer
    • the proces continues with the next line, then the flexspin thinks the string is no longer needed and reuses the memory for something else. The pointer in PSRAM is now invalid and the interpreter displays garbage

    What I need is to make the string permanent in the hub until the interpreter got a 'new' command. A table of strings to make Flexprop think the string is still in use, or even save them in the PSRAM.

    It sounds like you need to copy the string contents to PSRAM, not just the string pointer. Otherwise, you'll have to keep the string pointer in HUB memory. The FlexBasic garbage collector doesn't know about PSRAM, it only scans HUB and COG memory to find which pointers are still in use.

  • pik33pik33 Posts: 2,387
    edited 2023-08-12 11:35

    it only scans HUB and COG memory to find which pointers are still in use.

    And it is not in use anymore and even worse, the 'compiled_line' is recycled for the next line to interpret. That's why it disappears. A string table in hub doesn't help a lot too. I have to keep strings in PSRAM. And I already keep them there, for using by 'list' command, so the only thing I have to do is to use them.

  • pik33pik33 Posts: 2,387
    edited 2023-08-12 17:17

    There is a simple Mandelbrot example in Flexprop's examples folder. Rewritten for the current version of the interpreter :) Slow, but works. Listed after the fractal was drawn

  • pik33pik33 Posts: 2,387
    edited 2023-08-13 14:42

    The power of old style Basic interprerer is:

    • you power on your computer, you got the "Ready" prompt faster than the monitor starts displaying the picture
    • then you write several lines, and you have a result you can see or hear.

    The program below allows to draw using a mouse. A wheel sets the color (displayed at the upper right and cropped on this photo), then you can draw by pressing the left mouse button while the right mouse button clears the screen. 7 lines of code.
    That's why, in 80s, every kid knows how to program :) even here, in Eastern Block, where getting a home computer was much more difficult than it the West.

    New commands added:

    • click (on/off or 1/0) : The 8-bit Atari style keyboard click adds to the nostalgic feeling, but can be annoying, so click off switches it off.
    • cursor (on/off or 1/0) : the cursor is not needed when drawing a fractal, or something, it only blinks and annoys so it can now be switched off.
    • mouse (on/off or 1/0) : switches the mouse pointer on or off
    • gettime : returns getct. Internally it gets and stores all 64 bits of ct, so the result can be used when I implement int64 variables.
    • mousex, mousey : return mouse coordinates
    • mousek: returns the mouse key state
    • mousew: if the mouse is good enough to return its wheel data while in the boot mode, this returns the mouse wheel position.

    I forgot to add "<>" operator for compare ! That's why the line 30 looks this way :)

  • You can add to your BRUN command the ability to pass parameters that my funny emulators understand. You need to put some data at $FC000. For example, to load twinkle star sprites in neoyume you'd launch it with this data at $FC000:

    byte "ARGv"
    byte "twinspri",0
    byte 0
    

    Similar thing for megayume, but that one needs a file path like /sd/something.bin. The format is basically

    • ARGv signature
    • list of strings
    • empty string ends the list
  • pik33pik33 Posts: 2,387

    @Wuerfel_21 said:
    You can add to your BRUN command the ability to pass parameters that my funny emulators understand. You need to put some data at $FC000. For example, to load twinkle star sprites in neoyume you'd launch it with this data at $FC000:

    byte "ARGv"
    byte "twinspri",0
    byte 0
    

    Similar thing for megayume, but that one needs a file path like /sd/something.bin. The format is basically

    • ARGv signature
    • list of strings
    • empty string ends the list

    That's good :) This can be used for more binaries to pass parameters for them.

  • pik33pik33 Posts: 2,387

    I had to do some SD card cleaning before experimenting with *yume : its main directory was littered with *.bas tests and experiments.

    Now Basic starts with its own working directory /sd/bas and brun loads binaries from /sd/bin (or, if full path given, from there, so it is possible to brun /sd/megayume/megayume.bin)

    I have to enhance brun syntax to add parameters. Maybe simpy this: brun "megayume.bin twinspri"

    I lost Megayume when flash accessing in Mode 0 unformatted my SD : I have to recompile it now.

  • @pik33 said:
    I lost Megayume when flash accessing in Mode 0 unformatted my SD : I have to recompile it now.

    You need a recent-ish version to have the argv thing, anyways :)

    Though as mentioned megayume wants a path to a bin file, neoyume wants a mame ID (paths are hardcoded to /sd/neoyume/game/)

  • pik33pik33 Posts: 2,387

    I recompiled neoyume : can be started from Basic (without a parameter yet), but the yolkless P2 hit hard :( I have now to found and hack the code again.

    Also, I didn't manage to get a picture using HDMI. Tried to uncomment these 4 lines:

    VIDEO_MODE = vconst.MODE_HDMI
    VIDEO_SUBMODE = 0
    VGA_BASEPIN = 0
    VGA_VSYNC = -1

    with no result. I have HDMI at P0. All these pinput and snes set to -1

  • Wuerfel_21Wuerfel_21 Posts: 5,106
    edited 2023-08-13 21:35

    set VGA_VSYNC to 0 I think? Yea, that should be it, idk why the example config has -1.

    Also, try the slot-interleave branch. That one shuffles the code in that section around, so it might not trigger any yolk hazards.

    (this is a certified thinkpad-in-bed post, no guarantees)

Sign In or Register to comment.