2901 lines
90 KiB
ObjectPascal
2901 lines
90 KiB
ObjectPascal
unit jtag.vme;
|
|
|
|
interface
|
|
uses
|
|
jtag.types,
|
|
Classes;
|
|
|
|
const
|
|
VME_VERSION_NUMBER = '12.1';
|
|
|
|
//
|
|
// Maximum declarations
|
|
//
|
|
VMEHEXMAX = 60000; // The hex file is split 60k per file
|
|
SCANMAX = 64000; // The maximum SDR/SIR burst
|
|
|
|
//
|
|
// Supported JTAG state transitions
|
|
//
|
|
|
|
type
|
|
TJTAGTransition = packed record
|
|
CurrState : TJTAGState; // Transition from this state.
|
|
NextState : TJTAGState; // Transition to this state.
|
|
Pattern : byte; // The targetory of TMS
|
|
Pulses : byte; // The number of steps.
|
|
end;
|
|
|
|
//
|
|
// Flow control register nit definitions. A set bit indicates
|
|
// that the register currently exhibits the corresponding mode.
|
|
//
|
|
TFlowControlBit =
|
|
(
|
|
fcbIntelPrgm, // Intelligent programming is in effect.
|
|
fcbCascade, // Currently splitting large SDR.
|
|
fcbRepeatLoop, // Currently executing a repeat loop.
|
|
fcbShiftRight, // The next data stream needs a right shift.
|
|
fcbShiftLeft, // The next data stream needs a right left.
|
|
fcbVerifyUES // Continue if fail is in effect.
|
|
);
|
|
|
|
TFlowControl = set of TFlowControlBit;
|
|
|
|
//
|
|
// DataType register bit definitions. A set bit indicates that the
|
|
// register currently holds the corresponding type of data.
|
|
//
|
|
TDataTypeBit =
|
|
(
|
|
dtExpress, // Simultaneous program and verify.
|
|
dtCompress, // Data is compressed
|
|
dtSIRData, // SIR is the active SVF command.
|
|
dtSDRData, // SDR is the active SVF command.
|
|
dtTDIData, // TDI data is present.
|
|
dtTDOData, // TDO data is present.
|
|
dtMASKData, // MASK data is present.
|
|
dtCRCData, // CRC data is present.
|
|
dtHeap, // Data is from the heap.
|
|
dtLHeap, // Data is from intel data buffer.
|
|
dtVariable, // Data is from a declared variable.
|
|
dtCMASKData, // CMASK data is present.
|
|
dtDMASKData, // DMASK data is present.
|
|
dtRMASKData, // RMASK data is present,
|
|
dtREADData // READ data is present.
|
|
);
|
|
|
|
TDataType = set of TDataTypeBit;
|
|
|
|
TVendor =
|
|
(
|
|
vLattice = 1,
|
|
vAltera = 2,
|
|
vXilinx = 3
|
|
);
|
|
|
|
|
|
//
|
|
// Opcode definitions
|
|
//
|
|
TOpcode =
|
|
(
|
|
opEndData = $00, // The end of the current SDR data stream.
|
|
opRunTest = $01, // The duration to stay at the stable state.
|
|
opEndDR = $02, // The stable state after SDR.
|
|
opEndIR = $03, // The stable state after SIR.
|
|
opEndState = $04, // The stable state after RUNTEST.
|
|
opTRST = $05, // Assert the TRST pin.
|
|
opHIR = $06, // The sum of the IR bits of the leading devices.
|
|
opTIR = $07, // The sum of the IR bits of the trailing devices.
|
|
opHDR = $08, // The number of leading devices.
|
|
opTDR = $09, // The number of trailing devices.
|
|
opIspEN = $0a, // Assert the ispEN pin.
|
|
opFrequency = $0b, // The maximum clock rate to run the JTAG state machine.
|
|
opState = $10, // Move to the next stable(?) state.
|
|
opSIR = $11, // The instruction stream follows.
|
|
opSDR = $12, // The data stream follows.
|
|
opTDI = $13, // The following data stream feeds into device.
|
|
opTDO = $14, // The following data stream is compared against the device.
|
|
opMASK = $15, // The following data stream is used as a mask.
|
|
opXSDR = $16, // The following data stream is for simultaneous program and verify.
|
|
opXTDI = $17, // The following data stream is for shift in only. It must be stored
|
|
// for the next XSDR.
|
|
opXTDO = $18, // There is no data stream. The data stream was stored from the
|
|
// previous XTDI.
|
|
opMEM = $19, // The maximum memory needed to allocate in order to hold one row of data.
|
|
opWAIT = $1A, // The duration of delay to observe.
|
|
opTCK = $1B, // The number of TCK pulses.
|
|
opSEC = $1C, // The delay time in seconds that must be observed.
|
|
opSMASK = $1D, // The mask for TDI data.
|
|
opMAX = $1E, // The absolute maximum wait time.
|
|
opON = $1F, // Assert the targeted pin.
|
|
opOFF = $20, // Deassert the targeted pin.
|
|
opSHR = $23, // Set the flow control register for right shift.
|
|
opSHL = $24, // Set the flow control register for left shift.
|
|
opSetFlow = $30, // Change the flow control register.
|
|
opResetFlow = $31, // Clear the flow control register.
|
|
opHEAP = $32, // The memory size needed to hold one loop.
|
|
opREPEAT = $33, // The beginning of the loop.
|
|
opLeftParen = $35, // The beginning of data following the loop.
|
|
opVAR = $55, // Placeholder for loop data.
|
|
opCRC = $47, // The following data stream is used for CRC calculation.
|
|
opCMask = $48, // The following data steram is used as a mask for CRC calculation.
|
|
opRMask = $49, // The following data stream is used as a mask for read and save.
|
|
opREAD = $50, // The following data stream is used for read and save.
|
|
opVendor = $56, // Vendor code.
|
|
opENDLOOP = $59, // The end of the repeat loop.
|
|
opSecureHeap= $60, // Used to secure the HEAP opcode.
|
|
opVUES = $61, // Support continue if fail.
|
|
opDMask = $62, // The following data stream is used for dynamic I/O.
|
|
opComment = $63, // Support SVF comments in the VME file.
|
|
opHeader = $64, // Support header in VME file.
|
|
opFileCRC = $65, // Support crc-protected VME file.
|
|
opLCount = $66, // Support intelligent programming.
|
|
opLDelay = $67, // Support intelligent programming.
|
|
opLSDR = $68, // Support intelligent programming.
|
|
opLHeap = $69, // Memory needed to hold intelligent data buffer.
|
|
opContinue = $70, // Allow continuation.
|
|
opLVDS = $71, // Support LVDS.
|
|
opEndVME = $7F, // End of the VME file.
|
|
opEndFile = $FF // End of file.
|
|
);
|
|
|
|
TReturnCode =
|
|
(
|
|
VME_OK = 0,
|
|
VME_VerificationFailure = -1,
|
|
VME_FileReadFailure = -2,
|
|
VME_VersionFailure = -3,
|
|
VME_InvalidFile = -4,
|
|
VME_ArgumentFailure = -5,
|
|
VME_CRCFailure = -5
|
|
);
|
|
|
|
TLVDSPair = packed record
|
|
PositiveIndex : word;
|
|
NegativeIndex : word;
|
|
Update : boolean;
|
|
end;
|
|
|
|
type
|
|
TispVM = class;
|
|
|
|
TPin = (pinTCK,pinTMS,pinTDI,pinTDO,pinTRST,pinENA);
|
|
|
|
TTransferMode = (tmNone, tmRead, tmWrite);
|
|
|
|
TTransferEvent = procedure( Sender : TispVM;
|
|
Mode : TTransferMode) of object;
|
|
|
|
|
|
|
|
TispVM = class
|
|
protected
|
|
fJtag : IJTAG;
|
|
|
|
protected
|
|
fOnTransfer : TTransferEvent;
|
|
fTransferMode : TTransferMode;
|
|
|
|
protected
|
|
fBufTDI : array [0 .. 1023] of byte; // data to send to device
|
|
fBufTDO : array [0 .. 1023] of byte; // data received from device
|
|
fBufSMASK : array [0 .. 1023] of byte;
|
|
fBufMASK : array [0 .. 1023] of byte;
|
|
|
|
fBuffer : array [0 .. 1023] of byte;
|
|
fBufferSize : integer;
|
|
fBufferIndex : integer;
|
|
|
|
fMaskTCK : byte;
|
|
fMaskTMS : byte;
|
|
fMaskTDI : byte;
|
|
fMaskTDO : byte;
|
|
fMaskTRST : byte;
|
|
fMaskENA : byte;
|
|
fMaskPWR : byte;
|
|
|
|
fValTMS : boolean;
|
|
fValTDI : boolean;
|
|
fValTDO : boolean;
|
|
fValTRST : boolean;
|
|
fValENA : boolean;
|
|
|
|
fInitDone : boolean;
|
|
|
|
private
|
|
function GetData(i: word): byte;
|
|
procedure SetData(i: word; d: byte);
|
|
|
|
protected
|
|
procedure Init( BufferSize : word;
|
|
TCK : byte;
|
|
TMS : byte;
|
|
TDI : byte;
|
|
TDO : byte;
|
|
TRST : byte;
|
|
ENA : byte;
|
|
PWR : byte);
|
|
|
|
procedure SetPin( pin: TPin; Value: byte);
|
|
procedure Flush;
|
|
|
|
public
|
|
procedure InitDsoJtag; // prepare for DSO
|
|
procedure InitPrgJtag; // prepare for JTAG programmer
|
|
|
|
|
|
|
|
protected
|
|
fFlowControl : TFlowControl; // Flow control register.
|
|
fDataType : TDataType; // Data type of the current row.
|
|
|
|
fEndDR : TJTAGState; // The state that the device goes after SDR.
|
|
fEndIR : TJTAGState; // The state that the device goes after SIR.
|
|
|
|
fHeadDR : word; // The number of lead devices in bypass.
|
|
fHeadIR : word; // The sum of IR length of lead devices.
|
|
|
|
fTailDR : word; // The number of tail devices in bypass.
|
|
fTailIR : word; // The sum of IR length of tail devices.
|
|
|
|
fDataSize : word; // The number of bits of data or instruction
|
|
// to be shifted into or out from the device.
|
|
|
|
fFrequency : word; // The TCK frequency in MHz.
|
|
fMaxSize : word; // The maximum amount of data needed to hold a row of data.
|
|
fShiftValue : word; // Stores the LSH or RSH value.
|
|
fRepeatLoops : word; // Stores the current repeat loop value.
|
|
fVendor : TVendor; // Stores the current vendor.
|
|
fCalculatedCRC : word; // Stores the VME file CRC.
|
|
fCheckSum : cardinal; // Stores the device checksum.
|
|
fCheckSumIndex : integer;
|
|
|
|
fCurrentJTAGState : TJTAGState; // Stores the current state of the JTAG state machine.
|
|
|
|
//
|
|
// looping support
|
|
//
|
|
fHeapMemory : PByte; // Holds the entire repeat loop.
|
|
fHeapCounter : word; // Points to the current byte in the repeat loop.
|
|
fHeapSize : word; // The current size of the repeat loop in bytes.
|
|
|
|
//
|
|
// intelligent programming support
|
|
//
|
|
fIntelDataIndex : word; // Points to the current byte of the intelligent buffer.
|
|
fIntelBufferSize : word; // Holds the size of the intelligent buffer.
|
|
|
|
//
|
|
// The maximum size of each respective buffer. These variables are used to write
|
|
// the HEX files when converting VME to HEX.
|
|
//
|
|
fTDOSize : word;
|
|
fMASKSize : word;
|
|
fTDISize : word;
|
|
fDMASKSize : word;
|
|
fLCOUNTSize : word;
|
|
|
|
fHDRSize : word;
|
|
fTDRSize : word;
|
|
fHIRSize : word;
|
|
fTIRSize : word;
|
|
|
|
fHeapBufferSize : word;
|
|
|
|
//
|
|
// Variables used to store data
|
|
//
|
|
fOutMaskData : PByte;
|
|
fOutDMaskData : PByte;
|
|
|
|
fInData : PByte;
|
|
fOutData : PByte;
|
|
fHIRData : PByte;
|
|
fTIRData : PByte;
|
|
fHDRData : PByte;
|
|
fTDRData : PByte;
|
|
|
|
fIntelBuffer : PByte;
|
|
|
|
|
|
//
|
|
// List to hold all LVDS pairs.
|
|
//
|
|
// LVDSPair * ...
|
|
// count
|
|
fLVDs : array of TLVDSPair;
|
|
|
|
fStream : TStream;
|
|
|
|
private
|
|
function GetByte: byte;
|
|
procedure sclock(n:integer=1);
|
|
|
|
protected
|
|
function ispVMCode: TReturnCode;
|
|
|
|
function ispVMAmble( OpCode: TOpcode): TReturnCode;
|
|
function ispVMShift( OpCode: TOpcode): TReturnCode;
|
|
|
|
function ispVMDataSize: word;
|
|
procedure ispVMDelay( Delay: word);
|
|
procedure ispVMClocks( Count: word);
|
|
function ispVMLoop( LoopCount: word): TReturnCode;
|
|
function ispVMLCount( CountSize: word): TReturnCode;
|
|
|
|
procedure ispVMStateMachine( NextState: TJTAGState);
|
|
|
|
procedure ispVMComment( Size: word);
|
|
function ispVMProcessLVDS( Count: word):TReturnCode;
|
|
procedure ispVMHeader( Size: word);
|
|
|
|
function ispVMDataCode: TReturnCode;
|
|
procedure ispVMData( Data: PByte);
|
|
|
|
function ispVMBitShift( OpCode: TOpCode; Count: word): TReturnCode;
|
|
|
|
procedure ispVMBypass( ScanType: TOpCode; Count: word);
|
|
function ispVMSend( Count: word): TReturnCode;
|
|
function ispVMRead( Count: word): TReturnCode;
|
|
function ispVMReadAndSave( Count: word): TReturnCode;
|
|
|
|
procedure ispVMStart;
|
|
procedure ispVMEnd;
|
|
|
|
procedure ispVMMemManager( Target: TOpCode; Size: word);
|
|
|
|
public
|
|
function ispVM( Stream: TStream): TReturnCode;
|
|
|
|
public
|
|
procedure AfterConstruction; override;
|
|
|
|
public
|
|
property DataSize: integer read fBufferIndex;
|
|
property Data[i: word]: byte read GetData write SetData;
|
|
|
|
property JTAG : IJTAG read fJtag write fJtag;
|
|
|
|
property OnTransfer : TTransferEvent read fOnTransfer write fOnTransfer;
|
|
end;
|
|
|
|
implementation
|
|
uses
|
|
Windows,
|
|
jtag.vme.tools;
|
|
|
|
const
|
|
JTAGTransitions : array [0..24] of TJTAGTransition =
|
|
(
|
|
( CurrState : RESET; NextState : RESET; Pattern : $FC; Pulses : 6),
|
|
( CurrState : RESET; NextState : IDLE; Pattern : $00; Pulses : 1),
|
|
( CurrState : RESET; NextState : DRPAUSE; Pattern : $50; Pulses : 5),
|
|
( CurrState : RESET; NextState : IRPAUSE; Pattern : $68; Pulses : 6),
|
|
|
|
( CurrState : IDLE; NextState : RESET; Pattern : $E0; Pulses : 3),
|
|
( CurrState : IDLE; NextState : DRPAUSE; Pattern : $A0; Pulses : 4),
|
|
( CurrState : IDLE; NextState : IRPAUSE; Pattern : $D0; Pulses : 5),
|
|
( CurrState : IDLE; NextState : DRCAPTURE; Pattern : $80; Pulses : 2),
|
|
|
|
( CurrState : DRPAUSE; NextState : RESET; Pattern : $F8; Pulses : 5),
|
|
( CurrState : DRPAUSE; NextState : IDLE; Pattern : $C0; Pulses : 3),
|
|
( CurrState : DRPAUSE; NextState : IRPAUSE; Pattern : $F4; Pulses : 7),
|
|
( CurrState : DRPAUSE; NextState : DRPAUSE; Pattern : $E8; Pulses : 6),
|
|
( CurrState : DRPAUSE; NextState : DRSHIFT; Pattern : $80; Pulses : 2),
|
|
( CurrState : DRPAUSE; NextState : DRCAPTURE; Pattern : $E0; Pulses : 4),
|
|
|
|
( CurrState : IRPAUSE; NextState : RESET; Pattern : $F8; Pulses : 5),
|
|
( CurrState : IRPAUSE; NextState : IDLE; Pattern : $C0; Pulses : 3),
|
|
( CurrState : IRPAUSE; NextState : DRPAUSE; Pattern : $E8; Pulses : 6),
|
|
( CurrState : IRPAUSE; NextState : DRSHIFT; Pattern : $E0; Pulses : 5),
|
|
( CurrState : IRPAUSE; NextState : IRSHIFT; Pattern : $80; Pulses : 2),
|
|
( CurrState : IRPAUSE; NextState : DRCAPTURE; Pattern : $E0; Pulses : 4),
|
|
|
|
( CurrState : DRSHIFT; NextState : IDLE; Pattern : $C0; Pulses : 3),
|
|
( CurrState : DRSHIFT; NextState : DRPAUSE; Pattern : $80; Pulses : 2),
|
|
|
|
( CurrState : IRSHIFT; NextState : IDLE; Pattern : $C0; Pulses : 3),
|
|
( CurrState : IRSHIFT; NextState : IRPAUSE; Pattern : $80; Pulses : 2),
|
|
|
|
( CurrState : DRCAPTURE; NextState : DRPAUSE; Pattern : $80; Pulses : 2)
|
|
);
|
|
|
|
|
|
var
|
|
idx : integer;
|
|
data : array [0..3] of byte;
|
|
|
|
{ TvmeProgram }
|
|
|
|
// ================================================================================================
|
|
// After Construction
|
|
// ================================================================================================
|
|
procedure TispVM.AfterConstruction;
|
|
var
|
|
x: array [0..20] of byte;
|
|
|
|
begin
|
|
inherited;
|
|
|
|
fEndDR := DRPAUSE;
|
|
fEndIR := IRPAUSE;
|
|
|
|
fFrequency := 1000;
|
|
end;
|
|
|
|
|
|
// ================================================================================================
|
|
// Init
|
|
// ================================================================================================
|
|
procedure TispVM.Init( BufferSize : word;
|
|
TCK : byte;
|
|
TMS : byte;
|
|
TDI : byte;
|
|
TDO : byte;
|
|
TRST : byte;
|
|
ENA : byte;
|
|
PWR : byte);
|
|
begin
|
|
fBufferSize := 504;
|
|
// if (BufferSize <> 1024) and (BufferSize <> 512)
|
|
// then fBufferSize := 1024
|
|
// else fBufferSize := BufferSize;
|
|
|
|
if TCK <> $FF then fMaskTCK := 1 shl TCK else fMaskTCK := 0;
|
|
if TMS <> $FF then fMaskTMS := 1 shl TMS else fMaskTMS := 0;
|
|
if TDI <> $FF then fMaskTDI := 1 shl TDI else fMaskTDI := 0;
|
|
if TDO <> $FF then fMaskTDO := 1 shl TDO else fMaskTDO := 0;
|
|
if TRST <> $FF then fMaskTRST := 1 shl TRST else fMaskTRST := 0;
|
|
if ENA <> $FF then fMaskENA := 1 shl ENA else fMaskENA := 0;
|
|
if PWR <> $FF then fMaskPWR := 1 shl PWR else fMaskPWR := 0;
|
|
|
|
fInitDone := true;
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// InitDsoJtag
|
|
// ================================================================================================
|
|
procedure TispVM.InitDsoJtag;
|
|
begin
|
|
Init(256, 0, 1, 3, 7, $FF, $FF, $FF);
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// InitPrgJtag
|
|
// ================================================================================================
|
|
procedure TispVM.InitPrgJtag;
|
|
begin
|
|
Init(256, 0, 1, 7, 3, 5, 4, 6);
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// Get Data
|
|
// ================================================================================================
|
|
function TispVM.GetData(i: word): byte;
|
|
begin
|
|
if i < fBufferSize
|
|
then result := fBuffer[i]
|
|
else result := 0;
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// Set Data
|
|
// ================================================================================================
|
|
procedure TispVM.SetData(i: word; d: byte);
|
|
begin
|
|
if i < fBufferSize then
|
|
fBuffer[i] := d
|
|
end;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ================================================================================================
|
|
// Load
|
|
// ================================================================================================
|
|
function TispVM.ispVM(Stream: TStream): TReturnCode;
|
|
var
|
|
i : integer;
|
|
b : byte;
|
|
s : AnsiString;
|
|
|
|
begin
|
|
if Assigned(Stream) then
|
|
begin
|
|
fStream := Stream;
|
|
fStream.Seek(0, soFromBeginning);
|
|
|
|
b := GetByte;
|
|
|
|
case TOpCode(b) of
|
|
opFileCRC:
|
|
begin
|
|
// ----------------------------------------------
|
|
// Read and store the expected CRC to do the
|
|
// comparison at the end. Only versions 3.0 and
|
|
// higher support CRC protection.
|
|
// ----------------------------------------------
|
|
fCheckSum := GetByte shl 8;
|
|
fCheckSum := fCheckSum + GetByte;
|
|
|
|
// ----------------------------------------------
|
|
// Read and store the version of the VME file.
|
|
// Must be version 2.0.
|
|
// ----------------------------------------------
|
|
for i:=0 to 7 do
|
|
s := s + AnsiChar(GetByte);
|
|
end;
|
|
|
|
else begin
|
|
// -------------------------------------------------
|
|
// Read and store the version of the VME file.
|
|
// Must be version 2.0.
|
|
// -------------------------------------------------
|
|
s := AnsiChar(b);
|
|
|
|
for i:=1 to 7 do
|
|
s := s + AnsiChar(GetByte);
|
|
end;
|
|
end;
|
|
|
|
// ------------------------------------------------------------
|
|
// Compare the VME file version against the supported version.
|
|
// ------------------------------------------------------------
|
|
result := VME_VersionFailure;
|
|
|
|
if s = '__VME2.0' then result := VME_OK;
|
|
if s = '__VME3.0' then result := VME_OK;
|
|
if s = '____12.0' then result := VME_OK;
|
|
if s = '____12.1' then result := VME_OK;
|
|
|
|
if result <> VME_OK then
|
|
exit;
|
|
|
|
// ------------------------------------------------------------
|
|
// Enable the JTAG port to communicate with the deevice.
|
|
// Set the JTAG state machine to the RESET state.
|
|
// ------------------------------------------------------------
|
|
ispVMStart;
|
|
|
|
// ------------------------------------------------------------
|
|
// Process the VME file.
|
|
// ------------------------------------------------------------
|
|
result := ispVMCode;
|
|
|
|
// ------------------------------------------------------------
|
|
// Set the JTAG state machine to RESET state then disable the
|
|
// the communication with the JTAG port.
|
|
// ------------------------------------------------------------
|
|
ispVMEnd
|
|
end
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// Get Byte
|
|
//
|
|
// Returns a byte to the caller. The returned byte depends on the DataType register.
|
|
// If the HEAP_IN bit is set, then the byte is returned from the HEAP.
|
|
// If the LHEAP_IN bit is set, then the byte is returned from the intelligent buffer.
|
|
// Otherwise, the byte is returned directly from the VME file.
|
|
// ================================================================================================
|
|
function TispVM.GetByte: byte;
|
|
begin
|
|
result := 0;
|
|
|
|
if dtHeap in fDataType then
|
|
begin
|
|
if fHeapCounter > fHeapSize then
|
|
result := $FF
|
|
|
|
else begin
|
|
result := fHeapMemory[fHeapCounter];
|
|
INC(fHeapCounter)
|
|
end;
|
|
end
|
|
|
|
else if dtLHeap in fDataType then
|
|
begin
|
|
if fIntelDataIndex >= fIntelBufferSize then
|
|
result := $FF
|
|
|
|
else begin
|
|
result := fIntelBuffer[fIntelDataIndex];
|
|
INC(fIntelDataIndex);
|
|
end;
|
|
end
|
|
|
|
else begin
|
|
if Assigned(fStream) then
|
|
if fStream.Read(result,1) <> 1 then
|
|
result := $FF
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
|
|
// ================================================================================================
|
|
// ispVMCode
|
|
//
|
|
// This is the heart of the embedded engine. All the high-level opcodes are extracted here.
|
|
// Once they have been identified, then it will call other functions to handle the processing.
|
|
// ================================================================================================
|
|
function TispVM.ispVMCode: TReturnCode;
|
|
var
|
|
RepeatSize : word;
|
|
OpCode : TOpcode;
|
|
State : TJTAGState;
|
|
|
|
Delay : word;
|
|
Toggle : word;
|
|
Data : byte;
|
|
FlowControl : TFlowControl;
|
|
|
|
begin
|
|
RepeatSize := 0;
|
|
OpCode := opEndData;
|
|
result := VME_OK;
|
|
State := RESET;
|
|
Delay := 0;
|
|
Toggle := 0;
|
|
Data := 0;
|
|
|
|
// ---------------------------------------------------------------
|
|
// Check the compression flag only if this is the first time
|
|
// this function is entered. Do not check the compression flag if
|
|
// it is being called recursively from other functions within
|
|
// the embedded engine.
|
|
// ---------------------------------------------------------------
|
|
if not (dtHeap in fDataType) and not (dtLHeap in fDataType) then
|
|
begin
|
|
Data := GetByte;
|
|
|
|
if Data = $F1 then
|
|
Include( fDataType, dtCompress)
|
|
else if Data = $F2 then
|
|
Exclude( fDataType, dtCompress)
|
|
|
|
else begin
|
|
result := VME_InvalidFile;
|
|
exit
|
|
end
|
|
end;
|
|
|
|
// ---------------------------------------------------------------
|
|
// Loop through all the VME opcodes.
|
|
// ---------------------------------------------------------------
|
|
OpCode := TOpCode(GetByte);
|
|
|
|
while OpCode <> opEndData do
|
|
begin
|
|
case OpCode of
|
|
// --------------------------------------------
|
|
// opSTATE
|
|
// --------------------------------------------
|
|
opState:
|
|
begin
|
|
State := TJTAGState( GetByte);
|
|
|
|
if Assigned(fJtag) then
|
|
fJtag.state(State);
|
|
|
|
if (dtLHeap in fDataType) and (State = DRPAUSE) and (fCurrentJTAGState = State) then
|
|
if Assigned(fJtag) then
|
|
fJtag.state(DRCAPTURE);
|
|
|
|
ispVMStateMachine(State);
|
|
end;
|
|
|
|
// --------------------------------------------
|
|
// SIR,SDR,XSDR
|
|
// Shift data into the device.
|
|
// --------------------------------------------
|
|
opSIR,opSDR,opXSDR:
|
|
begin
|
|
result := ispVMShift(OpCode);
|
|
|
|
if result <> VME_OK then
|
|
break;
|
|
end;
|
|
|
|
// --------------------------------------------
|
|
// WAIT
|
|
// Observe delay.
|
|
// --------------------------------------------
|
|
opWAIT:
|
|
begin
|
|
Delay := ispVMDataSize;
|
|
ispVMDelay(Delay);
|
|
end;
|
|
|
|
// --------------------------------------------
|
|
// TCK
|
|
// Issue clock toggles.
|
|
// --------------------------------------------
|
|
opTCK:
|
|
begin
|
|
Toggle := ispVMDataSize;
|
|
ispVMClocks(Toggle);
|
|
end;
|
|
|
|
// --------------------------------------------
|
|
// ENDDR,ENDIR
|
|
// Set the ENDDR,ENDIR
|
|
// --------------------------------------------
|
|
opEndDR: fEndDR := TJTAGState( GetByte);
|
|
opEndIR: fEndIR := TJTAGState( GetByte);
|
|
|
|
// --------------------------------------------
|
|
// HIR,TIR,HDR,TDR
|
|
// --------------------------------------------
|
|
opHIR,opTIR,opHDR,opTDR:
|
|
begin
|
|
result := ispVMAmble( OpCode);
|
|
|
|
if result <> VME_OK then
|
|
break;
|
|
end;
|
|
|
|
// --------------------------------------------
|
|
// MEM
|
|
// --------------------------------------------
|
|
opMEM:
|
|
begin
|
|
//OutputDebugString('opMEM');
|
|
fMaxSize := ispVMDataSize;
|
|
end;
|
|
|
|
// --------------------------------------------
|
|
// Vendor
|
|
// --------------------------------------------
|
|
opVendor:
|
|
begin
|
|
//OutputDebugString('opVendor');
|
|
fVendor := TVendor( GetByte);
|
|
end;
|
|
|
|
// --------------------------------------------
|
|
// SETFLOW
|
|
// Set the flow control.
|
|
// Flow control determines the personality of
|
|
// the embedded engine.
|
|
//
|
|
// TODO: check this!
|
|
// --------------------------------------------
|
|
opSetFlow:
|
|
begin
|
|
OutputDebugString('opSetFlow');
|
|
// fFlowControl := fFlowControl + TFlowControl(GetByte);
|
|
end;
|
|
|
|
opResetFlow:
|
|
begin
|
|
OutputDebugString('opResetFlow');
|
|
// fFlowControl := fFlowControl + TFlowControl(GetByte);
|
|
end;
|
|
|
|
// --------------------------------------------
|
|
// HEAP
|
|
// Allocate heap to store loops
|
|
// --------------------------------------------
|
|
opHEAP:
|
|
begin
|
|
//OutputDebugString('opHEAP');
|
|
|
|
OpCode := TOpCode(GetByte);
|
|
|
|
if OpCode <> opSecureHeap then
|
|
break;
|
|
|
|
fHeapSize := ispVMDataSize;
|
|
ispVMMemManager( opHEAP, fHeapSize);
|
|
end;
|
|
|
|
// --------------------------------------------
|
|
// REPEAT
|
|
// --------------------------------------------
|
|
opREPEAT:
|
|
begin
|
|
//OutputDebugString('opREPEAT');
|
|
|
|
fRepeatLoops := 0;
|
|
result := ispVMLoop( ispVMDataSize);
|
|
|
|
if result <> VME_OK then
|
|
break;
|
|
end;
|
|
|
|
opENDLOOP: exit;
|
|
opEndVME : exit;
|
|
|
|
// --------------------------------------------
|
|
// SHR,SHL
|
|
// Right-shift/Left-shift address.
|
|
// --------------------------------------------
|
|
opSHR:
|
|
begin
|
|
//OutputDebugString('opSHR');
|
|
|
|
Include( fFlowControl, fcbShiftRight);
|
|
fShiftValue := fRepeatLoops * GetByte;
|
|
end;
|
|
|
|
opSHL:
|
|
begin
|
|
//OutputDebugString('opSHL');
|
|
|
|
Include( fFlowControl, fcbShiftLeft);
|
|
fShiftValue := fRepeatLoops * GetByte;
|
|
end;
|
|
|
|
// --------------------------------------------
|
|
// FREQUENCY
|
|
// --------------------------------------------
|
|
opFrequency:
|
|
begin
|
|
//OutputDebugString('opFREQUENCY');
|
|
|
|
fFrequency := ispVMDataSize;
|
|
|
|
if fFrequency >= 1000 then
|
|
begin
|
|
fFrequency := fFrequency div 1000;
|
|
|
|
if fFrequency = 1 then
|
|
fFrequency := 1000
|
|
end
|
|
|
|
else begin
|
|
if fFrequency = 0 then
|
|
fFrequency := 1000
|
|
end;
|
|
end;
|
|
|
|
// --------------------------------------------
|
|
// LCOUNT
|
|
// --------------------------------------------
|
|
opLCount:
|
|
begin
|
|
//OutputDebugString('opLCOUNT');
|
|
|
|
result := ispVMLCount( ispVMDataSize);
|
|
|
|
if result <> VME_OK then
|
|
break
|
|
end;
|
|
|
|
// --------------------------------------------
|
|
// VUES
|
|
// --------------------------------------------
|
|
opVUES:
|
|
begin
|
|
//OutputDebugString('opVUES');
|
|
|
|
Include(FlowControl,fcbVerifyUES);
|
|
end;
|
|
|
|
// --------------------------------------------
|
|
// COMMENT
|
|
// --------------------------------------------
|
|
opComment:
|
|
begin
|
|
//OutputDebugString('opCOMMENT');
|
|
|
|
|
|
ispVMComment( ispVMDataSize);
|
|
end;
|
|
|
|
// --------------------------------------------
|
|
// LVDS
|
|
// --------------------------------------------
|
|
opLVDS:
|
|
begin
|
|
//OutputDebugString('opLVDS');
|
|
|
|
ispVMProcessLVDS( ispVMDataSize);
|
|
end;
|
|
|
|
// --------------------------------------------
|
|
// HEADER
|
|
// --------------------------------------------
|
|
opHeader:
|
|
begin
|
|
//OutputDebugString('opHEADER');
|
|
|
|
ispVMHeader( ispVMDataSize);
|
|
end;
|
|
|
|
// --------------------------------------------
|
|
// ispEN
|
|
// --------------------------------------------
|
|
opIspEN:
|
|
begin
|
|
OpCode := TOpCode(GetByte);
|
|
|
|
case OpCode of
|
|
opON : SetPin(pinENA, 1);
|
|
opOFF : SetPin(pinENA, 0);
|
|
end;
|
|
end;
|
|
|
|
// --------------------------------------------
|
|
// TRST
|
|
// --------------------------------------------
|
|
opTRST:
|
|
begin
|
|
OpCode := TOpCode(GetByte);
|
|
|
|
case OpCode of
|
|
opON : SetPin(pinTRST, 1);
|
|
opOFF : SetPin(pinTRST, 0);
|
|
end;
|
|
end;
|
|
|
|
else
|
|
result := VME_InvalidFile
|
|
end;
|
|
|
|
OpCode := TOpCode(GetByte);
|
|
end;
|
|
|
|
//
|
|
// Invalid exit point.
|
|
// Processing token 'ENDVME' is the only valid
|
|
// way to exit the embedded engine.
|
|
//
|
|
result := VME_InvalidFile;
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// ispVMDataSize
|
|
//
|
|
// Returns a VME-encoded number, ususally used to indicate the bitlength of an SIR/SDR command.
|
|
// ================================================================================================
|
|
function TispVM.ispVMDataSize: word;
|
|
var
|
|
curr : byte;
|
|
idx : byte;
|
|
|
|
begin
|
|
result := 0;
|
|
idx := 0;
|
|
curr := GetByte;
|
|
|
|
while curr and $80 <> 0 do
|
|
begin
|
|
result := result or ((curr and $7f) shl idx);
|
|
curr := GetByte;
|
|
|
|
INC( idx, 7)
|
|
end;
|
|
|
|
result := result or ((curr and $7f) shl idx);
|
|
end;
|
|
|
|
|
|
|
|
// ================================================================================================
|
|
// ispVMDataCode
|
|
//
|
|
// Processes the TDI/TDO/MASK/DMASK etc of an SIR/SDR command.
|
|
// ================================================================================================
|
|
function TispVM.ispVMDataCode: TReturnCode;
|
|
var
|
|
DataByte : ShortInt;
|
|
DataSource : ShortInt;
|
|
pos : Int64;
|
|
|
|
begin
|
|
result := VME_OK;
|
|
|
|
if dtHeap in fDataType
|
|
then DataSource := 1 // data source is memory
|
|
else DataSource := 0; // data source is file
|
|
|
|
fDataType := fDataType - [dtTDIData, dtTDOData, dtMASKData, dtDMASKData, dtCMASKData];
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
// Iterate through SIR/SDR command and look for TDI, TDO, MASK, etc...
|
|
// --------------------------------------------------------------------
|
|
DataByte := ShortInt(GetByte);
|
|
|
|
while DataByte >= 0 do
|
|
begin
|
|
pos := fStream.Position -1;
|
|
|
|
ispVMMemManager( TOpCode(DataByte), fMaxSize);
|
|
|
|
case TOpCode(DataByte) of
|
|
// ----------------------------------------------------
|
|
// TDI
|
|
// ----------------------------------------------------
|
|
opTDI:
|
|
begin
|
|
// -----------------------------------------
|
|
// Store the maximum size of the TDI buffer.
|
|
// Used to convert VME to HEX.
|
|
// -----------------------------------------
|
|
if fTDISize <= fDataSize then
|
|
fTDISize := fDataSize;
|
|
|
|
// -----------------------------------------
|
|
// Update DataType register to indicate that
|
|
// TDI data is currently being used. Process
|
|
// the data in the VME file into the TDI
|
|
// buffer.
|
|
// -----------------------------------------
|
|
Include(fDataType, dtTDIData);
|
|
ispVMData( fInData);
|
|
end;
|
|
|
|
// ----------------------------------------------------
|
|
// TDO
|
|
// ----------------------------------------------------
|
|
opTDO:
|
|
begin
|
|
// -----------------------------------------
|
|
// Store the maximum size of the TDO buffer.
|
|
// Used to convert VME to HEX.
|
|
// -----------------------------------------
|
|
if fTDOSize <= fDataSize then
|
|
fTDOSize := fDataSize;
|
|
|
|
// -----------------------------------------
|
|
// Update DataType register to indicate that
|
|
// TDO data is currently being used. Process
|
|
// the data in the VME file into the TDO
|
|
// buffer.
|
|
// -----------------------------------------
|
|
Include(fDataType, dtTDOData);
|
|
ispVMData( fOutData);
|
|
end;
|
|
|
|
// ----------------------------------------------------
|
|
// XTDO
|
|
// ----------------------------------------------------
|
|
opXTDO:
|
|
begin
|
|
// -----------------------------------------
|
|
// Store the maximum size of the TDO buffer.
|
|
// Used to convert VME to HEX.
|
|
// -----------------------------------------
|
|
if fTDOSize <= fDataSize then
|
|
fTDOSize := fDataSize;
|
|
|
|
// -----------------------------------------
|
|
// Update DataType register to indicate that
|
|
// TDO data is currently being used. Process
|
|
// the data in the VME file into the TDO
|
|
// buffer.
|
|
// -----------------------------------------
|
|
Include(fDataType, dtTDOData);
|
|
end;
|
|
|
|
opMASK:
|
|
begin
|
|
// -----------------------------------------
|
|
// Store the maximum size of the MASK buffer.
|
|
// Used to convert VME to HEX.
|
|
// -----------------------------------------
|
|
if fMASKSize <= fDataSize then
|
|
fMASKSize := fDataSize;
|
|
|
|
// -----------------------------------------
|
|
// Update DataType register to indicate that
|
|
// MASK data is currently being used. Process
|
|
// the data in the VME file into the MASK
|
|
// buffer.
|
|
// -----------------------------------------
|
|
Include(fDataType, dtMASKData);
|
|
ispVMData( fOutMaskData);
|
|
end;
|
|
|
|
opDMask:
|
|
begin
|
|
// -----------------------------------------
|
|
// Store the maximum size of the DMASK
|
|
// buffer. Used to convert VME to HEX.
|
|
// -----------------------------------------
|
|
if fDMASKSize <= fDataSize then
|
|
fDMASKSize := fDataSize;
|
|
|
|
// -----------------------------------------
|
|
// Update DataType register to indicate that
|
|
// DMASK data is currently being used.
|
|
// Process the data in the VME file into the
|
|
// DMASK buffer.
|
|
// -----------------------------------------
|
|
Include(fDataType, dtDMASKData);
|
|
ispVMData( fOutDMaskData);
|
|
end;
|
|
|
|
opCMask:
|
|
begin
|
|
// -----------------------------------------
|
|
// Update DataType register to indicate that
|
|
// DMASK data is currently being used.
|
|
// Process the data in the VME file into the
|
|
// DMASK buffer.
|
|
// -----------------------------------------
|
|
Include(fDataType, dtCMASKData);
|
|
ispVMData( fOutMaskData);
|
|
end;
|
|
|
|
opContinue:
|
|
begin
|
|
result := VME_OK;
|
|
exit;
|
|
end;
|
|
|
|
else
|
|
begin
|
|
result := VME_InvalidFile;
|
|
exit
|
|
end;
|
|
end;
|
|
|
|
case TOpCode(DataByte) of
|
|
opTDI:
|
|
begin
|
|
// -----------------------------------------
|
|
// Left bit shift. Used when performing
|
|
// algorithm looping.
|
|
// -----------------------------------------
|
|
if fcbShiftLeft in fFlowControl then
|
|
begin
|
|
ispVMBitShift( opSHL, fShiftValue);
|
|
Exclude( fFlowControl, fcbShiftLeft)
|
|
end;
|
|
|
|
// -----------------------------------------
|
|
// Left bit shift. Used when performing
|
|
// algorithm looping.
|
|
// -----------------------------------------
|
|
if fcbShiftRight in fFlowControl then
|
|
begin
|
|
ispVMBitShift( opSHR, fShiftValue);
|
|
Exclude( fFlowControl, fcbShiftRight)
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if DataSource <> 0 then
|
|
Include( fDataType, dtHeap);
|
|
|
|
DataByte := ShortInt(GetByte);
|
|
end;
|
|
|
|
if DataSource <> 0 then
|
|
Include( fDataType, dtHeap);
|
|
|
|
if DataByte < 0 then
|
|
begin
|
|
pos := fStream.Position;
|
|
result := VME_InvalidFile;
|
|
end
|
|
else
|
|
result := VME_OK
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// ispVMData
|
|
//
|
|
// Extract one row of data operand from the current data type opcode. Perform the decompression if
|
|
// necessary. Extra RAM is not required for the decompression process. The decompression scheme
|
|
// employed in this module is on row by row basis. The format of the data stream:
|
|
//
|
|
// [compression code][compressed data stream]
|
|
// 0x00 --No compression
|
|
// 0x01 --Compress by 0x00.
|
|
// Example:
|
|
// Original stream: 0x000000000000000000000001
|
|
// Compressed stream: 0x01000901
|
|
// Detail: 0x01 is the code, 0x00 is the key,
|
|
// 0x09 is the count of 0x00 bytes,
|
|
// 0x01 is the uncompressed byte.
|
|
//
|
|
// 0x02 --Compress by 0xFF.
|
|
// Example:
|
|
// Original stream: 0xFFFFFFFFFFFFFFFFFFFFFF01
|
|
// Compressed stream: 0x02FF0901
|
|
// Detail: 0x02 is the code, 0xFF is the key,
|
|
// 0x09 is the count of 0xFF bytes,
|
|
// 0x01 is the uncompressed byte.
|
|
//
|
|
// 0x03
|
|
// : :
|
|
// 0xFE -- Compress by nibble blocks.
|
|
// Example:
|
|
// Original stream: 0x84210842108421084210
|
|
// Compressed stream: 0x0584210
|
|
// Detail: 0x05 is the code, means 5 nibbles block.
|
|
// 0x84210 is the 5 nibble blocks.
|
|
// The whole row is 80 bits given by fDataSize.
|
|
// The number of times the block repeat itself
|
|
// is found by fDataSize/(4*0x05) which is 4.
|
|
//
|
|
// 0xFF -- Compress by the most frequently happen byte.
|
|
// Example:
|
|
// Original stream: 0x04020401030904040404
|
|
// Compressed stream: 0xFF04(0,1,0x02,0,1,0x01,1,0x03,1,0x09,0,0,0)
|
|
// or: 0xFF044090181C240
|
|
// Detail: 0xFF is the code, 0x04 is the key.
|
|
// a bit of 0 represent the key shall be put into
|
|
// the current bit position and a bit of 1
|
|
// represent copying the next of 8 bits of data
|
|
// in.
|
|
|
|
// ================================================================================================
|
|
procedure TispVM.ispVMData(Data: PByte);
|
|
var
|
|
size : word;
|
|
i, j, m : integer;
|
|
getData : word;
|
|
DataByte : byte;
|
|
FFcount : integer;
|
|
compress : byte;
|
|
compr_char : byte;
|
|
index : integer;
|
|
compression : ShortInt;
|
|
pos : Int64;
|
|
|
|
begin
|
|
size := 0;
|
|
i := 0;
|
|
j := 0;
|
|
m := 0;
|
|
getData := 0;
|
|
compr_char := $FF;
|
|
|
|
// ---------------------------------------------------------------
|
|
// Convert "size in bits" to "size in bytes".
|
|
// ---------------------------------------------------------------
|
|
if fDataSize mod 8 > 0
|
|
then size := (fDataSize div 8) + 1
|
|
else size := (fDataSize div 8);
|
|
|
|
// ---------------------------------------------------------------
|
|
// If there is a compression, then check if compress by key of
|
|
// 0x00 or 0xff or by other keys by nibble blocks.
|
|
// ---------------------------------------------------------------
|
|
if dtCompress in fDataType then
|
|
begin
|
|
compression := 1;
|
|
compress := GetByte;
|
|
|
|
if (TOpCode(compress) = opVAR) and (dtHeap in fDataType) then
|
|
begin
|
|
getData := 1;
|
|
|
|
Exclude( fDataType, dtHeap);
|
|
compress := GetByte;
|
|
end;
|
|
|
|
case compress of
|
|
$00: compression := 0; // No compression
|
|
$01: compr_char := $00;
|
|
$02: compr_char := $ff;
|
|
|
|
$ff:
|
|
begin
|
|
pos := fStream.Position;
|
|
|
|
i := 8;
|
|
compr_char := GetByte;
|
|
pos := fStream.Position;
|
|
|
|
for index := 0 to size-1 do
|
|
begin
|
|
Data[index] := 0;
|
|
|
|
if i > 7 then
|
|
begin
|
|
DataByte := GetByte;
|
|
pos := fStream.Position;
|
|
i := 0;
|
|
end;
|
|
|
|
if (DataByte shl i) and $80 = $80 then
|
|
m := 8
|
|
else begin
|
|
Data[index] := compr_char;
|
|
m := 0;
|
|
end;
|
|
|
|
INC(i);
|
|
|
|
for j:=0 to m-1 do
|
|
begin
|
|
if i > 7 then
|
|
begin
|
|
DataByte := GetByte;
|
|
i := 0;
|
|
pos := fStream.Position;
|
|
end;
|
|
|
|
Data[index] := Data[index] or (((DataByte shl i) and $80) shr j);
|
|
INC(i);
|
|
end;
|
|
end;
|
|
|
|
size := 0;
|
|
pos := fStream.Position;
|
|
end;
|
|
|
|
else
|
|
begin
|
|
for index:=0 to size -1 do
|
|
Data[index] := 0;
|
|
|
|
for index:=0 to compress -1 do
|
|
begin
|
|
if (index mod 2) = 0 then
|
|
DataByte := GetByte;
|
|
|
|
for i:=0 to ((size*2) div compress) -1 do
|
|
begin
|
|
j := index + i * compress;
|
|
|
|
if (j mod 2) <> 0 then
|
|
if (index mod 2) <> 0
|
|
then Data[j div 2] := Data[j div 2] or (DataByte and $0F)
|
|
else Data[j div 2] := Data[j div 2] shr 4
|
|
else
|
|
if (index mod 2) <> 0
|
|
then Data[j div 2] := Data[j div 2] shl 4
|
|
else Data[j div 2] := Data[j div 2] and $F0
|
|
end;
|
|
|
|
size := 0;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// Decompress by byte 0x00 or 0xff
|
|
FFcount := 0;
|
|
|
|
for index := 0 to size -1 do
|
|
begin
|
|
if FFcount <= 0 then
|
|
begin
|
|
DataByte := GetByte;
|
|
|
|
if (TOpCode(DataByte) = opVar) and (dtHeap in fDataType) and (getData = 0) and not (dtCompress in fDataType) then
|
|
begin
|
|
getData := 1;
|
|
Exclude( fDataType, dtHeap);
|
|
DataByte := GetByte;
|
|
end;
|
|
|
|
Data[index] := DataByte;
|
|
|
|
if (compression <> 0) and (DataByte = compr_char) then // compression is on
|
|
FFcount := ispVMDataSize; // the number of $FF or $00 bytes
|
|
end
|
|
|
|
else begin
|
|
DEC(FFcount);
|
|
Data[index] := compr_char;
|
|
end;
|
|
end;
|
|
|
|
if getData <> 0 then
|
|
Include( fDataType, dtHeap);
|
|
end;
|
|
|
|
|
|
// ================================================================================================
|
|
// ispVMShift
|
|
//
|
|
// Process the SIR/SDR/XSDR commands.
|
|
// ================================================================================================
|
|
function TispVM.ispVMShift(OpCode: TOpcode): TReturnCode;
|
|
var
|
|
DataIndex : word;
|
|
ReadLoop : word;
|
|
|
|
begin
|
|
DataIndex := 0;
|
|
ReadLoop := 0;
|
|
result := VME_OK;
|
|
fDataSize := ispVMDataSize;
|
|
|
|
Exclude( fDataType, dtSIRData);
|
|
Exclude( fDataType, dtSDRData);
|
|
Exclude( fDataType, dtExpress);
|
|
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Els� lepeskent olvassuk be a TDI/TDO/... adatokat a megfelel� bufferekbe.
|
|
// Ha TDO adatok is vannak specifikalva, akkor a State Machine aktualizalasa
|
|
// utan toljuk ki a buffer tartalmat, hogy a TDO muvelet a buffer elejen
|
|
// kezd�dhessen. Igy max 512 (1024) byte-os adatot tudunk ellen�rizni.
|
|
// -------------------------------------------------------------------------
|
|
result := ispVMDataCode;
|
|
|
|
if result <> VME_OK then
|
|
begin
|
|
result := VME_InvalidFile;
|
|
exit
|
|
end;
|
|
|
|
if fDataSize > 250 then
|
|
Exclude( fDataType, dtTDOData);
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Move the device state machine and shift in any bypass data.
|
|
// -------------------------------------------------------------------------
|
|
case OpCode of
|
|
// ------------------------------------------------------------
|
|
// SIR
|
|
// ------------------------------------------------------------
|
|
opSIR:
|
|
begin
|
|
Include( fDataType, dtSIRData);
|
|
|
|
// --------------------------------------------
|
|
// If performing cascading, then go directly
|
|
// to IRSHIFT. Else go to IRPAUSE before going
|
|
// to IRSHIFT.
|
|
// --------------------------------------------
|
|
if Assigned( fJtag) then
|
|
begin
|
|
if fcbCascade in fFlowControl then
|
|
fJtag.state(IRSHIFT)
|
|
|
|
else begin
|
|
fJtag.state(IRPAUSE);
|
|
fJtag.state(IRSHIFT);
|
|
|
|
if fHeadIR > 0 then
|
|
begin
|
|
ispVMBypass( opHIR, fHeadIR);
|
|
sclock
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
// ------------------------------------------------------------
|
|
// SDR/XSDR
|
|
// ------------------------------------------------------------
|
|
opSDR, opXSDR:
|
|
begin
|
|
Include( fDataType, dtSDRData);
|
|
|
|
if OpCode = opXSDR then
|
|
Include( fDataType, dtExpress);
|
|
|
|
// ---------------------------------------------
|
|
// If already in DRSHIFT, then do not move state
|
|
// or shift in header. This would imply that the
|
|
// previously shifted frame was a cascaded frame
|
|
// ---------------------------------------------
|
|
if fCurrentJTAGState <> DRSHIFT then
|
|
begin
|
|
// ------------------------------------------
|
|
// If performing cascading, then go directly
|
|
// to DRSHIFT. Else goto DRPAUSE before going
|
|
// to DRSHIFT.
|
|
// ------------------------------------------
|
|
if fcbCascade in fFlowControl then
|
|
begin
|
|
if fCurrentJTAGState = DRPAUSE then
|
|
begin
|
|
ispVMStateMachine( DRSHIFT);
|
|
|
|
// ------------------------------------
|
|
// If cascade flag has been set and the
|
|
// current state is DRPAUSE, this imp-
|
|
// lies that the first cascaded frame
|
|
// is about to shifted in. The header
|
|
// must be shifted prior to shifting
|
|
// the first cascaded frame.
|
|
// ------------------------------------
|
|
if fHeadDR > 0 then
|
|
begin
|
|
ispVMBypass( opHDR, fHeadDR);
|
|
sclock
|
|
end;
|
|
end
|
|
|
|
else
|
|
ispVMStateMachine( DRSHIFT);
|
|
end
|
|
|
|
// ------------------------------------------
|
|
// No cascading.
|
|
// ------------------------------------------
|
|
else begin
|
|
ispVMStateMachine( DRPAUSE);
|
|
ispVMStateMachine( DRSHIFT);
|
|
|
|
if fHeadDR > 0 then
|
|
begin
|
|
ispVMBypass( opHDR, fHeadDR);
|
|
sclock
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
else
|
|
begin
|
|
result := VME_InvalidFile;
|
|
exit
|
|
end;
|
|
end;
|
|
|
|
// // --------------------------------------------------------------------
|
|
// // Read TDI,TDO,MASK data into internal buffers.
|
|
// // --------------------------------------------------------------------
|
|
// result := ispVMDataCode;
|
|
//
|
|
// if result <> VME_OK then
|
|
// begin
|
|
// result := VME_InvalidFile;
|
|
// exit
|
|
// end;
|
|
|
|
// --------------------------------------------------------------------
|
|
// If we have TDO data to check, then flush buffer first.
|
|
// --------------------------------------------------------------------
|
|
if dtTDOData in fDataType then
|
|
Flush;
|
|
|
|
// --------------------------------------------------------------------
|
|
// Do shifting, and process TDO or DATA MASK
|
|
// --------------------------------------------------------------------
|
|
if (dtTDOData in fDataType) or (dtDMASKData in fDataType) then
|
|
begin
|
|
// DMASK Data
|
|
if dtDMASKData in fDataType then
|
|
begin
|
|
result := ispVMReadAndSave( fDataSize);
|
|
|
|
if result = VME_OK then
|
|
begin
|
|
if fTailDR > 0 then
|
|
begin
|
|
sclock;
|
|
ispVMBypass( opTDR, fTailDR);
|
|
end;
|
|
|
|
ispVMStateMachine( DRPAUSE);
|
|
ispVMStateMachine( DRSHIFT);
|
|
|
|
if fHeadDR > 0 then
|
|
begin
|
|
ispVMBypass( opHDR, fHeadDR);
|
|
sclock
|
|
end;
|
|
|
|
for DataIndex:=0 to (fDataSize div 8) do
|
|
fInData[DataIndex] := fOutData[DataIndex];
|
|
|
|
Exclude( fDataType, dtTDOData);
|
|
Exclude( fDataType, dtDMASKData);
|
|
|
|
result := ispVMSend( fDataSize)
|
|
end;
|
|
end
|
|
|
|
// TDO Data
|
|
else begin
|
|
result := ispVMRead( fDataSize);
|
|
|
|
if (result = VME_VerificationFailure) and (fVendor = vXilinx) then
|
|
begin
|
|
for ReadLoop:=0 to 29 do
|
|
begin
|
|
result := ispVMRead( fDataSize);
|
|
|
|
if result = VME_OK then
|
|
break
|
|
|
|
else begin
|
|
ispVMStateMachine(DRPAUSE);
|
|
ispVMBypass( opTDR, fTailDR);
|
|
ispVMStateMachine( fEndDR);
|
|
ispVMStateMachine( IDLE);
|
|
ispVMDelay(1000);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end
|
|
|
|
else // TDI only
|
|
result := ispVMSend( fDataSize);
|
|
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Transfer the input data to the output buffer for the next verify.
|
|
// MoveMem ???
|
|
// -------------------------------------------------------------------------
|
|
if (dtExpress in fDataType) or (OpCode = opSDR) then
|
|
if Assigned(fOutData) then
|
|
for DataIndex:=0 to fDataSize - 1 do
|
|
fOutData[DataIndex] := fInData[DataIndex];
|
|
|
|
// -------------------------------------------------------------------------
|
|
// Update State Machine
|
|
// -------------------------------------------------------------------------
|
|
case OpCode of
|
|
opSIR:
|
|
begin
|
|
// If not performing cascading, then shift ENDIR
|
|
if not (fcbCascade in fFlowControl) then
|
|
begin
|
|
if fTailIR > 0 then
|
|
begin
|
|
sclock;
|
|
ispVMBypass( opTIR, fTailIR);
|
|
end;
|
|
|
|
ispVMStateMachine(fEndIR);
|
|
end;
|
|
end;
|
|
|
|
opSDR,opXSDR:
|
|
begin
|
|
// If not performing cascading, then shift ENDIR
|
|
if not (fcbCascade in fFlowControl) then
|
|
begin
|
|
if fTailDR > 0 then
|
|
begin
|
|
sclock;
|
|
ispVMBypass( opTDR, fTailDR);
|
|
end;
|
|
|
|
ispVMStateMachine(fEndDR);
|
|
|
|
if dtTDOData in fDataType then
|
|
Flush;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// ispVMAmble
|
|
//
|
|
// This routine is to extract Header and Trailer parameter for SIR and SDR operations.
|
|
//
|
|
// The Header and Trailer parameter are the pre-amble and post-amble bit stream need to be shifted
|
|
// into TDI or out of TDO of the devices. Mostly is for the purpose of bypassing the leading or
|
|
// trailing devices. ispVM supports only shifting data into TDI to bypass the devices.
|
|
//
|
|
// For a single device, the header and trailer parameters are all set to 0 as default by ispVM.
|
|
// If it is for multiple devices, the header and trailer value will change as specified by the
|
|
// VME file.
|
|
// ================================================================================================
|
|
function TispVM.ispVMAmble(OpCode: TOpcode): TReturnCode;
|
|
var
|
|
compress: byte;
|
|
|
|
begin
|
|
compress := 0;
|
|
fDataSize := ispVMDataSize;
|
|
|
|
if fDataSize > 0 then
|
|
begin
|
|
// ------------------------------------------------------------
|
|
// Discard the TDI byte and set the compression bit in the data
|
|
// type register to false if compression is set, because TDI
|
|
// data after HIR/HDR/TIR/TDR is not compressed.
|
|
// ------------------------------------------------------------
|
|
GetByte;
|
|
|
|
if dtCompress in fDataType then
|
|
begin
|
|
compress := 1;
|
|
Exclude( fDataType, dtCompress);
|
|
end;
|
|
end;
|
|
|
|
case OpCode of
|
|
opHIR:
|
|
begin
|
|
// -------------------------------------------------
|
|
// Store the maximum size of the HIR buffer. Used to
|
|
// convert VME to HEX.
|
|
// -------------------------------------------------
|
|
if fHIRSize <= fDataSize then
|
|
fHIRSize := fDataSize;
|
|
|
|
// -------------------------------------------------
|
|
// Assign the HIR value and allocate memory.
|
|
// -------------------------------------------------
|
|
fHeadIR := fDataSize;
|
|
|
|
if fHeadIR > 0 then
|
|
begin
|
|
ispVMMemManager( opHIR, fHeadIR);
|
|
ispVMData( fHIRData);
|
|
end;
|
|
end;
|
|
|
|
opTIR:
|
|
begin
|
|
// -------------------------------------------------
|
|
// Store the maximum size of the TIR buffer. Used to
|
|
// convert VME to HEX.
|
|
// -------------------------------------------------
|
|
if fTIRSize <= fDataSize then
|
|
fTIRSize := fDataSize;
|
|
|
|
// -------------------------------------------------
|
|
// Assign the TIR value and allocate memory.
|
|
// -------------------------------------------------
|
|
fTailIR := fDataSize;
|
|
|
|
if fTailIR > 0 then
|
|
begin
|
|
ispVMMemManager( opTIR, fTailIR);
|
|
ispVMData( fTIRData);
|
|
end;
|
|
end;
|
|
|
|
opHDR:
|
|
begin
|
|
// -------------------------------------------------
|
|
// Store the maximum size of the HDR buffer. Used to
|
|
// convert VME to HEX.
|
|
// -------------------------------------------------
|
|
if fHDRSize <= fDataSize then
|
|
fHDRSize := fDataSize;
|
|
|
|
// -------------------------------------------------
|
|
// Assign the HIR value and allocate memory.
|
|
// -------------------------------------------------
|
|
fHeadDR := fDataSize;
|
|
|
|
if fHeadDR > 0 then
|
|
begin
|
|
ispVMMemManager( opHDR, fHeadDR);
|
|
ispVMData( fHDRData);
|
|
end;
|
|
end;
|
|
|
|
opTDR:
|
|
begin
|
|
// -------------------------------------------------
|
|
// Store the maximum size of the TDR buffer. Used to
|
|
// convert VME to HEX.
|
|
// -------------------------------------------------
|
|
if fTDRSize <= fDataSize then
|
|
fTDRSize := fDataSize;
|
|
|
|
// -------------------------------------------------
|
|
// Assign the TIR value and allocate memory.
|
|
// -------------------------------------------------
|
|
fTailDR := fDataSize;
|
|
|
|
if fTailDR > 0 then
|
|
begin
|
|
ispVMMemManager( opTDR, fTailDR);
|
|
ispVMData( fTDRData);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// ---------------------------------------------------------------
|
|
// Re-enable compression if it was previously set.
|
|
// ---------------------------------------------------------------
|
|
if compress <> 0 then
|
|
Include( fDataType, dtCompress);
|
|
|
|
result := VME_OK;
|
|
|
|
if fDataSize > 0 then
|
|
begin
|
|
OpCode := TOpCode( GetByte);
|
|
|
|
if OpCode <> opContinue then
|
|
result := VME_InvalidFile;
|
|
end;
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// ispVMLoop
|
|
//
|
|
// Perform the function call upon by the REPEAT opcode. Memory is to be allocated to store the
|
|
// entire loop from REPEAT to ENDLOOP. After the loop is stored then execution begin. The
|
|
// REPEATLOOP flag is set on the fFlowControl register to indicate the repeat loop is in session
|
|
// and therefore fetch opcode from the memory instead of from the file.
|
|
// ================================================================================================
|
|
function TispVM.ispVMLoop(LoopCount: word): TReturnCode;
|
|
var
|
|
HeapIndex: word;
|
|
LoopIndex: word;
|
|
|
|
begin
|
|
HeapIndex := 0;
|
|
LoopIndex := 0;
|
|
fShiftValue := 0;
|
|
result := VME_OK;
|
|
|
|
for HeapIndex:=0 to fHeapSize -1 do
|
|
fHeapMemory[HeapIndex] := GetByte;
|
|
|
|
if TOpCode(fHeapMemory[HeapIndex-1]) = opEndLoop then
|
|
begin
|
|
Include( fFlowControl, fcbRepeatLoop);
|
|
Include( fDataType, dtHeap);
|
|
|
|
for LoopIndex:=0 to LoopCount -1 do
|
|
begin
|
|
fHeapCounter := 0;
|
|
result := ispVMCode;
|
|
fRepeatLoops := fRepeatLoops +1;
|
|
|
|
if result <> VME_OK then
|
|
break;
|
|
end;
|
|
|
|
Exclude( fFlowControl, fcbRepeatLoop);
|
|
Exclude( fDataType, dtHeap);
|
|
end
|
|
|
|
else
|
|
result := VME_InvalidFile;
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// ispVMBitShift
|
|
//
|
|
// Shift the TDI stream left or right by the number of bits. The data in fInData is of the VME
|
|
// format, so the actual shifting is the reverse of IEEE 1532 or SVF format.
|
|
// ================================================================================================
|
|
function TispVM.ispVMBitShift(OpCode: TOpCode; Count: word): TReturnCode;
|
|
var
|
|
i : word;
|
|
size : word;
|
|
tmp : word;
|
|
|
|
begin
|
|
i := 0;
|
|
result:= VME_OK;
|
|
|
|
if (fDataSize mod 8) > 0
|
|
then size := (fDataSize div 8) +1
|
|
else size := (fDataSize div 8);
|
|
|
|
case OpCode of
|
|
// ------------------------------------------------------------
|
|
// Right Shift
|
|
// ------------------------------------------------------------
|
|
opSHR:
|
|
begin
|
|
while i < size do
|
|
begin
|
|
if fInData[i] <> 0 then
|
|
begin
|
|
tmp := Count;
|
|
|
|
while tmp > 0 do
|
|
begin
|
|
fInData[i] := fInData[i] shl 1;
|
|
|
|
if fInData[i] = 0 then
|
|
begin
|
|
DEC(i);
|
|
fInData[i] := 1;
|
|
end;
|
|
|
|
DEC(tmp);
|
|
end;
|
|
end;
|
|
|
|
INC(i);
|
|
end;
|
|
end;
|
|
|
|
|
|
// ------------------------------------------------------------
|
|
// Left Shift
|
|
// ------------------------------------------------------------
|
|
opSHL:
|
|
begin
|
|
while i < size do
|
|
begin
|
|
if fInData[i] <> 0 then
|
|
begin
|
|
tmp := Count;
|
|
|
|
while tmp > 0 do
|
|
begin
|
|
fInData[i] := fInData[i] shr 1;
|
|
|
|
if fInData[i] = 0 then
|
|
begin
|
|
DEC(i);
|
|
fInData[i] := 8;
|
|
end;
|
|
|
|
DEC(tmp);
|
|
end;
|
|
end;
|
|
|
|
INC(i);
|
|
end;
|
|
end;
|
|
|
|
// ------------------------------------------------------------
|
|
// Invalud operation
|
|
// ------------------------------------------------------------
|
|
else
|
|
result := VME_InvalidFile
|
|
end
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// ispVMComment
|
|
//
|
|
// Iterate through the comment and ignore it.
|
|
// ================================================================================================
|
|
procedure TispVM.ispVMComment(Size: word);
|
|
var
|
|
c: AnsiChar;
|
|
s: AnsiString;
|
|
w: WideString;
|
|
|
|
begin
|
|
while Size > 0 do
|
|
begin
|
|
c := AnsiChar(GetByte);
|
|
s := s + c;
|
|
|
|
DEC(Size)
|
|
end;
|
|
|
|
w := '| '+s+' |';
|
|
|
|
// s := s +#13#10;
|
|
|
|
writeln(s);
|
|
// OutputDebugString(@w[1]);
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// ispVMHeader
|
|
//
|
|
// Iterate through the header and ignore it.
|
|
// ================================================================================================
|
|
procedure TispVM.ispVMHeader(Size: word);
|
|
begin
|
|
while Size > 0 do
|
|
begin
|
|
GetByte;
|
|
DEC(size)
|
|
end
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// ispVMLCount
|
|
//
|
|
// Process the intelligent programming loops.
|
|
// ================================================================================================
|
|
function TispVM.ispVMLCount(CountSize: word): TReturnCode;
|
|
var
|
|
Continue : boolean;
|
|
BufferIndex : word;
|
|
CountIndex : word;
|
|
|
|
RepeatHeap : boolean;
|
|
OpCode : TOpcode;
|
|
|
|
State : TJTAGState;
|
|
Delay : word;
|
|
Toggle : word;
|
|
usByte : byte;
|
|
|
|
begin
|
|
RepeatHeap := false;
|
|
fIntelBufferSize := ispVMDataSize;
|
|
|
|
ispVMMemManager(opLHEAP, fIntelBufferSize);
|
|
|
|
// ---------------------------------------------------------------
|
|
// Store the maximum size of the intelligent buffer.
|
|
// Used to convert VME to HEX.
|
|
// ---------------------------------------------------------------
|
|
if fLCOUNTSize <= fIntelBufferSize then
|
|
fLCOUNTSize := fIntelBufferSize;
|
|
|
|
// ---------------------------------------------------------------
|
|
// Copy intel data to the buffer.
|
|
// ---------------------------------------------------------------
|
|
for BufferIndex:=0 to fIntelBufferSize -1 do
|
|
fIntelBuffer[BufferIndex] := GetByte;
|
|
|
|
// ---------------------------------------------------------------
|
|
// Update data type register.
|
|
// ---------------------------------------------------------------
|
|
Include( fDataType, dtLHeap);
|
|
|
|
// ---------------------------------------------------------------
|
|
// If the HEAP flag is set, tmporarily unset the flag so data will
|
|
// be retrieved from the status buffer.
|
|
// ---------------------------------------------------------------
|
|
if dtHeap in fDataType then
|
|
begin
|
|
Exclude( fDataType, dtHeap);
|
|
RepeatHeap := true;
|
|
end;
|
|
|
|
// ---------------------------------------------------------------
|
|
// Iterate through the intelligent programming command.
|
|
// ---------------------------------------------------------------
|
|
for CountIndex:=0 to CountSize -1 do
|
|
begin
|
|
fIntelDataIndex := 0;
|
|
OpCode := opEndData;
|
|
State := RESET;
|
|
Delay := 0;
|
|
Toggle := 0;
|
|
usByte := 0;
|
|
Continue := true;
|
|
|
|
// --------------------------------------------------
|
|
// Begin looping through all the VME opcodes.
|
|
// --------------------------------------------------
|
|
while Continue do begin
|
|
OpCode := TOpCode(GetByte);
|
|
|
|
case OpCode of
|
|
opHIR,opTIR,opHDR,opTDR:
|
|
// Set the header/trailer of device in order
|
|
// to bypass successfully.
|
|
ispVMAmble( OpCode);
|
|
|
|
opState:
|
|
begin
|
|
// Step the JTAG state machine to DRCAPTURE
|
|
// to support looping.
|
|
State := TJTAGState(GetByte);
|
|
|
|
if (dtLHeap in fDataType) and (State = DRPAUSE) and (fCurrentJTAGState = DRPAUSE) then
|
|
ispVMStateMachine( DRCAPTURE);
|
|
|
|
ispVMStateMachine(State);
|
|
end;
|
|
|
|
opSIR : result := ispVMShift(OpCode);
|
|
opSDR : result := ispVMShift(OpCode);
|
|
|
|
opWAIT : ispVMDelay( ispVMDataSize);
|
|
opTCK : ispVMClocks( ispVMDataSize);
|
|
opComment : ispVMComment( ispVMDataSize);
|
|
|
|
opENDLOOP : Continue := false;
|
|
|
|
opIspEN:
|
|
begin
|
|
OpCode := TOpCode(GetByte);
|
|
|
|
case OpCode of
|
|
opON : SetPin( pinENA, 0);
|
|
opOFF : SetPin( pinENA, 0);
|
|
end;
|
|
|
|
ispVMDelay(1);
|
|
end;
|
|
|
|
opTRST:
|
|
begin
|
|
OpCode := TOpCode(GetByte);
|
|
|
|
case OpCode of
|
|
opON : SetPin( pinTRST, 0);
|
|
opOFF : SetPin( pinTRST, 0);
|
|
end;
|
|
|
|
ispVMDelay(1);
|
|
end;
|
|
|
|
else
|
|
result := VME_InvalidFile
|
|
end;
|
|
end;
|
|
|
|
if result = VME_OK then
|
|
break;
|
|
end;
|
|
|
|
if RepeatHeap then
|
|
Include( fDataType, dtHeap);
|
|
|
|
Exclude( fDataType, dtLHeap);
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// ispVMClocks
|
|
//
|
|
// Applies the specified number of pulses to TCK.
|
|
// ================================================================================================
|
|
procedure TispVM.ispVMClocks(Count: word);
|
|
var
|
|
i: integer;
|
|
|
|
begin
|
|
for i:=0 to Count -1 do
|
|
sclock
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// ispVMBypass
|
|
//
|
|
// This procedure takes care of the HIR, HDR, TIR, TDR for the purpose of putting the other devices
|
|
// into Bypass mode. The current state is checked to find out if it is at DRPAUSE or IRPAUSE.
|
|
// If it is at DRPAUSE, perform bypass register scan.
|
|
// If it is at IRPAUSE, scan into instruction registers the bypass instruction.
|
|
// ================================================================================================
|
|
procedure TispVM.ispVMBypass(ScanType: TOpCode; Count: word);
|
|
var
|
|
Index : word;
|
|
SourceIndex : word;
|
|
BitState : byte;
|
|
CurByte : byte;
|
|
Source : PByte;
|
|
|
|
begin
|
|
SourceIndex := 0;
|
|
|
|
if Count > 0 then
|
|
begin
|
|
case ScanType of
|
|
opHIR: Source := fHIRData;
|
|
opTIR: Source := fTIRData;
|
|
opHDR: Source := fHDRData;
|
|
opTDR: Source := fTDRData;
|
|
else Source := nil;
|
|
end;
|
|
|
|
for Index:=0 to Count -2 do
|
|
begin
|
|
if (Index mod 8) = 0 then
|
|
begin
|
|
CurByte := Source[SourceIndex];
|
|
INC(SourceIndex);
|
|
end;
|
|
|
|
if (CurByte shl (Index mod 8)) and $80 = $80
|
|
then BitState := 1
|
|
else BitState := 0;
|
|
|
|
SetPin( pinTDI, BitState);
|
|
sclock;
|
|
end;
|
|
|
|
if (Index mod 8) = 0 then
|
|
CurByte := Source[SourceIndex];
|
|
|
|
if (CurByte shl (Index mod 8)) and $80 = $80
|
|
then BitState := 1
|
|
else BitState := 0;
|
|
|
|
SetPin( pinTDI, BitState);
|
|
end;
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// ispVMStateMachine
|
|
//
|
|
// This procedure steps all devices in the daisy chain from a given JTAG state to the next
|
|
// desirable state. If the next state is TLR, the JTAG state machine is brute forced into
|
|
// TLR by driving TMS high and pulse TCK 6 times.
|
|
// ================================================================================================
|
|
procedure TispVM.ispVMStateMachine(NextState:TJTAGState);
|
|
var
|
|
PathIndex : byte;
|
|
StateIndex : byte;
|
|
|
|
begin
|
|
if (fCurrentJTAGState = NextState) and (NextState <> RESET) then
|
|
exit;
|
|
|
|
for StateIndex:=0 to 24 do
|
|
if (fCurrentJTAGState = JTAGTransitions[StateIndex].CurrState) and
|
|
(NextState = JTAGTransitions[StateIndex].NextState) then
|
|
break;
|
|
|
|
fCurrentJTAGState := NextState;
|
|
|
|
for PathIndex:=0 to JTAGTransitions[StateIndex].Pulses -1 do
|
|
begin
|
|
if (JTAGTransitions[StateIndex].Pattern shl PathIndex) and $80 = $80
|
|
then SetPin( pinTMS, 1)
|
|
else SetPin( pinTMS, 0);
|
|
|
|
sclock;
|
|
end;
|
|
|
|
SetPin( pinTDI, 0);
|
|
SetPin( pinTMS, 0);
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// ispVMSend
|
|
//
|
|
// Send the TDI data stream to devices. The data stream can be instructions or data.
|
|
// ================================================================================================
|
|
function TispVM.ispVMSend(Count: word): TReturnCode;
|
|
var
|
|
Index : word;
|
|
DataIndex: word;
|
|
CurByte : byte;
|
|
BitState : byte;
|
|
|
|
begin
|
|
// if Assigned(fJtag) then
|
|
// fJtag.xfer( fInData, Count, 1);
|
|
|
|
{
|
|
DataIndex := 0;
|
|
|
|
for Index:=0 to Count -2 do
|
|
begin
|
|
if (Index mod 8) = 0 then
|
|
begin
|
|
CurByte := fInData[DataIndex];
|
|
INC(DataIndex);
|
|
end;
|
|
|
|
if (CurByte shl (Index mod 8)) and $80 = $80
|
|
then BitState := 1
|
|
else BitState := 0;
|
|
|
|
SetPin( pinTDI, BitState);
|
|
sclock;
|
|
end;
|
|
|
|
// Take care of the last bit.
|
|
if (Index mod 8) = 0 then
|
|
CurByte := fInData[DataIndex];
|
|
|
|
if (CurByte shl (Index mod 8)) and $80 = $80
|
|
then BitState := 1
|
|
else BitState := 0;
|
|
|
|
SetPin( pinTDI, BitState);
|
|
|
|
// Clock in last bit for the first n-1 cascaded frames.
|
|
if fcbCascade in fFlowControl then
|
|
sclock;
|
|
}
|
|
result := VME_OK
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// ispVMRead
|
|
//
|
|
// Read the data stream from devices and verify.
|
|
// ================================================================================================
|
|
function TispVM.ispVMRead(Count: word): TReturnCode;
|
|
var
|
|
DataSizeIndex : word;
|
|
ErrorCount : word;
|
|
LastBitIndex : word;
|
|
DataByte : byte;
|
|
MaskByte : byte;
|
|
InDataByte : byte;
|
|
CurBit : byte;
|
|
ByteIndex : byte;
|
|
BufferIndex : word;
|
|
DisplayByte : byte;
|
|
DisplayFlag : boolean;
|
|
BitState : byte;
|
|
|
|
StrChecksum : array [0..255] of AnsiChar;
|
|
CalChecksum : boolean;
|
|
|
|
cnt : integer;
|
|
i : integer;
|
|
|
|
begin
|
|
ByteIndex := 0;
|
|
BufferIndex := 0;
|
|
DisplayByte := 0;
|
|
DisplayFlag := true;
|
|
CalChecksum := false;
|
|
LastBitIndex := Count -1;
|
|
|
|
// ---------------------------------------------------------------
|
|
// If mask is not all zeros, then set the display flag to 0x00,
|
|
// otherwise it shall be set to 0x01 to indicate that data read
|
|
// from the device shall be displayed.
|
|
// If VME_DEBUG is defined, always display data.
|
|
// ---------------------------------------------------------------
|
|
for DataSizeIndex:=0 to ((Count + 7) mod 8) -1 do
|
|
begin
|
|
if dtMASKData in fDataType then
|
|
begin
|
|
if fOutMaskData[DataSizeIndex] <> 0 then
|
|
begin
|
|
DisplayFlag := false;
|
|
break
|
|
end;
|
|
end
|
|
|
|
else if dtCMASKData in fDataType then
|
|
begin
|
|
CalChecksum := true;
|
|
DisplayFlag := false;
|
|
break
|
|
end
|
|
|
|
else begin
|
|
DisplayFlag := false;
|
|
break
|
|
end;
|
|
end;
|
|
|
|
// ---------------------------------------------------------------
|
|
// Send TDI data out.
|
|
// ---------------------------------------------------------------
|
|
fTransferMode := tmRead;
|
|
result := ispVMSend(Count);
|
|
|
|
exit;
|
|
// for i:=0 to (Count *2) -1 do
|
|
// fBuffer[i] := fBuffer[i] and fMaskTDO;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------
|
|
// Begin shifting data in and out of the device.
|
|
// ---------------------------------------------------------------
|
|
for DataSizeIndex:=0 to Count -1 do
|
|
begin
|
|
if ByteIndex = 0 then
|
|
begin
|
|
if dtTDOData in fDataType then
|
|
DataByte := fOutData[BufferIndex];
|
|
|
|
if dtMASKData in fDataType
|
|
then MaskByte := fOutMaskData[BufferIndex]
|
|
else MaskByte := $FF;
|
|
|
|
if dtCMASKData in fDataType then
|
|
begin
|
|
MaskByte := $00;
|
|
CalChecksum := true;
|
|
end;
|
|
|
|
if dtTDIData in fDataType then
|
|
InDataByte := fInData[BufferIndex];
|
|
|
|
INC(BufferIndex)
|
|
end;
|
|
|
|
// CurBit := ReadPort;
|
|
|
|
if DisplayFlag then
|
|
begin
|
|
DisplayByte := DisplayByte shl 1;
|
|
DisplayByte := DisplayByte or CurBit;
|
|
end;
|
|
|
|
// ------------------------------------------------------------
|
|
// Check if data read from port matches with expected TDO.
|
|
// ------------------------------------------------------------
|
|
if dtTDOData in fDataType then
|
|
begin
|
|
if CalChecksum then
|
|
begin
|
|
if CurBit = 1 then
|
|
fCheckSum := fCheckSum + (1 shl (fCheckSumIndex mod 8));
|
|
|
|
INC( fCheckSumIndex)
|
|
end
|
|
|
|
else begin
|
|
// TODO: b+
|
|
end;
|
|
end;
|
|
|
|
// ------------------------------------------------------------
|
|
// Write TDI data to the port.
|
|
// ------------------------------------------------------------
|
|
if (InDataByte shl ByteIndex) and $80 = $80
|
|
then BitState := 1
|
|
else BitState := 0;
|
|
|
|
SetPin( pinTDI, BitState);
|
|
|
|
if (DataSizeIndex < LastBitIndex) or (fcbCascade in fFlowControl) then
|
|
sclock;
|
|
|
|
// ------------------------------------------------------------
|
|
// Increment the byte index. If it exceeds 7, then resetit back
|
|
// to zero.
|
|
// ------------------------------------------------------------
|
|
INC(ByteIndex);
|
|
|
|
if ByteIndex > 7 then
|
|
begin
|
|
if DisplayFlag then
|
|
begin
|
|
// ------------------------------------------------------
|
|
// Store displayed data in the TDO buffer. By reusing the
|
|
// TDO buffer to store displayed data, there is no need
|
|
// to allocate a buffer simply to hold display data. This
|
|
// will not cause any false verification errors because
|
|
// the true TDO byte has already been consumed.
|
|
// ------------------------------------------------------
|
|
fOutData[BufferIndex -1] := DisplayByte;
|
|
DisplayByte := 0;
|
|
end;
|
|
|
|
ByteIndex := 0;
|
|
end
|
|
|
|
else if fDataSize = 1 then
|
|
begin
|
|
if DisplayFlag then
|
|
begin
|
|
// ------------------------------------------------------
|
|
// Store displayed data in the TDO buffer. By reusing the
|
|
// TDO buffer to store displayed data, there is no need
|
|
// to allocate a buffer simply to hold display data. This
|
|
// will not cause any false verification errors because
|
|
// the true TDO byte has already been consumed.
|
|
//
|
|
// Flip DisplayByte and store it in DataByte.
|
|
// ------------------------------------------------------
|
|
DataByte := FlipByte(DisplayByte);
|
|
fOutData[0] := DataByte;
|
|
DisplayByte := 0;
|
|
end;
|
|
|
|
ByteIndex := 0;
|
|
end;
|
|
end;
|
|
|
|
// ---------------------------------------------------------------
|
|
// Display data read from the device.
|
|
// ---------------------------------------------------------------
|
|
if DisplayFlag then
|
|
begin
|
|
// writeln....
|
|
|
|
cnt := (fDataSize +7) mod 8;
|
|
|
|
for DataSizeIndex := cnt-1 downto 0 do
|
|
begin
|
|
MaskByte := fOutData[DataSizeIndex];
|
|
DataByte := FlipByte(MaskByte);
|
|
|
|
// write DataByte
|
|
end;
|
|
|
|
if fCheckSum <> 0 then
|
|
begin
|
|
|
|
end;
|
|
end;
|
|
|
|
if ErrorCount > 0 then
|
|
begin
|
|
|
|
end;
|
|
|
|
result := VME_OK
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// ispVMReadAndSave
|
|
// ================================================================================================
|
|
function TispVM.ispVMReadAndSave(Count: word): TReturnCode;
|
|
var
|
|
DataSizeIndex : word;
|
|
ErrorCount : word;
|
|
LastBitIndex : word;
|
|
OutBitIndex : word;
|
|
DataByte : byte;
|
|
DMaskByte : byte;
|
|
InDataByte : byte;
|
|
CurBit : byte;
|
|
ByteIndex : byte;
|
|
BufferIndex : word;
|
|
DisplayByte : byte;
|
|
DisplayFlag : boolean;
|
|
BitState : byte;
|
|
|
|
StrChecksum : array [0..255] of AnsiChar;
|
|
CalChecksum : boolean;
|
|
|
|
cnt : integer;
|
|
i : integer;
|
|
|
|
begin
|
|
|
|
ByteIndex := 0;
|
|
BufferIndex := 0;
|
|
DisplayByte := 0;
|
|
DisplayFlag := true;
|
|
CalChecksum := false;
|
|
LastBitIndex := Count -1;
|
|
|
|
// ---------------------------------------------------------------
|
|
// Iterate through the data bits.
|
|
// ---------------------------------------------------------------
|
|
for DataSizeIndex := 0 to Count -1 do
|
|
begin
|
|
if ByteIndex = 0 then
|
|
begin
|
|
if dtDMASKData in fDataType
|
|
then DMaskByte := fOutDMaskData[BufferIndex]
|
|
else DMaskByte := $00;
|
|
|
|
if dtTDIData in fDataType
|
|
then InDataByte := fInData[BufferIndex];
|
|
|
|
INC(BufferIndex)
|
|
end;
|
|
|
|
// CurBit := ReadPort;
|
|
if (InDataByte shl ByteIndex) and $80 = $80
|
|
then DataByte := $01
|
|
else DataByte := $00;
|
|
|
|
// initialize the byte to be zero
|
|
if (OutBitIndex mod 8) = 0 then
|
|
fOutData[OutBitIndex div 8] := $00;
|
|
|
|
// ------------------------------------------------------------
|
|
// Use TDI, DMASK, and device TDO to create new TDI
|
|
// (actually stored in fOutData).
|
|
// ------------------------------------------------------------
|
|
if (DMaskByte shl ByteIndex) and $80 = $80 then
|
|
begin
|
|
if Length( fLVDs) > 0 then
|
|
for i:=Low(fLVDS) to High(fLVDS) do
|
|
if fLVDs[i].NegativeIndex = DataSizeIndex then
|
|
begin
|
|
fLVDs[i].Update := true;
|
|
break;
|
|
end;
|
|
|
|
// DMASK bit is 1, use TDI.
|
|
if DataByte and $01 = $01 then
|
|
fOutData[OutBitIndex mod 8] := fOutData[OutBitIndex mod 8] or $01;
|
|
end
|
|
|
|
else begin
|
|
// DMASK bit is 0, use TDO.
|
|
if CurBit and $01 = $01 then
|
|
fOutData[OutBitIndex mod 8] := fOutData[OutBitIndex mod 8] or $01;
|
|
end;
|
|
|
|
// ------------------------------------------------------------
|
|
// Shift in TDI in order to get TDO out.
|
|
// ------------------------------------------------------------
|
|
INC(OutBitIndex);
|
|
SetPin( pinTDI, DataByte);
|
|
|
|
if DataSizeIndex < LastBitIndex then
|
|
sclock;
|
|
|
|
// ------------------------------------------------------------
|
|
// Increment the byte index. If it exceeds 7, then reset it
|
|
// back to zero.
|
|
// ------------------------------------------------------------
|
|
INC(ByteIndex);
|
|
|
|
if ByteIndex >= 8 then
|
|
ByteIndex := 0;
|
|
end;
|
|
|
|
// ---------------------------------------------------------------
|
|
// If fLVDs list exists and pairs needed updating, then update the
|
|
// negative pair to receive the flipped positive pair value.
|
|
// Ezt a reszt most kihagyom! Fene tudja mikor kell.
|
|
// ---------------------------------------------------------------
|
|
if Length(fLVDs) > 0 then
|
|
begin
|
|
for i:=Low(fLVDs) to High(fLVDs) do
|
|
begin
|
|
if fLVDs[i].Update then
|
|
begin
|
|
// --------------------------------------------
|
|
// Read the positive value and invert it.
|
|
// --------------------------------------------
|
|
DataByte := fLVDs[i].PositiveIndex;
|
|
fLVDs[i].NegativeIndex := not DataByte;
|
|
|
|
// --------------------------------------------
|
|
// Get the byte that needs modification.
|
|
// --------------------------------------------
|
|
InDataByte := fOutData[ fLVDs[i].NegativeIndex div 8];
|
|
|
|
if DataByte <> 0 then
|
|
begin
|
|
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
result := VME_OK
|
|
end;
|
|
|
|
|
|
|
|
|
|
// ================================================================================================
|
|
// ispVMStart
|
|
//
|
|
// Enable the port to the device and set the state to RESET.
|
|
// ================================================================================================
|
|
procedure TispVM.ispVMStart;
|
|
begin
|
|
ispVMStateMachine(RESET);
|
|
Flush;
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// ispVMEnd
|
|
//
|
|
// Set the state of devices to RESET to enable the devices and disable the port.
|
|
// ================================================================================================
|
|
procedure TispVM.ispVMEnd;
|
|
begin
|
|
ispVMStateMachine(RESET);
|
|
Flush;
|
|
|
|
ispVMDelay(1000)
|
|
end;
|
|
|
|
|
|
// ================================================================================================
|
|
// ispVMProcessLVDS
|
|
// ================================================================================================
|
|
function TispVM.ispVMProcessLVDS(Count: word): TReturnCode;
|
|
var
|
|
i: word;
|
|
|
|
begin
|
|
// ---------------------------------------------------------------
|
|
// Allocate memory to hold LVDS pairs.
|
|
// ---------------------------------------------------------------
|
|
SetLength( fLVDs, Count);
|
|
|
|
// ---------------------------------------------------------------
|
|
// Iterate through each given LVDS pair.
|
|
// ---------------------------------------------------------------
|
|
for i:=0 to Count -1 do
|
|
begin
|
|
fLVDs[i].PositiveIndex := ispVMDataSize;
|
|
fLVDs[i].NegativeIndex := ispVMDataSize;
|
|
fLVDs[i].Update := false;
|
|
end;
|
|
|
|
result := VME_OK
|
|
end;
|
|
// ================================================================================================
|
|
// ispVMDelay
|
|
//
|
|
// Users must implement a delay to observe a_usTimeDelay, where
|
|
// bit 15 of the a_usTimeDelay defines the unit.
|
|
// 1 = milliseconds
|
|
// 0 = microseconds
|
|
// Example:
|
|
// a_usTimeDelay = 0x0001 = 1 microsecond delay.
|
|
// a_usTimeDelay = 0x8001 = 1 millisecond delay.
|
|
//
|
|
// This subroutine is called upon to provide a delay from 1 millisecond to a few hundreds
|
|
// milliseconds each time.
|
|
//
|
|
// It is understood that due to a_usTimeDelay is defined as unsigned short, a 16 bits integer,
|
|
// this function is restricted to produce a delay to 64000 micro-seconds or 32000 milli-second
|
|
// maximum. The VME file will never pass on to this function a delay time > those maximum number.
|
|
// If it needs more than those maximum, the VME file will launch the delay function several times
|
|
// to realize a larger delay time cummulatively.
|
|
//
|
|
// It is perfectly alright to provide a longer delay than required. It is not acceptable if the
|
|
// delay is shorter.
|
|
// ================================================================================================
|
|
procedure TispVM.ispVMDelay(Delay: word);
|
|
var
|
|
d: integer;
|
|
|
|
begin
|
|
if Delay and $8000 = $8000
|
|
then d := Delay and $7FFF
|
|
else d := Delay div 1000;
|
|
|
|
if d = 0 then
|
|
d := 1;
|
|
|
|
// if Assigned(fJtag) then
|
|
// fJtag.wait(d);
|
|
|
|
//@ Flush;
|
|
//@ Sleep(d);
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// SClock
|
|
// ================================================================================================
|
|
procedure TispVM.sclock(n:integer);
|
|
var
|
|
data : byte;
|
|
i : integer;
|
|
|
|
begin
|
|
data := 0;
|
|
|
|
if fValTMS then data := data or fMaskTMS;
|
|
if fValTDI then data := data or fMaskTDI;
|
|
if fValTRST then data := data or fMaskTRST;
|
|
if fValENA then data := data or fMaskENA;
|
|
|
|
for i:=0 to n-1 do
|
|
begin
|
|
if (fBufferSize - fBufferIndex) < 2 then
|
|
Flush;
|
|
|
|
data := data and not fMaskTCK;
|
|
fBuffer[fBufferIndex] := data;
|
|
INC(fBufferIndex);
|
|
|
|
data := data or fMaskTCK;
|
|
fBuffer[fBufferIndex] := data;
|
|
INC(fBufferIndex);
|
|
end;
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// SetPin
|
|
// ================================================================================================
|
|
procedure TispVM.SetPin( pin: TPin; Value: byte);
|
|
begin
|
|
case pin of
|
|
pinTMS : fValTMS := Value <> 0;
|
|
pinTDI : fValTDI := Value <> 0;
|
|
pinTRST : fValTRST := Value <> 0;
|
|
pinENA : fValENA := Value <> 0;
|
|
end;
|
|
end;
|
|
|
|
// ================================================================================================
|
|
// Flush the buffer
|
|
// ================================================================================================
|
|
procedure TispVM.Flush;
|
|
begin
|
|
if fBufferIndex > 0 then
|
|
if Assigned( fOnTransfer) then
|
|
fOnTransfer( self, fTransferMode);
|
|
|
|
fBufferIndex := 0;
|
|
end;
|
|
|
|
|
|
// ================================================================================================
|
|
// ispVMMemManager
|
|
//
|
|
// Allocate memory based on Target. The memory size specified by Size.
|
|
// ================================================================================================
|
|
procedure TispVM.ispVMMemManager(Target: TOpCode; Size: word);
|
|
begin
|
|
case Target of
|
|
opTDI,opXTDI:
|
|
begin
|
|
if Assigned(fInData) then
|
|
FreeMem(fInData);
|
|
|
|
fInData := AllocMem( (Size div 8) +2);
|
|
end;
|
|
|
|
opTDO,opXTDO:
|
|
begin
|
|
if Assigned(fOutData) then
|
|
FreeMem(fOutData);
|
|
|
|
fOutData := AllocMem( (Size div 8) +2);
|
|
end;
|
|
|
|
opMASK:
|
|
begin
|
|
if Assigned( fOutMaskData) then
|
|
FreeMem( fOutMaskData);
|
|
|
|
fOutMaskData := AllocMem( (Size div 8) +2);
|
|
end;
|
|
|
|
opDMASK:
|
|
begin
|
|
if Assigned( fOutDMaskData) then
|
|
FreeMem( fOutDMaskData);
|
|
|
|
fOutDMaskData := AllocMem( (Size div 8) +2);
|
|
end;
|
|
|
|
opHIR:
|
|
begin
|
|
if Assigned( fHIRData) then
|
|
FreeMem( fHIRData);
|
|
|
|
fHIRData := AllocMem( (Size div 8) +2);
|
|
end;
|
|
|
|
opTIR:
|
|
begin
|
|
if Assigned( fTIRData) then
|
|
FreeMem( fTIRData);
|
|
|
|
fTIRData := AllocMem( (Size div 8) +2);
|
|
end;
|
|
|
|
opHDR:
|
|
begin
|
|
if Assigned( fHDRData) then
|
|
FreeMem( fHDRData);
|
|
|
|
fHDRData := AllocMem( (Size div 8) +2);
|
|
end;
|
|
|
|
opTDR:
|
|
begin
|
|
if Assigned( fTDRData) then
|
|
FreeMem( fTDRData);
|
|
|
|
fTDRData := AllocMem( (Size div 8) +2);
|
|
end;
|
|
|
|
opHEAP:
|
|
begin
|
|
if Assigned( fHeapMemory) then
|
|
FreeMem( fHeapMemory);
|
|
|
|
fHeapMemory := AllocMem( (Size div 8) +2);
|
|
end;
|
|
|
|
opLHeap:
|
|
begin
|
|
if Assigned( fIntelBuffer) then
|
|
FreeMem( fIntelBuffer);
|
|
|
|
fIntelBuffer := AllocMem( (Size div 8) +2);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
initialization
|
|
|
|
end.
|