VHDL Code Generation

VHDL is a Hardware Description Language that is used for describing a digital system either for designs, tests, or synthesis onto some programmable hardware (ie a FPGA). It is a language that I hate the feel of, but love what is below the surface. Thanks to its history in Ada, it has a very nice type system. Much of what I dislike is also tied to Ada influences, the syntax. It is syntaxtically verbose, with the code style following along. For anyone who has programmed vhdl has most certainly written signalname: std_logic_vector(x downto 0); many times over and over. Many of the vhdl forms have their own peculiarities. All of these different forms, sometimes for similar uses creates an attitude of "there is more than one way to code it". Lastly, the code does not seem to have a standard method of indentation. For some this point may seem minor, but for the readability of code indentation is very helpful in seeing the structure.

Ideally I think a HDL should have a different set of priorities.

  • Simple regular language

  • Focus on synthesizable forms

  • Abbreviate common forms (state machines, combinational logic, ranges)

  • Sane indentation and code style

  • Ensure edge cases can be described

<!--:truncate:-->

For these reasons I built up a simple language ModV. It is an intermediate language that compiles down to VHDL.It does a decent job at the first few points and it leaves the possibility of offloading unknown edge cases to VHDL.

Language Description

Headers

One entity is described per file starting with the header that states the name and the ports. For vector ports, the size of the port or a range can be specified. At this time, all ranges are assumed to be high to low.

module entity_name
--port declarations
head:
    gen    generic logv[8]
    input  in      log
    clk    in      log
    output out     logv[7..0]
end

Signals

Signal declarations look similar to VHDL declarations with minor syntactical changes. As groups of signals are common, they can be placed into blocks.

--inline signals
signal sig integer
--block signals
signal:
    test    logv[8]
    foobar  boolean(false)
    asig,
    bsig,
    csig    log
end

Defining Basic Types

As state machines are one of the important elements of digital hardware, they have their own syntax for definitions.

enum state_t(state_a,state_b,testing)
signal state state_t

Basic Combinational Logic

For basic combinational logic, the when and with-input-select statements have been translated into alternatives. The idiom of setting something to '1’s or '0’s using the (others ⇒ val) form is fairly common so that is abbreviated with *.

--ternary operator
output = input=='1' ? gen : *'0'
--Lookup tables
test = lookup(state):
    state_a: 0xab
    state_b: 0x4f
    others:  0xff
end

Synchronous Systems

Synchronous systems need to have actions on a clock edge. The basic statement of a synchronous block requires the clock as an input to determine when to perform the assignments. Inside of this block an extra set of statements become available. This is a result of the thin veil over the way VHDL distinguishes between combinational and sequential logic.

sync(clk):
--abbreviated one statement blocks
    if(sig==123)
        foobar = true
    case(test)
        0xab:
            asig = 1
            bsig = 0
        0xf0:
            asig = 1
            bsig = 1
        others:
            asig = 0
            bsig = 0
    end
    async
        x = y
end

A Full Example

In order to get a better feel for this, a simple Hex Display Decoder was created. In my opinion this is a fairly clean result.

module HexDisplay

head:
    D  in   logv[4]
    en in   boolean
    Q  out logv[7]
end

arch:
    signal hex logv[7]

    Q = en ? hex : *'1'
    hex = lookup(D):
        0x0:"1000000"
        0x1:"1111001"
        0x2:"0100100"
        0x3:"0110000"
        0x4:"0011001"
        0x5:"0010010"
        0x6:"0000010"
        0x7:"1111000"
        0x8:"0000000"
        0x9:"0011000"
        0xa:"0001000"
        0xb:"0000011"
        0xc:"1000110"
        0xd:"0100001"
        0xe:"0000110"
        0xf:"0001110"
    end
end

Implementation

With this idea in mind a simple implementation was created using yacc and lex. This implementation is by no means robust or very well written, but it does translate the listed forms into their vhdl equivalents. This is hosted in git and can be downloaded from: git://fundamental-code.com/modv

Synthesizer Integration

Currently one demo of a synthesizer integration is available with Altera Quartus. Assuming that their tools are in the path, the project ("here":http://fundamental-code.com/log/modv/modv-stopwatch.tar.gz) should build a working project for the DE1 Board. As most people (that I have seen) tend not to call the binary tools for synthesis directly, I have the project populated with the generated files.

Future

I am not sure if I am going to work on extending this project in the future too much. It mostly depends if I get any response and if I am doing significant work in vhdl for synthesis. If future work is done, then the priorities are:

  • Error Handling

  • Parser cleanup

  • Sanity checks on semantics

EDIT: a sane translation of VHDL records should also be added to the implementation.