Shop OBEX P1 Docs P2 Docs Learn Events
HUB layout and mailboxes - time to revisit??? — Parallax Forums

HUB layout and mailboxes - time to revisit???

Cluso99Cluso99 Posts: 18,069
edited 2020-11-12 04:31 in Propeller 2
I have reached a point with my OS and Z80/CPM where I need to make some decisions about the layout of hub ram and also the mailboxes used to communicate between programs running in different COGs (which may include hubexec code too).

Mailboxes
The reason we need mailboxes is so that code can access drivers that are running in different COGs.

For example, we need an output COG. That cog may be a driver to the serial port, the VGA, and LCD, or even some WiFi device. Really, we just need the base code (user code) to be able to just output to a standard mailbox, and have the driver cog take care of outputting this data to whatever device it is hooked to. This is really just hardware indirection (hardware abstraction) which has been the mainstay of PC's for years. It is desirable to be able to load a different driver, including "on-the-fly".

For input, we need an input COG. That cog may be a driver to the serial port, a USB Keyboard, a PS2 Keyboard, a USB/PS2 Mouse, terminal over wifi, or something else. Again, it is desirable to be able to substitute the driver "on-the-fly". For some drivers, this could be a combination of input and output in one cog eg serial.

To achieve this, we really need to work out a standard interface to the Hub Mailbox. We tried to discuss this many times before, and failed miserably - more because no-one saw the need and so argued against any standard mechanism. Let's not fall into the same trap please. I know more of you are now realising the P2 offers us the possibility of self-hosting, and this is a requirement to achieve this.

I have code that achieves this. It has been refined from what I used in P1 and I use it in my serial drivers and SD Card drivers.
So, let's have this discussion now. If there's consensus then I'll post what I have. If you are not interested, just be polite and say so, and leave the discussion. Please don't derail it just because you don't want or need it.

Hub Layout
This is more complex, so let me explain a little more...

In my Z80/CPM emulation, I MUST have the hub ram divided into specific addressed regions.
I have hubexec code that must reside in $400-$00FFF because I use 12-bit entry points (vectors) to jump into the hubexec code. This may change later, but for now it is mandatory.
I also have a 64KB block of hub that is the Z80 RAM/EEPROM and it must be on a 64KB boundary (yes, it's really 65,536 bytes). Adding any extra indirection adds up significantly to the execution of almost every Z80 emulated instruction.

In my OS for P1, I dedicated certain areas for re-loading the OS commands (such as DIR, COPY, etc). Other areas at the top of hub remained resident and were loaded when the OS started/loaded. I never achieved the total residency that I was looking for.

Dilemma
I am using spin2 for some sections of code.

FlexProp allows me to better position my code, but because it compiles spin code to pasm, code is often much larger, and I don't have the control I'm really after. Having said this, it is working for now. I'm not totally sure how I'm going to achieve things going forward, but to be fair to Eric, I've not really asked either. It may even be possible now. I guess I need to be able to compile code which outputs a compiled "blob" which is coded to fit starting at a designated (non-zero) hub location, and I'll need to be able to load this from SD to this hub location (my code will need to do this - I have working code that can load to hub $0 and optionally execute it already.

pnut and/or PropTool has the benefit of using the spin2 interpreter, and AFAIK the hub code (spin2 compiled code) is relocatable. However, pnut does not allow me to position the code in hub, so I cannot use it. Note that I made it work in the past by moving the code from one hub location to another, but this isn't a viable solution here.

So, let the discussion begin :)

Comments

  • jmgjmg Posts: 15,148
    Cluso99 wrote: »
    ... However, pnut does not allow me to position the code in hub, so I cannot use it.

    Sounds like that capability needs to be added ?

  • If I remember correct Flexprop has a cmdline switch allowing you to specify the address to compile to, that may help for your commands like dir etc.

    But TAQOZ needs to be at the lower 64k, most other programs also like to start a HUB 0, so the best place for mailboxes or some OS/BIOS is at the upper end of the HUB.

    I also remember the failed discussions to find a common standard on the P1. I think @RossH has the ability to switch driver build into Catalina, maybe he can chime in to explain the details again.

    The ROM area would be a good place to put a resident OS/BIOS, but Chips use of it for the debugger might prevent this so there is some challenge to overcome having the OS/BIOS either in the ROM area or at the top of the HUB, maybe one location in ROM could be checked for a) its still ROM, b) its debug (so OS/BIOS is at top of normal HUB) or c) OS/BIOS is at the top of ROM.

    The SEND and RECV commands in Spin2 are a good start for redirection but the classic mailbox in HUB might be better to use from other languages and PASM.

    Having a SEND mailbox -1 if not in use, <256 to send a byte >255 to send a 0 terminated HUB string makes sense to me, one could use the upper bits of the long for send X bytes from HUB address Y to do block transfer without 0 termination.

    Alike that line RECEIVE would be -1 if not in use, <256 for cmd's to check for bytes available and receive bytes, >255 to receive a 0 terminated string at that address and also using the upper bits for receiving a block without 0 termination by giving the number of bytes to receive.

    This needs one long HUB per direction (send/receive) but seems feasible as long as you do not need to send/receive below HUB address 256.

    Enjoy!

    Mike
  • RossHRossH Posts: 5,347
    msrobots wrote: »
    I also remember the failed discussions to find a common standard on the P1. I think @RossH has the ability to switch driver build into Catalina, maybe he can chime in to explain the details again.

    I'm a bit reluctant to to go down this particular rabbit hole again. :(

    Ross.
  • Cluso99Cluso99 Posts: 18,069
    TAQOZ and Z80/CPM cannot co-exist as I must have hubexec code sitting at $400-$0FFF as I need to use a 12-bit vector address. IIRC Peter has the same issues where is code is 16-bit addresses. But that's a different problem.

    Here is the mailbox I use for the SD Driver (4 longs setup as byte,byte,word,long,long,long). The mbox_debug is just an optional debug holder.
    There is also a sector buffer but it can be anywhere really.
    DAT
    '+=============================================================================+
                    orgh
                    byte    0[$1000-$]
    sd_mailbox                    '\ [16] mailbox for SD Driver
    mbox_command    byte    0     '| [1] command 
    mbox_status     byte    0     '| [1] status
    mbox_spare      word    0     '| [2] -spare
    mbox_copy                     '| [3*4] following 3 longs copied with SETQ
    mbox_aux        long    0     '| [4] aux eg filesize
    mbox_sector     long    0     '| [4] sector
    mbox_bufad      long    0     '/ [4] address of disk buffer in hub
    
    mbox_debug      long    0[64]
    '+-----------------------------------------------------------------------------+
    
    And this is the code in the pasm driver cog waiting for something to do
    '+=============================================================================+
    '+ SD Driver mailbox interface                                                 +
    '+=============================================================================+
    '+-----------------------------------------------------------------------------+
    '+ Wait for something to do (via mailbox)                                      +
    '+-----------------------------------------------------------------------------+
    mainloop    wrbyte  #0,         ##mbox_command  ' clear command (after status updated)
    wait        rdbyte  sdx_status, ##mbox_command  wz  ' I/R/W/F
        if_z    jmp     #wait
               '+------------------------------------------------------------------+
                rdlong  sdx_bufad,  ##mbox_bufad    ' collect buffer address
                rdlong  sdx_sector, ##mbox_sector   ' collect sector address
               '+------------------------------------------------------------------+
                cmp     sdx_status, #"I"        wz  ' I = initialise?
        if_e    jmp     #cmd_I
                cmp     sdx_status, #"R"        wz  ' R = readFastSector
        if_e    jmp     #cmd_R
                cmp     sdx_status, #"W"        wz  ' W = writeFastSector
        if_e    jmp     #cmd_W
                cmp     sdx_status, #"D"        wz  ' D = find Directory
        if_e    jmp     #cmd_D
                cmp     sdx_status, #"F"        wz  ' F = findFile
        if_e    jmp     #cmd_F
                cmp     sdx_status, #"X"        wz  ' X = Load/Execute (usually after "F")
        if_e    jmp     #cmd_X
    done
        if_e    wrbyte  #0,         ##mbox_status   ' success status
        if_e    jmp     #mainloop
    ' can insert debug code here if necessary
                wrbyte  #$FF,       ##mbox_status   ' failed status
    
    '            call     #_hubMonitor       '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                setq    #32-1
                wrlong  sdx_status, ##$FC400        ' dump regs for debugging
    
                jmp     #mainloop
    '+-----------------------------------------------------------------------------+
    
  • Cluso99Cluso99 Posts: 18,069
    edited 2020-11-14 00:06
    This is my Serial Driver mailbox interface. Slightly different, but again 4 longs.
    '' +-------------------------------------------------------------------------------------------------------------------+
    '' | HUB Mailbox Interface:                                                                                            |
    '' +-------------------------------------------------------------------------------------------------------------------+
    '' |  +0:  ptr_cmd      long  command                                                                                  |
    '' |  +4:  ptr_data     long  data                                                                                     |
    '' |  +8:  ptr_addr1    long  address                                                                                  |
    '' | +12:  ptr_addr2    long  address2                                                                                 |
    '' +-------------------------------------------------------------------------------------------------------------------+
    '' | command    | 8 7 6 5 | 4 3 2 1 0 | comment                                                                        |
    '' |------------|---------|-----------|--------------------------------------------------------------------------------|
    '' | idle       | 0 0 0 0 | 0 0 0 0 0 | waiting for command                                                            |
    '' |            |         |-----------|--------------------------------------------------------------------------------|
    '' | initialise | 0 0 0 0 | 1 0 0 0 0 | initialise serial...                                                           |
    '' |            |         |           |   reg_x  = bitper (calc from baud)                                             |
    '' |            |         |           |   reg_p  = bufad in hub (for Rx buf)                                           |
    '' |            |         |           |   reg_p2 = rxpin<<8 + txpin                                                    |
    '' |            |         |-----------|--------------------------------------------------------------------------------|
    '' | monitor    | 0 0 0 0 | 1 1 1 1 1 | call the Monitor/Debugger (return with Q<cr>)                                  |
    '' |------------|---------|-----------|--------------------------------------------------------------------------------|
    '' | TxChar     | 0 0 0 1 | 0 . . . . | display 1-4 chars (in reg_x)                                                   |
    '' |            |         | 0 1 . . . | reverse byte order                                                             |
    '' |            |         | 0 . 1 . . |                                                                                |
    '' |            |         | 0 . . 1 . |                                                                                |
    '' |            |         | 0 . . . 1 |                                                                                |
    '' |            |         |-----------|--------------------------------------------------------------------------------|
    '' | TxString   | 0 0 0 1 | 1 . . . . | display nul-terminated string (from @reg_p)                                    |
    '' |            |         | 1 1 . . . |                                                                                |
    '' |            |         | 1 . 1 . . |                                                                                |
    '' |            |         | 1 . . 1 . |                                                                                |
    '' |            |         | 1 . . . 1 |                                                                                |
    '' |------------|---------|-----------|--------------------------------------------------------------------------------|
    '' | TxHex      | 0 0 1 0 | . . . . . | display in hex (in reg_x)                                                      |
    '' |            |         | 1 . . . . | space between hex pairs                                                        |
    '' |            |         | . 1 . . . | reverse byte order                                                             |
    '' |            |         | . . n n n | nnn = digits 1-7, 0 = 8 digits                                                 |
    '' |------------|---------|-----------|--------------------------------------------------------------------------------|
    '' | TxList     | 0 0 1 1 | . . . . . | display line(s) 16 hex bytes plus ascii (from @reg_p to @reg_p2)               |
    '' |            |         | 1 . . . . |                                                                                |
    '' |            |         | . 1 . . . |                                                                                |
    '' |            |         | . . 1 . . |                                                                                |
    '' |            |         | . . . 1 . | display as longs                                                               |
    '' |            |         | . . . . 1 | address range (from @reg_p to @reg_p2 else @reg_p[16])                         |
    '' |------------|---------|-----------|--------------------------------------------------------------------------------|
    '' | TxBinary   | 0 1 0 0 | . . . . . | display in binary (in reg_x)                                                   |
    '' |            |         | n n n n n | nnnnn = no.of digits 1-31, 0 = 32 digits                                       |
    '' |------------|---------|-----------|--------------------------------------------------------------------------------|
    '' | TxDecimal  | 0 1 0 1 | 0 . . . . | display in decimal (in reg_x)                                                  |
    '' |            |         | 0 1 . . . |                                                                                |
    '' |            |         | 0 . 1 . . |                                                                                |
    '' |            |         | 0 . . 1 . |                                                                                |
    '' |            |         | 0 . . . 1 | signed (else unsigned)                                                         |
    '' |            |         |-----------|--------------------------------------------------------------------------------|
    '' | ?          | 0 1 0 1 | 1 . . . . | ?                                                                              |
    '' |------------|---------|-----------|--------------------------------------------------------------------------------|
    '' | ?          | 0 1 1 0 | . . . . . | ?                                                                              |
    '' |------------|---------|-----------|--------------------------------------------------------------------------------|
    '' | RxChar     | 0 0 0 1 | 0 . . . . | receive 1 char (into reg_x)                                                    |
    '' |            |         | 0 1 . . . | echo                                                                           |
    '' |            |         | 0 . 1 . . | prompt (display prompt char(s) in reg_x first)                                 |
    '' |            |         | 0 . . 1 . | ?tbd? strip <lf>                                                               |
    '' |            |         | 0 . . . 1 | ?tbd? return $1FF if no char avail                                             |
    '' |            |         |-----------|--------------------------------------------------------------------------------|
    '' | RxString   | 0 0 0 1 | 1 . . . . | receive string (into @reg_p), <cr> terminates, adds <nul>, supports <bs> edit  |
    '' |            |         | 1 1 . . . | echo                                                                           |
    '' |            |         | 1 . 1 . . | prompt (display prompt char(s) in reg_x first)                                 |
    '' |            |         | 1 . . 1 . | strip <lf>                                                                     |
    '' |            |         | 1 . . . 1 | address for input (in @reg_p) else use equ._bufad                              |
    '' +-------------------------------------------------------------------------------------------------------------------+
    
  • Cluso99Cluso99 Posts: 18,069
    edited 2020-11-14 00:11
    I have found 4 longs works nicely. The first long is typically divided up into the first byte (or word) being the command where 0=idle.

    IIRC Catalina uses 2 longs per driver/cog but I found this a little restrictive.
    I think the second long was an address in hub where further parameters were to be found, so there was a level of indirection that I thought could be avoided. Remember, the P1 was tight for memory, particularly when used from C. At least we had a method.

    I don't think we would ever agree to where the mailbox resides in hub, so it will probably need to be positioned at runtime, excepting of course an OS which will need it to be fixed. But now that the whole 16KB of the top of hub has been taken by debug I'm not sure where it should go. In P1 I had it from the top down.
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2020-11-14 00:13
    The first 256 longs are directly addressable with rdxxxx and wrxxxx instructions using immediate addressing (above that is ptr addressing IIRC). So CPM and TAQOZ don't have to coexist, nor do any other programs, just as long as we have a common fixed and easily accessible area in memory to store our system parameters and vectors such as clock settings and baud rates etc.


    This is part of the TAQOZ listing below and I think that we have already agreed upon these locations for instance, we just need to agree on the mailbox addresses. For that Ray I have found it is easier to define what you want first and then see if there is any real objection to it. I am inclined to use vectors rather than pass data in mailboxes because mailboxes always assume that another cog or interrupt will be polling it whereas the vectors might lead to a few short lines of code in the calling cog itself. So in TAQOZ for instance I have vectors for input and output and when the output is switched to VGA it calls code that renders the text, but I could just as easily have code that latches the data for another cog to render. It's more flexible that way I find.

    00010 004 01312d00 _XIN		long	XIN			' input freqency'
    00014 005 0bebc200 _CPUHZ		long	CPUHZ			' final clock '
    00018 006 010009f8 _CLKCFG		long	CLKCFG		''$012C_B3FF $014CB3FC '
                       
                       '	*** SERIAL/VGA/KEYBOARD *** '
    0001c 007 0001c200 _BAUD		long	baud_rate
    
  • Cluso99Cluso99 Posts: 18,069
    These are the other things that I need to store for my OS, probably before/after the mailboxes. It is quite similar to my P1 OS.
    ' OS2 Hub Definitions...         
    ' -------------------          bytes
      _OS_Clkfreq   = _hub + $00  '    4     ' clkfreq(Hz): saved fm hub long $00044
      _OS_Clkmode   = _hub + $04  '    4     ' clkmode:    saved fm hub byte $00040
      _SDpins       = _hub + $08  '    4     ' \ sd pins packed 4 bytes
                                  '          ' / Byte 3=/CS, 2=CLK, 1=MOSI, 0=MISO
      _SIOpins      = _hub + $0c  '    4     ' \ serial pins and mode settings (and cog#)
                                  '          ' / Byte 3=cog, 2=mode, 1=SI, 0=SO
      _SIObaud      = _hub + $10  '    4     ' serial baud (speed typ 115,200)
                                                                                                       
      _OS_Rows      = _hub + $14  '    1     ' \ combined <lf> and rows
        _LF_MASK      = $80                  ' | b7  : 1= <lf> ON; 0= strip <lf>
        _ROW_MASK     = $7F                  ' / b0-6: no of rows on screen (0-127)
      _OS_Columns   = _hub + $15  '    1     '         no of cols on screen (0-255)
      _OS_Cogs      = _hub + $16  '    1     ' stay resident cogs: 1= don't stop on reboot
      _OS_sparebyte = _hub + $17  '    1     '
    
    ' _OS_spare1    = _hub + $18  '    4     '
    ' _OS_spare2    = _hub + $1c  '    4     '
    
      _AuxIn        = _hub + $20  '    4     ' auxilary input  rendezvous
      _AuxOut       = _hub + $24  '    4     ' auxilary output rendezvous
      _StdIn        = _hub + $28  '    4     ' standard input  rendezvous
      _StdOut       = _hub + $2c  '    4     ' standard output rendezvous
    
Sign In or Register to comment.