Orangepath/HPR Logic Synthesis Project: Hardware and Embedded Software Synthesis from Executable Specifications.
Compilation from .net CIL Bytecode (second example)

Kiwi Simple Demo: LCD display panel driven from C# CSharp HLS

FPGA evaluation cards, like the Xilinx VC-707, often have 16x2 LCD panels. These display up to two lines of 16 characters each.

There are numerous examples online showing how to exercise these displays using low-level RTL. It is much easier with a HLS flow such as Kiwi, where the thread of control with method call inlining neatly generates the same designs.

The standard 16x2 DisplayTech LCD is documented here https://www.openhacks.com/uploadsproductos/eone-1602a1.pdf.

Photo of Xilinx VC707 Eval Card LCD 1602 Module Controlled By Kiwi HLS Device Driver

Source File

The following CSharp file was compiled with mono mcs.

//
// Kiwi Scientific Acceleration
// (C) 2009 DJ Greaves - University of Cambridge, Computer Laboratory
//
// Demonstration of driving the 16x2 LCD display panel found on FPGA development boards.
//

using System;
using KiwiSystem;

class KiwiLCD1602Driver
{

/*
   // Put the following padring code in a Xilinx top-level file.
   // Instance of the Kiwi-generated LCD driver
   wire lcd_data4_openable; 
   wire [3:0] lcd_data4_in, lcd_data4_out;
   bufif1(LCD_DB4_LS, lcd_data4_out[0], lcd_data4_openable);  
   bufif1(LCD_DB5_LS, lcd_data4_out[1], lcd_data4_openable);  
   bufif1(LCD_DB6_LS, lcd_data4_out[2], lcd_data4_openable);  
   bufif1(LCD_DB7_LS, lcd_data4_out[3], lcd_data4_openable);  
   IBUF lcd_in40(lcd_data4_in[0], LCD_DB4_LS);
   IBUF lcd_in41(lcd_data4_in[1], LCD_DB5_LS);
   IBUF lcd_in42(lcd_data4_in[2], LCD_DB6_LS);
   IBUF lcd_in43(lcd_data4_in[3], LCD_DB7_LS);
   
   kiwi_lcd1602_driver  the_lcd_driver(  
			 .LCD_RS_LS(LCD_RS_LS),
			 .LCD_E_LS(LCD_E_LS),
			 .LCD_RW_LS(LCD_RW_LS),
			 .lcd_data4_in(lcd_data4_in),
			 .lcd_data4_out(lcd_data4_out),
			 .lcd_data4_openable(lcd_data4_openable)
			
   );
   

*/

// The standard 1602a DisplayTech LCD is documented here  https://www.openhacks.com/uploadsproductos/eone-1602a1.pdf
// http://embeddedlifehelp.blogspot.co.uk/2012/03/16x2-lcd-programming-for-beginners-made.html
//  https://learningmsp430.wordpress.com/2013/11/16/16x2-lcd-interfacing-in-4-bit-mode/

  // Use 4-bit, tri-state connection to the LCD panel.
  [Kiwi.OutputBitPort("LCD_RS_LS")] static bool LCD_RS;    
  [Kiwi.OutputBitPort("LCD_RW_LS")] static bool LCD_RW;   
  [Kiwi.OutputBitPort("LCD_E_LS")] static bool LCD_E;    
  [Kiwi.OutputBitPort("lcd_data4_openable")] static bool lcd_data4_openable;    
  [Kiwi.InputWordPort(3, 0, "lcd_data4_in")] static byte lcd_data4_in;
  [Kiwi.OutputWordPort(3, 0, "lcd_data4_out")] static byte lcd_data4_out;

  public static void PortIdle()
  { 
    lcd_data4_openable = true;
    LCD_RS = false;
    LCD_RW = false;
    LCD_E = false;
    lcd_data4_out = 0;
  }

  // To send a byte on the 4-bit bus, send high nibble first.
  // To read a byte on the 4-bit bus, get high nibble first.
  static byte readByte(bool dataf)
  {
    LCD_RS = dataf; 	// Low for control, high for readback of data.
    lcd_data4_openable = false;    LCD_RW = true;   
    Kiwi.Pause();    LCD_E = true;
    Kiwi.Pause();    byte r = (byte)(lcd_data4_in & 0xF);  LCD_E = false;
    Kiwi.Pause();    LCD_E = true;
    Kiwi.Pause();    r =  (byte)((r << 4) | (lcd_data4_in & 0xF)) ;    LCD_E = false;
    Kiwi.Pause();
    lcd_data4_openable = true;  // Re-enable outputs for next write.
    return r;
  }

  // To send a byte on the 4-bit bus, send high nibble first.
  static void sendByte(bool dataf, byte data)
  {
    LCD_RS = dataf; 	// Low for control, high for readback of data.
    lcd_data4_openable = true;     LCD_RW = false;    lcd_data4_out = (byte)((data >> 4) & 0xF);
    Kiwi.Pause();    LCD_E = true;
    Kiwi.Pause();    LCD_E = false;
    Kiwi.Pause();    lcd_data4_out = (byte)((data >> 0) & 0xF) ;  
    Kiwi.Pause();    LCD_E = true;
    Kiwi.Pause();    LCD_E = false;
    Kiwi.Pause();  
  }


  static void WaitNotBusy()
  {
    // Have two pauses to give it a chance to go busy.
    Kiwi.Pause();
    Kiwi.Pause();
    // Busy flag is bit seven of the status register - poll to be not busy.
    while (true)
      {
	byte status_reg = readByte(false); 
	Kiwi.Pause();
	if (((int)(status_reg) & 128)==0) break;
      }
  }

  static void wait_delay_40() 
  {
    for (int k=5; k != 0; k--) Kiwi.Pause();   // Wait 5*period for 4.1 ms or 100 us
  }

  static void LcdCmdD(byte cmd, int delay)      // Send a command byte using a delay.
  { sendByte(false, cmd);
    Console.WriteLine("LCD sent cmd byte using delay timing alue={0:X}", cmd);
  }

  static void LcdCmd(byte cmd)      // Send a command byte using polled busy.
  {
    WaitNotBusy();    
    wait_delay_40();
    sendByte(false, cmd);
    Console.WriteLine("LCD sent cmd byte value={0:X}", cmd);
  }

  public static void sendDataByte(byte data)
  {
    WaitNotBusy();    

    wait_delay_40();
    sendByte(true, data);
    Console.WriteLine("LCD sent data byte (datareg={1}) value={0:X}", data, LCD_RS);
  }


  public static void Reset()
  {
    lcd_data4_openable = false;
    Kiwi.Pause();
    PortIdle();
    wait_delay_40();
    // Wait >4.1ms and >100 us in the gaps between the first 2 '3' operations, then used BF polling instead of delays.
    LcdCmdD(0x33, 2000); // Reset code 30
    wait_delay_40();
    LcdCmdD(0x32, 2000); // Reset code 20
    wait_delay_40();
    LcdCmdD(0x28, 2000);   // 4-bit interface, 2 lines.
    wait_delay_40();
  }


  public static void Setup()
  { 
    LcdCmd(0x06);   // Entry mode, ID=1, S=0;
    LcdCmd(0x0f);   // Display: disp on, cursor on, blink on.
    LcdCmd(0x01);   // Home
    LcdCmd(0x80);   // Set data data RAM location 0 of top line write
  }

  public static void WriteString(string msg)
  {
    char [] cdata = msg.ToCharArray();
    for (int x=0; x<msg.Length; x++) sendDataByte((byte)cdata[x]);
  }
}


class tester
{
  [Kiwi.OutputBitPort("done")] static bool done;  
  [Kiwi.InputBitPort("select")] static bool select;    
 
  public static void Main()
  {
    select = false;
    RunHW();
  }

  [Kiwi.HardwareEntryPoint()]
  public static void RunHW()
  {
    done = false;
    Console.WriteLine("Hello from LCD 1602 driver");
    Kiwi.Pause();
    Kiwi.Pause();
    Kiwi.Pause();
    KiwiLCD1602Driver.PortIdle();    
    KiwiLCD1602Driver.Reset();
    KiwiLCD1602Driver.Setup();
    Kiwi.Pause();
    string msg = (select) ? "Hello World": "David Greaves";
    KiwiLCD1602Driver.WriteString(msg);
    Kiwi.Pause();
    while(true)
      {
	done = true;
	Kiwi.Pause();
      }
  }
}

// eof

Compile and Simulate

gmcs kiwi-lcd1602-driver.cs -r:/home/djg11/d320/hprls/kiwipro/kiwic/distro/support/Kiwi.dll 
kiwi-lcd1602-driver.cs(20,49): warning CS0414: The private field `KiwiLCD1602Driver.LCD_RW' is assigned but its value is never used
kiwi-lcd1602-driver.cs(21,48): warning CS0414: The private field `KiwiLCD1602Driver.LCD_E' is assigned but its value is never used
kiwi-lcd1602-driver.cs(24,58): warning CS0414: The private field `KiwiLCD1602Driver.LCD_DATA' is assigned but its value is never used
kiwi-lcd1602-driver.cs(97,44): warning CS0414: The private field `tester.done' is assigned but its value is never used
Compilation succeeded - 4 warning(s)
/home/djg11/d320/hprls/kiwipro/kiwic/distro/bin/kiwic -give-backtrace -vnl-rootmodname=DUT -vnl=kiwi-lcd1602-driver.v kiwi-lcd1602-driver.exe -vnl-resets=synchronous -kiwic-cil-dump=combined -kiwic-kcode-dump=enable -res2-loadstore-port-count=0 -vnl-roundtrip=disable
 devx  (getenv "HPRLS_DEVX"="1")  developer mode=true
+++ devx: other form in bifo GetLength pokidl: CT_arr (CTL_net (false,16,Signed,[Cil_at_native]),Some 11L)
+++ devx: other form in bifo GetLength pokidl: CT_arr (CTL_net (false,16,Signed,[Cil_at_native]),Some 11L)
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'3I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'0I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'3I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'0I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'2I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'12I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'0I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'8I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'0I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'1I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'0I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'6I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'0I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'12I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := C8u(15&(C8u("Hello World"[TKWr0.8_V_1]))>>4): assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := C8u(15&(C8u("Hello World"[TKWr0.8_V_1]))): assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'3I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'0I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'3I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'0I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'2I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'12I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'0I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'8I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'0I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'1I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'0I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'6I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'0I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'12I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := C8u(15&(C8u("Hello World"[TKWr0.8_V_1]))>>4): assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := C8u(15&(C8u("Hello World"[TKWr0.8_V_1]))): assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'3I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'0I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'3I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'0I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'2I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'12I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'0I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'8I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'0I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'1I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'0I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'6I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'0I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := U8'12I: assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := C8u(15&(C8u("Hello World"[TKWr0.8_V_1]))>>4): assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ wrap check warning: LCD_DATA_LS[3:0]:OUTPUT::Unsigned{init=0, io_output=true, username=LCD_DATA_LS, HwWidth=4, storage=8} := C8u(15&(C8u("Hello World"[TKWr0.8_V_1]))): assignment may wrap differently: rhs/w=8, lhs/w=4, store/w=8I
+++ devx: wrap_unaltered: no arg nn in net   $$AUTOFORMAT: This will be automatically replaced with a printf formatted string. 
iverilog kiwi-lcd1602-driver.v vsys.v 
./a.out
VCD info: dumpfile vcd.vcd opened for output.
Hello from LCD 1602 driver
LCD sent cmd byte (datareg=0) value=33
LCD sent cmd byte (datareg=0) value=33
LCD sent cmd byte (datareg=0) value=32
LCD sent cmd byte (datareg=0) value=2c
LCD sent cmd byte (datareg=0) value=8
LCD sent cmd byte (datareg=0) value=1
LCD sent cmd byte (datareg=0) value=6
LCD sent cmd byte (datareg=0) value=c
LCD sent data byte (datareg=1) value=48
LCD sent data byte (datareg=1) value=65
LCD sent data byte (datareg=1) value=6c
LCD sent data byte (datareg=1) value=6c
LCD sent data byte (datareg=1) value=6f
LCD sent data byte (datareg=1) value=20
LCD sent data byte (datareg=1) value=57
LCD sent data byte (datareg=1) value=6f
LCD sent data byte (datareg=1) value=72
LCD sent data byte (datareg=1) value=6c
LCD sent data byte (datareg=1) value=64

Process make finished


Download

Src files in this ZIP.

Archive:  kiwi_lcd1602_driver.zip
  Length      Date    Time    Name
---------  ---------- -----   ----
     7071  2016-06-30 10:44   cbguart1.v
     5796  2016-08-08 16:19   lcd_panel_top.v
     1863  2016-08-08 16:23   simsys.v
      908  2016-06-17 16:45   vsys.v
     6210  2016-08-08 16:19   kiwi_lcd1602_driver.cs
     2453  2016-06-22 14:22   lcd-panel.tcl
      888  2016-08-08 16:22   Makefile
     3437  2016-08-01 15:50   lcd-panel.xdc
---------                     -------
    28626                     8 files

Updated April 2016               UP.