Skip to content

Instantly share code, notes, and snippets.

@kazu1995
Last active February 5, 2022 16:37
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kazu1995/b22c2983a197316d6327634ace7cc138 to your computer and use it in GitHub Desktop.
Save kazu1995/b22c2983a197316d6327634ace7cc138 to your computer and use it in GitHub Desktop.
Experimental code of Virtual JTAG ( http://kazu1995.hatenablog.jp/entry/2017/11/18/202718 )
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using VirtualJtag.Constant;
using VirtualJtag.Instruction;
namespace VirtualJtag.Communicate
{
public unsafe class TmsControl
{
const string DLL_PATH = "ftd2xx.dll";
[DllImport(DLL_PATH)]
unsafe private static extern UInt32 FT_Open( Int16 DeviceNumber, UInt32* ftHandle );
[DllImport(DLL_PATH)]
private static extern UInt32 FT_Close( UInt32 ftHandle );
[DllImport(DLL_PATH)]
unsafe private static extern UInt32 FT_Write( UInt32 ftHandle,
[MarshalAs(UnmanagedType.LPArray)] short[] bdata, UInt32 BufferSize, UInt32* BytesWriten );
[DllImport(DLL_PATH)]
unsafe private static extern UInt32 FT_Read( UInt32 lngHandle,
[MarshalAs(UnmanagedType.LPArray)] byte[] bdata, UInt32 lngBufferSize, UInt32* lngBytesReturned );
const short L = 0x2D2C;
const short H = (short)(L | 0x1010);
const short TMS = (short)(L | 0x0202);
const short TMS_H = (short)(TMS | H);
const short WR = 0x81;
const short RD = 0xC0;
const short OFF = 0x0D0C;
UInt32 ftHandle;
DataByteLength DataByteLength = new DataByteLength();
private uint MoveIdle()
{
uint size;
var memory = new List<short> { TMS, TMS, TMS, TMS, TMS, L };
return FT_Write(ftHandle, memory.ToArray(), (UInt32)memory.Count << 1, &size);
}
private uint MoveIdleToShiftir()
{
uint size;
var memory = new List<short> { TMS, TMS, L, L };
return FT_Write(ftHandle, memory.ToArray(), (UInt32)memory.Count << 1, &size);
}
private uint MoveShiftirToShiftdr()
{
uint size;
var memory = new List<short> { TMS, TMS, TMS, L, L };
return FT_Write(ftHandle, memory.ToArray(), (UInt32)memory.Count << 1, &size);
}
private uint MoveShiftdrToShiftir()
{
uint size;
var memory = new List<short> { TMS_H, TMS, TMS, TMS, L, L };
return FT_Write(ftHandle, memory.ToArray(), (UInt32)memory.Count << 1, &size);
}
private List<byte> ReadShiftdr( short drCodeByteLength )
{
uint size;
var memory = new List<short> { (short)((0 << 8) | (RD | drCodeByteLength)), TMS_H, TMS, TMS, L, L };
FT_Write(ftHandle, memory.ToArray(), (UInt32)memory.Count << 1, &size);
var rxDataBuf = new List<byte>();
for (var i = 0; i < drCodeByteLength; i++)
{
byte[] rxData = new byte[64];
FT_Read(ftHandle, rxData, 1, &size);
rxDataBuf.Add(rxData[0]);
}
return rxDataBuf;
}
private uint WriteShiftir( byte irCodeValue )
{
uint size;
var memory = new List<short> { (short)((irCodeValue << 8) | WR), L };
return FT_Write(ftHandle, memory.ToArray(), (UInt32)memory.Count << 1, &size);
}
private uint WriteShiftdr( byte drCodeValue )
{
uint size;
var memory = new List<short> { (short)((drCodeValue << 8) | WR)};
return FT_Write(ftHandle, memory.ToArray(), (UInt32)memory.Count << 1, &size);
}
private uint LoopShiftDR()
{
uint size;
var memory = new List<short> { TMS_H, TMS, TMS, L, L };
return FT_Write(ftHandle, memory.ToArray(), (UInt32)memory.Count << 1, &size);
}
protected uint DeviceOpen()
{
UInt32 ftStatus;
UInt32 ftHandle_;
ftStatus = FT_Open(0, &ftHandle_); // FT_OpenExの方がよい
ftHandle = ftHandle_;
return ftStatus;
}
protected uint DeviceClose()
{
uint size;
var memory = new List<short> { TMS_H, TMS, OFF };
FT_Write(ftHandle, memory.ToArray(), (UInt32)memory.Count << 1, &size);
return FT_Close(ftHandle);
}
protected List<byte> GetBasicInformation( byte basicInstructionCode )
{
MoveIdle();
MoveIdleToShiftir();
WriteShiftir(basicInstructionCode);
MoveShiftirToShiftdr();
return ReadShiftdr(DataByteLength.Basic(basicInstructionCode));
}
private void VirtualInstruction( int virtualInstructionCode )
{
MoveIdle();
MoveIdleToShiftir();
WriteShiftir((byte)BasicInstruction.User1);
MoveShiftirToShiftdr();
WriteShiftdr((byte)(virtualInstructionCode));
MoveShiftdrToShiftir();
WriteShiftir((byte)BasicInstruction.User0);
MoveShiftirToShiftdr();
}
protected void SetVirtualInstruction( int virtualInstructionCode, List<byte> virtualInstructionData )
{
VirtualInstruction(virtualInstructionCode);
foreach(var x in virtualInstructionData)
{
WriteShiftdr(x);
}
}
protected List<byte> GetVirtualInstruction( byte virtualInstructionCode )
{
VirtualInstruction(virtualInstructionCode);
var rx = new List<byte>(ReadShiftdr((short)(DataByteLength.User(virtualInstructionCode)+1)));
for (var i = 0; i < rx.Count; i++)
{
rx[i] = (byte)(rx[i] >> 1);
if((i < rx.Count - 1) && ((rx[i+1] & 0x01) == 1))
{
rx[i] = (byte)(rx[i] + 0x80);
}
}
rx.RemoveAt(rx.Count - 1);
return rx;
}
}
public class De0Control : TmsControl
{
public uint Connection
{
get
{
return DeviceOpen();
}
}
public uint DisConnection
{
get
{
return DeviceClose();
}
}
public int Idcode
{
get
{
var rx = GetBasicInformation((byte)BasicInstruction.IdCode);
return BitConverter.ToInt32(rx.ToArray(), 0);
}
}
public int InternalSoftwareVirsion
{
get
{
var rx = new List<byte>(GetVirtualInstruction((byte)UserInstruction.GetInternalSoftwareVirsion));
return BitConverter.ToInt32(rx.ToArray(), 0);
}
}
public uint Sw
{
get
{
var sw = new List<byte>(GetVirtualInstruction((byte)UserInstruction.GetSw));
return BitConverter.ToUInt16(sw.ToArray(), 0);
}
}
public int Ledg
{
set
{
var output = new List<byte>();
output.Add((byte)(value & 0x00FF));
output.Add((byte)((value & 0x0300)>>8));
SetVirtualInstruction((int)UserInstruction.SetLedg, output);
}
}
public string HexLedArray
{
set
{
var output = new List<byte>();
var chars = new List<char>(value.ToUpper());
chars.Reverse();
bool spaceFlag = false;
for (int charDigit = 0; charDigit < chars.Count; charDigit++)
{
byte insertChar = new byte();
if (output.Count >= 4 && chars[charDigit-1] != '.')
{
break;
}
switch (chars[charDigit])
{
case '.': insertChar = (byte)LedSegment.Dot; break;
case '-': insertChar = (byte)LedSegment.Dash; break;
case '_': insertChar = (byte)LedSegment.Underline; break;
case '*': insertChar = (byte)LedSegment.All; break;
case '0': insertChar = (byte)LedSegment.Zero; break;
case '1': insertChar = (byte)LedSegment.One; break;
case '2': insertChar = (byte)LedSegment.Two; break;
case '3': insertChar = (byte)LedSegment.Three; break;
case '4': insertChar = (byte)LedSegment.Four; break;
case '5': insertChar = (byte)LedSegment.Five; break;
case '6': insertChar = (byte)LedSegment.Six; break;
case '7': insertChar = (byte)LedSegment.Seven; break;
case '8': insertChar = (byte)LedSegment.Eight; break;
case '9': insertChar = (byte)LedSegment.Nine; break;
default:
if ('A' <= chars[charDigit] & chars[charDigit] <= 'Z')
{
insertChar = Convert.ToByte((LedSegment)Enum.Parse(typeof(LedSegment), chars[charDigit].ToString()));
}
else
{
insertChar = (byte)LedSegment.Off;
}
break;
}
if ((charDigit > 0) && (output[output.Count - 1] == (byte)LedSegment.Dot) && (insertChar != (byte)LedSegment.Dot))
{
if (spaceFlag == false)
{
spaceFlag = true;
output[output.Count - 1] = (byte)(insertChar - ~(byte)LedSegment.Dot);
}
else
{
spaceFlag = false;
output.Add(insertChar);
}
}
else
{
spaceFlag = false;
output.Add(insertChar);
}
}
for (int i = output.Count; i < 4; i++)
{
output.Add((byte)LedSegment.Off);
}
output.Reverse();
SetVirtualInstruction((int)UserInstruction.SetHexLedArray, output);
}
}
}
}
namespace VirtualJtag.Constant
{
public enum InternalSoftware
{
Version = 20171117
}
public enum CycloneIdCode
{
EP3C16 = 34545885,
EP2C20 = 34287837
}
public enum LedSegment
{
Zero = 0xC0,
One = 0xF9,
Two = 0xA4,
Three = 0xB0,
Four = 0x99,
Five = 0x92,
Six = 0x82,
Seven = 0xF8,
Eight = 0x80,
Nine = 0x90,
A = 0x88,
B = 0x83,
C = 0xA7,
D = 0xA1,
E = 0x86,
F = 0x8E,
G = 0xC2,
H = 0x8B,
I = 0xFB,
J = 0xE1,
K = 0x8A,
L = 0xC7,
M = 0xC8,
N = 0xAB,
O = 0xA3,
P = 0x8C,
Q = 0x84,
R = 0xAF,
S = 0x93,
T = 0x87,
U = 0xE3,
V = 0xC1,
W = 0x81,
X = 0x89,
Y = 0x91,
Z = 0xE4,
Dash = 0xBF,
Underline = 0xF7,
Dot = 0x7F,
All = 0x00,
Off = 0xFF,
}
public enum FtDeviceStatus
{
FT_OK,
FT_INVALID_HANDLE,
FT_DEVICE_NOT_FOUND,
FT_DEVICE_NOT_OPENED,
FT_IO_ERROR,
FT_INSUFFICIENT_RESOURCES,
FT_INVALID_PARAMETER,
FT_INVALID_BAUD_RATE,
FT_DEVICE_NOT_OPENED_FOR_ERASE,
FT_DEVICE_NOT_OPENED_FOR_WRITE,
FT_FAILED_TO_WRITE_DEVICE,
FT_EEPROM_READ_FAILED,
FT_EEPROM_WRITE_FAILED,
FT_EEPROM_ERASE_FAILED,
FT_EEPROM_NOT_PRESENT,
FT_EEPROM_NOT_PROGRAMMED,
FT_INVALID_ARGS,
FT_NOT_SUPPORTED,
FT_OTHER_ERROR
}
}
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
use IEEE.std_logic_unsigned.all;
entity Cyclone is
port (
SW : in std_logic_vector( 9 downto 0);
LEDG : inout std_logic_vector( 9 downto 0);
HEX0_D : inout std_logic_vector( 6 downto 0);
HEX1_D : inout std_logic_vector( 6 downto 0);
HEX2_D : inout std_logic_vector( 6 downto 0);
HEX3_D : inout std_logic_vector( 6 downto 0);
HEX0_DP : inout std_logic;
HEX1_DP : inout std_logic;
HEX2_DP : inout std_logic;
HEX3_DP : inout std_logic
);
end Cyclone;
architecture RTL of Cyclone is
signal i : integer;
signal tck : std_logic;
signal tdi : std_logic;
signal tdo : std_logic;
signal ir_in : std_logic_vector( 7 downto 0);
signal ir_out : std_logic_vector( 7 downto 0);
signal virtual_state_uir : std_logic;
signal virtual_state_sdr : std_logic;
signal r_ir : std_logic_vector( 7 downto 0);
constant build_number : std_logic_vector( 31 downto 0)
:= (conv_std_logic_vector(20171117, 32));
begin
top_connection : entity work.virtualjtag
port map(
tck => tck,
tdi => tdi,
tdo => tdo,
ir_in => ir_in,
ir_out => ir_out,
virtual_state_uir => virtual_state_uir,
virtual_state_sdr => virtual_state_sdr
);
process(tck)
begin
if(tck'event and tck='1') then
if(virtual_state_uir = '1') then
r_ir(7 downto 0) <= ir_in;
i <= 0;
elsif(virtual_state_sdr='1') then
case r_ir is
when "00000000" =>
tdo <= SW(i);
when "00000001" =>
if(i < 10) then
LEDG(i) <= tdi;
end if;
when "00000011" =>
case i is
when 0 to 6 => HEX3_D(i) <= tdi;
when 7 => HEX3_DP <= tdi;
when 8 to 14 => HEX2_D(i) <= tdi;
when 15 => HEX2_DP <= tdi;
when 16 to 22 => HEX1_D(i) <= tdi;
when 23 => HEX1_DP <= tdi;
when 24 to 30 => HEX0_D(i) <= tdi;
when 31 => HEX0_DP <= tdi;
when others => null;
end case;
when "00001010" =>
tdo <= build_number(i);
when others => null;
end case;
i <= i + 1;
end if;
end if;
end process;
end RTL;
namespace VirtualJtag.Instruction
{
public enum BasicInstruction
{
SamplePreload = 0x05,
IdCode,
UserCode,
User0 = 0x0C,
User1 = 0x0E
}
public enum UserInstruction : byte
{
GetSw,
SetLedg,
SetHexLedArray = 0x03,
GetInternalSoftwareVirsion = 0x0A
}
class DataByteLength
{
public short Basic(byte basicInstructionCode)
{
switch(basicInstructionCode)
{
default:
return 4;
}
}
public short User(byte userInstructionCode)
{
switch (userInstructionCode)
{
case (byte)UserInstruction.GetSw:
return 2;
case (byte)UserInstruction.SetLedg:
return 2;
case (byte)UserInstruction.SetHexLedArray:
return 4;
case (byte)UserInstruction.GetInternalSoftwareVirsion:
return 4;
default:
return 0;
}
}
}
}
using System;
using VirtualJtag.Constant;
using VirtualJtag.Communicate;
namespace VirtualJtag
{
class Program
{
static void Main( string[] args )
{
var De0 = new De0Control();
uint ftStatus = De0.Connection;
if (ftStatus != (uint)FtDeviceStatus.FT_OK)
{
Console.WriteLine("Don't Connect.");
Console.WriteLine("Error Code = " + Enum.GetName(typeof(FtDeviceStatus), ftStatus));
Console.ReadKey();
return;
}
Console.WriteLine("Connection!");
int idcode = De0.Idcode;
Console.WriteLine("Device IDCODE -> " + idcode + "(" + Enum.GetName(typeof(CycloneIdCode), De0.Idcode) + ")");
Console.WriteLine("VSdesign ver. -> " + (int)InternalSoftware.Version);
int virsion = De0.InternalSoftwareVirsion;
Console.WriteLine("DE0 .sof ver. -> " + virsion);
Console.WriteLine("---");
Console.WriteLine(" h : Set HEX 3 to 0(7-segment LED)");
Console.WriteLine(" inputable characer : 0~9 a~z A~Z '-' '_' '.'");
Console.WriteLine(" special character : '*' segment all lighting.");
Console.WriteLine(" ' ' segment all off");
Console.WriteLine(" If other character are entered, segment off.");
Console.WriteLine(" l : Set LEDG 9 to 0 by binary");
Console.WriteLine(" 0:LED off, 1:LED on. MSB is LEDG9 and LSB is LEDG0.");
Console.WriteLine(" L : Set LEDG 9 to 0 by decimal");
Console.WriteLine(" s : Get SW state by binary");
Console.WriteLine(" 0:SW off, 1:SW on");
Console.WriteLine(" S : Get SW state by Decimal");
Console.WriteLine(" e : Escape sequence");
Console.WriteLine("---");
while (true)
{
switch(Console.ReadKey().KeyChar)
{
case 'h':
Console.Write(" input HEX (str) -> ");
De0.HexLedArray = Console.ReadLine();
break;
case 'l':
Console.Write(" Input Ledg(bin) -> ");
De0.Ledg = Convert.ToInt16(Console.ReadLine(), 2);
break;
case 'L':
Console.Write(" Input Ledg(dec) -> ");
De0.Ledg = Convert.ToInt16(Console.ReadLine());
break;
case 's':
Console.WriteLine(" SW State (bin) -> " + Convert.ToString(De0.Sw, 2).PadLeft(10,'0'));
break;
case 'S':
Console.WriteLine(" SW State (dec) -> " + De0.Sw);
break;
case 'e':
ftStatus = De0.DisConnection;
Console.WriteLine(" Disconnection...");
return;
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment