I want to attempt to make a digital circuit modelling/simulation library and DSL for Nimrod. I've been looking a while for a language that would be suitable for this, and after playing with Nimrod on and off for a few weeks I think it could be the only language that's really up for the task.
First step is, I need to create a bit vector type. In a digital circuit model they would represent a set of wires in a 0 or 1 state, each wire representing a power of 2.
The requirements are:
I am quite certain that Nimrod covers me on all these requirements.
But here's the first challange: I can't actually figure out how to define the type. Here's a code sample:
type
BitVector[I] = object
data: array[0..((max(I.a,I.b)-min(I.a,I.b)/32+1)), int32]
var x: BitVector[2..0]
As you can see I'm trying to store the bits as the smallest amount of 32-bit words needed. That's just an example though. I imagine that this logic might be subject to a lot of optimisation.
Anyway, I understand that generics expects types and not values, which is why the example doesn't work. The definition of array and range in system.nim is not a help, since it's magic.
So.. Is it possible to do something like this with the current version of Nimrod? Or in the future maybe? If not yet, is there some hack I could do to make it temporarily so I can get started on the implementation?
Thanks!
type
Bit = range[0..1]
Base = seq[int]
BitVector = distinct Base
proc `[]`(b: BitVector, i: TSlice[int]): BitVector =
(if i.a < i.b: Base(b)[i] else: Base(b)[i.b .. i.a])
proc `[]=`(b: var BitVector; i: TSlice[int], value: BitVector) = ...
proc `[]`(b: BitVector, i: int): Bit = Base(b)[i div 32] shr (i mod 32) and 1
proc `[]=`(b: var BitVector, i: int, value: Bit) =
var w = addr Base(b)[i div 32]
if value == 0: w[] = w[] and not (1'i32 shl (i mod 32))
else: w[] = w[] or (1'i32 shl (i mod 32))
proc bv(s: string): BitVector =
# idea: use bv"0010101" to construct bit vectors at compile time
Thanks for the great replies.
I'm a bit conserned about the sequence approach. In this application,adding or removing bits is not necessary. We're simulating static circuits and performance is critical. Dont sequences incur some performance hit over arrays?
On the other hand, what I like about your suggestion Araq, is that it seems to be easier to generalize to support 4-state bits. This includes Z to represent high impedance (no value) and X (illegal value, simulation error). These can be quite useful in digital design simulation
Good suggestion for the bv proc as a literal-like construct. Would need to allow to specify a range too though. Can't assume that the right most bit represents 2^0.
I think I might try to get my hands dirty with devel and compare the approaches.
You know, i think actually defining a bitvector as a array[I, Bit] where Bit is range [0..1] . It doesn't matter if it doesn't compile to optimal code in the beginning. I can work with he compiler later.
I also realize I should NOT implement integer arithmetic on bitvector, but on subtypes of it. In one type a multiplication might return a bitvector of length max(a.len,b.len) (modular arithmetic) while another type would return one of width a.len+b.len (integer arithmetic with no information loss). This is more like VHDL does it which is the more type safe of the two major Hardware Description Languages.
type
Bit = range[0..1]
BitVector[I] = object
bits: array[I, Bit]
I'm hoping this is possible in the devel version? Oh, and maybe there's a better way to define this without using an object ? Maybe
type
BitVector[I] = distinct array[I, Bit]
To implement the arithmetic version of BitVector we would need support for expressions in generics I think.
type
BVInteger [I] = distinct BitVector[I]
proc `*`[I,J](a:BVInteger[I],b:BVInteger[J]) = BVInteger[I.a+J.a .. 0]
....
I'm really hoping something like this will be possible in the future.