Shop OBEX P1 Docs P2 Docs Learn Events
90's style 3D (Now at 16bpp, using PSRAM) - Page 5 — Parallax Forums

90's style 3D (Now at 16bpp, using PSRAM)

1235»

Comments

  • RaymanRayman Posts: 15,743

    Got it switched over to 16bpp. Still looks the same though because using same graphics, just switched to 16bpp...
    Next is to make some better graphics.

    Also, need to figure out how to dim a 16bpp color.
    Think need to RGBEXP on it, then do something magic, then do RGBSQZ

    With 16 bit wide PSRAM, don't need to break the buffer copying into two parts.
    Doesn't actually work when broken in two. Have to get back to 4-bit PSRAM and see if that was actually working...

  • RaymanRayman Posts: 15,743

    Sadly, seems that 4bit PSRAM is not fast enough for display buffer to be in PSRAM. 16bit works, but would really like to support 4bit.
    Think will change direction and have both working and display buffers be in HUB.

    Hopefully, there is still enough HUB space left to add sprites and such later...

  • roglohrogloh Posts: 6,071
    edited 2025-10-11 05:38

    4 bit PSRAM will have a raw bandwidth of about 75MBps at a P2 clock of 300MHz. Some of that is lost to overheads - I think I can manage to get 8bpp VGA and SVGA video out of it but it then doesn't leave a lot spare for writes. 16 bit colour doubles that requirement and if you are writing an entire frame at the same time I doubt it can work for VGA. 320x200 is smaller so may still be possible though. You'd have to do the numbers and probe the CS lines of a PSRAM to see how much free bandwidth is left over when attempting it. It was surprising to me how much a single nibble of PSRAM could do in the end after tuning the burst sizes to maximize read bandwidth possible.

  • RaymanRayman Posts: 15,743

    Switched display buffer back to hub.

    Updated the code that copies the offscreen buffer to the display buffer from this:

                    mov       my,#120
    myloop4
                    mov       mx,#2*320/4
                    rdfast    #320*2,ptra
    mxloop4
                    rflong    ml
                    wrlong    ml,ptrb++
                    djnz      mx,#mxloop4
                    add     ptra,##320*2
                    djnz      my,#myloop4
    

    to this:

                    mov     my,#120
    myloop4
                    setq2   #40-1
                    rdlong  LutBuf,ptra++
                    setq2   #40-1
                    wrlong  LutBuf,ptrb++
                    setq2   #40-1
                    rdlong  LutBuf,ptra++
                    setq2   #40-1
                    wrlong  LutBuf,ptrb++
                    setq2   #40-1
                    rdlong  LutBuf,ptra++
                    setq2   #40-1
                    wrlong  LutBuf,ptrb++
                    setq2   #40-1
                    rdlong  LutBuf,ptra++
                    setq2   #40-1
                    wrlong  LutBuf,ptrb++
                    djnz      my,#myloop4
    

    This is based on the "fast block move" section of the P2 Silicon Doc.

    There is something mysterious going on though... First tried doing 320 longs at a time start from the beginning of LUT.
    This failed miserably, then remembered moved some code to LUT, so that's a problem...

    Then, changed the FIT at the end of LUT code to this "fit $2FF".
    Tried doing 160 long reads from $300, but that also fails.
    Seems like something is using the end of LUT, but have no idea what...

    This is fine though. Maximum frame rate increased from 90 fps to 100 fps with P2 clock at 300 MHz.
    Well above the 60 Hz needed.

  • RaymanRayman Posts: 15,743

    Using Midjourney to generate new graphics. It's going to be a process to get it to do something useful.
    Think it's getting there though.

    Having but buffers in HUB takes up most of HUB RAM. But, there's still 90 kB left.
    Want to add variety of floor and wall tiles next.
    Wall and floor tiles are 8 kB each. So, maybe don't need to dynamically load those to hub right away...

  • RaymanRayman Posts: 15,743

    Feeling like simpler tiles are better...
    Also, remembered that want to darken far away tiles...

  • RaymanRayman Posts: 15,743

    Implemented darkening of further away walls and floors.
    Used the simplest method, but may look into the other ways from here:
    https://forums.parallax.com/discussion/174921/

    This works, but max. frame rate drops from 100 to 90... Still good.

                    rdword  f2,ptra
    
    DarkenPixel
                    mov     dista,dist
                    mul     dista,#50
                    shr     dista,#8
                    fle     dista,#255
    
    
                    mov     level,#255
                    sub     level,dista
    
                    movbyts level, #%%0000                        ' make multiplier
                    rgbexp  f2
                    mulpix  f2, level                         ' scale the color
                    rgbsqz  f2
    
    640 x 480 - 198K
  • RaymanRayman Posts: 15,743

    Found some floor tiles to play with here:
    https://opengameart.org/content/200-tile-floor-textures

    Added a static status bar as an image in PSRAM that gets copied to buffer every frame.
    In future, this can be written on top of to show useful things...

    Max. frame rate dropped from 90 to 85 fps, still good.

  • RaymanRayman Posts: 15,743

    Seeing some strangeness, think due to graphics cogs being nearly full.
    The "fit $1F0" doesn't save it from going off the rails, but a smaller fit does.

    Also, seems to depend on whether in debug mode or not...
    Shouldn't asm debug statements change the fit count?

  • roglohrogloh Posts: 6,071
    edited 2025-10-12 02:20

    Was hoping to try this out but am having issues getting this code to work. Are you using PNut or flexspin @Rayman? I'm having trouble with your latest SpinMain1c version above and the startup of the FAT engine - it's failing right away before even mounting the partition yet all it does is assign pins. I modified to use the normal P2-EVAL pins 58-61 and am running a recent flexspin 7.5.0 that I built about a month ago. Not sure what is happening here, seems like it is written to work with aborts but I don't see any in the called code at init time.

    ...snip...
        'Start uSD driver
        debug("Starting fat engine")
        if \FS.FATEngineStart(uSD_MISO, uSD_CLK, uSD_MOSI, uSD_CS, 0)
            debug("Missing SD Card 1?")
            repeat
        if \FS.mountPartition(0)
            debug("Can't mount FS")
            debug("Missing SD Card?")
            repeat
        'if \FS.openfile(string("bgr4x.bmp"),"R")
        if \FS.openfile(string("back1b.bmp"),"R") 
            debug("Missing file?")
            repeat
    
    
    
    PUB  start_explicit(iDO, iCLK, iDI, iCS) : rc
        debug("start explicit")
        do_pin := iDO
        clk_pin := iCLK
        di_pin := iDI
        cs_pin := iCS
    

    loadp2 -t -b 2000000 raycast7a_SpinMain1c.binary
    ( Entering terminal mode. Press Ctrl-] or Ctrl-Z to exit. )
    Cog0 INIT $0000_0000 $0000_0000 load
    Cog0 INIT $0000_0404 $0000_0000 load
    Cog0 Starting fat engine
    Cog0 start explicit
    Cog0 Missing SD Card 1?

    Then when I forcibly bypass the first FATEngineStart failure by not processing any abort, it gets further but stops below. Can't tell what is going wrong. I tried a couple of SD cards and the requested file is definitely on the card in the top level folder.

    Cog0 SD clock divider set to sysclock/750 (0.4 MHz)
    Cog0 v2 Card Idle
    Cog0 SD clock divider set to sysclock/8 (37.5 MHz)
    Cog0 OCR register $80FF_8000
    Cog0 SDSC Card
    Cog0 Can't mount FS
    Cog0 Missing SD Card?

    EDIT: I was able to bypass the bmp file loading stuff and at least see your 3d graphics engine working with a USB keyboard. So I'm happier now. Be awesome to see this at true 640x480 instead of pixel doubled but I guess the performance won't be fast enough...

  • evanhevanh Posts: 16,789
    edited 2025-10-12 03:38

    hmm, I see it's reporting as a SDSC card. Is it 2GB?

  • evanhevanh Posts: 16,789
    edited 2025-10-12 03:54

    @rogloh said:

        if \FS.FATEngineStart(uSD_MISO, uSD_CLK, uSD_MOSI, uSD_CS, 0)
            debug("Missing SD Card 1?")
            repeat
    

    Looking at the source code for FATEngineStart() it always returns a non-zero value. Positive values are "cog+1" it is running on, and -1 for error.

  • @evanh said:
    hmm, I see it's reporting as a SDSC card. Is it 2GB?

    One was yeah, and this one typically works with the P2. The other is a 32GB Sandisk Ultra (a Raspi disk but has a FAT32 boot partition).

  • roglohrogloh Posts: 6,071
    edited 2025-10-12 04:05

    @evanh said:

    @rogloh said:

        if \FS.FATEngineStart(uSD_MISO, uSD_CLK, uSD_MOSI, uSD_CS, 0)
            debug("Missing SD Card 1?")
            repeat
    

    Looking at the source code for FATEngineStart() it always returns a non-zero value. Positive values are "cog+1" it is running on, and -1 for error.

    Yeah the code didn't make sense running the abort. The FATEngineStart seemed to call sdspi.getCog() method which returned 1 (hard coded) but this somehow triggered the abort code to be executed.

    PUB  getCog() : rc
    
        return 1    ' no cogs here!
    
  • evanhevanh Posts: 16,789

    As for mountPartition(), it seems to be a confused return code according to its own docs.

    '' // Returns true if the partition was improperly unmounted the last time it was mounted and false if not.
    '' //
    '' // If an error occurs this method will abort and return a pointer to a string describing that error.
    
  • evanhevanh Posts: 16,789
    edited 2025-10-12 04:11

    @rogloh said:
    Yeah the code didn't make sense running the abort. The FATEngineStart seemed to call sdspi.getCog() method which returned 1 (hard coded) but this somehow triggered the abort code to be executed.

    It's just the IF true condition right there in Rayman's code. All results are true so it's always going to abort. I suspect other examples don't check anything. This might be the first time anyone has tried to check return codes from FATEngine.

  • roglohrogloh Posts: 6,071
    edited 2025-10-12 04:35

    @evanh said:

    @rogloh said:
    Yeah the code didn't make sense running the abort. The FATEngineStart seemed to call sdspi.getCog() method which returned 1 (hard coded) but this somehow triggered the abort code to be executed.

    It's just the IF true condition right there in Rayman's code. All results are true so it's always going to abort. I suspect other examples don't check anything. This might be the first time anyone has tried to check return codes from FATEngine.

    Yeah I figured that sequence was bad so I skipped past the abort by converting to look for a negative error code instead, but the rest of the code still failed to mount and read the file. I guess it's my choice of SD card or something. I've sort of expected SDs to just fail to work on the P2 these days after being burned so often in the past before. It's hit or miss. I have the P2-EVAL dip switches set to BOD=off, Flash=off, P59 up=on, P59 down=off.
    This is where it fails now (it pauses for a second after the clock divider output).
    Cog0 INIT $0000_0000 $0000_0000 load
    Cog0 INIT $0000_0404 $0000_0000 load
    Cog0 Starting fat engine
    Cog0 SD clock divider set to sysclock/750 (0.4 MHz)
    Cog0 Can't mount FS
    Cog0 Missing SD Card?

    Mount code has this - so it looks like the ocr register cannot be read. This was the 32GB Sandisk. EDIT: actually it must be failing before this as it only prints the first divider message, not the second.

    PUB  mountCard() : rc | clk, di, cs, ocr
    
        clk := clk_pin
        di := di_pin
        cs := cs_pin
        ocr := (clkfreq + 400_000) / 800_000    ' 400 kHz during init
        xwait := ocr - 6
        rc := clkfreq +/ (ocr * 200_000)
        debug("SD clock divider set to sysclock/",udec_(ocr*2)," (",udec_(rc/10),".",udec_(rc//10)," MHz)")
    
        pinf(cs)
        waitus(10)
    
        pinh(cs)   ' Deselect the card
        pinh(di)
        pinh(clk)
    
        repeat 600
            read()
    
        cmd(0, 0)
        cmd(8, $1aa)
        read32()
    
        if cmd(0, 0) <> 1    ' R1 response
            deselect()
            return -40    ' abort, card not responding
    
        if cmd(8, $1aa) == 1    ' R7 response (R1 + IFC)
            if read32() <> $1aa
                deselect()
                return -40    ' abort, card error
            debug("v2 Card Idle")
    
        else
            debug("v1 Card Idle")
            cmd(16, 512)    ' R1 response, set block size
    
        repeat 200
            cmd(55, 0)    ' R1 response
            rc := cmd(41, $4020_0000)    ' R1 response
            if rc <> 1
                quit
            waitms(1)
        if rc
            deselect()
            return -40    ' could not initialize card
    
        xwait := 0    ' full speed
        rc := clkfreq +/ (8 * 100_000)
        debug("SD clock divider set to sysclock/8 (",udec_(rc/10),".",udec_(rc//10)," MHz)")
    
        cmd(58, 0)    ' R3 response (R1 + OCR)
        ocr := read32()
        deselect()
        debug("OCR register ",uhex_(ocr))
        if ocr>>30 <> 3    ' check CCS bit
            sdhc := 0
            debug("SDSC Card")    ' byte addressed card type
        else
            sdhc := 1
            debug("SDHC/SDXC Card")    ' block addressed card type
    
        return sdhc +1              ' return card type 2=SDHC,1=SD
    
  • The other card (2GB) gets further but still fails.

    Cog0 INIT $0000_0000 $0000_0000 load
    Cog0 INIT $0000_0404 $0000_0000 load
    Cog0 Starting fat engine
    Cog0 SD clock divider set to sysclock/750 (0.4 MHz)
    Cog0 v2 Card Idle
    Cog0 SD clock divider set to sysclock/8 (37.5 MHz)
    Cog0 OCR register $80FF_8000
    Cog0 SDSC Card
    Cog0 Can't mount FS
    Cog0 Missing SD Card?

  • evanhevanh Posts: 16,789

    @rogloh said:
    .... EDIT: actually it must be failing before this as it only prints the first divider message, not the second.

    Right, not going "Idle". So not even the initial CMD0/CMD8 working.

    I assume all is fine with those cards using my C based testers?

  • @evanh said:

    @rogloh said:
    .... EDIT: actually it must be failing before this as it only prints the first divider message, not the second.

    Right, not going "Idle". So not even the initial CMD0/CMD8 working.

    I assume all is fine with those cards using my C based testers?

    Haven't tried yet, though I know the smaller 2GB card works out okay with Wuerfel_21's emulator stuff - that's why I sort of use it.

  • roglohrogloh Posts: 6,071
    edited 2025-10-12 05:01

    One thing I'm finding out about is that mountPartition seems to be returning -1 due to this strange looking code:

        readWriteFATBlock(0, "R")
        debug("fstype=", UDEC_LONG(fileSystemType), UHEX_LONG(readFATEntry(1)))
        result := ((readFATEntry(1) >> (14 + (12 & fileSystemType))) <> $3)
        debug("got a result here", UDEC_LONG(result))
    

    Cog0 v2 Card Idle
    Cog0 SD clock divider set to sysclock/8 (37.5 MHz)
    Cog0 OCR register $80FF_8000
    Cog0 SDSC Card
    Cog0 fstype=fileSystemType = 0, readFATEntry(1) = $0000_3FFF
    Cog0 got a result hereresult = 4_294_967_295
    Cog0 Can't mount FS i = -1
    Cog0 Missing SD Card?

  • evanhevanh Posts: 16,789

    Just done a little testing myself. When I try a fresh card I get:

    ...
    Cog0  SDHC/SDXC Card
    Cog0  fileSystemType = $FCD8_0976, readFATEntry(1) = $0FFF_FFFF
    Cog0  got a result here: result = 0
    

    When I retest any of the cards I get:

    Cog0  SDHC/SDXC Card
    Cog0  fileSystemType = $FCD8_0976, readFATEntry(1) = $03FF_FFFF
    Cog0  got a result here: result = -1
    Cog0  Can't mount FS
    

    Order and power cycling don't matter. Happened with three consecutive cards now.

  • evanhevanh Posts: 16,789
    edited 2025-10-12 06:01

    Ah! Mounting often fails the first attempt. Just have to repeat it.

        'Try to mount a few times then give up if not successful
        repeat 3
            rc := \FS.mountPartition(0)
            if rc
                debug("Mount Error: ",sdec_(rc))
            else
                quit
            waitms(100)
        if rc
            debug("uSD Failed to mount!")
            repeat  'Give up and stay here
                waitms(500)
        debug("SD Volume Mounted")
    
  • roglohrogloh Posts: 6,071
    edited 2025-10-12 07:16

    Yeah that helped @evanh. I have it working now (also had to skip the abort checks for subsequent openFile operations).

    We should try to get a FAT32 filesystem reader that is stable to init the first time around. Not sure why it needs retries.

    Brings back the Wolfenstein vibes big time.

  • RaymanRayman Posts: 15,743

    That must be with FlexProp right?

    Always mounts first time with spin tools…

Sign In or Register to comment.