-
Notifications
You must be signed in to change notification settings - Fork 12
To do
Ideas for stuff that could be implemented
- Switch to a Cheney style allocator/gc to allow variable sized allocations.
Usually a macro, but we cannot do it that way because macros do not currently support variable arguments. Could either try to extend macro system or simply add this as a built-in type in the compiler.
A lot of basic functions are implemented in runtime.l. Since many may be unused, they should be stripped. Currently, if a function is not referenced at all, it will be stripped, but if it is called by a dead function, it will still be emitted. This is not uncommon.
Currently performing operations on invalid object types will have undefined behavior. Should probably check pointers.
- first and rest should check that pointer is list node
- Should verify that function pointer is valid before jumping to it
- Should also probably check pointer arithmetic (but need to be careful to avoid breaking runtime routines that do pointer arithmetic with store/load)
- Check the number of arguments to a function (hard because this is currently implicit)
Checking is relatively easy to do in hardware routines (and can be done with no performance penalty), but need to figure out what to do when a check fails. At very least, may want to flag an error and stop running. Some LISP implementations use a conditions/restarts, which would be more complicated.
Since this is a stack machine, switching contexts is relatively easy: the stack pointer and instruction pointers needs to be changed. The top of stack register also needs to be saved.
- Ability to call functions (since we now have the function construct, just build those into a list that the macro processor can use)
- loops
Interrupts could invoke a function routine directly. Basically, in the DECODE state, logic would check the interrupt pending flag and switch to a new state that sets up the interrupt. The same function activation frame could be used, probably setting the highest bit to indicate that return should have additional side effects to restore the old state.
There would need to be a way of indicating to the hardware which function should be invoked when an interrupt is taken. There could be a special instruction to set an internal register, or it could jump to a fixed address.
This may also require the ability for sensitive code to be able to disable interrupts. Code in an interrupt handler could not make any calls that allocate memory.
Imagine a serial driver that stores characters in a list structure:
(assign free-buffer-queue '(0 0 0 0 0 0)) ; create some dummy nodes to use
(assign char-buffer-queue 0)
(function handle-interrupt ()
(let ((buf (car free-buffer-queue)))
(assign free-buffer-queue (cdr free-buffer-queue))
(setcdr buf char-buffer-queue)
(setcar buf (read-register $serial))
(assign char-buffer-queue buf)
)
)
(function poll-char ()
(if (= char-buffer-queue 0)
0 ; nothing ready
; grab a character
(let ((node 0))
($disable-interrupts)
(assign node (last-element char-buffer-queue))
(assign char-buffer-queue (cdr node))
($enable-interrupts)
node
)
)
)