The main part of the Kiwi Project is the KiwiC compiler. This, itself, consists of a front end for the HPR L/S (Orangepath) logic synthesis library. KiwiC reads .net CIL portable assembly bytecode files and converts them into the internal HPR virtual machine format. The standard KiwiC recipe invokes processing stages that emit the design is synthesisable Verilog RTL or SystemC. This .net bytecode is generated by Microsoft tools or the MCS compiler from the mono project.
This web page shows output from our first, simple trial.
In this example, the following C# program was compiled to .net CIL bytecode. The program simply prints out a multiplication table.
The C# source code is:
using System; //NameSpace class TimesTable { static int limit = 5; public static void Main() { int i, j; Console.WriteLine("Times Table Up To " + limit); for (i=1;i<=limit;i++) { for (j=1;j<=limit;j++) Console.Write(i*j + " "); Console.WriteLine(""); } } }
The C# source code was fed into the mono project's mcs compiler. This generates a .exe file. It can probably also generate the IL assembly code directly but we used monodis to create the following listing from the .exe file.
The .net CIL assembly listing from monodis is:
.assembly extern mscorlib { .ver 1:0:5000:0 .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. } .assembly 'timestable' { .hash algorithm 0x00008004 .ver 0:0:0:0 } .module timestable.exe // GUID = {FCF8AA38-DB18-4622-8121-C10C03FD4078} .class private auto ansi beforefieldinit TimesTable extends [mscorlib]System.Object { .field private static int32 limit // method line 1 .method public hidebysig specialname rtspecialname instance default void .ctor () cil managed { // Method begins at RVA 0x20ec // Code size 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void object::.ctor() IL_0006: ret } // end of method TimesTable::instance default void .ctor () // method line 2 .method private static specialname rtspecialname default void .cctor () cil managed { // Method begins at RVA 0x20f4 // Code size 7 (0x7) .maxstack 8 IL_0000: ldc.i4.5 IL_0001: stsfld int32 TimesTable::limit IL_0006: ret } // end of method TimesTable::default void .cctor () // method line 3 .method public static hidebysig default void Main () cil managed { // Method begins at RVA 0x20fc .entrypoint // Code size 103 (0x67) .maxstack 8 .locals init ( int32 V_0, int32 V_1) IL_0000: ldstr "Times Table Up To " IL_0005: ldsfld int32 TimesTable::limit IL_000a: box [mscorlib]System.Int32 IL_000f: call string string::Concat(object, object) IL_0014: call void class [mscorlib]System.Console::WriteLine(string) IL_0019: ldc.i4.1 IL_001a: stloc.0 IL_001b: br IL_005b IL_0020: ldc.i4.1 IL_0021: stloc.1 IL_0022: br IL_0042 IL_0027: ldloc.0 IL_0028: ldloc.1 IL_0029: mul IL_002a: box [mscorlib]System.Int32 IL_002f: ldstr " " IL_0034: call string string::Concat(object, object) IL_0039: call void class [mscorlib]System.Console::Write(string) IL_003e: ldloc.1 IL_003f: ldc.i4.1 IL_0040: add IL_0041: stloc.1 IL_0042: ldloc.1 IL_0043: ldsfld int32 TimesTable::limit IL_0048: ble IL_0027 IL_004d: ldstr "" IL_0052: call void class [mscorlib]System.Console::WriteLine(string) IL_0057: ldloc.0 IL_0058: ldc.i4.1 IL_0059: add IL_005a: stloc.0 IL_005b: ldloc.0 IL_005c: ldsfld int32 TimesTable::limit IL_0061: ble IL_0020 IL_0066: ret } // end of method TimesTable::default void Main () } // end of class TimesTable
Note, the KiwiC front end can also write its own disassembly if requested (default output file is called obj/ast.cil). There are minor syntax differences in the disassemblies.
The CIL bytecode was read in by the CIL parser of the Orange tool and converted from stack code to a sequential program in the internal HPR L/S virtual machine format. The VM code is as follows:
sensitivity=NONE 0:*APPLYprintf(*APPLYconcat("Times Table Up To ", limit)); 1:V_0 := 1; 2:Xgoto(IL_005b, 13); 3:IL_0020: 4:V_1 := 1; 5:Xgoto(IL_0042, 9); 6:IL_0027: 7:*APPLYwrite(*APPLYconcat(V_0*V_1, " ")); 8:V_1 := V_1+1; 9:IL_0042: 10:beq( !(V_1<=limit),IL_0027, 6) 11:*APPLYprintf(""); 12:V_0 := V_0+1; 13:IL_005b: 14:beq( !(V_0<=limit),IL_0020, 3) 15:return 0; ----------------------- sensitivity=NONE 0:limit := 5; 1:return 0; ----------------------- sensitivity=initiolon 0:return 0; -----------------------
The design was output as Verilog in two forms: high-level and gate-level.
The high-level Verilog RTL was output as follows:
module timetable1(clk, reset); input clk; input reset; reg [31:0] limit; reg [31:0] V_1; reg [31:0] V_0; reg pcnet105; reg [1:0] pcnet106; always @(posedge clk) begin if (!((pcnet106[1]|pcnet106[0]))) $display("%s%d", "Times Table Up To ", limit); end always @(posedge clk) begin if (!((!(pcnet106[1])|pcnet106[0]))) $write("%d%s", (V_0*V_1), " "); end always @(posedge clk) begin if (V_1==6) $display(""); end always @(posedge clk) begin V_1 <= ((!((pcnet106^2))&(V_1<=limit))) ? (V_1+1):((!((pcnet106^1))&(V_0<=limit))) ? 1:V_1; V_0 <= ((!((pcnet106^2))&!((V_1<=limit)))) ? (V_0+1):(!((pcnet106^0))) ? 1:V_0; pcnet106 <= ((!((pcnet106^2))&!((V_1<=limit)))) ? 1:((!((pcnet106^2))&(V_1<=limit))) ? 2:((!((pcnet106^1))&(V_0<=limit))) ? 2:(!((pcnet106^0))) ? 1:pcnet106; end always @(posedge clk) begin limit <= (!((pcnet105^0))) ? 5:limit; pcnet105 <= pcnet105; end endmodule
The low-level Verilog netlist is on this link: netlist.v.
One of the Verilog forms was placed in a simple testbench that provides clock and reset. An RTL simulator was then run. The same output is generated when using either Verilog form, although a gate cell library must also be loaded for the netlist version. HPR L/S contains an internal simulator that operates on any of the intermediate forms generated by the Kiwi recipe and these all produce the same output as well.
Testwrapper:
module SIMSYS(); reg clk, reset; initial begin reset = 1; clk = 0; # 4000 reset = 0; end always #1000 clk = !clk; initial #200000 $finish; timetable1 dut(clk, reset); endmodule
The following screen shot shows the nets being traced in the simulator:
The console output from the simulator was:
Times Table Up To 00 01 02 03 04 05 06 02 04 06 08 10 12 03 06 09 12 15 18 04 08 12 16 20 24 05 10 15 20 25 30
Note that there are race conditions between the assignment to limit and its printing in the title banner and in the output of the newline at the end of each row and the last item on each row. But this was the first ever run from C# input code and we need to adopt some coding conventions and so on...
The race on the setting up of limit will be solved by causing the constructor code to run before entering the main body, instead of concurrently! Also, the reset input is not being used, but that's a small oversight as well.
31st October 2007. UP.