janestreet / hardcaml Goto Github PK
View Code? Open in Web Editor NEWHardcaml is an OCaml library for designing hardware.
License: MIT License
Hardcaml is an OCaml library for designing hardware.
License: MIT License
Dear developers, I was trying to translate your codes to obtain the Verilog codes. I set up an Amazon Linux (Inferred) EC2 instance, and successfully installed opam (4.13.1) and other software packages. However, when executing opam install . --deps-only
, I got the process Killed. I locate the problematic package is the core_unix
. Here's a snapshot of the issue.
[ec2-user@ip-172-31-83-229 hardcaml_zprize]$ opam install core_unix.v0.15.2
The following actions will be performed:
∗ install core_unix v0.15.2
<><> Processing actions <><><><><><><><><><><><><><><><><><><><><><><><><><><><>
⬇ retrieved core_unix.v0.15.2 (cached)
Processing 2/3: [core_unix: dune build]Killed
Do you have any idea about this issue? Or, is it possible for me to directly obtain your Verilog files? I hope to understand your work with the Verilog codes since I'm not familiar with the ocaml.
Thanks your time in advance!
Hi! We're the guys working on a MIPS CPU from the OCaml forums.
We're starting on the decoder/control unit, and we were wondering if there's a way to use variants for internal logic? For context:
Back when we made this in Verilog, our control unit module looked like this. We could convert this pretty much 1:1 to Hardcaml via the Always DSL, but I was wondering if we could leverage OCaml's type system to make the implementation cleaner / more maintainable.
A potential design we came up with looks a bit like this:
First, we'd figure out what format and instruction type it is.
Then, we'd use that information to:
A design like this would make adding/maintaining the various supported instructions a lot simpler.
For simplicity, I'll just talk about the classifier and the splitter units for the remainder of this issue. Thinking about this in terms of OCaml, we'd like to do something like this for implementation:
open Hardcaml
open Hardcaml.Signal
module Parsed_instruction = struct
type 'a t = {
rs : 'a; [@bits 5]
rt : 'a; [@bits 5]
rdest : 'a; [@bits 5]
shamt : 'a; [@bits 5]
imm : 'a; [@bits 32]
}
[@@deriving sexp_of, hardcaml]
end
module I = struct
type 'a t = { instruction : 'a [@bits 32] } [@@deriving sexp_of, hardcaml]
end
module O = struct
type 'a t = { parsed_instruction : 'a Parsed_instruction.t }
[@@deriving sexp_of, hardcaml]
end
type rtype_instr = Add | Sub | Sll
type itype_instr = Addi | Lw | Sw
type instr_format = RType of rtype_instr | IType of itype_instr
exception Invalid_instruction
let classify_rtype funct =
let noop = Sll in
match funct with
| f when f == of_string "6'b100000" -> Add
| f when f == of_string "6'b100010" -> Sub
| f when f == of_string "6'b000000" -> Sll
| _ -> noop
let classifier instr =
let opcode = instr.:[(31, 26)] in
let noop = RType(Sll) in
match opcode with
| o when o == of_string "6'b000000" ->
let funct = instr.:[(5, 0)] in
RType (classify_rtype funct)
| o when o == of_string "6'b001000" -> IType Addi
| o when o == of_string "6'b100011" -> IType Lw
| o when o == of_string "6'b101011" -> IType Sw
| _ -> noop
let splitter instr instr_type =
let rt = instr.:[(20, 16)] in
let rd = instr.:[(15, 11)] in
let rdest = match instr_type with RType _x -> rd | IType _x -> rt in
let module P = Parsed_instruction in
{
P.rs = instr.:[(25, 21)];
rt;
rdest;
shamt = instr.:[(10, 6)];
imm = sresize instr.:[(15, 0)] 32;
}
let circuit_impl (_scope : Scope.t) (input : _ I.t) =
let instr_type = classifier input.instruction in
let parsed = splitter input.instruction instr_type in
{ O.parsed_instruction = parsed }
This compiles, but doesn't actually work since ==
doesn't work with signals. The signal comparison operator (==:
) doesn't seem to work with the match
, since that just outputs another signal.
Looking at the hardcaml source code, we found Enum
, which seems like it could support splitter
's match via an Enum mux. However, I'm not sure how we could actually generate the enum values in classifier
: The only "conditional" primitive for signals seems to be mux
, but that can only output Signal.t
, and we need to output Signal.t Our_enum.Binary.t
.
We'd also eventually like to do something similar with the ALU Control output, but it looks like we can include Signal.t Our_enum.Binary.t
entries in Hardcaml interface records, so I believe that if we could generate those enum values in classifier
, we could use that same solution for control_core
and this would work too.
Is something like this possible in Hardcaml?
I tried naming one of my signals "dist", but Yosys failed to parse the resulting file.
Looking at its source code it uses the SystemVerilog reserved word list, even when parsing regular Verilog: https://github.com/YosysHQ/yosys/blob/main/backends/verilog/verilog_backend.cc#L133-L155
I think it'd be better to update 'reserved_words.ml' and include the SystemVerilog list too.
If you want I can send a PR that does that.
I'm trying out the serial multiplier example in the documentation but I can't seem to get the Hardcaml Bits implementation working. I'm using hardcaml v0.14.1 (the one on OPAM).
# open Hardcaml
# open Hardcaml.Bits
# let rec umul' a b =
if to_int b = 0
then
zero (width a)
else
let partial_product = mux2 b.:[0,0] a (zero (width a)) in
partial_product +: umul' (sll a 1) (srl b 1)
val umul' : t -> t -> t = <fun>
# let umul a b = umul' (uresize a (width a + width b)) b
val umul : t -> t -> t = <fun>
# to_int (umul (of_int ~width:2 3) (of_int ~width:3 5));;
- : int = 21
The last line be evaluating to 15 (which is 3 * 5), but it is instead evaluating to 21!
The issue seems to be arising from the use of b.:[0,0]
and mux2
, where every iteration of the algorithm is being added to the sum, not only those where b mod 2 = 1.
I have tested it with this simple example below:
# let b = of_int ~width:2 2
val b : t = 10
# b. :[0,0]
- : t = 0
# mux2 b.:[0,0] (of_int ~width:1 1) (of_int ~width:1 0)
- : t = 1
and the issue still seems to arise.
Is there something I'm missing here?
while Install getting this error
$ opam install hardcaml
#=== ERROR while installing hardcaml.1.2.0 ====================================#
# opam-version 1.2.2
# os linux
# command ocaml pkg/pkg.ml build --with-ctypes false --with-ctypes-foreign false --with-camlp4 true --with-js_of_ocaml true --with-lwt true
# path /home/abhishek/.opam/system/build/hardcaml.1.2.0
# compiler system (4.06.0)
# exit-code 1
# env-file /home/abhishek/.opam/system/build/hardcaml.1.2.0/hardcaml-29565-6d07ae.env
# stdout-file /home/abhishek/.opam/system/build/hardcaml.1.2.0/hardcaml-29565-6d07ae.out
# stderr-file /home/abhishek/.opam/system/build/hardcaml.1.2.0/hardcaml-29565-6d07ae.err
### stdout ###
# [...]
# ocamlfind ocamldep -package bytes -package astring -modules src/utils.ml > src/utils.ml.depends
# ocamlfind ocamldep -package bytes -package astring -modules src/comb.mli > src/comb.mli.depends
# ocamlfind ocamlc -c -g -bin-annot -safe-string -package bytes -package astring -I src -I dynlink -I syntax -I js -I csim -o src/comb.cmi src/comb.mli
# ocamlfind ocamldep -package bytes -package astring -modules src/comb.ml > src/comb.ml.depends
# ocamlfind ocamldep -package bytes -package astring -modules src/bits.mli > src/bits.mli.depends
# ocamlfind ocamlc -c -g -bin-annot -safe-string -package bytes -package astring -I src -I dynlink -I syntax -I js -I csim -o src/bits.cmi src/bits.mli
# + ocamlfind ocamlc -c -g -bin-annot -safe-string -package bytes -package astring -I src -I dynlink -I syntax -I js -I csim -o src/bits.cmi src/bits.mli
# File "src/bits.mli", line 67, characters 33-48:
# Error: Unbound module Big_int
# Command exited with code 2.
### stderr ###
# pkg.ml: [ERROR] cmd ['ocamlbuild' '-use-ocamlfind' '-classic-display' '-j' '4' '-tag' 'debug'
# [...]
# 'src/transform.mli' 'src/fixed.mli' 'src/rtl.mli' 'src/circuit.mli'
# 'src/signal.mli' 'src/bits.mli' 'src/comb.mli' 'src/utils.mli'
# 'dynlink/HardCamlDynlink.cmxs' 'dynlink/HardCamlDynlink.cmxa'
# 'dynlink/HardCamlDynlink.cmx' 'dynlink/HardCamlDynlink.cma'
# 'dynlink/HardCamlDynlink.cmi' 'dynlink/HardCamlDynlink.a'
# 'dynlink/sim_provider.mli' 'js/HardCamlJS.cmxs' 'js/HardCamlJS.cmxa'
# 'js/HardCamlJS.cmx' 'js/HardCamlJS.cma' 'js/HardCamlJS.cmi'
# 'js/HardCamlJS.a' 'js/wave.mli' 'syntax/pa_hardcaml.cmi'
# 'syntax/pa_hardcaml.cmx' 'syntax/pa_hardcaml.cmo']: exited with 10
=-=- Error report -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
We're running into a bit of trouble simulating our register file. We'd like to implement it as "write before read", so that we can write to a register in writeback and read from the same register in decode without needing to explicitly forward writeback => decode. By default, it looks like synchronous reads occur before writes. ram_wbr
doesn't work because it only supports one read port. We're extended this to 2 read ports, and that works. We've confirmed so by generating RTL and simulating in Vivado.
However, in our Hardcaml simulator tests, the written data is only read on the next cycle. My guess is that this occurs because Cyclesim only reads at the start of every clock cycle, and might be mitigated by reading at every clock edge. We haven't found configuration for evaluating the signal graph twice a cycle though. Is there support for simulating write-before-read memory in Hardcaml?
I am little clueless now...
Document or a quick start guide would be helpful.
FPGA world suffers a lot from fragmentation - some tools produce Verilog, some VHDL, some - only subsets of them, creating low-level LLVM-like alternative will help everyone, so HDL implementations will opt only for generating this low-level HDL and routing/synthesizers accept it. LLVM or WebAssembly - you can see how many languages and targets are supported now by both. With more open source tools for FPGA this is more feasible now than ever.
See f4pga/ideas#19
One of the few downsides of Hardcaml as opposed to Verilog+Vivado is the inability to simulate the internals of a circuit. Currently, Circuit.t
allows accessing input and output signals, but not anything in between. As a result, only inputs and outputs of circuits can be monitored in waveforms. This can make it difficult to both debug why an implementation isn't working during development, and to create integration tests for some part of a design that can't easily be expressed as an input or output of the total system.
For an example of the latter, see the datapath and CPU components of our Hardcaml MIPS project. writeback_data
and writeback_pc
are used in integration tests to confirm that some representative instruction sequences are processed correctly. However, they are not used directly higher up in the design, and so aren't really outputs, but we needed to make them outputs anyways so we could test them.
I would like to propose that Hardcaml add optional "debug signals" to circuits. These could be arbitrary signals (or functions of signals), as long as all their leaf dependencies are inputs to the circuit's computation graph. They would be evaluated during simulation and included in waveforms, but pruned during RTL generation to avoid any performance implications. There could also be an option to keep them in the generated RTL in case a different simulation engine is used.
I'm not 100% sure as to an ergonomic way of supporting this in hierarchical circuits, but several ideas are:
scope
argument that's provided to all implementations of hierarchical functions.debug
argument to implementation functions.log
function, then inspecting the dependency tree to figure out between which input/output signals it corresponds to. This is my least favorite option, since its very magicky, and I suspect it wouldn't be possible to uniquely identify this.Beyond this, there could also be a print
function that, when given a signal, clock cycle number, and optional message, would print the signal value and message at the given clock cycle in expect tests. I'm not sure how useful this would be if we had debug
signals though.
I think this feature could significantly speed up development of new Hardcaml designs by allowing "printf" debugging of sorts, and help increase meaningful test coverage of existing ones.
Is there any written documentation on this package, esp.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.