📄 ivm_core.c
字号:
/****************************************************************************
ispVM Core Of Embedded Version Of ispVM
Lattice Semiconductor Corp. Copyright 1998 - 2001.
ispVME for Embedded Applications Where Resources is A Premium.
This is the scale down version of the full ispVM target for embedded
applications. The footprint of this VM is less than 8K bytes in size.
Huffman encoding is used to minimize the Virtual Machine Format file size
without increasing the VM footprint and addtional RAM for decompression
is not required.
Typically only 100 bytes of RAM is required to hold one row of data when
processing the VMF file. The VM itself also need less than 100 bytes of
RAM to hold all the variables it needs.
This is the core of the ispVM Embedded. All the high level opcode of the
ispVM required to support all industry standard SVF constructs are included.
All ispVM opcodes for decision branching, math and low level bit banging
are not included to reduce the ispVM Embedded footprint to the minimum.
Decision branching and math operations are still carried out by ispVM
Embedded by using native code instead. It is to achieve the highest
efficiency possible for ispVM Embedded. For example:
Using native code to add A and B is: sum=a+b;
Using ispVM opcode is: PUSH a; PUSH b; ADD sum;
It is obvious that the ispVM actually interprets the compiled opcode
and call the appropriate function to perform the action in native code.
Native code vs ispVM opcode represents respectively the efficiency and
flexibility trade off. The priority number one for ispVM Embedded is
efficiency.
The functional blocks:
ispVMCode() Extract and interpret the ispVM high level opcodes.
ispVMDataCode() Extract and interpret ispVM data type opcode.
ispVMDataSize() Extract the operand of size (a 16 bit number).
ispVMData() Extract and decompress one row of data stream.
4/26/01 Add support to a non-zero HIR, HDR, TIR and TDR for multiple devices
in one SVF file.
8/23/01 Add support to cascading turn on and off.
Add some sort of flow control to support the program the part if usercode
verify fail requirement.
Add support of repeat looping for vme file size reduction.
12/03/01 Checks for SECUREHEAP opcode immediately following HEAP opcode to
maintain VME integrity
tnt 03/13/02 New opcodes added CRC, CMASK, READ, and RMASK to calculate data
CRC and perform Read and Save.
3/25/02 tnt No longer issue DRPAUSE/IRPAUSE to the state machine after sending
or receiving data
1/15/04 Support cascade by checking is current state is SHIFTDR. If SHIFTDR is active,
then do not step into DRPAUSE.
2/11/04 Remove IEEE 1532 support.
*****************************************************************************/
#include <stdio.h>
#include "vmopcode.h"
#include "hardware.h"
#ifdef VME_DEBUG
#include "debug.h"
#endif
unsigned short usFlowControl = 0x0000, /*Flow control register*/
usDataType = 0x0000; /*holds the data type of the current row
default is all operations selected*/
extern unsigned char * OutMaskData, /*holds Mask data*/
* InData, /*holds data to be shift into device*/
* OutData, /*holds data to be compared with those read from device*/
* HIRData, /*holds data of SIR header*/
* TIRData, /*holds data of SIR trailer*/
* HDRData, /*holds data of SDR header*/
* TDRData, /*holds data of SDR trailer*/
* OutDMaskData;/*holds DMask data*/
extern char cCurrentJTAGState;
extern unsigned char * pucHeapMemory; /*holds the repeat loop*/
extern unsigned short iHeapCounter; /*holds the current byte address of the Heap*/
/*set all to default*/
static unsigned char
End_DR = DRPAUSE, /*after shift data, part at PAUSE DR by default*/
End_IR = IRPAUSE; /*after shift IR, part at PAUSE IR by default */
static unsigned short
HeadDR = 0, /*the number of lead devices in bypass*/
HeadIR = 0, /*the sum of IR length of lead devices*/
TailDR = 0, /*the number of tail devices in bypass*/
TailIR = 0; /*the sum of IR length of tail devices*/
static unsigned short usiDataSize = 0; /*the number(bits) of data or instruction
to be shifted into or out from devices*/
extern unsigned short iHEAPSize; /*the number of bytes in the HEAP*/
unsigned short Frequency = 1000;
static unsigned short MaxSize = 0; /*the maximum amount of rams(bytes) needed to
hold a row of data*/
unsigned short iShiftValue = 0; /*holds the updated value of LSH or RSH*/
unsigned short RepeatLoops= 0; /*holds the current repeat loop value*/
unsigned short rightShift = 0; /*holds permission to rightShift or not*/
char cVendor; /*holds the name of the vendor*/
extern char GetByte(void);
extern void ispVMMemManager(char types, unsigned short size);
/*prototypes*/
char ispVMCode(void);
char ispVMDataCode(void);
unsigned short ispVMDataSize(void);
void ispVMData(unsigned char *Data);
char ispVMShift(char Code);
char ispVMAmble(char Code);
char ispVMLoop( unsigned short a_usLoopCount );
char ispVMBitShift(char mode, unsigned short bits);
/****************************************************************************
ispVMDataSize
Extract the data size of the current row from the VME file.
Return
usiDataSize-----------The data bit length of the current row.
*****************************************************************************/
unsigned short ispVMDataSize()
{
unsigned short usiSize = 0;
char cCurrentByte, cIndex;
cIndex = 0;
while ( ( cCurrentByte = GetByte() ) & 0x80 ) {
usiSize |= ( ( unsigned short ) ( cCurrentByte & 0x7F ) ) << cIndex;
cIndex += 7;
}
usiSize |= ( ( unsigned short ) ( cCurrentByte & 0x7F ) ) << cIndex;
return usiSize;
}
/****************************************************************************
ispVMCode
This is the core of ispVM Embedded. The ispVM opcodes are extracted and
interpreted in this module. The ispVM opcodes supported here are only
high level ispVM opcodes. High level opcodes simplify users' task in
creating the VME files. For example:
To scan an instruction into the targeted device(s), the VME program is:
SVF: SIR 5 TDI (0x0A);
VME: 0x01,0x00,0x05,0x03,0x50,0x00;
SIR opcode = 0x01;
size = 0x00, 0x05;
TDI opcode = 0x03;
data = 0x50 which is reverse of 0x0A;
ENDDATA opcode = 0x00;
The high level opcode is splitted into multiple low level tasks by the ispVM
Embedded:
task 1: Fetch and keep all the operands, size and data stream etc.
Allocate memory if necessary to keep the operands.
task 2: Move the BSCAN state of the device to IRPAUSE.
task 3: Put the leading and trailing devices into BYPASS mode.
task 4: Move the BSCAN state machine to Shift-IR state.
task 5: Shift the data stream into the target device(s);
task 6: Move the BSCAN state machine to IRPAUSE.
task 7: Move the BSCAN state machine to state as specified by ENDDR opcode.
task 8: Put the leading and trailing devices into BYPASS mode.
If low level opcodes are used instead, each task will require an opcode.
This will go against the objective of having a small VME file size and
fast programming time.
Return
Global var:
compression --read instruction without compression read data with
compression
tdodata --true if TDO opcode is detected to indicate reading is
necessary
express --true if EXPRESS SDR(XSDR) token is detected.
XSDR will be carried out with Input data transferred to
Output data buffer for next verify against. The XTDO opcode
does not have data. The effect is to reduce the VME file
size by half.
usiDataSize --the number of bits of data to be processed
*****************************************************************************/
char ispVMCode()
{
unsigned short iRepeatSize;
char cOpcode;
char cRetCode = 0;
#ifdef VME_DEBUG
unsigned short siDebugRow = 0;
unsigned short iOpcodeIndex;
#endif
while ( ( cOpcode = GetByte() ) >= 0 ) { /* All opcode except ENDFILE are all positive */
#ifdef VME_DEBUG
siDebugRow++;
for ( iOpcodeIndex = 0; iOpcodeIndex < iOpcodeCount; iOpcodeIndex++ ) {
if ( ispVMOpcodes[ iOpcodeIndex ].token == cOpcode ) {
break;
}
}
printf( "Row = %d Opcode = %s\n", siDebugRow, ispVMOpcodes[ iOpcodeIndex ].text );
#endif
switch ( cOpcode ) {
case STATE: /*step BSCAN state machine to specified state*/
ispVMStateMachine( GetByte() );
break;
case SIR: /*shift instruction stream into devices*/
case SDR: /*shift data stream into devices*/
case XSDR:
cRetCode = ispVMShift( cOpcode );
if ( cRetCode != 0 ) {
return ( cRetCode );
}
break;
case WAIT: /*opcode to wait for specified time in us or ms*/
ispVMDelay( ispVMDataSize() );
break;
case TCK: /*pulse TCK signal the specified time*/
ispVMClocks( ispVMDataSize() );
break;
case ENDDR: /*modify the BSCAN state after SDR opcode*/
End_DR = GetByte();
break;
case ENDIR: /*modify the BSCAN state after SIR opcode*/
End_IR = GetByte();
break;
case HIR: /*modify the IR length of lead devices*/
case TIR: /*modify the IR length of the trailing devices*/
case HDR: /*modify the DATA length of the lead devices*/
case TDR: /*modify the DATA length of the trailing devices*/
cRetCode = ispVMAmble( cOpcode );
if ( cRetCode != 0 ) {
return ( cRetCode );
}
break;
case MEM: /*The maximum RAM required for current VME file*/
MaxSize = ispVMDataSize();
break;
case VENDOR:
cOpcode = GetByte();
switch ( cOpcode ) {
case LATTICE:
cVendor = LATTICE;
break;
case ALTERA:
cVendor = ALTERA;
break;
case XILINX:
cVendor = XILINX;
break;
default:
break;
}
break;
case SETFLOW:
usFlowControl |= ispVMDataSize();
break;
case RESETFLOW: /*Clear the continue if fail flag*/
usFlowControl &= ~( ispVMDataSize() );
break;
case HEAP: /*the size of HEAP memory to store loops*/
cRetCode = GetByte();
if ( cRetCode != SECUREHEAP ) {
return -4;
}
iHEAPSize = ispVMDataSize(); /*HEAP size in bytes*/
ispVMMemManager( HEAP, ( unsigned short ) iHEAPSize );
break;
case REPEAT: /*the begin of a monolithic loop*/
RepeatLoops = 0;
iRepeatSize = ispVMDataSize();
cRetCode = ispVMLoop( ( unsigned short ) iRepeatSize );
#ifndef VME_DEBUG
if ( cRetCode != 0 ) {
return ( cRetCode );
}
#endif
break;
case ENDLOOP:
return ( cRetCode ); /*force a return*/
case ENDVME:
case ENDFILE: /*reach end of the current VME file*/
return( cRetCode ); /*return the result*/
case SHR:
usFlowControl |= SHIFTRIGHT;
iShiftValue = RepeatLoops * GetByte();
break;
case SHL:
usFlowControl |= SHIFTLEFT;
iShiftValue = RepeatLoops * GetByte();
break;
case FREQUENCY:
Frequency = ispVMDataSize();
break;
case VUES:
usFlowControl |= VERIFYUES;
break;
default: /* Invalid opcode encountered */
#ifdef VME_DEBUG
printf( "Illegal opcode (%02X)!\n", cOpcode );
#endif
return -4;
}
}
if ( ( cOpcode < 0 ) && ( cOpcode != ( char ) ENDFILE ) ) {
return ( -4 );
}
else {
return ( cRetCode );
}
}
/****************************************************************************
ispVM Data Code
This routine is to extract the data operator which follows the TDI, TDO
and MASK and perform operations on the data stream. The possible
operator codes are:
if the data follows has compression, then add 0x80 to the opcode shown
LOCAL 0x00 the data follows immediately
SHR 0x01 from data follows immediately
SHL 0x02 from data follows immediately
ROMARRAY 0x03 from read only array follows
RAMARRAY 0x04 from a read and write array
CPYDATARRAY 0x05 copy to data array (i.e. $addr=1;)
CPYDATAVAR 0x06 copy to data variable
SHLARRAY 0x07 from data array with shift left operation
SHRARRAY 0x08 from data array with shift right operation
INVARRAY 0x09 from data array with complement operation
INCDATA 0x0A from variable array with increment operation
DECDATA 0x0B from variable array with decement operation
INVDATA 0x0C from variable array with complement operation
SHLDATA 0x0D from variable array with shift left operation
SHRDATA 0x0E from varaible array with shift right operation
This version V9.001 supports only LOCAL and ROMARRAY data operator.
If other operators are desired, contact Lattice's Application for
the library functions.
Extract tdi tdo or mask from the VME file.
Return
usDataType------------Set EXPRESS bit true if XTDI, XTDO found.
Set TDI_DATA, TDO_DATA, MASK_DATA bit true if found.
*****************************************************************************/
char ispVMDataCode()
{
char cDataByte;
char siDataSource = 0; /*source of data from file by default*/
#ifdef VME_DEBUG
unsigned short iOpcodeIndex;
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -