Wouldn't it make sense to add some C-bindings to the forth kernel? I have examined all the built-in tokens and as far as far as I can tell there is currently no way to call an external function (well, save abusing the inb/outb mechanism).
Some background:
The forth kernel and the MOL OF loader are statically linked as a single binary (the ROM image).
The MOL part of the code contains low-level support for exceptions and similar things. It also contains filesystem support, SCSI support, boot disk search algorithms, device tree handling and the OF client interface (and some other stuff).
To make the C-code and the forth code interoperate, I would like to be able to
1. Call C-functions from forth code by pushing the address of the function on the stack. Something like
call ( function_addr -- <whatever> )
2. Be able to invoke the forth interpreter from C-code (I think this can be implementable without modifying the kernel code, but I haven't looked into it yet).
I can of course solve the first point be adding a primitive to the words[] table, but wouldn't it make sense also for other projects? I imagine that a real-world implementation will implement some things in C (more people are familiar with C and there are already plenty of code written in C that can be reused; filesystems for instance...).
/Samuel
* Samuel Rydh samuel@ibrium.se [031030 13:03]:
Wouldn't it make sense to add some C-bindings to the forth kernel? I have examined all the built-in tokens and as far as far as I can tell there is currently no way to call an external function (well, save abusing the inb/outb mechanism).
true. it is definitely needed.
To make the C-code and the forth code interoperate, I would like to be able to
- Call C-functions from forth code by pushing the address
of the function on the stack. Something like
call ( function_addr -- <whatever> )
see attachment.
- Be able to invoke the forth interpreter from C-code
(I think this can be implementable without modifying the kernel code, but I haven't looked into it yet).
this can be done for example with kernel/openbios.c:void openbios(ucell dictstart, ucell dictend) or directly by calling enterforth(). Note that the engine does not allow running multiple concurrent instances (yet).
Stefan
On Thu, Oct 30, 2003 at 02:50:09PM +0100, Stefan Reinauer wrote:
- Call C-functions from forth code by pushing the address
of the function on the stack. Something like
call ( function_addr -- <whatever> )
see attachment.
Great! I'm trying to make it simple to track the latest openbios source so I'm avoiding MOL specific modifications whenever possible...
- Be able to invoke the forth interpreter from C-code
(I think this can be implementable without modifying the kernel code, but I haven't looked into it yet).
this can be done for example with kernel/openbios.c:void openbios(ucell dictstart, ucell dictend) or directly by calling enterforth(). Note that the engine does not allow running multiple concurrent instances (yet).
Well, I don't need concurrent instances, just recursive. enterforth() seems to be able to handle that. What I need though is runtime translation of C-string forth into tokens. I.e. basically I need to do the same stuff as interpret does. I will look into it; I doubt it will be a problem.
/Samuel
* Samuel Rydh samuel@ibrium.se [031030 17:16]:
call ( function_addr -- <whatever> )
Great! I'm trying to make it simple to track the latest openbios source so I'm avoiding MOL specific modifications whenever possible...
I checked this into CVS, so it will be part of BeginAgain 1.2
- Be able to invoke the forth interpreter from C-code
(I think this can be implementable without modifying the kernel code, but I haven't looked into it yet).
Well, I don't need concurrent instances, just recursive. enterforth() seems to be able to handle that. What I need though is runtime translation of C-string forth into tokens. I.e. basically I need to do the same stuff as interpret does. I will look into it;
Ok, I wrote a little example which can be used as a plugin i.e. with: ~/openbios/kernel/obj-x86> ./unix openfirmware.dict -P . -p mol
The C function calls the interpreter giving it the string in forthcode[]. It's the same thing as typing the following on the interpreter: ." This is a forth statement" cr 23 dup
Hope this helps...
Stefan
On Thu, Oct 30, 2003 at 10:15:12PM +0100, Stefan Reinauer wrote:
- Samuel Rydh samuel@ibrium.se [031030 17:16]:
Great! I'm trying to make it simple to track the latest openbios source so I'm avoiding MOL specific modifications whenever possible...
I checked this into CVS, so it will be part of BeginAgain 1.2
Well, I don't need concurrent instances, just recursive. enterforth() seems to be able to handle that. What I need though is runtime translation of C-string forth into tokens. I.e. basically I need to do the same stuff as interpret does. I will look into it;
Ok, I wrote a little example which can be used as a plugin i.e. with: ~/openbios/kernel/obj-x86> ./unix openfirmware.dict -P . -p mol
The C function calls the interpreter giving it the string in forthcode[]. It's the same thing as typing the following on the interpreter: ." This is a forth statement" cr 23 dup
Thanks a lot.
/Samuel
* Samuel Rydh samuel@ibrium.se [031030 23:56]:
Well, I don't need concurrent instances, just recursive. enterforth() seems to be able to handle that. What I need though is runtime translation of C-string forth into tokens. I.e. basically I need to do the same stuff as interpret does. I will look into it;
Ok, I wrote a little example which can be used as a plugin i.e. with: ~/openbios/kernel/obj-x86> ./unix openfirmware.dict -P . -p mol
The C function calls the interpreter giving it the string in forthcode[]. It's the same thing as typing the following on the interpreter: ." This is a forth statement" cr 23 dup
One thing that might come handy is not possible yet: Adding words to the dictionary this way in the plugin init function. This could look like:
char *prom_next_property( mol_device_node_t *dn, const char *prev_name);
static void plugin_mol_next_property(void) { mol_device_node_t *dn=POP(); POP(); // drop len char *prev_name=POP(); prom_next_property(dn, prev_name); }
int add_c_function(char *name, void (*cfunc)(void)) { char forthcode[80]; snprintf(address, 17, ": %s h# %lx call ;\n", name, (unsigned long)cfunc); PUSH((ucell)forthcode); PUSH(strlen(forthcode)); enterforth(findword("evaluate")); }
int plugin_mol_init(void) { add_c_function("next-property", plugin_mol_next_property); ... }
Unfortunately this is not yet possible since plugins are initialized quite a bit before the dictionary is available. I'll seperate plugin dependencies and plugin initialization and move the init part beyound dictionary init. This way the above scenario can be used to directly add forth words that are written in C while still keeping them out of the openbios kernel.
Does this sound reasonable?
Stefan
On Fri, Oct 31, 2003 at 12:20:29PM +0100, Stefan Reinauer wrote:
Unfortunately this is not yet possible since plugins are initialized quite a bit before the dictionary is available. I'll seperate plugin dependencies and plugin initialization and move the init part beyound dictionary init. This way the above scenario can be used to directly add forth words that are written in C while still keeping them out of the openbios kernel.
Does this sound reasonable?
Well, the first thing I did was to strip down the unix kernel into something which was suitable for statically linking into the mol-of image (which doesn't link against anything). In particular, there is no plug-in interface (dlopen is not available for one thing).
All that is needed really is a hook once OpenFirmware has initialized itself. One can do some stuff just before calling initialize although the OF memory stuff (and probably more things in the future?) is not initialized at that point. I think the best thing would be to invoke a hook (if defined) just before quit is called.
Or one should perhaps add a more generic system for static initializers. I bet that other parts of OF will need some eventually... (nvram parsing, device tree probing etc).
/Samuel