HUB layout and mailboxes - time to revisit???
Cluso99
Posts: 18,069
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
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
Sounds like that capability needs to be added ?
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
I'm a bit reluctant to to go down this particular rabbit hole again.
Ross.
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. And this is the code in the pasm driver cog waiting for something to do
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.
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.