Orangepath/HPRLS Project: Hardware and Embedded Software Synthesis from Executable Specifications.
Compilation from .net CIL Bytecode

Kiwi: Logic Synthesis from .net CIL Bytecode

The Orangepath tool can accept a variety of input formats, including .net CIL bytecode. This bytecode is generated by Microsoft tools the tools from the mono project.

Currently we are defining a compilation profile for C# called Kiwi.

This web page shows output from our first, simple trial.

H/W Compilation from .net CIL Bytecode to RTL/Netlist

In this example, the following C# program was compiled to .net CIL bytecode. The program simply prints out a multiplication table.

C# Source Code

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 + " ");

The .net CIL Assembly Code

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
	// 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

Internal Representation

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 virtual machine format. The VM code is as follows:

0:*APPLYprintf(*APPLYconcat("Times Table Up To ", limit));
1:V_0 := 1;

2:Xgoto(IL_005b, 13);

4:V_1 := 1;

5:Xgoto(IL_0042, 9);

7:*APPLYwrite(*APPLYconcat(V_0*V_1, " "));
8:V_1 := V_1+1;

10:beq( !(V_1<=limit),IL_0027, 6)
12:V_0 := V_0+1;

14:beq( !(V_0<=limit),IL_0020, 3)
15:return 0;
0:limit := 5;

1:return 0;
0:return 0;

Verilog Output

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);
 always @(posedge clk) begin if (!((!(pcnet106[1])|pcnet106[0]))) $write("%d%s", (V_0*V_1), " ");
 always @(posedge clk) begin if (V_1==6) $display("");
 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;
 always @(posedge clk) begin limit <= (!((pcnet105^0))) ? 5:limit;
   pcnet105 <= pcnet105;

The low-level Verilog netlist is on this link: netlist.v.

Simulation Output

One of the Verilog forms was placed in a simple testbench that provides clock and reset. The 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.


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);

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 
02 04 06 08 10 
03 06 09 12 15 
04 08 12 16 20 
05 10 15 20 25 

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.