CTOV Manual: Ansi C to Verilog Compiler (Jan 00)

CTOV Compiler

CTOV is a compiler that reads ANSI C source code
and generates a synthesisable Verilog design which
performs the same function.

A given input design can be compiled and run as a normal C program,
using gcc, or can be compiled with CTOV to a chosen hardware
architecture. The architecture is characterised by the
number of RAMs, adders and multipliers allowed: the compiler works
out how to use these resources on a cycle-by-cycle basis.

It is intended that CTOV is normally run from inside a makefile
and that, for large designs, separate compilations from CTOV (and
other Verilog producing compilers) are combined as instances in a
higher-level Verilog module.

Special features of CTOV are:

A design can be compiled with parameters which minimise
clock cycle consumption or else minimise the number of RAMs,
adders and multipliers generated.

Advanced SRAM mapping functions which determine access
schedules for synchronous SRAMs of various sizes and number of access
ports.

Scalar variables and arrays from the source program
may be packed together into memory arrays in the hardware design.

Array variables in the source program
can be unpacked into registers in the hardware design.

Low-level design is possible, where the exact
structure of the resulting gate-level net-list can be
controlled from the source file.

The source C code can be run as normal using the TENOS libraries
to produce an emulation of the hardware, although a threads
library is needed if threads are used by the source C code.

The source C code may be multi-threaded and use the pthreads
library to create threads and for mutexes.

Designs can be compiled back and forwards between C and Verilog
using alternately VTOC and CTOV.

Language Restrictions

The exact number of bits required for data storage must be
determined at compile time. Therefore the C code for compilation may
not use recursive routines or malloc for heap access. All pointer
variables must be compile-time resolvable to specific arrays or
functions.

In version 2, the restriction to non-recursive
functions will be lifted.

Basic Operation

CTOV is run from a command line or makefile. It reads
one or more C files and special versions of the standard
C library files and include files. The include files are in
the cxincludes directory which forms part
of the distribution.

In a given compilation, the C routine whose name is given by the
command line flage -iroot and all routines called
by it are compiled. The output is a single Verilog module whose name
is given by the -oroot command line option.

The inputs and outputs to the generated hardware are the formal
parameters to the top level module and any free variables which have
been declared to be I/O using an IOMAP macro. SRAM blocks can be
placed outside the generated target module, which is useful for large
RAMs with FPGA targets, in which case the connections to such SRAM
blocks may also be present as I/O ports to the generated module.
IOMAP can be used to set the widths of I/O ports and the pin number
for some FPGA implementions. IOMAP is a C macro which is defined as
null under normal C compilation.

A pair of additional inputs are generated by the compiler for all
designs (except for fully combinatorial designs) `clk' and
`cx_reset'. These are the master clock and the master synchronous,
active low reset. If these signals are alread present in the signature
of the top-level routine then the existing signals are used.
The input design should list them in the order clk, cx_reset as
the first two arguments. Note that this is the order generated
by the companion VTOC program.

Other files: report and control

Apart from the main input C file(s) and the main output Verilog file,
an additional `.ctl' file may be read in to control the compilation
and a `.rpt' file is written out.

The control file name may be specified with the `-ctl fn' command
line flag. The report file name may be specified with the `-rpt fn'
command line flag.

If no control file is specified, the `.c' source file is used
read as the control file. Owing to the form of control commands,
they may be embedded by the user inside comments in the `.c' file.

If no report file is specified, the default name is the same
as the `.c' source file but with the suffix changed to `.rpt'.

Note that the report file generated by one compilation is suitable
for direct use as the control file for a subsequent compilation.
However, in practice, users might paste selected lines from a report
file into a manually-maintained control file using a text editor.

Control File Syntax

So that the control file commands can be easily extracted when they
are embedded in source files or report files, each command starts with
the string `$TTSET' and ends with the string `$'. The command
consists of a number of alphanumeric strings separated by white space
or other punctuations characters, including the vertical
stile used in tables.

Link Editing

CTOV will accept exactly one C filename from the command line. Access
to source code from multiple files in one compilation is either via
system libraries or via #include directives in the C file first specified.

Multiple compilations from CTOV will lead to multiple output
Verilog modules. These can be stitched together, manually, in the
Verilog domain by instantiating them in higher-level modules.

Three modes of compilation

The compiler will automatically select one of the
following three modes of compilation.

Fully combinatorial

One cycle (simple RTL)

Sequenced.

A fully combinatorial design needs no clock and so the compiler will
not automatically add the clock and reset nets to the signature port list.

A one cycle design corresponds to a design with no requirement
for a run time program counter. All assignments to variables can
be made in parallel using Verilog RTL constructs.

A sequenced design requires a run-time program counter. The
compiler generates RTL Verilog (as opposed to behavioural Verilog) and
an additional variable called `tt_state' which acts as a program
counter and as a sequencer to schedule accesses to RAM arrays. For
multi-threaded designs where the number of threads does not change at
run-time, one such state register is created per thread. When the
number of threads may change, the compiler generates multiple DFFs and
uses one hot coding to recored the thread state where necessary.
Multiple-threads are not supported in version 0 or 1 of CTOV.

Variable Declaration

The user can use the normal C datatypes: byte, short, int and long int.
These may be qualified as signed or unsigned. In addtion, the
include file &ltcxtypes.h&gt has definitions of variables
with explicit widths in bits. For instance a u5
is a five-bit unsigned quantity. For normal C compilation, these
macro definitions expand to the next largest standard C type, but
for CTOV compilation, the compiler takes not of the detailed width.
This can lead to variations in program function if a design relies
on the bits which fall between a CTOV sized variable and the next
largest C variable.

Memories

Memories must be on chip or offchip. CTOV will generate instances
of memories and the signals to connect to them, but the user must
provide the actual memories in the target technology environment.

The name of a memory always starts `SSRAM' and is then extended
with width, length and port descriptions encoded into part of the
name.

All memories have a clock input and data is stored in a memory
via a write port if the associated write enable signal is high on
the positive edge of the clock. Memories are L words long and W bits
wide and L must be a power of 2. Write ports have a write enable signal
and a W-bit wide input bus. Read ports have a W-bit wide read bus.

A memory may have any number of ports. Each port has
an address bus of log2 L bits. Each port must fit one of
the following forms:

RW - read or write, half duplex.

RAW - read and write (at once of of one location)

RO - read only

WO - write only

WD - write, but destructive of existing contents
at the write address for reads on other ports during the same cycle

The RW and RWD ports have two sets of data wires, one for reading and
one for writing, but only one set is used during any clock cycle. The
two sets can be merged into a tri-state bus if the user places
suitable tri-state buffers in a wrapper file (pad ring) which instantiates
the module(s) generated by CTOV run(s).

Each output array needs to be delcared and then the ports
can be defined afterwards.

The following command will define an output array called `holya'
of width 32 bits and length 5 words. The minus sign is shorthand
for `onchip'. The alternative allowable value is `offchip'.

declare_output_array - holya 32 5

This declaration will make an entry in the Ram Array Report as
follows. The number of ports and other information is added after the
closing dollars marker and so does not form part of the declaration
command.

Mapping to Output Array

An input scalar or array can be manually mapped to a location in an
output array provided the output array is sufficiently wide. The
locations selected for the mapping should not be in use for other
purposes.

The following command will map input scalar `mm' to location 5 of output
array `holya'. TODO explain about multiple instances and scoping.

mapto_output_array mm holya 5

The scalar `mm' could equaly be an input array, in which
case the nunmber given becomes the base address of a sequence of
consecutive locations used for the input array in the output array.

The number '5' could be replaced with a minus sign, in which case
the compiler will chose an otherwise unused location in the output array.

The output array name can be replaced with a minus sign, in which
case the compiler will chose an output array to keep the scalar in.
It is inadvisable to allow the comipler to select if low compilation
effort is selected since a poor result is possible.

The final chosen maping of input variables is shown in the `CTOV
Input Register Report' table of the report file. This table is for
information only since it does not contain embedded control commands.

TODO explain how to map part of an input array to an output array.

Default Array Creation

Uninitialised, static arrays in the C source file will default to
onchip SSRAMs with a single RW port.

Initialised arrays in the C source file are converted to ROMs
and cannot be changed at runtime. This is a source language
restriction in CTOV version 1.

If an array has no ports declared, a single RW port is assumed.

Ram Simulation Models

If needed, a simulation model in Verilog of a RAM produced by CTOV can be
automatically generated by the CTOV_RAMGEN program which can be
run from the commandline.

Parameter Passing

CTOV V1 operates by expanding all subroutine calls into a flat
structure before further compilation. For both the top-level routine
and those called below it, input and output can be via free variables
(globals in C) or the parameters. Call-by-value parameters can only
be used as inputs since changes made to the formal parameter inside a
routine do not have side-effects on the outside environment. For
output, a value can be returned by a routine and call-by-reference
can be used to pass out other values.

Major Design Styles

CTOV supports three modes of compilation and these
support more than three major design styles.

Purely Combinatorial

A purely combinatorial design requires no clock or reset input and
has no internal state. This is illustrated here with an AND
gate.

Here is a section of C which makes a single AND gate.
It is important for practical hardware design that an engineer can
instruct the tools to produce gate-level features where required.

void and2gate(u1 *y, u1 a, u1 b)
{
*y = a && b;
}

In the example, the AND output is via a call by reference parameter
instead of a returned value. An alternative would be as follows

u1 and2gate(u1 a, u1 b)
{
return a & b;
}

The switch to logical AND (&&) from binary AND (&) makes no difference
in this example. The output from compiling the first version of this
simple gate is as follows. The second version does not make sense to
compile as a top level routine since the CTOV compiler discards the value
returned from the top level routine.

Note that the combinatorial output from the simple AND gate is
equivalent to a Mealy output from the sequential examples presented
next.

A Simple Sequential Example

We can generate a four bit counter with clock enable, synchronous
reset and combinatorial indication that the output is 15, with the
following section of C.

In this example, the first two terminals given by the user are
called clk and cx_reset. Therefore the compiler will not need
to add these to the output Verilog module, meaning the output
module will have the same number of connections as the input module.

The most striking aspect of this section of code is the call the
the subroutine `cx_barrier'. The assignment to strobe on after the
barrier makes this a Mealy output that is a combinatorial function of
the current state and the input values, whereas state is a registered
(Moore) output.

If the barrier statement were missing.... TODO

The output Verilog created from this compilation is ... TODO

Sequential Example that creates a State Register for User States

Sequential Example that creates a State Register for Array Sequencing

Compilation Effort and Metrics

There is no unique, optimal solution to non-trivial compilations.
The compiler makes heuristic choices at many points within its algorithms.
The user can influence the number of choices available and the number
of solutions explored. This alters the trade off between quality of
results and compile time.

The decisions made by CTOV during a particular compilation are
reflected in the report file in many places, but particularly in a
concise decision report table. The information in the decision report
table is not intended to be fully comprehensible by the user but it
can be read in as part for the control file for a subsequent
recompilation, perhaps after a minor modification. The user needs to
be aware that decision information from previous compilations may not
be helpful if there have been significant changes to the source
program or if it is intended to recompile with greater effort or
different metrics: therefore the user should delete or otherwise avoid
feeding the decision information into subsequent comilations in these
circumstances.

C Library Routines

A set of basic, standard C library routines is provided in the
directory cxlibc which is part of the standard
distribution. These libraries include basic string routines and
ctypes and so on. The routines are written in standard C.

Installation and Directory Structure

The system currently requires VTOC to have been installed and that
a soft link to the cv3core binary with the name `ctov' is placed on
the PATH shell variable.

The CTOV shell variable should point to a directory containing
the CTOV distribution, including the following directories:

sml - the system files interpreted by the cv3core executable

cxinclude - the include files used instead of /usr/include during compilation

cxlibc - versions of basic C library functions such `strcmp'.

cxccfe - the C front end executable

The CVMETAPATH variable must include the directory CTOV/sml ahead
of the VTOC entries.

A valid license file called LICENSE.cv3 should be in one of the
directories on the CVMETAPATH. Contact us for license information.

Once installed and setup, the following help message should be
displayed upon executing `ctov'.

Pathlen

The pathlen parameter is a limit on the number of barrier steps from
the top of the flow graph derived from the input C files to any point
that is actually executed. If the compiler exits with `pathlen exceeded'
error, then the user can try to increase this limit. This situation
may occur when a great deal of loop unwinding is needed or when the
input program is long in the sense of a linear chain of barriers.