Last active
May 23, 2024 16:58
-
-
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 )
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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