Shop Learn
MicroDOS - a simple loader for PSRAM based system — Parallax Forums

MicroDOS - a simple loader for PSRAM based system

We have more and more toys like NeoYume and the standard way of uploading them from PC is less and less convenient. So I made this loader. This is a first, crude, but working, version of it.

The loader searches for binary files in /sd/microDOS, lists them and allows to select and load the program. It uses hacked version of PSRAM driver, where I moved mailboxes to $7F000. After the Enter key pressed, MicroDOS loads the binary to PSRAM, stops all cogs except PSRAM driver and runs a cog which moves the binary from PSRAM to HUB. The cog then stops the PSRAM driver, inits the cog #0 from address #0 and stops itself.

The name of the program comes from the 8-bit Atari world. Atari microdos boots from the floppy disk, then searches and lists executable files on it.

There are no standard way to attach a keyboard, so if you want to play with the program. you have to replace my "retrocog.spin2" which uses the RPi based serial kbd interface with your keyboard driver, and add a "readkey" function to it so the main program can call it and read a pressed key code.

Comments

  • Wuerfel_21Wuerfel_21 Posts: 2,782
    edited 2022-06-13 19:36

    I kinda wanted to write something to this extent at some point, but, like, fancier. Never got around to it.

    @pik33 said:
    There are no standard way to attach a keyboard

    I'd argue native USB is, on account of being the only thing you can just plug straight into the Parallax-provided hardware without building some custom contraption. It's not good standard though, USB driver is huge and sucks bong.

    Speaking of, I guess you don't actually have input working in neoyume? Serial input should be easy. Look at the way the raw pin input "driver" works, it's really simple. Just need a cogless serial driver.

    Also, is it just me or is there no sound during the logo screen on mslug?

    Back on topic, SD load should be possible without PSRAM (that's how hot-reload works on P1, afterall. (Spin Hexagon even hot-reloads with some state kept so the main game executable doesn't need to worry about FAT)), but I guess it is easier this way.

  • pik33pik33 Posts: 1,672

    I'd argue native USB is, on account of being the only thing you can just plug straight into the Parallax-provided hardware without building some custom contraption. It's not good standard though, USB driver is huge and sucks bong.

    I simply don't have enough place for another full sized keyboard, and P2 USB driver doesn't like this RPi small kbd. Maybe the best way is to buy another small format keyboard which is compatible with a P2 USB.

    Speaking of, I guess you don't actually have input working in neoyume? Serial input should be easy. Look at the way the raw pin input "driver" works, it's really simple. Just need a cogless serial driver.

    I don't have an input yet but I think it will not be too difficult to replace the USB driver with this serial thing. I wanted to have a MicroDOS first :)

    Also, is it just me or is there no sound during the logo screen on mslug?

    It is there, the amplifier volume was set too low

    Back on topic, SD load should be possible without PSRAM

    Instead of loading from PSRAM you have to have a cog which will do the SD loading. Too complex, and if it is a file system, a bunch of file system related code has to reside in the HUB RAM. This limits the loaded program size. With PSRAM only mailboxes have to reside in HUB and they can be relocated even up to $7FF00.

  • @pik33 said:
    and P2 USB driver doesn't like this RPi small kbd.

    > USB driver is huge and sucks bong

    Back on topic, SD load should be possible without PSRAM

    Instead of loading from PSRAM you have to have a cog which will do the SD loading. Too complex, and if it is a file system, a bunch of file system related code has to reside in the HUB RAM. This limits the loaded program size. With PSRAM only mailboxes have to reside in HUB and they can be relocated even up to $7FF00.

    The way it works on P1/KyeFAT is that the FS code figures out the 64 sectors to load (64*512 = 32k) and then the SD cog code does the rest.

  • pik33pik33 Posts: 1,672

    The way it works on P1/KyeFAT is that the FS code figures out the 64 sectors to load (64*512 = 32k) and then the SD cog code does the rest.

    We have 512 k here, so things are somewhat harder, as the file may be fragmented. For a P1 we may avoid that, using 32kB cluster size. But it seems to be doable: first a list of sectors has to be done using the file system stuff, then the low level SD cog can do what my PSRAM loading cog does, using that list.

    However, we already need a PSRAM for all these ****yumes, the player and whatever fancy will be written in the future so if it is already needed, why not use it in the loader?

  • Yep, might aswell.

  • roglohrogloh Posts: 4,218
    edited 2022-06-14 08:23

    A while back I had this crazy idea of using the same mailbox interface to the memory driver for accessing SD card's file data as well as the usual suite of other memory devices. This would be somewhat like having a memory mapped method for accessing the file. Hasn't eventuated yet but it's in the back of my mind to eventually look at it again to see if there is any scope/use for it, at least in read-only mode. This sort of thing may be useful for a loader tool like pik33's MicroDOS above for example, although it still needs its own standalone COG and it would not be combined with the PSRAM driver COG for example because each driver type runs as an independent COG. A multi-COG initial loader is not beyond the realms of possibility though; we do have 8 COGs free at boot time for such things.

    For an SD file driver I was planning to extend some of the mailbox parameters to refer to sectors instead of bytes so it could handle file sizes > 4GB. It also needs a high level way to open/close files and initialize cards etc, but if that was available it could be neat to be able to open a file and then access its contents just like other memory with the same set of transfer commands already available, it would give you random access to data and do all seeking automatically. This could simplify accessing files quite a bit, especially if you have a PASM COG that wanted access to the SD files and you can't just use the SPIN2 or C driver APIs. Due to the complexity of SD & filesystem stuff, I'm expecting some of this code would have to run as HUB exec, but that's not an issue for the less speed critical paths like file table lookups and directory traversal.

    By using its mailbox polling scheme it would inherently allow sharing of SD file data by multiple COGs which is always handy and it already has the support for locked transfers if writes were enabled too at some point. But there's a lot more to getting this going and I've not had the time to look into it so far. We sort of need some "best of breed" SD sector access code too to leverage and so many people still seem to be doing their own thing there. Got to be rock solid stable over the P2 frequency range for it to be reliable.

    Relatedly I also still want to have a way to use the onboard SPI flash memory chip (e.g. Winbond part) by including it into my memory drivers, similar to what we have for HyperFlash, for example. I've actually started some of that driver work but it's in limbo right now (among several other things). One day...

  • pik33pik33 Posts: 1,672
    edited 2022-06-14 06:21

    Relatedly I also still want to have a way to use the onboard SPI flash memory chip (e.g. Winbond part) by including it into my memory drivers, similar to what we have for HyperFlash, for example. I've actually started some of that driver work but it's in limbo right now (among several other things). One day...

    I extracted simple read and write flash procedures from "jm_p2_flash.spin2" for the robot so it can keep sounds ("the robot is ready", "please remove an object" etc)and maps for autonomic drive in it. My idea is to keep fonts, cursor definitions, sound waves etc in there. There can be also cog driver code kept there so the main program can use them instead of having objects added at the compilation time. These objects eat the memory: you initialize the cog, but the code is still in RAM and this means the heap and stack space is shorter. Maybe something like "use once" may be added to flexprop so it can place the code in the heap space to initialize and forget.

  • pik33pik33 Posts: 1,672
    edited 2022-06-14 10:20

    0.02.

    It is now not as raw as 0.01

    I replaced the "retrocog.spin2" with a "keyboard.spin2" which is a version doing only a keyboard and not mouse or midi, so it can be replaced easier. Todo is to use USB KBM instead. To do this, I have to add a "readkey" method to it.

    To avoid screen switching between VGA and HDMI the program now outputs on both of them at the same time :) (yes, we can :) ) I added color definitions to make them display at different colors.
    I also added a keycodes constants at the starts of it

    The underscores in file names (compile with LFN enabled or it will not work !) are now replaced with spaces.

    There are more comments, and the code is somewhat cleaned.

  • pik33pik33 Posts: 1,672

    0.03

    Cosmetic changes. I changed a font size for a file list and made the space between lines higher. Now it is more readable and there is a place for more columns if needed.

  • pik33pik33 Posts: 1,672
    edited 2022-06-14 12:02

    Speaking of, I guess you don't actually have input working in neoyume?

    Now I have.

    #ifdef INPUT_USE_RPI
    kbd : "keyboard.spin2"
    #endif
    
    #ifdef INPUT_USE_RPI
    kbd.start()
    cogstop(cogid)
    #endif
    

    The keyboard.spin2 has to be cleaned, but it is based on a MicroDos kbd code and instead of putting reports to the buffer it puts bits to $60.

    ' A keyboard contraption cog 
    ' The purpose: to read keyboard serial data from a RPi contraption keyboard interface
    ' v. 0.01 pik33@o2.pl
    '
    con
    
    rxpin=16
    txpin=17
    baudrate=1920000
    
    var
    
    long kbdfront,kbdtail
    long kbdbuf[32]
    long serialstack[64]
    
    pub dummy()
    
    repeat
    'this is the object and not a program
    
    pub start() :cog
    cog:=cogspin(16,serialcog(),@serialstack)
    return cog
    
    pub readrawkey:key |result
    
    if kbdfront<>kbdtail
      result:=kbdbuf[kbdtail]
      kbdtail++
      kbdtail:= kbdtail // 32
    else
      result:=0  
    return result
    
    pub readkey:key |result
    
    if kbdfront<>kbdtail
      result:=(kbdbuf[kbdtail] & $00007F00)>>8
      kbdtail++
      kbdtail:= kbdtail // 32
    else
      result:=0  
    return result
    
    pub serialcog()| rr, mrr, srr, b, mb, midireport, kbmreport
    
    ' This cog listens to the serial port at rxpin and fills a keyboard event buffer.
    
    serial_start(rxpin, txpin, baudrate)
    
    mb:=(-1)
    b:=(-1)
    
    kbdfront:=0
    kbdtail:=0
    
    repeat
    
      rr:=rxcheck(rxpin)
      if (rr>=$80) && (rr<>$FF) && (b==(-1))
        b:=3
        kbmreport:=rr<<24
    
      elseif (b>0) && (rr>=0)
        b--
        kbmreport+=rr<<(b<<3)  
    
      elseif (rr==$FF)
        b:=0   
    
      if b==0  
    
        if (kbmreport +>= $80000000) && (kbmreport +< $87000000)  'mouse, ignore
        b:=(-1)
    
        if (kbmreport +>= $87000000) && (kbmreport +< $8a000000)  'keyboard
          kbmreport:=kbmreport>>16
          if kbmreport==$8852
            long[$60]:=long[$60] | 1  
          if kbmreport==$8851
            long[$60]:=long[$60] | 2  
          if kbmreport==$8850
            long[$60]:=long[$60] | 4  
          if kbmreport==$884f
            long[$60]:=long[$60] | 8 
          if kbmreport==$881D
            long[$60]:=long[$60] | 16  
          if kbmreport==$881B
            long[$60]:=long[$60] | 32  
          if kbmreport==$8806
            long[$60]:=long[$60] | 64 
          if kbmreport==$8819
            long[$60]:=long[$60] | 128  
          if kbmreport==$8828
            long[$60]:=long[$60] | 256 
          if kbmreport==$882a
            long[$60]:=long[$60] | 512
          if kbmreport==$8752
            long[$60]:=long[$60] & %1111_1111_1111_1111__1111_1111_1111_1110      
          if kbmreport==$8751
            long[$60]:=long[$60] & %1111_1111_1111_1111__1111_1111_1111_1101     
          if kbmreport==$8750
            long[$60]:=long[$60] & %1111_1111_1111_1111__1111_1111_1111_1011    
          if kbmreport==$874f
            long[$60]:=long[$60] & %1111_1111_1111_1111__1111_1111_1111_0111   
          if kbmreport==$871D
            long[$60]:=long[$60] & %1111_1111_1111_1111__1111_1111_1110_1111    
          if kbmreport==$871B
            long[$60]:=long[$60] & %1111_1111_1111_1111__1111_1111_1101_1111      
          if kbmreport==$8706
            long[$60]:=long[$60] & %1111_1111_1111_1111__1111_1111_1011_1111    
          if kbmreport==$8719
            long[$60]:=long[$60] & %1111_1111_1111_1111__1111_1111_0111_1111     
          if kbmreport==$8728
            long[$60]:=long[$60] & %1111_1111_1111_1111__1111_1110_1111_1111    
          if kbmreport==$872a
            long[$60]:=long[$60] & %1111_1111_1111_1111__1111_1101_1111_1111       
        b:=(-1)
    
    ''---------------------- Serial functions from jm_serial.spin2, modified
    
    pub serial_start(rxpin, txpin, baud) | bitmode
    
    bitmode := muldiv64(clkfreq, $1_0000, baud) & $FFFFFC00       ' set bit timing
    bitmode |= 7                                                  ' set bits (8)
    pinstart(rxpin,P_HIGH_15K|P_ASYNC_RX,bitmode,0)
    pinstart(txpin,P_ASYNC_TX|P_OE,bitmode,0)
    pinhigh(rxpin)
    
    pub rxcheck(pin) : rxbyte | check
    
    '' Check for serial input
    '' -- returns -1 if nothing available
    
      rxbyte := -1
      check := pinr(pin)
      if (check)
        rxbyte := rdpin(pin) >> 24
    
    pub tx(pin,b)
    
    '' Emit byte
    
      wypin(pin, b)
      txflush(pin)
    
    pub txflush(pin) | check
    
    '' Wait until last byte has finished
    
      repeat
        check := pinr(pin)
      while (check == 0)
    
  • pik33pik33 Posts: 1,672

    .. I have to add a real joystick to this. I have: a 9-pin joystick, a resistor based contraption to connect it to 2 pins, a code which reads the joy... So, what I need is to connect all things together. The joy can be up, down, left, right, A. The rest have to be entered from the keyboard...

Sign In or Register to comment.