HardCaml implementation of the OCaml ZINC Abstract Machine
OCaml
47
23 commits
updated Jan 5, 2020
An implementation of the ZINC Abstract Machine (ZAM) in HardCaml for running OCaml bytecode programs in hardware.
Status Transitioning to a new way of implementating the hardware core which includes a software model, derivied from the same code, for much easier (and faster) debugging.
The module Interp includes a reasonably well tested implementation of the bytecode instruction set. It is functorized and can execute bytecode programs or produce an AST.
The executable implementation is useful for tracing bytecode programs,
testing the implementation of the instruction set and, crucially,
the included C-runtime. A fair amount of tracing functionality is
included and can be compared to the traces generated by ocamlrund.
Further, the OCaml REPL can be used as a simple debugger
(Framework.Interp.interactive).
The AST implementation records how machine registers are updated along with the memory accesses required. Such a sequence of operations covers much of the functionality of the instruction set. In addition we have loops, conditionals and some more abstract AST nodes to represent operations we want to defer the implementation of (c calls, oo method ops).
This leads us to the current status of the project; compile the AST into hardware.
The initial plan is to compile each instruction seperately into a statemachine (sequenced by memory accesses), and mux them together based on an instruction decoder. This should quickly lead to a working and pretty complete implementation. On the downside it will be a lot bigger and slower (frequency and cycles/instruction) than necessary.
Various ongoing tasks to make this core useful include;
C\_runtimeTO BE DEPRECIATED
Implemented as a large statemachine in Zinc. A major concern with this
approach is the size of the statemachine - dozens of states so far, and
a number of the more complex instructions still to go. A complete version
would probably need hundreds of states which makes this approach a bit
impractical.
Status; says 'hello world!' which actually exercises a pretty good chuck of the bytecode instruction set, and requires integration with a very basic (C-)runtime
Simulation only at the moment and will need some additions before a move to real hardware is worthwhile (proper memory interface - and probably caches - along with a more complete runtime system)
Currently only models a 64 bit OCaml ZAM as this matches my compiler.
Should be fairly straight forward to model 32 bit as well.
Memory layout is shown below. A tiny c-heap is provided seperately for the c-runtime to simplify things for the time being. The ml-heap grows upwards and the stack starts at the top of memory and grows downwards.
| Memory layout |
|---|
| program data |
| atom table |
| global data |
| c-heap |
| ml-heap |
| stack |
No garbage collector for the time being. Will need to address this in stages;
For C_CALLs the testbench intercepts the call and executes it with routines defined in C_runtime. Hopefully there's a better way than just re-implementing lots and lots of OCaml C primitives here.
A number of instructions are not yet implemented - todo as testcases are found.
23 commits
OCaml
96.5%
Standard ML
3.5%
HardCaml implementation of the OCaml ZINC Abstract Machine
OCaml
47
23 commits
updated Jan 5, 2020
An implementation of the ZINC Abstract Machine (ZAM) in HardCaml for running OCaml bytecode programs in hardware.
Status Transitioning to a new way of implementating the hardware core which includes a software model, derivied from the same code, for much easier (and faster) debugging.
The module Interp includes a reasonably well tested implementation of the bytecode instruction set. It is functorized and can execute bytecode programs or produce an AST.
The executable implementation is useful for tracing bytecode programs,
testing the implementation of the instruction set and, crucially,
the included C-runtime. A fair amount of tracing functionality is
included and can be compared to the traces generated by ocamlrund.
Further, the OCaml REPL can be used as a simple debugger
(Framework.Interp.interactive).
The AST implementation records how machine registers are updated along with the memory accesses required. Such a sequence of operations covers much of the functionality of the instruction set. In addition we have loops, conditionals and some more abstract AST nodes to represent operations we want to defer the implementation of (c calls, oo method ops).
This leads us to the current status of the project; compile the AST into hardware.
The initial plan is to compile each instruction seperately into a statemachine (sequenced by memory accesses), and mux them together based on an instruction decoder. This should quickly lead to a working and pretty complete implementation. On the downside it will be a lot bigger and slower (frequency and cycles/instruction) than necessary.
Various ongoing tasks to make this core useful include;
C\_runtimeTO BE DEPRECIATED
Implemented as a large statemachine in Zinc. A major concern with this
approach is the size of the statemachine - dozens of states so far, and
a number of the more complex instructions still to go. A complete version
would probably need hundreds of states which makes this approach a bit
impractical.
Status; says 'hello world!' which actually exercises a pretty good chuck of the bytecode instruction set, and requires integration with a very basic (C-)runtime
Simulation only at the moment and will need some additions before a move to real hardware is worthwhile (proper memory interface - and probably caches - along with a more complete runtime system)
Currently only models a 64 bit OCaml ZAM as this matches my compiler.
Should be fairly straight forward to model 32 bit as well.
Memory layout is shown below. A tiny c-heap is provided seperately for the c-runtime to simplify things for the time being. The ml-heap grows upwards and the stack starts at the top of memory and grows downwards.
| Memory layout |
|---|
| program data |
| atom table |
| global data |
| c-heap |
| ml-heap |
| stack |
No garbage collector for the time being. Will need to address this in stages;
For C_CALLs the testbench intercepts the call and executes it with routines defined in C_runtime. Hopefully there's a better way than just re-implementing lots and lots of OCaml C primitives here.
A number of instructions are not yet implemented - todo as testcases are found.
23 commits
OCaml
96.5%
Standard ML
3.5%