Cyclicity CDL Language Specification - Language Examples
Gavin J Stark
v0.01
April 14th 2004
|
Some example designs are included here,
with notes on their use.
|
|
|
Simple register |
The following code is a simple D flip-flop, with and active high
reset, and reset low value.
module reg( clock int_clock, input bit int_reset, input bit D, output bit Q )
{
clocked rising int_clock active_high int_reset bit Q = 0;
main_code "Main code":
{
Q <= D;
}
}
|
Simple adder |
The following code is a simple arbitrary width adder; the width is
given by a constant.
constant integer width=16;
typedef bit[width] t_value;
module adder( input t_value A, input t_value B, output t_value Z )
{
main_code "Main code":
{
Z = A+B;
}
}
|
Simple clocked adder |
This code uses the simple adder module above, and registers the
result.
constant integer width=16;
typedef bit[width] t_value;
extern module adder( input t_value A, input t_value B, output t_value Z )
{
timing comb input A, B;
timing comb output Z;
}
module clocked_adder( clock int_clock,
input bit int_reset,
input t_value A,
input t_value B,
output t_value clocked_result,
)
{
net t_value result;
clocked rising int_clock active_high int_reset t_value clocked_result = 0;
instances "Adder instance":
{
adder add1( A<=A, B<=B, Z=>result );
}
registers "Register the result from the adder instance":
{
clocked_result <= result;
}
}
|
|
This section includes some potential implementations for a CPU
core.
These are more realistic coding examples than those described
previously, and they are included to show the real nature of the
language and the readability that it supplies.
By convention types are all prefixed 't_', constants 'c_'. This is
again for readability; it is not required by the Cyclicity CDL
language.
|
Headers |
A few header files are required to define the types and such for
the core.
constant integer c_cpu_word_width=32;
typedef bit[c_cpu_word_width] t_cpu_word;
typedef enum[4]
{
alu_op_shift_rotate=0,
alu_op_add=1,
alu_op_sub=2,
alu_op_add_with_carry=3,
alu_op_and=4,
alu_op_or=5,
alu_op_xor=6,
alu_op_not=7,
alu_op_mov=8,
} t_cpu_alu_op;
typedef enum[2]
{
shift_op_shift_left=0,
shift_op_shift_right=1,
shift_op_rotate_right=2,
} t_cpu_shift_op;
|
ALU |
This section supplies an ALU that
performs the operations required by an ALU in a simple CPU core. It
consists of a barrel shifter, an adder with preconditioning logic,
and a result multiplexor with additional logic for the ALU logical
operations.
typedef bit[c_cpu_word_width+1] t_cpu_word_extended;
module cpu_alu(
input t_cpu_word a "First operand input to the ALU",
input t_cpu_word b "Second operand input to the ALU",
input bit carry_in "Carry in to the ALU; used by add_with_carry only",
input t_cpu_alu_op alu_op "ALU operation to perform, including 'use shifter'",
input t_cpu_shift_op shift_op "Operation for the barrel shifter to perform",
output t_cpu_word result "Result of the ALU/shift operation, given by alu_op and the operands",
output bit carry_out "Carry out of an arithmetic operation, if alu_op specified one",
output bit result_is_zero "Indicates that the result is zero; useful for comparisons and tests"
)
"
This module implements the arithmeritc, logical, shift, and compare operations for a cpu core
The module is purely combinatorial.
It consists of:
an adder, whose inputs are preconditioned to perform subtract as well as add, with arbitrary carry.
a barrel shifter, which can do shift left, right, and rotate right, by an amount specified by an input
a result mux (with the ALU logic operation gates) which takes the adder or shifter result or a logical
combination of the inputs, and produces the final results.
"
{
comb bit adder_carry_in "Carry in for the adder";
comb t_cpu_word_extended adder_input_a "First input to the adder,
extended by one bit to provide a carry out";
comb t_cpu_word_extended adder_input_b "Second input to the adder,
extended by one bit to provide a carry out";
comb t_cpu_word_extended adder_result "Full result of the adder,
including carry out in the top bit";
comb t_cpu_word shifter_result "Result from the shifter";
adder_code "Adder inputs and the adder itself; generates the adder_result":
{
adder_input_a[ c_cpu_word_width; 0] = a;
adder_input_a[ c_cpu_word_width ] = 0;
adder_carry_in = 0;
full_switch( alu_op )
{
case alu_op_sub:
{
adder_input_b[ c_cpu_word_width; 0] = ~b;
adder_input_b[ c_cpu_word_width ] = 0;
adder_carry_in = 1;
}
case alu_op_add_with_carry:
{
adder_input_b[ c_cpu_word_width; 0] = b;
adder_input_b[ c_cpu_word_width ] = 0;
adder_carry_in = carry_in;
}
default:
{
adder_input_b[ c_cpu_word_width; 0] = b;
adder_input_b[ c_cpu_word_width ] = 0;
adder_carry_in = 0;
}
}
adder_result = adder_input_a + adder_input_b;
if (adder_carry_in)
{
adder_result = adder_result + 1;
}
}
shifter_code "Simple shifter, produces the shifter_result":
{
shifter_result = 0;
part_switch (shift_op)
{
case shift_op_shift_left:
{
shifter_result = a << b[5;0];
}
case shift_op_shift_right:
{
shifter_result = a >> b[5;0];
}
case shift_op_rotate_right:
{
shifter_result = (a >> b[5;0]) | (a<<(32-b[5;0]));
}
}
}
result_code "Generate the final outputs from the intermediate results":
{
carry_out = 0;
full_switch ( t_cpu_alu_op )
{
case alu_op_shift_rotate:
{
result = shifter_result;
}
case alu_op_add,
alu_op_sub,
alu_op_add_with_carry:
{
result = adder_result[32;0];
carry_out = adder_result[32];
}
case alu_op_and:
{
result = a & b;
}
case alu_op_or:
{
result = a | b;
}
case alu_op_xor:
{
result = a ^ b;
}
case alu_op_not:
{
result = ~b;
}
case alu_op_mov:
{
result = b;
}
}
result_is_zero = (result==0);
}
}
|
|
|
|