From a30568e2a9e9e1bf17d81faf8d8866d240780e4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=B3ka=20Mikl=C3=B3s?= Date: Thu, 8 Jan 2026 19:12:06 +0100 Subject: [PATCH] Initial check in --- .gitignore | 9 + doc/svf.pdf | Bin 0 -> 87261 bytes doc/xapp503.pdf | Bin 0 -> 251306 bytes prj.jtag/Delphi12Athens/mr.jtag.dpk | 58 + prj.jtag/Delphi12Athens/mr.jtag.dproj | 1025 ++++++ src.jtag/jtag.bstream.pas | 1128 +++++++ src.jtag/jtag.types.pas | 48 + src.jtag/svf/grammar/jtag.svfLexer.g | 247 ++ src.jtag/svf/grammar/jtag.svfLexer.pas | 785 +++++ src.jtag/svf/grammar/jtag.svfLexerTokens.pas | 77 + src.jtag/svf/grammar/jtag.svfLexerTokens.txt | 65 + src.jtag/svf/grammar/jtag.svfParser.g | 376 +++ src.jtag/svf/grammar/jtag.svfParser.pas | 688 ++++ src.jtag/svf/grammar/jtag.svfParserTokens.pas | 79 + src.jtag/svf/grammar/jtag.svfParserTokens.txt | 67 + src.jtag/svf/grammar/jtag.svfScanLexer.g | 137 + src.jtag/svf/grammar/jtag.svfScanLexer.pas | 448 +++ .../svf/grammar/jtag.svfScanLexerTokens.pas | 79 + .../svf/grammar/jtag.svfScanLexerTokens.txt | 67 + src.jtag/svf/jtag.svfAstComment.pas | 37 + src.jtag/svf/jtag.svfAstEndDR.pas | 57 + src.jtag/svf/jtag.svfAstEndIR.pas | 56 + src.jtag/svf/jtag.svfAstFreq.pas | 37 + src.jtag/svf/jtag.svfAstNode.pas | 22 + src.jtag/svf/jtag.svfAstPrint.pas | 34 + src.jtag/svf/jtag.svfAstRuntest.pas | 110 + src.jtag/svf/jtag.svfAstScan.pas | 438 +++ src.jtag/svf/jtag.svfAstState.pas | 168 + src.jtag/svf/jtag.svfFreq.pas | 35 + src.jtag/svf/jtag.svfLex.pas | 515 +++ src.jtag/svf/jtag.svfPar.pas | 424 +++ src.jtag/svf/jtag.svfProgram.pas | 155 + src.jtag/svf2/jtag.svf2.pas | 1333 ++++++++ src.jtag/vme/jtag.vme.pas | 2900 +++++++++++++++++ src.jtag/vme/jtag.vme.tools.pas | 46 + 35 files changed, 11750 insertions(+) create mode 100644 .gitignore create mode 100644 doc/svf.pdf create mode 100644 doc/xapp503.pdf create mode 100644 prj.jtag/Delphi12Athens/mr.jtag.dpk create mode 100644 prj.jtag/Delphi12Athens/mr.jtag.dproj create mode 100644 src.jtag/jtag.bstream.pas create mode 100644 src.jtag/jtag.types.pas create mode 100644 src.jtag/svf/grammar/jtag.svfLexer.g create mode 100644 src.jtag/svf/grammar/jtag.svfLexer.pas create mode 100644 src.jtag/svf/grammar/jtag.svfLexerTokens.pas create mode 100644 src.jtag/svf/grammar/jtag.svfLexerTokens.txt create mode 100644 src.jtag/svf/grammar/jtag.svfParser.g create mode 100644 src.jtag/svf/grammar/jtag.svfParser.pas create mode 100644 src.jtag/svf/grammar/jtag.svfParserTokens.pas create mode 100644 src.jtag/svf/grammar/jtag.svfParserTokens.txt create mode 100644 src.jtag/svf/grammar/jtag.svfScanLexer.g create mode 100644 src.jtag/svf/grammar/jtag.svfScanLexer.pas create mode 100644 src.jtag/svf/grammar/jtag.svfScanLexerTokens.pas create mode 100644 src.jtag/svf/grammar/jtag.svfScanLexerTokens.txt create mode 100644 src.jtag/svf/jtag.svfAstComment.pas create mode 100644 src.jtag/svf/jtag.svfAstEndDR.pas create mode 100644 src.jtag/svf/jtag.svfAstEndIR.pas create mode 100644 src.jtag/svf/jtag.svfAstFreq.pas create mode 100644 src.jtag/svf/jtag.svfAstNode.pas create mode 100644 src.jtag/svf/jtag.svfAstPrint.pas create mode 100644 src.jtag/svf/jtag.svfAstRuntest.pas create mode 100644 src.jtag/svf/jtag.svfAstScan.pas create mode 100644 src.jtag/svf/jtag.svfAstState.pas create mode 100644 src.jtag/svf/jtag.svfFreq.pas create mode 100644 src.jtag/svf/jtag.svfLex.pas create mode 100644 src.jtag/svf/jtag.svfPar.pas create mode 100644 src.jtag/svf/jtag.svfProgram.pas create mode 100644 src.jtag/svf2/jtag.svf2.pas create mode 100644 src.jtag/vme/jtag.vme.pas create mode 100644 src.jtag/vme/jtag.vme.tools.pas diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ddfb82f --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*.dcu +*.exe +*.res + +*.identcache +*.local +*.dsk +*.dsv + diff --git a/doc/svf.pdf b/doc/svf.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ab421f1e46bdf8f41a145d1dfe20053702c05333 GIT binary patch literal 87261 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≶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.WL@?4ktS9 z!10N0G9-k+(Hf)x4(A{Ru*ZWGz%D_t4OFo8YC&;iW@w~fZfOLHXXGLs z6fOvhor_WvL1n*&Z)S2)esO+Ui9&dOQHp{lFPA=8E;B#RC9xz`K_fghB`>u&C9zUR z!8freIYYtFKu5vQ($Z4F!phLd%Gg-J(HEpEB(o$ZRY4;-%uO%A#SJ9lSXz>iU!aSJcXEJ-a=FxE3LQb@}$QV7q?OUW-U z2C4T>tt`(kN-0**0P%uLld@8iOTZjtuYpn@!fW6hqyP?R(6ACDteg`|5_9s?dAamm zQqvMkb4uKc5-Sxf!6A`LRtUBtTHiS_2c(&o3tTsbXJnS72IObv zl_*3T=vkVX7%Lbm80c9TnHqv(K;JzvH#bqiP|s2UVqz?KL=S8f*dj0sY-o_X6G>)9 zgA9dXP*LKWSW=W(0dj^ZsIt;CvNSMOFwiqFG6zw{MrI}o26|>DmX-Gcqu+Kr_$6*Z>s$ zDC!Ih3_yi1s+ggXsX2yTV^G#ZQ)g+4>1Gp9A&aig7~Q`H#^#_h8C9K;0jMxR6*D$B zutal%0drb@sF~Y#o)WR4o zTnvqkK$Q!MUPBX0Q*^%>8k>OXJal!&=y7RbY>pvjXl`kUuFlZZ&;&!w9Mlm2S%L7c zk)eSBdb%>SFf=eg^M{dvC5GRO4b3sa#mLYQbZa2U5_nh{8=7O}El?IWLbJoz&=Mn# zjE&4N!r9maGpsC33^CHUv5|!Vh8-p*Mi^q|CZL)U)y*bm##q#up@)^Rg$bxdfvVTs z3{-xhidmR|DoqqI6GJ16JOe6*(9@8Kp^-UyUNymzKTHfwOij_k)WpOTqYN`KGsK7w z6BBa-3_Hv)!_>sm2-JK-@rQ+p5vILn#u(|;#L~zB-F>Eph8SUQVrhaAZ>ENz-Z;ow zMA|hqF~qRL)X*3s>`hG!4bjuHskt#myqTI98(~q0;a@WYV^AFgatu6;o0@}0Qb0lo z_n8?Oo1^DJb4vrz{WTzkaJ^;*rWo;SZfSr~-kV!mnxLmY3ln2dm5E}Wxg}4 zf-|d9!Bw?>P=0=i0;p{SY6f}crR9TKCJJDVi$b)GWum2Fl8LE_p@CtdiK&61p{0?z sfw57Ng+;Q3d7_Dl9bpx*kTy+mNn%k6q?KS{Y6uz=R8@8LcjM&(02W$(J^%m! literal 0 HcmV?d00001 diff --git a/doc/xapp503.pdf b/doc/xapp503.pdf new file mode 100644 index 0000000000000000000000000000000000000000..2707fb6de2f472e7b884763a80b2a7a485f22e71 GIT binary patch literal 251306 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 z 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 z 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 O49$&sRaIU6-FN{&qKXIr literal 0 HcmV?d00001 diff --git a/prj.jtag/Delphi12Athens/mr.jtag.dpk b/prj.jtag/Delphi12Athens/mr.jtag.dpk new file mode 100644 index 0000000..7506c04 --- /dev/null +++ b/prj.jtag/Delphi12Athens/mr.jtag.dpk @@ -0,0 +1,58 @@ +package mr.jtag; + +{$R *.res} +{$IFDEF IMPLICITBUILDING This IFDEF should not be used by users} +{$ALIGN 8} +{$ASSERTIONS ON} +{$BOOLEVAL OFF} +{$DEBUGINFO OFF} +{$EXTENDEDSYNTAX ON} +{$IMPORTEDDATA ON} +{$IOCHECKS ON} +{$LOCALSYMBOLS ON} +{$LONGSTRINGS ON} +{$OPENSTRINGS ON} +{$OPTIMIZATION OFF} +{$OVERFLOWCHECKS ON} +{$RANGECHECKS ON} +{$REFERENCEINFO ON} +{$SAFEDIVIDE OFF} +{$STACKFRAMES ON} +{$TYPEDADDRESS OFF} +{$VARSTRINGCHECKS ON} +{$WRITEABLECONST OFF} +{$MINENUMSIZE 1} +{$IMAGEBASE $400000} +{$DEFINE DEBUG} +{$ENDIF IMPLICITBUILDING} +{$LIBVERSION '290'} +{$IMPLICITBUILD ON} + +requires + rtl, + vcl; + +contains + jtag.bstream in '..\..\src.jtag\jtag.bstream.pas', + jtag.types in '..\..\src.jtag\jtag.types.pas', + jtag.svfAstComment in '..\..\src.jtag\svf\jtag.svfAstComment.pas', + jtag.svfAstEndDR in '..\..\src.jtag\svf\jtag.svfAstEndDR.pas', + jtag.svfAstEndIR in '..\..\src.jtag\svf\jtag.svfAstEndIR.pas', + jtag.svfAstFreq in '..\..\src.jtag\svf\jtag.svfAstFreq.pas', + jtag.svfAstNode in '..\..\src.jtag\svf\jtag.svfAstNode.pas', + jtag.svfAstPrint in '..\..\src.jtag\svf\jtag.svfAstPrint.pas', + jtag.svfAstRuntest in '..\..\src.jtag\svf\jtag.svfAstRuntest.pas', + jtag.svfAstScan in '..\..\src.jtag\svf\jtag.svfAstScan.pas', + jtag.svfAstState in '..\..\src.jtag\svf\jtag.svfAstState.pas', + jtag.svfFreq in '..\..\src.jtag\svf\jtag.svfFreq.pas', + jtag.svfLex in '..\..\src.jtag\svf\jtag.svfLex.pas', + jtag.svfPar in '..\..\src.jtag\svf\jtag.svfPar.pas', + jtag.svfProgram in '..\..\src.jtag\svf\jtag.svfProgram.pas', + jtag.svfLexer in '..\..\src.jtag\svf\grammar\jtag.svfLexer.pas', + jtag.svfLexerTokens in '..\..\src.jtag\svf\grammar\jtag.svfLexerTokens.pas', + jtag.svfParser in '..\..\src.jtag\svf\grammar\jtag.svfParser.pas', + jtag.svfParserTokens in '..\..\src.jtag\svf\grammar\jtag.svfParserTokens.pas', + jtag.svfScanLexer in '..\..\src.jtag\svf\grammar\jtag.svfScanLexer.pas', + jtag.svfScanLexerTokens in '..\..\src.jtag\svf\grammar\jtag.svfScanLexerTokens.pas'; + +end. diff --git a/prj.jtag/Delphi12Athens/mr.jtag.dproj b/prj.jtag/Delphi12Athens/mr.jtag.dproj new file mode 100644 index 0000000..e33922a --- /dev/null +++ b/prj.jtag/Delphi12Athens/mr.jtag.dproj @@ -0,0 +1,1025 @@ + + + {170520DD-7A28-4FC8-B9F7-197528EE4BC3} + mr.jtag.dpk + 20.3 + VCL + True + Debug + Win32 + mr.jtag + 1 + Package + + + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + ..\..\dcu\Delphi12Athens\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + true + true + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + mr_jtag + 1033 + CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= + 290 + + + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + Debug + true + + + DEBUG;$(DCC_Define) + true + false + true + true + true + true + true + + + false + true + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + true + + + + MainSource + + + + + + + + + + + + + + + + + + + + + + + + + + Base + + + Cfg_1 + Base + + + Cfg_2 + Base + + + + Delphi.Personality.12 + Package + + + + mr.jtag.dpk + + + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + + + true + + + + + true + + + + + true + + + + + mr.jtag.bpl + true + + + + + 1 + + + 0 + + + + + res\xml + 1 + + + res\xml + 1 + + + + + library\lib\armeabi + 1 + + + library\lib\armeabi + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + library\lib\mips + 1 + + + library\lib\mips + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-anydpi-v21 + 1 + + + res\drawable-anydpi-v21 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-v21 + 1 + + + res\values-v21 + 1 + + + + + res\values-v31 + 1 + + + res\values-v31 + 1 + + + + + res\values-v35 + 1 + + + res\values-v35 + 1 + + + + + res\drawable-anydpi-v26 + 1 + + + res\drawable-anydpi-v26 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-anydpi-v33 + 1 + + + res\drawable-anydpi-v33 + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\values-night-v21 + 1 + + + res\values-night-v21 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-ldpi + 1 + + + res\drawable-ldpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-mdpi + 1 + + + res\drawable-mdpi + 1 + + + + + res\drawable-hdpi + 1 + + + res\drawable-hdpi + 1 + + + + + res\drawable-xhdpi + 1 + + + res\drawable-xhdpi + 1 + + + + + res\drawable-xxhdpi + 1 + + + res\drawable-xxhdpi + 1 + + + + + res\drawable-xxxhdpi + 1 + + + res\drawable-xxxhdpi + 1 + + + + + res\drawable-small + 1 + + + res\drawable-small + 1 + + + + + res\drawable-normal + 1 + + + res\drawable-normal + 1 + + + + + res\drawable-large + 1 + + + res\drawable-large + 1 + + + + + res\drawable-xlarge + 1 + + + res\drawable-xlarge + 1 + + + + + res\values + 1 + + + res\values + 1 + + + + + res\drawable-anydpi-v24 + 1 + + + res\drawable-anydpi-v24 + 1 + + + + + res\drawable + 1 + + + res\drawable + 1 + + + + + res\drawable-night-anydpi-v21 + 1 + + + res\drawable-night-anydpi-v21 + 1 + + + + + res\drawable-anydpi-v31 + 1 + + + res\drawable-anydpi-v31 + 1 + + + + + res\drawable-night-anydpi-v31 + 1 + + + res\drawable-night-anydpi-v31 + 1 + + + + + 1 + + + 1 + + + 0 + + + + + 1 + .framework + + + 1 + .framework + + + 1 + .framework + + + 0 + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 0 + .dll;.bpl + + + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 0 + .bpl + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 1 + + + 1 + + + + + + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + Contents\Resources + 1 + + + + + library\lib\armeabi-v7a + 1 + + + library\lib\arm64-v8a + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 1 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + + + + 1 + + + 1 + + + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + Assets + 1 + + + Assets + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\LaunchScreenImage.imageset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + ..\$(PROJECTNAME).launchscreen\Assets\AppIcon.appiconset + 1 + + + + + + + + + + + + + + + + + True + False + False + + + 12 + + + + + diff --git a/src.jtag/jtag.bstream.pas b/src.jtag/jtag.bstream.pas new file mode 100644 index 0000000..6f046c6 --- /dev/null +++ b/src.jtag/jtag.bstream.pas @@ -0,0 +1,1128 @@ +unit jtag.bstream; + +interface + +uses + Classes, + Types, + jtag.svfAstScan, + jtag.svfAstRuntest, + jtag.svfAstState; + +type + TjtagBStream = class; + + TjtagCepMode = (cmNone, cmRead, cmWrite); + + TjtagTapState = (stInvalid, stReset, stIdle, stDrScan, stIrScan, + stDrCapture, stIrCapture, stDrShift, stIrShift, stDrExit1, stIrExit1, + stDrPause, stIrPause, stDrExit2, stIrExit2, stDrUpdate, stIrUpdate); + + TjtagOnFullEvent = procedure(Sender: TjtagBStream; + CEPMode: TjtagCepMode) of object; + + TjtagOnDumpEvent = procedure( Sender: TjtagBStream; Data: string) of object; + + TjtagBStream = class + protected + fBufTDI: array [0 .. 1023] of byte; + fBufTDO: array [0 .. 1023] of byte; + fBufSMASK: array [0 .. 1023] of byte; + fBufMASK: array [0 .. 1023] of byte; + + fInitDone: boolean; + fBufferSize: word; + fBuffer: array [0 .. 1023] of byte; + fCursor : word; + fCursorR : word; + + fEndDR: TjtagTapState; + fEndIR: TjtagTapState; + + fMaskTCK: byte; + fMaskTMS: byte; + fMaskTDI: byte; + fMaskTDO: byte; + fMaskTRST: byte; + fMaskENA: byte; + fMaskPWR: byte; + + // current value of the pins + fValTCK: byte; + fValTMS: byte; + fValTDI: byte; + fValTDO: byte; + fValTRST: byte; + fValENA: byte; + fValPWR: byte; + + fCEPMode: TjtagCepMode; + + fLastCEPMode: TjtagCepMode; + fLastWrite: integer; + + // events + fOnFull: TjtagOnFullEvent; + fOnDump: TjtagOnDumpEvent; + + // ------------------------------------------------------------ + // JTAG TAP state machine + // ------------------------------------------------------------ + protected + fState: TjtagTapState; + + function FlipByte( Data: byte): byte; + + + // ------------------------------------------------------------ + public + procedure SendBit(TDI: byte; TMS: byte); + + procedure SendByte(Value: byte; length: byte; last: boolean = false); + overload; + + procedure SendByte(TDI: byte; TDO: byte; SMASK: byte; MASK: byte; + length: word; last: boolean = false); overload; + + function ReceiveByte(length: byte): byte; + + // ------------------------------------------------------------ + // Property handlers + // ------------------------------------------------------------ + private + function GetData(i: word): byte; + procedure SetData(i: word; d: byte); + + procedure SetState(newState: TjtagTapState); + procedure SetEndDR(Value: TjtagTapState); + procedure SetEndIR(Value: TjtagTapState); + + + + protected + procedure Init(BufferSize: word; TCK: byte; TMS: byte; TDI: byte; + TDO: byte; TRST: byte; ENA: byte; PWR: byte); + + public + procedure InitDsoJtag; + procedure InitPrgJtag; + + procedure Clear; + procedure Emit; + procedure Pulse(n: cardinal = 1); + procedure Flush; + + protected + fBufHIR: array [0 .. 255] of byte; + fBufTIR: array [0 .. 255] of byte; + fBufHDR: array [0 .. 255] of byte; + fBufTDR: array [0 .. 255] of byte; + + fLenHIR: integer; + fLenTIR: integer; + fLenHDR: integer; + fLenTDR: integer; + + fBitHIR: integer; + fBitTIR: integer; + fBitHDR: integer; + fBitTDR: integer; + + procedure SendHTIDR(stmt: TsvfAstScan); + + public + procedure Send(stmt: TsvfAstScan); overload; + procedure Send(stmt: TsvfAstRuntest); overload; + procedure Send(stmt: TsvfAstState); overload; + + public + procedure AfterConstruction; override; + procedure BeforeDestruction; override; + + public + property Size: word read fBufferSize; + property DataSize: word read fCursor; + property Data[i: word]: byte read GetData write SetData; + + property CEPMode: TjtagCepMode read fCEPMode write fCEPMode; + + property State: TjtagTapState read fState write SetState; + property EndDR: TjtagTapState read fEndDR write SetEndDR; + property EndIR: TjtagTapState read fEndIR write SetEndIR; + + property TCK: byte read fValTCK write fValTCK; + property TMS: byte read fValTMS write fValTMS; + property TDI: byte read fValTDI write fValTDI; + property TRST: byte read fValTRST write fValTRST; + property ENA: byte read fValENA write fValENA; + + public + property OnFull: TjtagOnFullEvent read fOnFull write fOnFull; + property OnDump: TjtagOnDumpEvent read fOnDump write fOnDump; + + end; + +implementation + +uses + Vcl.Forms, + Windows, + SysUtils; + +{ TjtagBStream } + +{ TjtagBStream } + +// @@@: Construction/destruction ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// Construction/destruction +// +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +// ================================================================================================ +// AfterConstruction +// ================================================================================================ +procedure TjtagBStream.AfterConstruction; +begin + inherited; + + fMaskTCK := 0; + fMaskTMS := 0; + fMaskTDI := 0; + fMaskTDO := 0; + fMaskTRST := 0; + fMaskENA := 0; + fMaskPWR := 0; + + fCursor := 0; + fState := stInvalid; + + fEndDR := stIdle; + fEndIR := stIdle; + + fLastWrite := 0; + fCEPMode := cmNone; +end; + +// ================================================================================================ +// BeforeDestruction +// ================================================================================================ +procedure TjtagBStream.BeforeDestruction; +begin + + inherited; +end; + +// ================================================================================================ +// Init +// ================================================================================================ +procedure TjtagBStream.Init(BufferSize: word; TCK, TMS, TDI, TDO, TRST, ENA, + 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 TjtagBStream.InitDsoJtag; +begin + Init(256, 0, 1, 3, 7, $FF, $FF, $FF); +end; + +// ================================================================================================ +// InitPrgJtag +// ================================================================================================ +procedure TjtagBStream.InitPrgJtag; +begin + Init(256, 0, 1, 7, 3, 5, 4, 6); +end; + + +// @@@: JTAG TAP state machine interface ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// JTAG TAP state machine interface +// +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +// ================================================================================================ +// State +// ================================================================================================ +procedure TjtagBStream.SetState(newState: TjtagTapState); +var + i: integer; + rc: boolean; + +begin + rc := true; + + // ----------------------------------------------------- + // xxx -> RESET + // ----------------------------------------------------- + if newState = stReset then + for i := 0 to 4 do + SendBit(0, 1) + + // ----------------------------------------------------- + // IDLE + // ----------------------------------------------------- + else if newState = stIdle then + begin + case fState of + stReset: + begin + SendBit(0, 0); + end; + + stDrShift, stDrPause, stIrShift, stIrPause: + begin + SendBit(0, 1); + SendBit(0, 1); + SendBit(0, 0); + end; + + stDrExit1, stIrExit1: + begin + SendBit(0, 1); + SendBit(0, 0); + end; + + else + rc := false; + end; + end + + // ----------------------------------------------------- + // DRSHIFT + // ----------------------------------------------------- + else if newState = stDrShift then + begin + case fState of + stReset: + begin + SendBit(0, 0); // IDLE + SendBit(0, 1); // DRSELECT + SendBit(0, 0); // DRCAPTURE + SendBit(0, 0); // DRSHIFT + end; + + stIdle: + begin + SendBit(0, 1); // DRSELECT + SendBit(0, 0); // DRCAPTURE + SendBit(0, 0); // DRSHIFT + end; + + stDrPause: + begin + SendBit(0, 1); // DREXIT2 + SendBit(0, 0); // DRSHIFT + end; + + else + rc := false; + end; + end + + // ----------------------------------------------------- + // IRSHIFT + // ----------------------------------------------------- + else if newState = stIrShift then + begin + case fState of + stReset: + begin + SendBit(0, 0); // IDLE + SendBit(0, 1); // DRSELECT + SendBit(0, 1); // IRSELECT + SendBit(0, 0); // IRCAPTURE + SendBit(0, 0); // IRSHIFT + end; + + stIdle: + begin + SendBit(0, 1); // DRSELECT + SendBit(0, 1); // IRSELECT + SendBit(0, 0); // IRCAPTURE + SendBit(0, 0); // IRSHIFT + end; + + stIrPause: + begin + SendBit(0, 1); // IREXIT2 + SendBit(0, 0); // IRSHIFT + end; + + else + rc := false; + end; + end + + // ----------------------------------------------------- + // DRPAUSE + // ----------------------------------------------------- + else if newState = stDrPause then + begin + case fState of + stReset: + begin + SendBit(0, 0); // IDLE + SendBit(0, 1); // DRSELECT + SendBit(0, 0); // DRCAPTURE + SendBit(0, 1); // DREXIT1 + SendBit(0, 0); // DRPAUSE + end; + + stIdle: + begin + SendBit(0, 1); // DRSELECT + SendBit(0, 0); // DRCAPTURE + SendBit(0, 1); // DREXIT1 + SendBit(0, 0); // DRPAUSE + end; + + stDrShift: + begin + SendBit(0, 1); // DREXIT1 + SendBit(0, 0); // DRPAUSE + end; + + else + rc := false; + end; + end + + // ----------------------------------------------------- + // IRPAUSE + // ----------------------------------------------------- + else if newState = stIrPause then + begin + case fState of + stReset: + begin + SendBit(0, 0); // IDLE + SendBit(0, 1); // DRSELECT + SendBit(0, 1); // IRSELECT + SendBit(0, 0); // IRCAPTURE + SendBit(0, 1); // IREXIT1 + SendBit(0, 0); // IRPAUSE + end; + + stIdle: + begin + SendBit(0, 1); // DRSELECT + SendBit(0, 1); // IRSELECT + SendBit(0, 0); // IRCAPTURE + SendBit(0, 1); // IREXIT1 + SendBit(0, 0); // IRPAUSE + end; + + stIrShift: + begin + SendBit(0, 1); // IREXIT1 + SendBit(0, 0); // IRPAUSE + end; + + else + rc := false; + end; + end; + + if rc then + fState := newState; +end; + +// ================================================================================================ +// Pulse +// ================================================================================================ +procedure TjtagBStream.Pulse(n: cardinal); +var + i: cardinal; + +begin + for i := 0 to n - 1 do + begin + fValTCK := 0; + Emit; + fValTCK := 1; + Emit; + end; +end; + +// ================================================================================================ +// Emit +// ================================================================================================ +procedure TjtagBStream.Emit; +var + b: byte; + +begin + b := 0; + + if fValTCK <> 0 then + b := b or fMaskTCK; + if fValTMS <> 0 then + b := b or fMaskTMS; + if fValTDI <> 0 then + b := b or fMaskTDI; + if fValTRST <> 0 then + b := b or fMaskTRST; + if fValENA = 0 then + b := b or fMaskENA; + + fBuffer[fCursor] := b; + INC(fCursor); + + if fCursor > fBufferSize - 1 then + Flush; +end; + +// ================================================================================================ +// Flush +// ================================================================================================ +procedure TjtagBStream.Flush; +begin + if Assigned(fOnFull) then + fOnFull(self, fCEPMode); + + fCursor := 0; + fCursorR := 0; +end; + +function TjtagBStream.FlipByte(Data: byte): byte; +var + i: integer; + +begin + result := 0; + + for i:=0 to 7 do + begin + result := result shl 1; + + if Data and $01 = $01 then + result := result or $1; + + Data := Data shr 1; + end; +end; + +// ================================================================================================ +// Clear +// ================================================================================================ +procedure TjtagBStream.Clear; +var + i: integer; + b: byte; + +begin + b := 0; + + if fValTCK <> 0 then + b := b or fMaskTCK; + if fValTMS <> 0 then + b := b or fMaskTMS; + if fValTDI <> 0 then + b := b or fMaskTDI; + if fValTRST <> 0 then + b := b or fMaskTRST; + if fValENA <> 0 then + b := b or fMaskENA; + + for i := 0 to 1023 do + fBuffer[i] := b; + + fCursor := 0; +end; + +// ================================================================================================ +// SendBit +// ================================================================================================ +procedure TjtagBStream.SendBit(TDI: byte; TMS: byte); +begin + fValTDI := TDI; + fValTMS := TMS; + + Pulse; +end; + +// ================================================================================================ +// SendByte +// +// Send entire byte to the device. If 'last' is 1, TMS will be high for the last bit transmitted, +// forcing transition to EXIT1 state. From EXIT1 state the TAP state will be moved to the specified +// end state, automatically. +// ================================================================================================ +procedure TjtagBStream.SendByte(Value: byte; length: byte; last: boolean); +var + i: integer; + xtdi: byte; + xtms: byte; + val: byte; + +begin + val := Value; + + if (length > 0) and (length < 9) then + begin + for i := 0 to length - 1 do + begin +// xtdi := val and $01; +// val := val shr 1; + + if val and $80 = $80 + then xtdi := 1 + else xtdi := 0; + + val := val shl 1; + + if last and (i = length - 1) + then xtms := 1 + else xtms := 0; + + SendBit(xtdi, xtms); + end; + + if last then + begin + if fState = stDrShift then + begin + fState := stDrExit1; + SetState(fEndDR); + end + + else if fState = stIrShift then + begin + fState := stIrExit1; + SetState(fEndIR); + end + end + end +end; + +// ================================================================================================ +// SendByte +// +// Send entire byte to the device. If 'last' is 1, TMS will be high for the last bit transmitted, +// forcing transition to EXIT1 state. From EXIT1 state the TAP state will be moved to the specified +// end state, automatically. +// ================================================================================================ +procedure TjtagBStream.SendByte(TDI: byte; TDO: byte; SMASK: byte; MASK: byte; + length: word; last: boolean = false); + +begin + +end; + +// ================================================================================================ +// ReceiveByte +// ================================================================================================ +function TjtagBStream.ReceiveByte(length: byte): byte; +var + i: integer; + +begin + result := 0; + + for i := 0 to length - 1 do + begin + if (fBuffer[fCursorR] and fMaskTDO) <> 0 then + result := result or (1 shl i); + + INC(fCursorR, 2); + end; +end; + + +// @@@: Property Handlers +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// Property Handlers +// +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +// ================================================================================================ +// GetData +// ================================================================================================ +function TjtagBStream.GetData(i: word): byte; +begin + if i < 1024 then + result := fBuffer[i] + else + result := 0; +end; + +// ================================================================================================ +// SetData +// ================================================================================================ +procedure TjtagBStream.SetData(i: word; d: byte); +begin + if i < 1024 then + fBuffer[i] := d; +// fBuffer[i] := d and fMaskTDO; + + fCursor := 0; +end; + +// ================================================================================================ +// SetEndDR +// ================================================================================================ +procedure TjtagBStream.SetEndDR(Value: TjtagTapState); +begin + if Value in [stReset, stIdle, stDrPause] then + fEndDR := Value; +end; + +// ================================================================================================ +// SetEndIR +// ================================================================================================ +procedure TjtagBStream.SetEndIR(Value: TjtagTapState); +begin + if Value in [stReset, stIdle, stIrPause] then + fEndIR := Value; +end; + + + +// @@@: Send SVF statements +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// Send SVF statements +// +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +// ================================================================================================ +// SendHTIDR +// ================================================================================================ +procedure TjtagBStream.SendHTIDR(stmt: TsvfAstScan); +var + i: integer; + +begin + // ------------------------------------------- + // Header Instruction Register + // ------------------------------------------- + if stmt.Inst = 'HIR' then + begin + fLenHIR := stmt.LenTDI; + fBitHIR := stmt.Bits; + + for i := 0 to fLenHIR - 1 do + fBufHIR[i] := stmt.DataTDI[i] + + // if stmt.LenTDI = stmt.LenSMASK + // then for i:=0 to fLenHIR -1 do fBufHIR[i] := stmt.DataTDI[i] and stmt.DataSMASK[i] + // else for i:=0 to fLenHIR -1 do fBufHIR[i] := stmt.DataTDI[i] + end + + // ------------------------------------------- + // Trailer Instruction Register + // ------------------------------------------- + else if stmt.Inst = 'TIR' then + begin + fLenTIR := stmt.LenTDI; + fBitTIR := stmt.Bits; + + for i := 0 to fLenTIR - 1 do + fBufTIR[i] := stmt.DataTDI[i] + + // if stmt.LenTDI = stmt.LenSMASK + // then for i:=0 to fLenTIR -1 do fBufTIR[i] := stmt.DataTDI[i] and stmt.DataSMASK[i] + // else for i:=0 to fLenTIR -1 do fBufTIR[i] := stmt.DataTDI[i] + end + + // ------------------------------------------- + // Header Data Register + // ------------------------------------------- + else if stmt.Inst = 'HDR' then + begin + fLenHDR := stmt.LenTDI; + fBitHDR := stmt.Bits; + + for i := 0 to fLenHDR - 1 do + fBufHDR[i] := stmt.DataTDI[i] + + // if stmt.LenTDI = stmt.LenSMASK + // then for i:=0 to fLenHDR -1 do fBufHDR[i] := stmt.DataTDI[i] and stmt.DataSMASK[i] + // else for i:=0 to fLenHDR -1 do fBufHDR[i] := stmt.DataTDI[i] + end + + // ------------------------------------------- + // Trailer Data Register + // ------------------------------------------- + else if stmt.Inst = 'TDR' then + begin + fLenTDR := stmt.LenTDI; + fBitTDR := stmt.Bits; + + for i := 0 to fLenTDR - 1 do + fBufTDR[i] := stmt.DataTDI[i] + + // if stmt.LenTDI = stmt.LenSMASK + // then for i:=0 to fLenTDR -1 do fBufTDR[i] := stmt.DataTDI[i] and stmt.DataSMASK[i] + // else for i:=0 to fLenTDR -1 do fBufTDR[i] := stmt.DataTDI[i] + end +end; + +// ================================================================================================ +// SCAN +// +// Note: Scan statements may define TDO values to check the result from the device. The data length +// of these kind of statements must be less then 512 bits. The checking of the result will be +// done in thos routine, because the bstream will be fulshed before data sending, so the +// buffer will contain the data that must be checked. The event handler must fill then data +// buffer with the readed data. +// ================================================================================================ +procedure TjtagBStream.Send(stmt: TsvfAstScan); +var + i: integer; + n: integer; + b: integer; + l: boolean; + s: string; + t: string; + + x1: byte; + x2: byte; + + zm : boolean; + d : boolean; + +begin + if (stmt.Inst = 'HIR') or + (stmt.Inst = 'TIR') or + (stmt.Inst = 'HDR') or + (stmt.Inst = 'TDR') then + SendHTIDR(stmt) + + // --------------------------------------------------------------- + // SIR + // --------------------------------------------------------------- + else if stmt.Inst = 'SIR' then + begin + // ---------------------------------------- + // Move to IRSHIFT + // ---------------------------------------- + fCEPMode := cmWrite; + State := stIrShift; + + // ---------------------------------------- + // If output checking is necessary, then + // first flush the stream. + // All SIR statement that needs checking + // must fit in one package. + // ---------------------------------------- + if stmt.LenTDI = stmt.LenTDO then + begin + Flush; + fCEPMode := cmRead; + end; + + // ---------------------------------------- + // Send HIR + // ---------------------------------------- + b := fBitHIR mod 8; + if b = 0 then + b := 8; + + for i := 0 to fLenHIR - 1 do + if i <> fLenHIR - 1 then + SendByte(fBufHIR[i], 8) + else + SendByte(fBufHIR[i], b); + + // ---------------------------------------- + // Send SIR + // ---------------------------------------- + b := stmt.Bits mod 8; + if b = 0 then + b := 8; + + l := fBitTIR = 0; + n := (stmt.Bits +7) div 8; +// for i := 0 to stmt.LenTDI - 1 do + + for i := 0 to n - 1 do + if i <> n - 1 + then SendByte(stmt.DataTDI[i], 8) + else SendByte(stmt.DataTDI[i], b, l); + + // ---------------------------------------- + // Send TIR + // ---------------------------------------- + b := fBitTIR mod 8; + if b = 0 then + b := 8; + + for i := 0 to fLenTIR - 1 do + if i <> fLenTIR - 1 + then SendByte(fBufTIR[i], 8) + else SendByte(fBufTIR[i], b, true); + + // ---------------------------------------- + if stmt.LenTDI = stmt.LenTDO then + begin + Flush; + + // ------------------------------------- + // Skip head data + // ------------------------------------- + b := fBitHIR mod 8; + if b = 0 then + b := 8; + + for i := 0 to fLenHIR - 1 do + if i <> fLenHIR - 1 + then ReceiveByte(8) + else ReceiveByte(b); + + // ------------------------------------- + // Check result + // fBuffer contains the readed data. + // ------------------------------------- + for i := 0 to stmt.LenTDI - 1 do + begin + if stmt.LenMASK = stmt.LenTDI then + begin + x1 := ReceiveByte(8) and stmt.DataMASK[i]; + x2 := stmt.DataTDO[i] and stmt.DataMASK[i]; + end + + else + begin + x1 := ReceiveByte(8); + x2 := stmt.DataTDO[i]; + end; + + s := Format('SIR:[%2.2x, %2.2x]', [x1, x2]); + + if Assigned(OnDump) then + OnDump( self, s); + + Application.ProcessMessages; + end; + + fCEPMode := cmWrite; + end; + end + + // --------------------------------------------------------------- + // SDR + // --------------------------------------------------------------- + else if stmt.Inst = 'SDR' then + begin + n := (stmt.Bits +7) div 8; + + // ---------------------------------------- + // Move to DRSHIFT + // ---------------------------------------- + fCEPMode := cmWrite; + State := stDrShift; + + // ---------------------------------------- + // If output checking is necessary, then + // first flush the stream. + // All SDR statement that needs checking + // can fit in one package. + // ---------------------------------------- + if stmt.LenTDI = stmt.LenTDO then + begin + Flush; + fCEPMode := cmRead; + end; + + // ---------------------------------------- + // Send HDR + // ---------------------------------------- + b := fBitHDR mod 8; + if b = 0 then + b := 8; + + for i := 0 to fLenHDR - 1 do + if i <> fLenHDR - 1 + then SendByte(fBufHDR[i], 8) + else SendByte(fBufHDR[i], b); + + // ---------------------------------------- + // Send SDR + // ---------------------------------------- + b := stmt.Bits mod 8; + if b = 0 then + b := 8; + + l := fBitTDR = 0; + +// for i := 0 to stmt.LenTDI - 1 do + for i := 0 to n - 1 do + begin + if i <> n - 1 + then SendByte(stmt.DataTDI[i], 8) + else SendByte(stmt.DataTDI[i], b, l); + + Application.ProcessMessages; + end; + + // ---------------------------------------- + // Send TDR + // ---------------------------------------- + b := fBitTDR mod 8; + if b = 0 then + b := 8; + + for i := 0 to fLenTDR - 1 do + if i <> fLenTDR - 1 + then SendByte(fBufTDR[i], 8) + else SendByte(fBufTDR[i], b, true); + + // ---------------------------------------- + // Check result if any + // ---------------------------------------- + if (stmt.LenTDI = stmt.LenTDO) and (stmt.LenTDI < 129)then + begin + Flush; + + // ------------------------------------- + // Skip head data + // ------------------------------------- + b := fBitHDR mod 8; + if b = 0 then + b := 8; + + for i := 0 to fBitHDR - 1 do + if i <> n - 1 + then x1 := ReceiveByte(8) + else x1 := ReceiveByte(b); + + // ------------------------------------- + // Check result + // fBuffer contains the readed data. + // ------------------------------------- + s := ''; + t := ''; + + // ------------------------------------- + // If MASK is 0000...00 then don't mask + // the data. In this case, the data must + // be dumped only. + // It is a Read operation without check! + // ------------------------------------- + zm := false; + + if stmt.LenMASK = stmt.LenTDO then + begin + zm := true; + + for i:=0 to n-1 do + if stmt.DataMASK[i] <> 0 then + begin + zm := false; + break; + end; + end; + + for i := 0 to n - 1 do + begin + if (stmt.LenSMASK = stmt.LenTDI) and (not zm) + then x1 := ReceiveByte(8) and FlipByte(stmt.DataSMASK[i]) + else x1 := ReceiveByte(8); + + if (stmt.LenMASK = stmt.LenTDO) and (not zm) + then x2 := stmt.DataTDO[i] and FlipByte(stmt.DataMASK[i]) + else x2 := stmt.DataTDO[i]; + + s := Format('%2.2x',[(x1)]) +s; + t := Format('%2.2x',[(x2)]) +t; + + Application.ProcessMessages; + end; + + if Assigned(fOnDump) then + begin + // if mask is zero, then simply dump data ... + if zm then + fOnDump( self, s) + + // ... else check for difference + else begin + d := false; + + for i:=1 to Length(s) do + begin + x1 := ord(s[i]); + x2 := ord(t[i]); + + if ((x1 and x2) <> x2) and (x2 <> 0) then + begin + d := true; + break + end; + end; + + if d then + begin + fOnDump(self,':: '+t); + fOnDump(self,'>> '+s); + end; + end; + end; + + fCEPMode := cmWrite; + end; + + Application.ProcessMessages; + end +end; + +// ================================================================================================ +// RUNTEST +// ================================================================================================ +procedure TjtagBStream.Send(stmt: TsvfAstRuntest); +begin + Pulse(StrToInt(stmt.RunCount)); +end; + +// ================================================================================================ +// STATE +// ================================================================================================ +procedure TjtagBStream.Send(stmt: TsvfAstState); +var + i: integer; + +begin + for i := 0 to stmt.StateCount - 1 do + begin + case stmt.States[i] of + 0: State := jtag.bstream.stReset; + 1: State := jtag.bstream.stIdle; + end + end; +end; + +end. diff --git a/src.jtag/jtag.types.pas b/src.jtag/jtag.types.pas new file mode 100644 index 0000000..91e7a5b --- /dev/null +++ b/src.jtag/jtag.types.pas @@ -0,0 +1,48 @@ +unit jtag.types; + +interface + +type + // ========================================================================= + // Keep this values synchronized with "tri.h" !!!! + // ========================================================================= + TJTAGState = + ( + TS_RESET = 0, + TS_IDLE = 1, + TS_IRPAUSE = 2, + TS_DRPAUSE = 3, + TS_IRSHIFT = 4, + TS_DRSHIFT = 5, + TS_DRCAPT = 6, + TS_IREXIT1 = 7, + TS_DREXIT1 = 8, + + TS_UNDEF = $FF + ); + + IJTAG = interface + procedure init; + procedure trst( value : BYTE); + procedure ena( value : BYTE); + + procedure endir( state : TJTAGState); + procedure enddr( state : TJTAGState); + procedure state( state : TJTAGState); + + procedure sir( data : PBYTE; length: WORD); + procedure sdr( data : PBYTE; length: WORD); + + procedure run( state : TJTAGState; count: WORD); + + procedure test; + end; + + IJTAGLOG = interface + procedure info( msg : string); + procedure warning( msg : string); + end; + +implementation + +end. diff --git a/src.jtag/svf/grammar/jtag.svfLexer.g b/src.jtag/svf/grammar/jtag.svfLexer.g new file mode 100644 index 0000000..dafe65d --- /dev/null +++ b/src.jtag/svf/grammar/jtag.svfLexer.g @@ -0,0 +1,247 @@ +unit jtag.svfLexer; + +// ---------------------------------------------------------------------------- +// This section is used for generating "uses" clause in the unit 'svfLexer'. +// Every unit name must be terminated with ';' +// e.g: +// +// uses +// { +// Classes; +// SysUtils; +// } +// ---------------------------------------------------------------------------- +uses +{ +} + +// ---------------------------------------------------------------------------- +// This section is used for generating "const" clause in the unit 'svfLexer'. +// The content of the section is verbatim copied into the generated code. +// ---------------------------------------------------------------------------- +//const +//{ +//} + +// ---------------------------------------------------------------------------- +// This section is used for generating "type" clause in the unit 'svfLexer'. +// The content of the section is verbatim copied into the generated code. +// ---------------------------------------------------------------------------- +type +{ +} + +// ============================================================================ +// Lexer class declaration +// ============================================================================ +lexer TsvfLexer; +// ---------------------------------------------------------------------------- +// Lexer options +// ---------------------------------------------------------------------------- +options +{ + k = 2; + exportVocab = jtag.svfLexer; + caseSensitive = false; +} + +// ---------------------------------------------------------------------------- +// Lexer tokens. Usualy string literals. +// ---------------------------------------------------------------------------- +tokens +{ + // ------------ + // SVF Commands + // ------------ + "ENDDR"; + "ENDIR"; + "FREQUENCY"; + "HDR"; + "HIR"; + "PIO"; + "PIOMAP"; + "RUNTEST"; + "SDR"; + "SIR"; + "STATE"; + "TDR"; + "TIR"; + "TRST"; + + // ------------ + // TAP States + // ------------ + "RESET"; + "IDLE"; + + "DRSELECT"; + "DRCAPTURE"; + "DRSHIFT"; + "DRPAUSE"; + "DREXIT1"; + "DREXIT2"; + "DRUPDATE"; + + "IRSELECT"; + "IRCAPTURE"; + "IRSHIFT"; + "IRPAUSE"; + "IREXIT1"; + "IREXIT2"; + "IRUPDATE"; + + "HZ"; + "TDI"; + "TDO"; + "MASK"; + "SMASK"; + + "IN"; + "OUT"; + "INOUT"; + + "SEC"; + "MAXIMUM"; + "ENDSTATE"; + "TCK"; + "SCK"; + + "ON"; + "OFF"; + "Z"; + "ABSENT"; + + INT; + FLOAT; +} + +// ---------------------------------------------------------------------------- +// Lexer member declarations. +// All user defined member declarations should be placed here. +// The content of the section is verbatim copied into the generated code. +// ---------------------------------------------------------------------------- +memberdecl +{ + protected + fOnNewline : TNotifyEvent; + + public + property OnNewline : TNotifyEvent read fOnNewline write fOnNewline; +} + +// ============================================================================ +// Begin rule definitions +// +// Remember: All lexer rule names must begin with UPPERCASE letter! +// ============================================================================ +SEMI : ';'; +LPAREN : '('; +RPAREN : ')'; + +ID +options +{ + testLiterals = true; +} + : ('A'..'Z' | 'a'..'z') ('A'..'Z' | 'a'..'z' | '0'..'9')* +; + +NUMBER + : + DIGITS { _ttype := TT_INT; } + ( '.' DIGITS { _ttype := TT_FLOAT;} )? + ( EXP (SIGN)? DIGITS { _ttype := TT_FLOAT;} )? + ; + +protected +VECTOR + : + 'H' | 'L' | 'Z' | 'U' | 'D' | 'X' | + 'h' | 'l' | 'z' | 'u' | 'd' | 'x' + ; + +protected +EXP + : 'E' | 'e' + ; + +protected +SIGN + : '+' | '-' + ; + +protected DIGIT : '0'..'9'; +protected DIGITS : (DIGIT)+ ; + +//protected XDIGIT : 'a'..'f' | 'A'..'F' | '0'..'9'; +//protected XDIGITS : (XDIGIT)+ ; + + + + +// ---------------------------------------------------------------------------- +// SLCOMMENT +// ---------------------------------------------------------------------------- +SLCOMMENT + : + ("//" | '!') + ( ~( '\r' | '\n') )* + ( + options + { + generateAmbigWarnings = false; + } + : '\r' '\n' { newLine; if Assigned( fOnNewline) then fOnNewline(self); } + | '\r' { newLine; if Assigned( fOnNewline) then fOnNewline(self); } + | '\n' { newLine; if Assigned( fOnNewline) then fOnNewline(self); } + ) + { + _ttype := TT_SKIP; + } + ; + +// ---------------------------------------------------------------------------- +// NEWLINE +// ---------------------------------------------------------------------------- +NEWLINE + : + ( + options + { + generateAmbigWarnings = false; + } + : '\r' '\n' { newLine; if Assigned( fOnNewline) then fOnNewline(self); } + | '\r' { newLine; if Assigned( fOnNewline) then fOnNewline(self); } + | '\n' { newLine; if Assigned( fOnNewline) then fOnNewline(self); } + ) + { + _ttype := TT_SKIP; + } + ; + +// ---------------------------------------------------------------------------- +// WHITESPACE +// ---------------------------------------------------------------------------- +WHITESPACE + : + ( + ' ' + | '\t' { tab; } + ) + { + _ttype := TT_SKIP; + } + ; + +// ============================================================================ +// End rule definitions +// ============================================================================ + +// ---------------------------------------------------------------------------- +// This section is used for generating member defintions in the unit 'svfLexer'. +// The content of the section is verbatim copied into the generated code. +// ---------------------------------------------------------------------------- +memberdef +{ +} + diff --git a/src.jtag/svf/grammar/jtag.svfLexer.pas b/src.jtag/svf/grammar/jtag.svfLexer.pas new file mode 100644 index 0000000..7b5d396 --- /dev/null +++ b/src.jtag/svf/grammar/jtag.svfLexer.pas @@ -0,0 +1,785 @@ +// ============================================================================ +// This file is generated by the Delphi Parser Generator. +// ---------------------------------------------------------------------------- +// DPG version: 2.1.0.0r +// Grammar: jtag.svfLexer.g +// ============================================================================ +unit jtag.svfLexer; + +interface + +uses + System.Classes, + dpgrtl.lexer, + dpgrtl.types, + jtag.svfLexerTokens, + SysUtils; + +type + // ========================================================================= + // Type declarations from grammar. + // ========================================================================= + + // ========================================================================= + // Class TsvfLexer declaration + // ========================================================================= + TsvfLexer = class( TLexer) + + protected + fOnNewline : TNotifyEvent; + + public + property OnNewline : TNotifyEvent read fOnNewline write fOnNewline; + + protected // Internals + procedure initialize; override; + + public // Protected grammar rules + // Must callable from parser too + procedure mDIGITS ( pCreate: boolean); + procedure mEXP ( pCreate: boolean); + procedure mSIGN ( pCreate: boolean); + procedure mVECTOR ( pCreate: boolean); + procedure mDIGIT ( pCreate: boolean); + + public // Public grammar rules + procedure mSEMI ( pCreate: boolean); + procedure mLPAREN ( pCreate: boolean); + procedure mRPAREN ( pCreate: boolean); + procedure mID ( pCreate: boolean); + procedure mNUMBER ( pCreate: boolean); + procedure mSLCOMMENT ( pCreate: boolean); + procedure mNEWLINE ( pCreate: boolean); + procedure mWHITESPACE ( pCreate: boolean); + + public + function NextToken: IToken; override; + end; + +implementation +uses + dpgrtl.exception, + dpgrtl.token; + + +// ============================================================================ +// mSEMI +// ============================================================================ +procedure TsvfLexer.mSEMI( pCreate: boolean); +var + _begin: integer; + _save: integer; + _token: IToken; + _ttype: integer; + +begin + _begin := Length( TokenText) +1; + _token := nil; + _ttype := TT_SEMI; + + match(';'); + + if (_ttype <> TT_SKIP) and (pCreate = true) then + begin + _token := makeToken( _ttype); + _token.TokenText := Copy( TokenText, _begin, Length(TokenText)-_begin+1); + end; + + ReturnToken := _token; +end; + +// ============================================================================ +// mLPAREN +// ============================================================================ +procedure TsvfLexer.mLPAREN( pCreate: boolean); +var + _begin: integer; + _save: integer; + _token: IToken; + _ttype: integer; + +begin + _begin := Length( TokenText) +1; + _token := nil; + _ttype := TT_LPAREN; + + match('('); + + if (_ttype <> TT_SKIP) and (pCreate = true) then + begin + _token := makeToken( _ttype); + _token.TokenText := Copy( TokenText, _begin, Length(TokenText)-_begin+1); + end; + + ReturnToken := _token; +end; + +// ============================================================================ +// mRPAREN +// ============================================================================ +procedure TsvfLexer.mRPAREN( pCreate: boolean); +var + _begin: integer; + _save: integer; + _token: IToken; + _ttype: integer; + +begin + _begin := Length( TokenText) +1; + _token := nil; + _ttype := TT_RPAREN; + + match(')'); + + if (_ttype <> TT_SKIP) and (pCreate = true) then + begin + _token := makeToken( _ttype); + _token.TokenText := Copy( TokenText, _begin, Length(TokenText)-_begin+1); + end; + + ReturnToken := _token; +end; + +// ============================================================================ +// mID +// ============================================================================ +procedure TsvfLexer.mID( pCreate: boolean); +var + _begin: integer; + _save: integer; + _token: IToken; + _ttype: integer; + +begin + _begin := Length( TokenText) +1; + _token := nil; + _ttype := TT_ID; + + if (( LA(1) in ['A'..'Z'])) then + begin + match( ['A'..'Z']); + end + + else if (( LA(1) in ['a'..'z'])) then + begin + match( ['a'..'z']); + end + + else + Raise EMismatchedChar.Create( LA(1), ['A'..'Z','a'..'z'], InputState.FileName, InputState.Line, InputState.Column); + + while(true) do + begin + if (( LA(1) in ['A'..'Z'])) then + begin + match( ['A'..'Z']); + end + + else if (( LA(1) in ['a'..'z'])) then + begin + match( ['a'..'z']); + end + + else if (( LA(1) in ['0'..'9'])) then + begin + match( ['0'..'9']); + end + + else + break; + end; + + _ttype := TestLiteral( _ttype); + + + if (_ttype <> TT_SKIP) and (pCreate = true) then + begin + _token := makeToken( _ttype); + _token.TokenText := Copy( TokenText, _begin, Length(TokenText)-_begin+1); + end; + + ReturnToken := _token; +end; + +// ============================================================================ +// mNUMBER +// ============================================================================ +procedure TsvfLexer.mNUMBER( pCreate: boolean); +var + _begin: integer; + _save: integer; + _token: IToken; + _ttype: integer; + +begin + _begin := Length( TokenText) +1; + _token := nil; + _ttype := TT_NUMBER; + + mDIGITS(false); + _ttype := TT_INT; + if (( LA(1) in ['.'])) then + begin + match('.'); + mDIGITS(false); + _ttype := TT_FLOAT; + end; + if (( LA(1) in ['E','e'])) then + begin + mEXP(false); + if (( LA(1) in ['+','-'])) then + begin + mSIGN(false); + end; + mDIGITS(false); + _ttype := TT_FLOAT; + end; + + if (_ttype <> TT_SKIP) and (pCreate = true) then + begin + _token := makeToken( _ttype); + _token.TokenText := Copy( TokenText, _begin, Length(TokenText)-_begin+1); + end; + + ReturnToken := _token; +end; + +// ============================================================================ +// mDIGITS +// ============================================================================ +procedure TsvfLexer.mDIGITS( pCreate: boolean); +var + _begin: integer; + _cnt_18: integer; + _save: integer; + _token: IToken; + _ttype: integer; + +begin + _begin := Length( TokenText) +1; + _token := nil; + _ttype := TT_DIGITS; + + _cnt_18 := 0; + + while(true) do + begin + if (( LA(1) in ['0'..'9'])) then + begin + mDIGIT(false); + end + + else + begin + if _cnt_18 >= 1 then + break + else + Raise EMismatchedChar.Create( LA(1), ['0'..'9'], InputState.FileName, InputState.Line, InputState.Column); + end; + + INC(_cnt_18); + end; + + if (_ttype <> TT_SKIP) and (pCreate = true) then + begin + _token := makeToken( _ttype); + _token.TokenText := Copy( TokenText, _begin, Length(TokenText)-_begin+1); + end; + + ReturnToken := _token; +end; + +// ============================================================================ +// mEXP +// ============================================================================ +procedure TsvfLexer.mEXP( pCreate: boolean); +var + _begin: integer; + _save: integer; + _token: IToken; + _ttype: integer; + +begin + _begin := Length( TokenText) +1; + _token := nil; + _ttype := TT_EXP; + + if (( LA(1) in ['E'])) then + begin + match('E'); + end + + else if (( LA(1) in ['e'])) then + begin + match('e'); + end + + else + Raise EMismatchedChar.Create( LA(1), ['E','e'], InputState.FileName, InputState.Line, InputState.Column); + + if (_ttype <> TT_SKIP) and (pCreate = true) then + begin + _token := makeToken( _ttype); + _token.TokenText := Copy( TokenText, _begin, Length(TokenText)-_begin+1); + end; + + ReturnToken := _token; +end; + +// ============================================================================ +// mSIGN +// ============================================================================ +procedure TsvfLexer.mSIGN( pCreate: boolean); +var + _begin: integer; + _save: integer; + _token: IToken; + _ttype: integer; + +begin + _begin := Length( TokenText) +1; + _token := nil; + _ttype := TT_SIGN; + + if (( LA(1) in ['+'])) then + begin + match('+'); + end + + else if (( LA(1) in ['-'])) then + begin + match('-'); + end + + else + Raise EMismatchedChar.Create( LA(1), ['+','-'], InputState.FileName, InputState.Line, InputState.Column); + + if (_ttype <> TT_SKIP) and (pCreate = true) then + begin + _token := makeToken( _ttype); + _token.TokenText := Copy( TokenText, _begin, Length(TokenText)-_begin+1); + end; + + ReturnToken := _token; +end; + +// ============================================================================ +// mVECTOR +// ============================================================================ +procedure TsvfLexer.mVECTOR( pCreate: boolean); +var + _begin: integer; + _save: integer; + _token: IToken; + _ttype: integer; + +begin + _begin := Length( TokenText) +1; + _token := nil; + _ttype := TT_VECTOR; + + if (( LA(1) in ['H'])) then + begin + match('H'); + end + + else if (( LA(1) in ['L'])) then + begin + match('L'); + end + + else if (( LA(1) in ['Z'])) then + begin + match('Z'); + end + + else if (( LA(1) in ['U'])) then + begin + match('U'); + end + + else if (( LA(1) in ['D'])) then + begin + match('D'); + end + + else if (( LA(1) in ['X'])) then + begin + match('X'); + end + + else if (( LA(1) in ['h'])) then + begin + match('h'); + end + + else if (( LA(1) in ['l'])) then + begin + match('l'); + end + + else if (( LA(1) in ['z'])) then + begin + match('z'); + end + + else if (( LA(1) in ['u'])) then + begin + match('u'); + end + + else if (( LA(1) in ['d'])) then + begin + match('d'); + end + + else if (( LA(1) in ['x'])) then + begin + match('x'); + end + + else + Raise EMismatchedChar.Create( LA(1), ['D','H','L','U','X','Z','d','h','l','u','x','z'], InputState.FileName, InputState.Line, InputState.Column); + + if (_ttype <> TT_SKIP) and (pCreate = true) then + begin + _token := makeToken( _ttype); + _token.TokenText := Copy( TokenText, _begin, Length(TokenText)-_begin+1); + end; + + ReturnToken := _token; +end; + +// ============================================================================ +// mDIGIT +// ============================================================================ +procedure TsvfLexer.mDIGIT( pCreate: boolean); +var + _begin: integer; + _save: integer; + _token: IToken; + _ttype: integer; + +begin + _begin := Length( TokenText) +1; + _token := nil; + _ttype := TT_DIGIT; + + match( ['0'..'9']); + + if (_ttype <> TT_SKIP) and (pCreate = true) then + begin + _token := makeToken( _ttype); + _token.TokenText := Copy( TokenText, _begin, Length(TokenText)-_begin+1); + end; + + ReturnToken := _token; +end; + +// ============================================================================ +// mSLCOMMENT +// ============================================================================ +procedure TsvfLexer.mSLCOMMENT( pCreate: boolean); +var + _begin: integer; + _save: integer; + _token: IToken; + _ttype: integer; + +begin + _begin := Length( TokenText) +1; + _token := nil; + _ttype := TT_SLCOMMENT; + + if (( LA(1) in ['/'])) then + begin + match('//'); + end + + else if (( LA(1) in ['!'])) then + begin + match('!'); + end + + else + Raise EMismatchedChar.Create( LA(1), ['!','/'], InputState.FileName, InputState.Line, InputState.Column); + + while(true) do + begin + if (( LA(1) in [#1..#9,#11..#12,#14..#255])) then + begin + match( [#1..#9,#11..#12,#14..#255]); + end + + else + break; + end; + + if (( LA(1) in [#13]) and (LA(2) in [#10])) then + begin + match(#13); + match(#10); + newLine; if Assigned( fOnNewline) then fOnNewline(self); + end + + else if (( LA(1) in [#13])) then + begin + match(#13); + newLine; if Assigned( fOnNewline) then fOnNewline(self); + end + + else if (( LA(1) in [#10])) then + begin + match(#10); + newLine; if Assigned( fOnNewline) then fOnNewline(self); + end + + else + Raise EMismatchedChar.Create( LA(1), [#10,#13], InputState.FileName, InputState.Line, InputState.Column); + _ttype := TT_SKIP; + + if (_ttype <> TT_SKIP) and (pCreate = true) then + begin + _token := makeToken( _ttype); + _token.TokenText := Copy( TokenText, _begin, Length(TokenText)-_begin+1); + end; + + ReturnToken := _token; +end; + +// ============================================================================ +// mNEWLINE +// ============================================================================ +procedure TsvfLexer.mNEWLINE( pCreate: boolean); +var + _begin: integer; + _save: integer; + _token: IToken; + _ttype: integer; + +begin + _begin := Length( TokenText) +1; + _token := nil; + _ttype := TT_NEWLINE; + + if (( LA(1) in [#13]) and (LA(2) in [#10])) then + begin + match(#13); + match(#10); + newLine; if Assigned( fOnNewline) then fOnNewline(self); + end + + else if (( LA(1) in [#13])) then + begin + match(#13); + newLine; if Assigned( fOnNewline) then fOnNewline(self); + end + + else if (( LA(1) in [#10])) then + begin + match(#10); + newLine; if Assigned( fOnNewline) then fOnNewline(self); + end + + else + Raise EMismatchedChar.Create( LA(1), [#10,#13], InputState.FileName, InputState.Line, InputState.Column); + _ttype := TT_SKIP; + + if (_ttype <> TT_SKIP) and (pCreate = true) then + begin + _token := makeToken( _ttype); + _token.TokenText := Copy( TokenText, _begin, Length(TokenText)-_begin+1); + end; + + ReturnToken := _token; +end; + +// ============================================================================ +// mWHITESPACE +// ============================================================================ +procedure TsvfLexer.mWHITESPACE( pCreate: boolean); +var + _begin: integer; + _save: integer; + _token: IToken; + _ttype: integer; + +begin + _begin := Length( TokenText) +1; + _token := nil; + _ttype := TT_WHITESPACE; + + if (( LA(1) in [' '])) then + begin + match(' '); + end + + else if (( LA(1) in [#9])) then + begin + match(#9); + tab; + end + + else + Raise EMismatchedChar.Create( LA(1), [#9,' '], InputState.FileName, InputState.Line, InputState.Column); + _ttype := TT_SKIP; + + if (_ttype <> TT_SKIP) and (pCreate = true) then + begin + _token := makeToken( _ttype); + _token.TokenText := Copy( TokenText, _begin, Length(TokenText)-_begin+1); + end; + + ReturnToken := _token; +end; + +// ---------------------------------------------------------------------------- +// NextToken +// ---------------------------------------------------------------------------- +function TsvfLexer.NextToken : IToken; +var + _first : TCharSet; + +begin + _first := [#9..#10,#13,' '..'!','('..')','/'..'9',';','A'..'Z','a'..'z']; + + while( true) do + begin + ResetText; + + try + if (( LA(1) in [';'])) then + begin + mSEMI(true); + result := ReturnToken; + end + + else if (( LA(1) in ['('])) then + begin + mLPAREN(true); + result := ReturnToken; + end + + else if (( LA(1) in [')'])) then + begin + mRPAREN(true); + result := ReturnToken; + end + + else if (( LA(1) in ['A'..'Z','a'..'z'])) then + begin + mID(true); + result := ReturnToken; + end + + else if (( LA(1) in ['0'..'9'])) then + begin + mNUMBER(true); + result := ReturnToken; + end + + else if (( LA(1) in ['!','/'])) then + begin + mSLCOMMENT(true); + result := ReturnToken; + end + + else if (( LA(1) in [#10,#13])) then + begin + mNEWLINE(true); + result := ReturnToken; + end + + else if (( LA(1) in [#9,' '])) then + begin + mWHITESPACE(true); + result := ReturnToken; + end + + else + begin + if LA(1) = EOF_CHAR then + begin + uponEof; + result := TToken.Create(TT_EOF); + end + + else + Raise EMismatchedChar.Create(LA(1), _first, InputState.FileName, InputState.Line, InputState.Column); + end; + + // -------------------------------------------------------------- + // If we found a SKIP token, then try again... + // -------------------------------------------------------------- + if result = nil then + continue; + + // -------------------------------------------------------------- + // Now we have a valid token, so exit the function + // -------------------------------------------------------------- + break; + + except + Raise; + end; + end; +end; + +// ---------------------------------------------------------------------------- +// InitLiterals +// ---------------------------------------------------------------------------- +procedure TsvfLexer.initialize; +begin + fCaseSensitive := false; + fLiterals.CaseSensitive := false; + + fLiterals['drselect' ] := 20; + fLiterals['pio' ] := 9; + fLiterals['mask' ] := 37; + fLiterals['absent' ] := 50; + fLiterals['idle' ] := 19; + fLiterals['drupdate' ] := 26; + fLiterals['tdo' ] := 36; + fLiterals['hdr' ] := 7; + fLiterals['ircapture' ] := 28; + fLiterals['enddr' ] := 4; + fLiterals['out' ] := 40; + fLiterals['drpause' ] := 23; + fLiterals['off' ] := 48; + fLiterals['tir' ] := 16; + fLiterals['drexit2' ] := 25; + fLiterals['irupdate' ] := 33; + fLiterals['tdr' ] := 15; + fLiterals['on' ] := 47; + fLiterals['inout' ] := 41; + fLiterals['sdr' ] := 12; + fLiterals['irexit1' ] := 31; + fLiterals['state' ] := 14; + fLiterals['drexit1' ] := 24; + fLiterals['irpause' ] := 30; + fLiterals['endir' ] := 5; + fLiterals['drshift' ] := 22; + fLiterals['maximum' ] := 43; + fLiterals['tdi' ] := 35; + fLiterals['frequency' ] := 6; + fLiterals['hir' ] := 8; + fLiterals['hz' ] := 34; + fLiterals['runtest' ] := 11; + fLiterals['smask' ] := 38; + fLiterals['in' ] := 39; + fLiterals['tck' ] := 45; + fLiterals['z' ] := 49; + fLiterals['reset' ] := 18; + fLiterals['sck' ] := 46; + fLiterals['sir' ] := 13; + fLiterals['irselect' ] := 27; + fLiterals['trst' ] := 17; + fLiterals['irshift' ] := 29; + fLiterals['irexit2' ] := 32; + fLiterals['endstate' ] := 44; + fLiterals['drcapture' ] := 21; + fLiterals['piomap' ] := 10; + fLiterals['sec' ] := 42; +end; + +end. diff --git a/src.jtag/svf/grammar/jtag.svfLexerTokens.pas b/src.jtag/svf/grammar/jtag.svfLexerTokens.pas new file mode 100644 index 0000000..a51cb84 --- /dev/null +++ b/src.jtag/svf/grammar/jtag.svfLexerTokens.pas @@ -0,0 +1,77 @@ +// ============================================================================ +// This file is generated by the Delphi Parser Generator. +// ---------------------------------------------------------------------------- +// DPG version: 2.1.0.0r +// Grammar: jtag.svfLexer.g +// ============================================================================ +unit jtag.svfLexerTokens; + +interface + +const + LT_DRSELECT = 20; + LT_PIO = 9; + LT_MASK = 37; + LT_ABSENT = 50; + TT_ID = 56; + TT_NEWLINE = 64; + TT_EOF = 1; + TT_SEMI = 53; + TT_DIGIT = 61; + LT_IDLE = 19; + LT_DRUPDATE = 26; + LT_TDO = 36; + LT_HDR = 7; + LT_IRCAPTURE = 28; + LT_ENDDR = 4; + LT_OUT = 40; + LT_DRPAUSE = 23; + LT_OFF = 48; + LT_TIR = 16; + LT_DREXIT2 = 25; + TT_SIGN = 60; + LT_IRUPDATE = 33; + LT_TDR = 15; + TT_RPAREN = 55; + LT_ON = 47; + LT_INOUT = 41; + LT_SDR = 12; + LT_IREXIT1 = 31; + LT_STATE = 14; + TT_DIGITS = 62; + LT_DREXIT1 = 24; + LT_IRPAUSE = 30; + TT_SLCOMMENT = 63; + LT_ENDIR = 5; + LT_DRSHIFT = 22; + LT_MAXIMUM = 43; + LT_TDI = 35; + LT_FREQUENCY = 6; + LT_HIR = 8; + LT_HZ = 34; + LT_RUNTEST = 11; + LT_SMASK = 38; + LT_IN = 39; + LT_TCK = 45; + LT_Z = 49; + LT_RESET = 18; + TT_INT = 51; + LT_SCK = 46; + TT_FLOAT = 52; + TT_VECTOR = 58; + LT_SIR = 13; + TT_EXP = 59; + LT_IRSELECT = 27; + LT_TRST = 17; + LT_IRSHIFT = 29; + TT_LPAREN = 54; + TT_NUMBER = 57; + LT_IREXIT2 = 32; + TT_WHITESPACE = 65; + LT_ENDSTATE = 44; + LT_DRCAPTURE = 21; + LT_PIOMAP = 10; + LT_SEC = 42; + +implementation +end. diff --git a/src.jtag/svf/grammar/jtag.svfLexerTokens.txt b/src.jtag/svf/grammar/jtag.svfLexerTokens.txt new file mode 100644 index 0000000..a075a89 --- /dev/null +++ b/src.jtag/svf/grammar/jtag.svfLexerTokens.txt @@ -0,0 +1,65 @@ +// $Delphi Parser Generator: jtag.svfLexer.g -> jtag.svfLexer.gTokens.txt$ +TsvfLexer +LT_DRSELECT="DRSELECT"=20 +LT_PIO="PIO"=9 +LT_MASK="MASK"=37 +LT_ABSENT="ABSENT"=50 +TT_ID=56 +TT_NEWLINE=64 +TT_EOF=1 +TT_SEMI=53 +TT_DIGIT=61 +LT_IDLE="IDLE"=19 +LT_DRUPDATE="DRUPDATE"=26 +LT_TDO="TDO"=36 +LT_HDR="HDR"=7 +LT_IRCAPTURE="IRCAPTURE"=28 +LT_ENDDR="ENDDR"=4 +LT_OUT="OUT"=40 +LT_DRPAUSE="DRPAUSE"=23 +LT_OFF="OFF"=48 +LT_TIR="TIR"=16 +LT_DREXIT2="DREXIT2"=25 +TT_SIGN=60 +LT_IRUPDATE="IRUPDATE"=33 +LT_TDR="TDR"=15 +TT_RPAREN=55 +LT_ON="ON"=47 +LT_INOUT="INOUT"=41 +LT_SDR="SDR"=12 +LT_IREXIT1="IREXIT1"=31 +LT_STATE="STATE"=14 +TT_DIGITS=62 +LT_DREXIT1="DREXIT1"=24 +LT_IRPAUSE="IRPAUSE"=30 +TT_SLCOMMENT=63 +LT_ENDIR="ENDIR"=5 +LT_DRSHIFT="DRSHIFT"=22 +LT_MAXIMUM="MAXIMUM"=43 +LT_TDI="TDI"=35 +LT_FREQUENCY="FREQUENCY"=6 +LT_HIR="HIR"=8 +LT_HZ="HZ"=34 +LT_RUNTEST="RUNTEST"=11 +LT_SMASK="SMASK"=38 +LT_IN="IN"=39 +LT_TCK="TCK"=45 +LT_Z="Z"=49 +LT_RESET="RESET"=18 +TT_INT=51 +LT_SCK="SCK"=46 +TT_FLOAT=52 +TT_VECTOR=58 +LT_SIR="SIR"=13 +TT_EXP=59 +LT_IRSELECT="IRSELECT"=27 +LT_TRST="TRST"=17 +LT_IRSHIFT="IRSHIFT"=29 +TT_LPAREN=54 +TT_NUMBER=57 +LT_IREXIT2="IREXIT2"=32 +TT_WHITESPACE=65 +LT_ENDSTATE="ENDSTATE"=44 +LT_DRCAPTURE="DRCAPTURE"=21 +LT_PIOMAP="PIOMAP"=10 +LT_SEC="SEC"=42 diff --git a/src.jtag/svf/grammar/jtag.svfParser.g b/src.jtag/svf/grammar/jtag.svfParser.g new file mode 100644 index 0000000..902138f --- /dev/null +++ b/src.jtag/svf/grammar/jtag.svfParser.g @@ -0,0 +1,376 @@ +unit jtag.svfParser; + +// ---------------------------------------------------------------------------- +// This section is used for generating "uses" clause in the unit 'svfParser'. +// Every unit name must be terminated with ';' +// e.g: +// +// uses +// { +// Classes; +// SysUtils; +// } +// ---------------------------------------------------------------------------- +uses +{ + jtag.svfScanLexer; + + jtag.svfProgram; + jtag.svfAstNode; + jtag.svfAstEndDR; + jtag.svfAstEndIR; + jtag.svfAstState; + jtag.svfAstScan; + jtag.svfAstRuntest; + + dpgrtl.tokenbuffer; + dpgrtl.parserstate; +} + +// ---------------------------------------------------------------------------- +// This section is used for generating "const" clause in the unit 'svfParser'. +// The content of the section is verbatim copied into the generated code. +// ---------------------------------------------------------------------------- +//const +//{ +//} + +// ---------------------------------------------------------------------------- +// This section is used for generating "type" clause in the unit 'svfParser'. +// The content of the section is verbatim copied into the generated code. +// ---------------------------------------------------------------------------- +type +{ +} + +// ============================================================================ +// Parser class declaration +// ============================================================================ +parser TsvfParser; +// ---------------------------------------------------------------------------- +// Parser options +// ---------------------------------------------------------------------------- +options +{ + k = 2; + importVocab = jtag.svfScanLexer; + exportVocab = jtag.svfParser; +} + +// ---------------------------------------------------------------------------- +// Parser member declarations. +// All user defined member declarations should be placed here. +// The content of the section is verbatim copied into the generated code. +// ---------------------------------------------------------------------------- +memberdecl +{ + protected + fProgram : TsvfProgram; + + fScanLexer : TsvfScanLexer; + fOldPS : IParserState; + fNewPS : IParserState; + + public + procedure AfterConstruction; override; + procedure BeforeDestruction; override; + + protected + procedure AddENDDR( Value : byte); + procedure AddENDIR( Value : byte); + procedure AddFREQ( t : IToken); +} + +// ============================================================================ +// Begin rule definitions +// +// Remember: All parser rule names must begin with LOWERCASE letter! +// ============================================================================ +svf[scan: TsvfScanLexer] returns [TsvfProgram] +local +{ + ntb : ITokenBuffer; +} +{ + fScanLexer := scan; + + ntb := TTokenBuffer.Create( fScanLexer); + fOldPS := InputState; + fNewPS := TParserState.Create( ntb); +} + : + (command SEMI)* + + { + result := fProgram; + } + ; + + +command +local +{ + xstate : byte; + sstate : byte; + trst : AnsiString; + s : AnsiString; + astScan : TsvfAstScan; + astState : TsvfAstState; + astRun : TsvfAstRuntest; +} +{ + xstate := stNONDEF; // intermediate state + sstate := stNONDEF; // stable state + trst := ''; + + t := nil; + n := nil; +} + : + "ENDDR" sstate=stable_state { AddENDDR( sstate); } + | "ENDIR" sstate=stable_state { AddENDIR( sstate); } + + + | (t:"HDR" | t:"HIR" | t:"TDR" | t:"TIR" | t:"SDR" | t:"SIR" ) n:INT + { + astScan := TsvfAstScan.Create( t.TokenText, n.TokenText); + } + ( + ("TDI" scandata[0,astScan]) + | ("TDO" scandata[1,astScan]) + | ("MASK" scandata[2,astScan]) + | ("SMASK" scandata[3,astScan]) + )* + + { + fProgram.AddStatement( astScan); + } + + // ----------------------------------------------------- + // STATE + // ----------------------------------------------------- + | "STATE" + { + astState := TsvfAstState.Create; + astState.BeginData; + } + + ( + xstate=state + { + astState.AddState( xstate); + } + )* + + sstate=stable_state + { + astState.AddState( sstate); + astState.EndData; + + fProgram.AddStatement( astState); + } + + // --------------------------------------------------------------- + // RUNTEST + // --------------------------------------------------------------- + | "RUNTEST" + { + astRun := TsvfAstRuntest.Create; + astRun.BeginData; + } + + ( + sstate=stable_state + { + astRun.RunState := sstate; + } + )? + + ( + t:INT s=run_clk + { + astRun.RunCount := t.Tokentext; + astRun.RunClock := s; + } + + ( + (t:INT | t:FLOAT) "SEC" + { + astRun.MinTime := t.TokenText; + } + ( + "MAXIMUM" t:INT "SEC" + { + astRun.MaxTime := t.Tokentext; + } + )? + )? + + | + (t:INT | t:FLOAT) "SEC" + { + astRun.MinTime := t.TokenText; + } + ( + "MAXIMUM" t:INT "SEC" + { + astRun.MaxTime := t.Tokentext; + } + )? + ) + + ( + "ENDSTATE" sstate=stable_state + { + astRun.EndState := sstate; + } + )? + + { + astRun.EndData; + fProgram.AddStatement( astRun); + } + + // --------------------------- + // Not implemented commands... + // --------------------------- + | "TRST" trst=trst_val + | "FREQUENCY" f:FLOAT "HZ" + | "PIO" VECTOR + | "PIOMAP" LPAREN (direction ID)+ RPAREN + ; + +run_clk returns [AnsiString] + : + "TCK" { result := 'TCK'; } + | "SCK" { result := 'SCK'; } + ; + +trst_val returns [AnsiString] + : + "ON" { result := 'ON'; } + | "OFF" { result := 'OFF'; } + | "Z" { result := 'Z'; } + | "ABSENT" { result := 'ABSENT'; } + ; + +state returns [byte] + : + "RESET" { result := stRESET; } + | "IDLE" { result := stIDLE; } + + | "DRSELECT" { result := stDRSELECT; } + | "DRCAPTURE" { result := stDRCAPTURE; } + | "DRSHIFT" { result := stDRSHIFT; } + | "DRPAUSE" { result := stDRPAUSE; } + | "DREXIT1" { result := stDREXIT1; } + | "DREXIT2" { result := stDREXIT2; } + | "DRUPDATE" { result := stDRUPDATE; } + + | "IRSELECT" { result := stIRSELECT; } + | "IRCAPTURE" { result := stIRCAPTURE; } + | "IRSHIFT" { result := stIRSHIFT; } + | "IRPAUSE" { result := stIRPAUSE; } + | "IREXIT1" { result := stIREXIT1; } + | "IREXIT2" { result := stIREXIT2; } + | "IRUPDATE" { result := stIRUPDATE; } + ; + + +stable_state returns [byte] + : + "RESET" { result := stRESET; } + | "IDLE" { result := stIDLE; } + | "DRPAUSE" { result := stDRPAUSE; } + | "IRPAUSE" { result := stIRPAUSE; } + ; + +// ============================================================================ +// This is the tricky part... Use another lexer for scandata parsing. +// ============================================================================ +scandata [idx: byte; scan: TsvfAstScan] +: + LPAREN + { + InputState := fNewPS; + scan.BeginData; + } + + ( + t:XDIGITS + { + case idx of + 0: scan.AddTDI( t.TokenText); + 1: scan.AddTDO( t.TokenText); + 2: scan.AddMASK( t.TokenText); + 3: scan.AddSMASK( t.TokenText); + end; + } + )+ + + RPAREN + { + scan.EndData; + InputState := fOldPS; + } + ; + +direction + : + "IN" | "OUT" | "INOUT" + ; + +// ============================================================================ +// End rule definitions +// ============================================================================ + +// ---------------------------------------------------------------------------- +// This section is used for generating member defintions in the unit 'svfParser'. +// The content of the section is verbatim copied into the generated code. +// ---------------------------------------------------------------------------- +memberdef +{ +// ============================================================================ +// AfterConstruction +// ============================================================================ +procedure TsvfParser.AfterConstruction; +begin + fProgram := TsvfProgram.Create; +end; + +// ============================================================================ +// BeforeDestruction +// ============================================================================ +procedure TsvfParser.BeforeDestruction; +begin + fProgram.Free; +end; + + + + +// ============================================================================ +// ENDDR +// ============================================================================ +procedure TsvfParser.AddENDDR( Value: byte); +begin + fProgram.AddStatement( TsvfAstEndDR.Create( Value)); +end; + +// ============================================================================ +// ENDIR +// ============================================================================ +procedure TsvfParser.AddENDIR( Value: byte); +begin + fProgram.AddStatement( TsvfAstEndIR.Create( Value)); +end; + +// ============================================================================ +// FREQUENCY +// ============================================================================ +procedure TsvfParser.AddFREQ( t: IToken); +begin +end; + +} + diff --git a/src.jtag/svf/grammar/jtag.svfParser.pas b/src.jtag/svf/grammar/jtag.svfParser.pas new file mode 100644 index 0000000..7045301 --- /dev/null +++ b/src.jtag/svf/grammar/jtag.svfParser.pas @@ -0,0 +1,688 @@ +// ============================================================================ +// This file is generated by the Delphi Parser Generator. +// ---------------------------------------------------------------------------- +// DPG version: 2.1.0.0r +// Grammar: jtag.svfParser.g +// ============================================================================ +unit jtag.svfParser; + +interface + +uses + Classes, + dpgrtl.llkparser, + dpgrtl.parserstate, + dpgrtl.tokenbuffer, + dpgrtl.types, + jtag.svfAstEndDR, + jtag.svfAstEndIR, + jtag.svfAstNode, + jtag.svfAstRuntest, + jtag.svfAstScan, + jtag.svfAstState, + jtag.svfParserTokens, + jtag.svfProgram, + jtag.svfScanLexer, + SysUtils; + +type + // ========================================================================= + // Type declarations from grammar. + // ========================================================================= + + // ========================================================================= + // Class TsvfParser declaration + // ========================================================================= + TsvfParser = class( TLLkParser) + + protected + fProgram : TsvfProgram; + + fScanLexer : TsvfScanLexer; + fOldPS : IParserState; + fNewPS : IParserState; + + public + procedure AfterConstruction; override; + procedure BeforeDestruction; override; + + protected + procedure AddENDDR( Value : byte); + procedure AddENDIR( Value : byte); + procedure AddFREQ( t : IToken); + + public // Public grammar rules + function svf ( scan: TsvfScanLexer): TsvfProgram; + procedure command ; + function stable_state : byte; + procedure scandata ( idx: byte; scan: TsvfAstScan); + function state : byte; + function run_clk : AnsiString; + function trst_val : AnsiString; + procedure direction ; + + end; + +implementation +uses + dpgrtl.exception, + dpgrtl.token; + + +// ============================================================================ +// svf +// ============================================================================ +function TsvfParser.svf( scan: TsvfScanLexer): TsvfProgram; +var + ntb : ITokenBuffer; + +begin + + fScanLexer := scan; + + ntb := TTokenBuffer.Create( fScanLexer); + fOldPS := InputState; + fNewPS := TParserState.Create( ntb); + + + while(true) do + begin + if (( LA(1) in [LT_ENDDR..LT_TRST])) then + begin + command; + match(TT_SEMI); + end + + else + break; + end; + + result := fProgram; +end; + +// ============================================================================ +// command +// ============================================================================ +procedure TsvfParser.command; +var + _cnt_23: integer; + f: IToken; + n: IToken; + t: IToken; + xstate : byte; + sstate : byte; + trst : AnsiString; + s : AnsiString; + astScan : TsvfAstScan; + astState : TsvfAstState; + astRun : TsvfAstRuntest; + +begin + + xstate := stNONDEF; // intermediate state + sstate := stNONDEF; // stable state + trst := ''; + + t := nil; + n := nil; + + if (( LA(1) in [LT_ENDDR])) then + begin + match(LT_ENDDR); + sstate := stable_state; + AddENDDR( sstate); + end + + else if (( LA(1) in [LT_ENDIR])) then + begin + match(LT_ENDIR); + sstate := stable_state; + AddENDIR( sstate); + end + + else if (( LA(1) in [LT_HDR..LT_HIR,LT_SDR..LT_SIR,LT_TDR..LT_TIR])) then + begin + if (( LA(1) in [LT_HDR])) then + begin + t := LT(1); + match(LT_HDR); + end + + else if (( LA(1) in [LT_HIR])) then + begin + t := LT(1); + match(LT_HIR); + end + + else if (( LA(1) in [LT_TDR])) then + begin + t := LT(1); + match(LT_TDR); + end + + else if (( LA(1) in [LT_TIR])) then + begin + t := LT(1); + match(LT_TIR); + end + + else if (( LA(1) in [LT_SDR])) then + begin + t := LT(1); + match(LT_SDR); + end + + else if (( LA(1) in [LT_SIR])) then + begin + t := LT(1); + match(LT_SIR); + end + + else + Raise EMismatchedToken.Create( LT(1), [LT_HDR..LT_HIR,LT_SDR..LT_SIR,LT_TDR..LT_TIR], InputState.FileName); + n := LT(1); + match(TT_INT); + astScan := TsvfAstScan.Create( t.TokenText, n.TokenText); + + while(true) do + begin + if (( LA(1) in [LT_TDI])) then + begin + match(LT_TDI); + scandata(0,astScan); + end + + else if (( LA(1) in [LT_TDO])) then + begin + match(LT_TDO); + scandata(1,astScan); + end + + else if (( LA(1) in [LT_MASK])) then + begin + match(LT_MASK); + scandata(2,astScan); + end + + else if (( LA(1) in [LT_SMASK])) then + begin + match(LT_SMASK); + scandata(3,astScan); + end + + else + break; + end; + + fProgram.AddStatement( astScan); + end + + else if (( LA(1) in [LT_STATE])) then + begin + match(LT_STATE); + astState := TsvfAstState.Create; + astState.BeginData; + + while(true) do + begin + if (( LA(1) in [LT_RESET..LT_IRUPDATE]) and (LA(2) in [LT_RESET..LT_IRUPDATE])) then + begin + xstate := state; + astState.AddState( xstate); + end + + else + break; + end; + + sstate := stable_state; + astState.AddState( sstate); + astState.EndData; + + fProgram.AddStatement( astState); + end + + else if (( LA(1) in [LT_RUNTEST])) then + begin + match(LT_RUNTEST); + astRun := TsvfAstRuntest.Create; + astRun.BeginData; + if (( LA(1) in [LT_RESET..LT_IDLE,LT_DRPAUSE,LT_IRPAUSE])) then + begin + sstate := stable_state; + astRun.RunState := sstate; + end; + if (( LA(1) in [TT_INT]) and (LA(2) in [LT_TCK..LT_SCK])) then + begin + t := LT(1); + match(TT_INT); + s := run_clk; + astRun.RunCount := t.Tokentext; + astRun.RunClock := s; + if (( LA(1) in [TT_INT..TT_FLOAT])) then + begin + if (( LA(1) in [TT_INT])) then + begin + t := LT(1); + match(TT_INT); + end + + else if (( LA(1) in [TT_FLOAT])) then + begin + t := LT(1); + match(TT_FLOAT); + end + + else + Raise EMismatchedToken.Create( LT(1), [TT_INT..TT_FLOAT], InputState.FileName); + match(LT_SEC); + astRun.MinTime := t.TokenText; + if (( LA(1) in [LT_MAXIMUM])) then + begin + match(LT_MAXIMUM); + t := LT(1); + match(TT_INT); + match(LT_SEC); + astRun.MaxTime := t.Tokentext; + end; + end; + end + + else if (( LA(1) in [TT_INT..TT_FLOAT]) and (LA(2) in [LT_SEC])) then + begin + if (( LA(1) in [TT_INT])) then + begin + t := LT(1); + match(TT_INT); + end + + else if (( LA(1) in [TT_FLOAT])) then + begin + t := LT(1); + match(TT_FLOAT); + end + + else + Raise EMismatchedToken.Create( LT(1), [TT_INT..TT_FLOAT], InputState.FileName); + match(LT_SEC); + astRun.MinTime := t.TokenText; + if (( LA(1) in [LT_MAXIMUM])) then + begin + match(LT_MAXIMUM); + t := LT(1); + match(TT_INT); + match(LT_SEC); + astRun.MaxTime := t.Tokentext; + end; + end + + else + Raise EMismatchedToken.Create( LT(1), [TT_INT..TT_FLOAT], InputState.FileName); + if (( LA(1) in [LT_ENDSTATE])) then + begin + match(LT_ENDSTATE); + sstate := stable_state; + astRun.EndState := sstate; + end; + astRun.EndData; + fProgram.AddStatement( astRun); + end + + else if (( LA(1) in [LT_TRST])) then + begin + match(LT_TRST); + trst := trst_val; + end + + else if (( LA(1) in [LT_FREQUENCY])) then + begin + match(LT_FREQUENCY); + f := LT(1); + match(TT_FLOAT); + match(LT_HZ); + end + + else if (( LA(1) in [LT_PIO])) then + begin + match(LT_PIO); + match(TT_VECTOR); + end + + else if (( LA(1) in [LT_PIOMAP])) then + begin + match(LT_PIOMAP); + match(TT_LPAREN); + _cnt_23 := 0; + + while(true) do + begin + if (( LA(1) in [LT_IN..LT_INOUT])) then + begin + direction; + match(TT_ID); + end + + else + begin + if _cnt_23 >= 1 then + break + else + Raise EMismatchedToken.Create( LT(1), [LT_IN..LT_INOUT], InputState.FileName); + end; + + INC(_cnt_23); + end; + match(TT_RPAREN); + end + + else + Raise EMismatchedToken.Create( LT(1), [LT_ENDDR..LT_TRST], InputState.FileName); +end; + +// ============================================================================ +// stable_state +// ============================================================================ +function TsvfParser.stable_state: byte; +begin + + if (( LA(1) in [LT_RESET])) then + begin + match(LT_RESET); + result := stRESET; + end + + else if (( LA(1) in [LT_IDLE])) then + begin + match(LT_IDLE); + result := stIDLE; + end + + else if (( LA(1) in [LT_DRPAUSE])) then + begin + match(LT_DRPAUSE); + result := stDRPAUSE; + end + + else if (( LA(1) in [LT_IRPAUSE])) then + begin + match(LT_IRPAUSE); + result := stIRPAUSE; + end + + else + Raise EMismatchedToken.Create( LT(1), [LT_RESET..LT_IDLE,LT_DRPAUSE,LT_IRPAUSE], InputState.FileName); +end; + +// ============================================================================ +// scandata +// ============================================================================ +procedure TsvfParser.scandata( idx: byte; scan: TsvfAstScan); +var + _cnt_30: integer; + t: IToken; + +begin + + match(TT_LPAREN); + InputState := fNewPS; + scan.BeginData; + _cnt_30 := 0; + + while(true) do + begin + if (( LA(1) in [TT_XDIGITS])) then + begin + t := LT(1); + match(TT_XDIGITS); + case idx of + 0: scan.AddTDI( t.TokenText); + 1: scan.AddTDO( t.TokenText); + 2: scan.AddMASK( t.TokenText); + 3: scan.AddSMASK( t.TokenText); + end; + end + + else + begin + if _cnt_30 >= 1 then + break + else + Raise EMismatchedToken.Create( LT(1), [TT_XDIGITS], InputState.FileName); + end; + + INC(_cnt_30); + end; + match(TT_RPAREN); + scan.EndData; + InputState := fOldPS; +end; + +// ============================================================================ +// state +// ============================================================================ +function TsvfParser.state: byte; +begin + + if (( LA(1) in [LT_RESET])) then + begin + match(LT_RESET); + result := stRESET; + end + + else if (( LA(1) in [LT_IDLE])) then + begin + match(LT_IDLE); + result := stIDLE; + end + + else if (( LA(1) in [LT_DRSELECT])) then + begin + match(LT_DRSELECT); + result := stDRSELECT; + end + + else if (( LA(1) in [LT_DRCAPTURE])) then + begin + match(LT_DRCAPTURE); + result := stDRCAPTURE; + end + + else if (( LA(1) in [LT_DRSHIFT])) then + begin + match(LT_DRSHIFT); + result := stDRSHIFT; + end + + else if (( LA(1) in [LT_DRPAUSE])) then + begin + match(LT_DRPAUSE); + result := stDRPAUSE; + end + + else if (( LA(1) in [LT_DREXIT1])) then + begin + match(LT_DREXIT1); + result := stDREXIT1; + end + + else if (( LA(1) in [LT_DREXIT2])) then + begin + match(LT_DREXIT2); + result := stDREXIT2; + end + + else if (( LA(1) in [LT_DRUPDATE])) then + begin + match(LT_DRUPDATE); + result := stDRUPDATE; + end + + else if (( LA(1) in [LT_IRSELECT])) then + begin + match(LT_IRSELECT); + result := stIRSELECT; + end + + else if (( LA(1) in [LT_IRCAPTURE])) then + begin + match(LT_IRCAPTURE); + result := stIRCAPTURE; + end + + else if (( LA(1) in [LT_IRSHIFT])) then + begin + match(LT_IRSHIFT); + result := stIRSHIFT; + end + + else if (( LA(1) in [LT_IRPAUSE])) then + begin + match(LT_IRPAUSE); + result := stIRPAUSE; + end + + else if (( LA(1) in [LT_IREXIT1])) then + begin + match(LT_IREXIT1); + result := stIREXIT1; + end + + else if (( LA(1) in [LT_IREXIT2])) then + begin + match(LT_IREXIT2); + result := stIREXIT2; + end + + else if (( LA(1) in [LT_IRUPDATE])) then + begin + match(LT_IRUPDATE); + result := stIRUPDATE; + end + + else + Raise EMismatchedToken.Create( LT(1), [LT_RESET..LT_IRUPDATE], InputState.FileName); +end; + +// ============================================================================ +// run_clk +// ============================================================================ +function TsvfParser.run_clk: AnsiString; +begin + + if (( LA(1) in [LT_TCK])) then + begin + match(LT_TCK); + result := 'TCK'; + end + + else if (( LA(1) in [LT_SCK])) then + begin + match(LT_SCK); + result := 'SCK'; + end + + else + Raise EMismatchedToken.Create( LT(1), [LT_TCK..LT_SCK], InputState.FileName); +end; + +// ============================================================================ +// trst_val +// ============================================================================ +function TsvfParser.trst_val: AnsiString; +begin + + if (( LA(1) in [LT_ON])) then + begin + match(LT_ON); + result := 'ON'; + end + + else if (( LA(1) in [LT_OFF])) then + begin + match(LT_OFF); + result := 'OFF'; + end + + else if (( LA(1) in [LT_Z])) then + begin + match(LT_Z); + result := 'Z'; + end + + else if (( LA(1) in [LT_ABSENT])) then + begin + match(LT_ABSENT); + result := 'ABSENT'; + end + + else + Raise EMismatchedToken.Create( LT(1), [LT_ON..LT_ABSENT], InputState.FileName); +end; + +// ============================================================================ +// direction +// ============================================================================ +procedure TsvfParser.direction; +begin + + if (( LA(1) in [LT_IN])) then + begin + match(LT_IN); + end + + else if (( LA(1) in [LT_OUT])) then + begin + match(LT_OUT); + end + + else if (( LA(1) in [LT_INOUT])) then + begin + match(LT_INOUT); + end + + else + Raise EMismatchedToken.Create( LT(1), [LT_IN..LT_INOUT], InputState.FileName); +end; + +// ============================================================================ +// AfterConstruction +// ============================================================================ +procedure TsvfParser.AfterConstruction; +begin + fProgram := TsvfProgram.Create; +end; + +// ============================================================================ +// BeforeDestruction +// ============================================================================ +procedure TsvfParser.BeforeDestruction; +begin + fProgram.Free; +end; + + + + +// ============================================================================ +// ENDDR +// ============================================================================ +procedure TsvfParser.AddENDDR( Value: byte); +begin + fProgram.AddStatement( TsvfAstEndDR.Create( Value)); +end; + +// ============================================================================ +// ENDIR +// ============================================================================ +procedure TsvfParser.AddENDIR( Value: byte); +begin + fProgram.AddStatement( TsvfAstEndIR.Create( Value)); +end; + +// ============================================================================ +// FREQUENCY +// ============================================================================ +procedure TsvfParser.AddFREQ( t: IToken); +begin +end; +end. diff --git a/src.jtag/svf/grammar/jtag.svfParserTokens.pas b/src.jtag/svf/grammar/jtag.svfParserTokens.pas new file mode 100644 index 0000000..baa35e2 --- /dev/null +++ b/src.jtag/svf/grammar/jtag.svfParserTokens.pas @@ -0,0 +1,79 @@ +// ============================================================================ +// This file is generated by the Delphi Parser Generator. +// ---------------------------------------------------------------------------- +// DPG version: 2.1.0.0r +// Grammar: jtag.svfParser.g +// ============================================================================ +unit jtag.svfParserTokens; + +interface + +const + LT_DRSELECT = 20; + LT_PIO = 9; + LT_MASK = 37; + LT_ABSENT = 50; + TT_ID = 56; + TT_NEWLINE = 64; + TT_EOF = 1; + TT_SEMI = 53; + TT_DIGIT = 61; + LT_TDO = 36; + LT_DRUPDATE = 26; + LT_OUT = 40; + LT_HDR = 7; + LT_OFF = 48; + LT_IRCAPTURE = 28; + LT_ENDDR = 4; + LT_DRPAUSE = 23; + LT_IDLE = 19; + TT_XDIGIT = 66; + LT_TIR = 16; + LT_DREXIT2 = 25; + TT_SIGN = 60; + LT_IRUPDATE = 33; + TT_RPAREN = 55; + LT_TDR = 15; + LT_ON = 47; + LT_INOUT = 41; + LT_SDR = 12; + LT_IREXIT1 = 31; + LT_STATE = 14; + TT_DIGITS = 62; + LT_DREXIT1 = 24; + LT_IRPAUSE = 30; + TT_SLCOMMENT = 63; + LT_ENDIR = 5; + LT_DRSHIFT = 22; + LT_MAXIMUM = 43; + LT_SMASK = 38; + LT_FREQUENCY = 6; + LT_TCK = 45; + LT_HZ = 34; + LT_RUNTEST = 11; + LT_HIR = 8; + LT_IN = 39; + TT_INT = 51; + LT_Z = 49; + LT_TDI = 35; + LT_RESET = 18; + LT_SCK = 46; + TT_VECTOR = 58; + TT_XDIGITS = 67; + LT_SIR = 13; + TT_EXP = 59; + LT_IRSELECT = 27; + LT_TRST = 17; + LT_IRSHIFT = 29; + TT_FLOAT = 52; + TT_LPAREN = 54; + TT_NUMBER = 57; + LT_IREXIT2 = 32; + TT_WHITESPACE = 65; + LT_ENDSTATE = 44; + LT_PIOMAP = 10; + LT_DRCAPTURE = 21; + LT_SEC = 42; + +implementation +end. diff --git a/src.jtag/svf/grammar/jtag.svfParserTokens.txt b/src.jtag/svf/grammar/jtag.svfParserTokens.txt new file mode 100644 index 0000000..0e68129 --- /dev/null +++ b/src.jtag/svf/grammar/jtag.svfParserTokens.txt @@ -0,0 +1,67 @@ +// $Delphi Parser Generator: jtag.svfParser.g -> jtag.svfParser.gTokens.txt$ +TsvfParser +LT_DRSELECT="DRSELECT"=20 +LT_PIO="PIO"=9 +LT_MASK="MASK"=37 +LT_ABSENT="ABSENT"=50 +TT_ID=56 +TT_NEWLINE=64 +TT_EOF=1 +TT_SEMI=53 +TT_DIGIT=61 +LT_TDO="TDO"=36 +LT_DRUPDATE="DRUPDATE"=26 +LT_OUT="OUT"=40 +LT_HDR="HDR"=7 +LT_OFF="OFF"=48 +LT_IRCAPTURE="IRCAPTURE"=28 +LT_ENDDR="ENDDR"=4 +LT_DRPAUSE="DRPAUSE"=23 +LT_IDLE="IDLE"=19 +TT_XDIGIT=66 +LT_TIR="TIR"=16 +LT_DREXIT2="DREXIT2"=25 +TT_SIGN=60 +LT_IRUPDATE="IRUPDATE"=33 +TT_RPAREN=55 +LT_TDR="TDR"=15 +LT_ON="ON"=47 +LT_INOUT="INOUT"=41 +LT_SDR="SDR"=12 +LT_IREXIT1="IREXIT1"=31 +LT_STATE="STATE"=14 +TT_DIGITS=62 +LT_DREXIT1="DREXIT1"=24 +LT_IRPAUSE="IRPAUSE"=30 +TT_SLCOMMENT=63 +LT_ENDIR="ENDIR"=5 +LT_DRSHIFT="DRSHIFT"=22 +LT_MAXIMUM="MAXIMUM"=43 +LT_SMASK="SMASK"=38 +LT_FREQUENCY="FREQUENCY"=6 +LT_TCK="TCK"=45 +LT_HZ="HZ"=34 +LT_RUNTEST="RUNTEST"=11 +LT_HIR="HIR"=8 +LT_IN="IN"=39 +TT_INT=51 +LT_Z="Z"=49 +LT_TDI="TDI"=35 +LT_RESET="RESET"=18 +LT_SCK="SCK"=46 +TT_VECTOR=58 +TT_XDIGITS=67 +LT_SIR="SIR"=13 +TT_EXP=59 +LT_IRSELECT="IRSELECT"=27 +LT_TRST="TRST"=17 +LT_IRSHIFT="IRSHIFT"=29 +TT_FLOAT=52 +TT_LPAREN=54 +TT_NUMBER=57 +LT_IREXIT2="IREXIT2"=32 +TT_WHITESPACE=65 +LT_ENDSTATE="ENDSTATE"=44 +LT_PIOMAP="PIOMAP"=10 +LT_DRCAPTURE="DRCAPTURE"=21 +LT_SEC="SEC"=42 diff --git a/src.jtag/svf/grammar/jtag.svfScanLexer.g b/src.jtag/svf/grammar/jtag.svfScanLexer.g new file mode 100644 index 0000000..c5e387f --- /dev/null +++ b/src.jtag/svf/grammar/jtag.svfScanLexer.g @@ -0,0 +1,137 @@ +unit jtag.svfScanLexer; + +// ---------------------------------------------------------------------------- +// This section is used for generating "uses" clause in the unit 'svfScanLexer'. +// Every unit name must be terminated with ';' +// e.g: +// +// uses +// { +// Classes; +// SysUtils; +// } +// ---------------------------------------------------------------------------- +uses +{ +} + +// ---------------------------------------------------------------------------- +// This section is used for generating "type" clause in the unit 'svfScanLexer'. +// The content of the section is verbatim copied into the generated code. +// ---------------------------------------------------------------------------- +type +{ +} + +// ============================================================================ +// Lexer class declaration +// ============================================================================ +lexer TsvfScanLexer; +// ---------------------------------------------------------------------------- +// Lexer options +// ---------------------------------------------------------------------------- +options +{ + k = 2; + importVocab = jtag.svfLexer; + exportVocab = jtag.svfScanLexer; + caseSensitive = false; +} + +// ---------------------------------------------------------------------------- +// Lexer tokens. Usualy string literals. +// ---------------------------------------------------------------------------- +tokens +{ +} + +// ---------------------------------------------------------------------------- +// Lexer member declarations. +// All user defined member declarations should be placed here. +// The content of the section is verbatim copied into the generated code. +// ---------------------------------------------------------------------------- +memberdecl +{ + protected + fOnNewline : TNotifyEvent; + + public + property OnNewline : TNotifyEvent read fOnNewline write fOnNewline; +} + +// ============================================================================ +// Begin rule definitions +// +// Remember: All lexer rule names must begin with UPPERCASE letter! +// ============================================================================ +RPAREN: ')'; + +protected XDIGIT: '0'..'9' | 'a'..'f' | 'A'..'F' ; +XDIGITS: (XDIGIT)+; + +// ---------------------------------------------------------------------------- +// SLCOMMENT +// ---------------------------------------------------------------------------- +SLCOMMENT + : + "//" + ( ~( '\r' | '\n') )* + ( + options + { + generateAmbigWarnings = false; + } + : '\r' '\n' { newLine; if Assigned( fOnNewline) then fOnNewline(self); } + | '\r' { newLine; if Assigned( fOnNewline) then fOnNewline(self); } + | '\n' { newLine; if Assigned( fOnNewline) then fOnNewline(self); } + ) + { + _ttype := TT_SKIP; + } + ; + +// ---------------------------------------------------------------------------- +// NEWLINE +// ---------------------------------------------------------------------------- +NEWLINE + : + ( + options + { + generateAmbigWarnings = false; + } + : '\r' '\n' { newLine; if Assigned( fOnNewline) then fOnNewline(self); } + | '\r' { newLine; if Assigned( fOnNewline) then fOnNewline(self); } + | '\n' { newLine; if Assigned( fOnNewline) then fOnNewline(self); } + ) + { + _ttype := TT_SKIP; + } + ; + +// ---------------------------------------------------------------------------- +// WHITESPACE +// ---------------------------------------------------------------------------- +WHITESPACE + : + ( + ' ' + | '\t' { tab; } + ) + { + _ttype := TT_SKIP; + } + ; + +// ============================================================================ +// End rule definitions +// ============================================================================ + +// ---------------------------------------------------------------------------- +// This section is used for generating member defintions in the unit 'svfScanLexer'. +// The content of the section is verbatim copied into the generated code. +// ---------------------------------------------------------------------------- +memberdef +{ +} + diff --git a/src.jtag/svf/grammar/jtag.svfScanLexer.pas b/src.jtag/svf/grammar/jtag.svfScanLexer.pas new file mode 100644 index 0000000..f87ad1b --- /dev/null +++ b/src.jtag/svf/grammar/jtag.svfScanLexer.pas @@ -0,0 +1,448 @@ +// ============================================================================ +// This file is generated by the Delphi Parser Generator. +// ---------------------------------------------------------------------------- +// DPG version: 2.1.0.0r +// Grammar: jtag.svfscanLexer.g +// ============================================================================ +unit jtag.svfScanLexer; + +interface + +uses + Classes, + dpgrtl.lexer, + dpgrtl.types, + jtag.svfScanLexerTokens, + SysUtils; + +type + // ========================================================================= + // Type declarations from grammar. + // ========================================================================= + + // ========================================================================= + // Class TsvfScanLexer declaration + // ========================================================================= + TsvfScanLexer = class( TLexer) + + protected + fOnNewline : TNotifyEvent; + + public + property OnNewline : TNotifyEvent read fOnNewline write fOnNewline; + + protected // Internals + procedure initialize; override; + + public // Protected grammar rules + // Must callable from parser too + procedure mXDIGIT ( pCreate: boolean); + + public // Public grammar rules + procedure mRPAREN ( pCreate: boolean); + procedure mXDIGITS ( pCreate: boolean); + procedure mSLCOMMENT ( pCreate: boolean); + procedure mNEWLINE ( pCreate: boolean); + procedure mWHITESPACE ( pCreate: boolean); + + public + function NextToken: IToken; override; + end; + +implementation +uses + dpgrtl.exception, + dpgrtl.token; + + +// ============================================================================ +// mRPAREN +// ============================================================================ +procedure TsvfScanLexer.mRPAREN( pCreate: boolean); +var + _begin: integer; + _save: integer; + _token: IToken; + _ttype: integer; + +begin + _begin := Length( TokenText) +1; + _token := nil; + _ttype := TT_RPAREN; + + match(')'); + + if (_ttype <> TT_SKIP) and (pCreate = true) then + begin + _token := makeToken( _ttype); + _token.TokenText := Copy( TokenText, _begin, Length(TokenText)-_begin+1); + end; + + ReturnToken := _token; +end; + +// ============================================================================ +// mXDIGIT +// ============================================================================ +procedure TsvfScanLexer.mXDIGIT( pCreate: boolean); +var + _begin: integer; + _save: integer; + _token: IToken; + _ttype: integer; + +begin + _begin := Length( TokenText) +1; + _token := nil; + _ttype := TT_XDIGIT; + + if (( LA(1) in ['0'..'9'])) then + begin + match( ['0'..'9']); + end + + else if (( LA(1) in ['a'..'f'])) then + begin + match( ['a'..'f']); + end + + else if (( LA(1) in ['A'..'F'])) then + begin + match( ['A'..'F']); + end + + else + Raise EMismatchedChar.Create( LA(1), ['0'..'9','A'..'F','a'..'f'], InputState.FileName, InputState.Line, InputState.Column); + + if (_ttype <> TT_SKIP) and (pCreate = true) then + begin + _token := makeToken( _ttype); + _token.TokenText := Copy( TokenText, _begin, Length(TokenText)-_begin+1); + end; + + ReturnToken := _token; +end; + +// ============================================================================ +// mXDIGITS +// ============================================================================ +procedure TsvfScanLexer.mXDIGITS( pCreate: boolean); +var + _begin: integer; + _cnt_5: integer; + _save: integer; + _token: IToken; + _ttype: integer; + +begin + _begin := Length( TokenText) +1; + _token := nil; + _ttype := TT_XDIGITS; + + _cnt_5 := 0; + + while(true) do + begin + if (( LA(1) in ['0'..'9','A'..'F','a'..'f'])) then + begin + mXDIGIT(false); + end + + else + begin + if _cnt_5 >= 1 then + break + else + Raise EMismatchedChar.Create( LA(1), ['0'..'9','A'..'F','a'..'f'], InputState.FileName, InputState.Line, InputState.Column); + end; + + INC(_cnt_5); + end; + + if (_ttype <> TT_SKIP) and (pCreate = true) then + begin + _token := makeToken( _ttype); + _token.TokenText := Copy( TokenText, _begin, Length(TokenText)-_begin+1); + end; + + ReturnToken := _token; +end; + +// ============================================================================ +// mSLCOMMENT +// ============================================================================ +procedure TsvfScanLexer.mSLCOMMENT( pCreate: boolean); +var + _begin: integer; + _save: integer; + _token: IToken; + _ttype: integer; + +begin + _begin := Length( TokenText) +1; + _token := nil; + _ttype := TT_SLCOMMENT; + + match('//'); + + while(true) do + begin + if (( LA(1) in [#1..#9,#11..#12,#14..#255])) then + begin + match( [#1..#9,#11..#12,#14..#255]); + end + + else + break; + end; + + if (( LA(1) in [#13]) and (LA(2) in [#10])) then + begin + match(#13); + match(#10); + newLine; if Assigned( fOnNewline) then fOnNewline(self); + end + + else if (( LA(1) in [#13])) then + begin + match(#13); + newLine; if Assigned( fOnNewline) then fOnNewline(self); + end + + else if (( LA(1) in [#10])) then + begin + match(#10); + newLine; if Assigned( fOnNewline) then fOnNewline(self); + end + + else + Raise EMismatchedChar.Create( LA(1), [#10,#13], InputState.FileName, InputState.Line, InputState.Column); + _ttype := TT_SKIP; + + if (_ttype <> TT_SKIP) and (pCreate = true) then + begin + _token := makeToken( _ttype); + _token.TokenText := Copy( TokenText, _begin, Length(TokenText)-_begin+1); + end; + + ReturnToken := _token; +end; + +// ============================================================================ +// mNEWLINE +// ============================================================================ +procedure TsvfScanLexer.mNEWLINE( pCreate: boolean); +var + _begin: integer; + _save: integer; + _token: IToken; + _ttype: integer; + +begin + _begin := Length( TokenText) +1; + _token := nil; + _ttype := TT_NEWLINE; + + if (( LA(1) in [#13]) and (LA(2) in [#10])) then + begin + match(#13); + match(#10); + newLine; if Assigned( fOnNewline) then fOnNewline(self); + end + + else if (( LA(1) in [#13])) then + begin + match(#13); + newLine; if Assigned( fOnNewline) then fOnNewline(self); + end + + else if (( LA(1) in [#10])) then + begin + match(#10); + newLine; if Assigned( fOnNewline) then fOnNewline(self); + end + + else + Raise EMismatchedChar.Create( LA(1), [#10,#13], InputState.FileName, InputState.Line, InputState.Column); + _ttype := TT_SKIP; + + if (_ttype <> TT_SKIP) and (pCreate = true) then + begin + _token := makeToken( _ttype); + _token.TokenText := Copy( TokenText, _begin, Length(TokenText)-_begin+1); + end; + + ReturnToken := _token; +end; + +// ============================================================================ +// mWHITESPACE +// ============================================================================ +procedure TsvfScanLexer.mWHITESPACE( pCreate: boolean); +var + _begin: integer; + _save: integer; + _token: IToken; + _ttype: integer; + +begin + _begin := Length( TokenText) +1; + _token := nil; + _ttype := TT_WHITESPACE; + + if (( LA(1) in [' '])) then + begin + match(' '); + end + + else if (( LA(1) in [#9])) then + begin + match(#9); + tab; + end + + else + Raise EMismatchedChar.Create( LA(1), [#9,' '], InputState.FileName, InputState.Line, InputState.Column); + _ttype := TT_SKIP; + + if (_ttype <> TT_SKIP) and (pCreate = true) then + begin + _token := makeToken( _ttype); + _token.TokenText := Copy( TokenText, _begin, Length(TokenText)-_begin+1); + end; + + ReturnToken := _token; +end; + +// ---------------------------------------------------------------------------- +// NextToken +// ---------------------------------------------------------------------------- +function TsvfScanLexer.NextToken : IToken; +var + _first : TCharSet; + +begin + _first := [#9..#10,#13,' ',')','/'..'9','A'..'F','a'..'f']; + + while( true) do + begin + ResetText; + + try + if (( LA(1) in [')'])) then + begin + mRPAREN(true); + result := ReturnToken; + end + + else if (( LA(1) in ['0'..'9','A'..'F','a'..'f'])) then + begin + mXDIGITS(true); + result := ReturnToken; + end + + else if (( LA(1) in ['/'])) then + begin + mSLCOMMENT(true); + result := ReturnToken; + end + + else if (( LA(1) in [#10,#13])) then + begin + mNEWLINE(true); + result := ReturnToken; + end + + else if (( LA(1) in [#9,' '])) then + begin + mWHITESPACE(true); + result := ReturnToken; + end + + else + begin + if LA(1) = EOF_CHAR then + begin + uponEof; + result := TToken.Create(TT_EOF); + end + + else + Raise EMismatchedChar.Create(LA(1), _first, InputState.FileName, InputState.Line, InputState.Column); + end; + + // -------------------------------------------------------------- + // If we found a SKIP token, then try again... + // -------------------------------------------------------------- + if result = nil then + continue; + + // -------------------------------------------------------------- + // Now we have a valid token, so exit the function + // -------------------------------------------------------------- + break; + + except + Raise; + end; + end; +end; + +// ---------------------------------------------------------------------------- +// InitLiterals +// ---------------------------------------------------------------------------- +procedure TsvfScanLexer.initialize; +begin + fCaseSensitive := false; + fLiterals.CaseSensitive := false; + + fLiterals['drselect' ] := 20; + fLiterals['pio' ] := 9; + fLiterals['mask' ] := 37; + fLiterals['absent' ] := 50; + fLiterals['drupdate' ] := 26; + fLiterals['idle' ] := 19; + fLiterals['out' ] := 40; + fLiterals['hdr' ] := 7; + fLiterals['ircapture' ] := 28; + fLiterals['enddr' ] := 4; + fLiterals['off' ] := 48; + fLiterals['drpause' ] := 23; + fLiterals['tdo' ] := 36; + fLiterals['tir' ] := 16; + fLiterals['drexit2' ] := 25; + fLiterals['irupdate' ] := 33; + fLiterals['tdr' ] := 15; + fLiterals['sdr' ] := 12; + fLiterals['inout' ] := 41; + fLiterals['on' ] := 47; + fLiterals['irexit1' ] := 31; + fLiterals['state' ] := 14; + fLiterals['drexit1' ] := 24; + fLiterals['irpause' ] := 30; + fLiterals['endir' ] := 5; + fLiterals['drshift' ] := 22; + fLiterals['maximum' ] := 43; + fLiterals['tdi' ] := 35; + fLiterals['frequency' ] := 6; + fLiterals['hir' ] := 8; + fLiterals['hz' ] := 34; + fLiterals['runtest' ] := 11; + fLiterals['smask' ] := 38; + fLiterals['in' ] := 39; + fLiterals['tck' ] := 45; + fLiterals['z' ] := 49; + fLiterals['reset' ] := 18; + fLiterals['sck' ] := 46; + fLiterals['sir' ] := 13; + fLiterals['irselect' ] := 27; + fLiterals['trst' ] := 17; + fLiterals['irshift' ] := 29; + fLiterals['irexit2' ] := 32; + fLiterals['endstate' ] := 44; + fLiterals['drcapture' ] := 21; + fLiterals['piomap' ] := 10; + fLiterals['sec' ] := 42; +end; + +end. diff --git a/src.jtag/svf/grammar/jtag.svfScanLexerTokens.pas b/src.jtag/svf/grammar/jtag.svfScanLexerTokens.pas new file mode 100644 index 0000000..dd72ffe --- /dev/null +++ b/src.jtag/svf/grammar/jtag.svfScanLexerTokens.pas @@ -0,0 +1,79 @@ +// ============================================================================ +// This file is generated by the Delphi Parser Generator. +// ---------------------------------------------------------------------------- +// DPG version: 2.1.0.0r +// Grammar: jtag.svfscanLexer.g +// ============================================================================ +unit jtag.svfScanLexerTokens; + +interface + +const + LT_DRSELECT = 20; + LT_PIO = 9; + LT_MASK = 37; + LT_ABSENT = 50; + TT_ID = 56; + TT_NEWLINE = 64; + TT_EOF = 1; + TT_SEMI = 53; + TT_DIGIT = 61; + LT_DRUPDATE = 26; + LT_IDLE = 19; + LT_OUT = 40; + LT_HDR = 7; + LT_IRCAPTURE = 28; + LT_ENDDR = 4; + LT_OFF = 48; + LT_DRPAUSE = 23; + LT_TDO = 36; + TT_XDIGIT = 66; + LT_TIR = 16; + LT_DREXIT2 = 25; + TT_SIGN = 60; + LT_IRUPDATE = 33; + LT_TDR = 15; + TT_RPAREN = 55; + LT_SDR = 12; + LT_INOUT = 41; + LT_ON = 47; + LT_IREXIT1 = 31; + LT_STATE = 14; + TT_DIGITS = 62; + LT_DREXIT1 = 24; + LT_IRPAUSE = 30; + TT_SLCOMMENT = 63; + LT_ENDIR = 5; + LT_DRSHIFT = 22; + LT_MAXIMUM = 43; + LT_TDI = 35; + LT_FREQUENCY = 6; + LT_HIR = 8; + LT_HZ = 34; + LT_RUNTEST = 11; + LT_SMASK = 38; + LT_IN = 39; + LT_TCK = 45; + LT_Z = 49; + LT_RESET = 18; + TT_INT = 51; + LT_SCK = 46; + TT_FLOAT = 52; + TT_VECTOR = 58; + LT_SIR = 13; + TT_EXP = 59; + LT_IRSELECT = 27; + LT_TRST = 17; + LT_IRSHIFT = 29; + TT_XDIGITS = 67; + TT_LPAREN = 54; + TT_NUMBER = 57; + LT_IREXIT2 = 32; + TT_WHITESPACE = 65; + LT_ENDSTATE = 44; + LT_DRCAPTURE = 21; + LT_PIOMAP = 10; + LT_SEC = 42; + +implementation +end. diff --git a/src.jtag/svf/grammar/jtag.svfScanLexerTokens.txt b/src.jtag/svf/grammar/jtag.svfScanLexerTokens.txt new file mode 100644 index 0000000..65cf0c6 --- /dev/null +++ b/src.jtag/svf/grammar/jtag.svfScanLexerTokens.txt @@ -0,0 +1,67 @@ +// $Delphi Parser Generator: jtag.svfscanLexer.g -> jtag.svfscanLexer.gTokens.txt$ +TsvfScanLexer +LT_DRSELECT="DRSELECT"=20 +LT_PIO="PIO"=9 +LT_MASK="MASK"=37 +LT_ABSENT="ABSENT"=50 +TT_ID=56 +TT_NEWLINE=64 +TT_EOF=1 +TT_SEMI=53 +TT_DIGIT=61 +LT_DRUPDATE="DRUPDATE"=26 +LT_IDLE="IDLE"=19 +LT_OUT="OUT"=40 +LT_HDR="HDR"=7 +LT_IRCAPTURE="IRCAPTURE"=28 +LT_ENDDR="ENDDR"=4 +LT_OFF="OFF"=48 +LT_DRPAUSE="DRPAUSE"=23 +LT_TDO="TDO"=36 +TT_XDIGIT=66 +LT_TIR="TIR"=16 +LT_DREXIT2="DREXIT2"=25 +TT_SIGN=60 +LT_IRUPDATE="IRUPDATE"=33 +LT_TDR="TDR"=15 +TT_RPAREN=55 +LT_SDR="SDR"=12 +LT_INOUT="INOUT"=41 +LT_ON="ON"=47 +LT_IREXIT1="IREXIT1"=31 +LT_STATE="STATE"=14 +TT_DIGITS=62 +LT_DREXIT1="DREXIT1"=24 +LT_IRPAUSE="IRPAUSE"=30 +TT_SLCOMMENT=63 +LT_ENDIR="ENDIR"=5 +LT_DRSHIFT="DRSHIFT"=22 +LT_MAXIMUM="MAXIMUM"=43 +LT_TDI="TDI"=35 +LT_FREQUENCY="FREQUENCY"=6 +LT_HIR="HIR"=8 +LT_HZ="HZ"=34 +LT_RUNTEST="RUNTEST"=11 +LT_SMASK="SMASK"=38 +LT_IN="IN"=39 +LT_TCK="TCK"=45 +LT_Z="Z"=49 +LT_RESET="RESET"=18 +TT_INT=51 +LT_SCK="SCK"=46 +TT_FLOAT=52 +TT_VECTOR=58 +LT_SIR="SIR"=13 +TT_EXP=59 +LT_IRSELECT="IRSELECT"=27 +LT_TRST="TRST"=17 +LT_IRSHIFT="IRSHIFT"=29 +TT_XDIGITS=67 +TT_LPAREN=54 +TT_NUMBER=57 +LT_IREXIT2="IREXIT2"=32 +TT_WHITESPACE=65 +LT_ENDSTATE="ENDSTATE"=44 +LT_DRCAPTURE="DRCAPTURE"=21 +LT_PIOMAP="PIOMAP"=10 +LT_SEC="SEC"=42 diff --git a/src.jtag/svf/jtag.svfAstComment.pas b/src.jtag/svf/jtag.svfAstComment.pas new file mode 100644 index 0000000..e14109c --- /dev/null +++ b/src.jtag/svf/jtag.svfAstComment.pas @@ -0,0 +1,37 @@ +unit jtag.svfAstComment; + +interface +uses + jtag.svfAstNode; + +type + TsvfAstComment = class( TsvfAstNode) + private + fComment : AnsiString; + + public + function AsText: AnsiString; override; + + public + constructor Create(Comment: AnsiString); + + public + property Comment : AnsiString read fComment; + + end; + +implementation + +{ TsvfAstEndDR } + +function TsvfAstComment.AsText: AnsiString; +begin + result := fComment; +end; + +constructor TsvfAstComment.Create(Comment: AnsiString); +begin + fComment := Comment +#13#10 +end; + +end. diff --git a/src.jtag/svf/jtag.svfAstEndDR.pas b/src.jtag/svf/jtag.svfAstEndDR.pas new file mode 100644 index 0000000..df05e9b --- /dev/null +++ b/src.jtag/svf/jtag.svfAstEndDR.pas @@ -0,0 +1,57 @@ +unit jtag.svfAstEndDR; + +interface +uses + jtag.svfAstNode, + jtag.svfLex; + +type + TsvfAstEndDR = class( TsvfAstNode) + private + fState : byte; + + public + function AsText: AnsiString; override; + public + constructor Create(State: byte); + + public + property State: byte read fState; + + end; + +implementation +uses + System.SysUtils, + jtag.svfProgram; + +{ TsvfAstEndDR } + +// ================================================================================================ +// Constructor +// ================================================================================================ +constructor TsvfAstEndDR.Create(State: byte); +begin + inherited Create; + fState := State; +end; + +// ================================================================================================ +// As Text +// ================================================================================================ +function TsvfAstEndDR.AsText: AnsiString; +var + s: AnsiString; + +begin + case fState of + stRESET : s := 'RESET'; + stIDLE : s := 'IDLE'; + stDRPAUSE : s := 'DRPAUSE'; + stIRPAUSE : s := 'IRPAUSE'; + end; + + result := 'ENDDR ' +s+ ';' +#13#10; +end; + +end. diff --git a/src.jtag/svf/jtag.svfAstEndIR.pas b/src.jtag/svf/jtag.svfAstEndIR.pas new file mode 100644 index 0000000..e190ffb --- /dev/null +++ b/src.jtag/svf/jtag.svfAstEndIR.pas @@ -0,0 +1,56 @@ +unit jtag.svfAstEndIR; + +interface +uses + jtag.svfAstNode, + jtag.svfLex; + +type + TsvfAstEndIR = class( TsvfAstNode) + private + fState : byte; + fStateX : TTokenType; + + public + function AsText: AnsiString; override; + + public + constructor Create(State: byte); + + public + property State: byte read fState; + + end; + + +implementation +uses + System.sysutils, + jtag.svfProgram; + +{ TsvfAstEndIR } + +constructor TsvfAstEndIR.Create(State: byte); +begin + inherited Create; + fState := State; +end; + + +function TsvfAstEndIR.AsText: AnsiString; +var + s: AnsiString; + +begin + case fState of + stRESET : s := 'RESET'; + stIDLE : s := 'IDLE'; + stDRPAUSE : s := 'DRPAUSE'; + stIRPAUSE : s := 'IRPAUSE'; + end; + + result := 'ENDIR ' +s+ ';' +#13#10; +end; + + +end. diff --git a/src.jtag/svf/jtag.svfAstFreq.pas b/src.jtag/svf/jtag.svfAstFreq.pas new file mode 100644 index 0000000..33cf4db --- /dev/null +++ b/src.jtag/svf/jtag.svfAstFreq.pas @@ -0,0 +1,37 @@ +unit jtag.svfAstFreq; + +interface +uses + jtag.svfAstNode; + +type + TsvfAstFreq = class( TsvfAstNode) + private + fFrequency: double; + + public + function AsText: AnsiString; override; + public + constructor Create(Freq: double); + + public + property Frequency : double read fFrequency; + end; + +implementation +uses + System.SysUtils; + +{ TsvfAstFreq } + +function TsvfAstFreq.AsText: AnsiString; +begin + result := Format('FREQUENCY %8.4e HZ;',[fFrequency])+#13#10; +end; + +constructor TsvfAstFreq.Create(Freq: double); +begin + fFrequency := Freq +end; + +end. diff --git a/src.jtag/svf/jtag.svfAstNode.pas b/src.jtag/svf/jtag.svfAstNode.pas new file mode 100644 index 0000000..b444a61 --- /dev/null +++ b/src.jtag/svf/jtag.svfAstNode.pas @@ -0,0 +1,22 @@ +unit jtag.svfAstNode; + +interface + +type + TsvfAstNode = class + + + public + function AsText: AnsiString; virtual; + end; + +implementation + +{ TsvfAstNode } + +function TsvfAstNode.AsText: AnsiString; +begin + result := ''; +end; + +end. diff --git a/src.jtag/svf/jtag.svfAstPrint.pas b/src.jtag/svf/jtag.svfAstPrint.pas new file mode 100644 index 0000000..aa7b570 --- /dev/null +++ b/src.jtag/svf/jtag.svfAstPrint.pas @@ -0,0 +1,34 @@ +unit jtag.svfAstPrint; + +interface +uses + jtag.svfAstNode; + +type + TsvfAstPrint = class( TsvfAstNode) + public + Text : AnsiString; + + public + constructor Create( AText: AnsiString); + function AsText: AnsiString; override; + end; + + +implementation +uses + System.AnsiStrings; + +{ TsvfAstPrint } + +function TsvfAstPrint.AsText: AnsiString; +begin + result := Text +end; + +constructor TsvfAstPrint.Create( AText: AnsiString); +begin + Text := AnsiReplaceText(AText, '"', ''); +end; + +end. diff --git a/src.jtag/svf/jtag.svfAstRuntest.pas b/src.jtag/svf/jtag.svfAstRuntest.pas new file mode 100644 index 0000000..3022442 --- /dev/null +++ b/src.jtag/svf/jtag.svfAstRuntest.pas @@ -0,0 +1,110 @@ +unit jtag.svfAstRuntest; + +interface +uses + jtag.svfAstNode; + +type + TsvfAstRuntest = class( TsvfAstNode) + private + fAllowData : boolean; + + public + RunClock : AnsiString; + RunCount : AnsiString; + MinTime : AnsiString; + MaxTime : AnsiString; + RunState : byte; + EndState : byte; + + public + constructor Create; + function AsText: AnsiString; override; + + public + procedure BeginData; + procedure EndData; + end; + +implementation +uses + jtag.svfProgram; + +{ TsvfAstRuntest } + +// @@@: Constructor/destructor ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// Constructor/destructor +// +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ====================================================================================== +// Constructor +// ====================================================================================== +constructor TsvfAstRuntest.Create; +begin + inherited; + + fAllowData := false; + + RunClock := 'TCK'; + RunCount := ''; + MinTime := ''; + MaxTime := ''; + RunState := 1; + EndState := $FF; +end; + +// ====================================================================================== +// BeginData +// ====================================================================================== +procedure TsvfAstRuntest.BeginData; +begin + fAllowData := true; +end; + +// ====================================================================================== +// EndData +// ====================================================================================== +procedure TsvfAstRuntest.EndData; +begin + fAllowData := false; +end; + +// ================================================================================================ +// As Text +// ================================================================================================ +function TsvfAstRuntest.AsText: AnsiString; +begin + result := 'RUNTEST'; + + if RunClock <> ''then + result := result +' '+ RunCount +' '+ RunClock; + + if MinTime <> '' then + result := result +' '+ MinTime +' SEC'; + + if MaxTime <> '' then + result := result +' MAXIMUM '+ MaxTime +' SEC'; + + if EndState <> $FF then + begin + result := result +' ENDSTATE '; + + case EndState of + stRESET : result := result +'RESET'; + stIDLE : result := result +'IDLE'; + stDRPAUSE : result := result +'DRPAUSE'; + stIRPAUSE : result := result +'IRPAUSE'; + else result := result +'InVaLiD'; + end; + end; + + result := result +';' +#13#10#13#10; +end; + + +end. diff --git a/src.jtag/svf/jtag.svfAstScan.pas b/src.jtag/svf/jtag.svfAstScan.pas new file mode 100644 index 0000000..b216fa3 --- /dev/null +++ b/src.jtag/svf/jtag.svfAstScan.pas @@ -0,0 +1,438 @@ +unit jtag.svfAstScan; + +interface +uses + System.SysUtils, + jtag.svfAstNode; + +type + TsvfAstScan = class( TsvfAstNode) + + private + fInst : AnsiString; + fLength : integer; + fBytes : integer; + fNibbles : integer; // memory size in 4 bit nibbles + + fDataTDI : PByte; + fDataTDO : PByte; + fDataMASK : PByte; + fDataSMASK : PByte; + + + fLenTDI : integer; + fLenTDO : integer; + fLenMASK : integer; + fLenSMASK : integer; + + fCursor : integer; + fCursorN : integer; // Cursor in 4 bit nibbles for data input + + strict private + function GetDataTDI : pByteArray; + function GetDataTDO : pByteArray; + function GetDataMASK : pByteArray; + function GetDataSMASK : pByteArray; + + public + function AsText: AnsiString; override; + + public + constructor Create( Inst: AnsiString; Length: AnsiString); + destructor Destroy; override; + + public + procedure AddTDI( Data: AnsiString); + procedure AddTDO( Data: AnsiString); + procedure AddMASK( Data: AnsiString); + procedure AddSMASK( Data: AnsiString); + + procedure BeginData; + procedure EndData; + + public + property Inst : AnsiString read fInst; + property Bits : integer read fLength; + property Bytes : integer read fBytes; + + property DataTDI : PByteArray read GetDataTDI; + property DataTDO : PByteArray read GetDataTDO; + property DataMASK : PByteArray read GetDataMASK; + property DataSMASK: PByteArray read GetDataSMASK; + + property LenTDI : integer read fLenTDI; + property LenTDO : integer read fLenTDO; + property LenMASK : integer read fLenMASK; + property LenSMASK : integer read fLenSMASK; + + end; + +implementation +uses + Winapi.Windows, +// Dialogs, + jtag.svfProgram; + +{ TsvfAstScan } + +function hex2bin( hex: AnsiChar): byte; +begin + case hex of + '0'..'9': result := ord(hex) -ord('0'); + 'a'..'f': result := ord(hex) -ord('a') +10; + 'A'..'F': result := ord(hex) -ord('A') +10; + else result := 0; + end; +end; + +function hex2rbin( hex: AnsiChar): byte; +begin + case hex of + '0': result := $0; + '1': result := $8; + '2': result := $4; + '3': result := $C; + '4': result := $2; + '5': result := $A; + '6': result := $6; + '7': result := $E; + '8': result := $1; + '9': result := $9; + + 'A','a': result := $5; + 'B','b': result := $D; + 'C','c': result := $3; + 'D','d': result := $B; + 'E','e': result := $7; + 'F','f': result := $F; + else result := 0; + end; +end; + +// ================================================================================================ +// Constructor +// ================================================================================================ +constructor TsvfAstScan.Create(Inst: AnsiString; Length: AnsiString); +begin + fInst := Inst; + fLength := StrToIntDef( Length, 0); + fBytes := ((fLength +7) div 8); + fNibbles := ((fLength +3) div 4); + + + fDataTDI := nil; + fDataTDO := nil; + fDataMASK := nil; + fDataSMASK := nil; +end; + + +// ================================================================================================ +// Destructor +// ================================================================================================ +destructor TsvfAstScan.Destroy; +begin + if Assigned( fDataTDI) then FreeMem( fDataTDI); + if Assigned( fDataTDO) then FreeMem( fDataTDO); + if Assigned( fDataMASK) then FreeMem( fDataMASK); + if Assigned( fDataSMASK) then FreeMem( fDataSMASK); + + inherited; +end; + +// ================================================================================================ +// BeginData +// ================================================================================================ +procedure TsvfAstScan.BeginData; +begin +end; + +// ================================================================================================ +// EndData +// ================================================================================================ +procedure TsvfAstScan.EndData; +begin +end; + +// ================================================================================================ +// GetDataTDI +// ================================================================================================ +function TsvfAstScan.GetDataTDI: pByteArray; +begin + result := PByteArray( fDataTDI); +end; + +// ================================================================================================ +// GetDataTDO +// ================================================================================================ +function TsvfAstScan.GetDataTDO: pByteArray; +begin + result := PByteArray( fDataTDO); +end; + +// ================================================================================================ +// GetDataMASK +// ================================================================================================ +function TsvfAstScan.GetDataMASK: pByteArray; +begin + result := PByteArray( fDataMASK); +end; + +// ================================================================================================ +// GetDataSMASK +// ================================================================================================ +function TsvfAstScan.GetDataSMASK: pByteArray; +begin + result := PByteArray( fDataSMASK); +end; + +// ================================================================================================ +// AddTDI +// +// Note: The TDI stream can have an arbitrary length. +// ================================================================================================ +procedure TsvfAstScan.AddTDI( Data: AnsiString); +var + i : integer; + +begin + i := 1; + + if not Assigned( fDataTDI) then + begin + fLenTDI := 0; + fCursor := fBytes -1; + fCursorN := fNibbles -1; + fDataTDI := AllocMem( fBytes); + end; + + while i <= Length(Data) do + begin + if fCursorN mod 2 <> 0 + then DataTDI[fCursorN div 2] := hex2rbin(Data[i]) + else DataTDI[fCursorN div 2] := (hex2rbin(Data[i]) shl 4) or DataTDI[fCursorN div 2]; + + DEC(fCursorN); + + INC(fLenTDI); + INC(i); + +// DataTDI[fCursor] := (hex2bin(Data[i]) shl 4) or hex2bin(Data[i+1]);; + +// DEC(fCursor); +// INC(fLenTDI); + +// INC(i, 2); + end; +end; + +// ================================================================================================ +// AddTDO +// ================================================================================================ +procedure TsvfAstScan.AddTDO( Data: AnsiString); +var + i: integer; + +begin + i := 1; + + if not Assigned( fDataTDO) then + begin + fLenTDO := 0; + fCursor := fBytes -1; + fCursorN := fNibbles -1; + fDataTDO := AllocMem( fBytes); + end; + + while i <= Length(Data) do + begin + if fCursorN mod 2 <> 0 + then DataTDO[fCursorN div 2] := hex2bin(Data[i]) shl 4 + else DataTDO[fCursorN div 2] := hex2bin(Data[i]) or (byte(DataTDO[fCursorN div 2])); + + DEC(fCursorN); + + INC(fLenTDO); + INC(i); + +// DataTDO[fCursor] := (hex2bin(Data[i]) shl 4) or hex2bin(Data[i+1]);; +// +// DEC(fCursor); +// INC(fLenTDO); +// +// INC(i); + end; +end; + +// ================================================================================================ +// AddSMASK +// ================================================================================================ +procedure TsvfAstScan.AddSMASK( Data: AnsiString); +var + i: integer; + +begin + i := 1; + + if not Assigned( fDataSMASK) then + begin + fLenSMASK := 0; + fCursor := fBytes-1; + fCursorN := fNibbles -1; + fDataSMASK := AllocMem( fBytes); + end; + + while i <= Length(Data) do + begin + if fCursorN mod 2 <> 0 + then DataSMASK[fCursorN div 2] := hex2rbin(Data[i]) + else DataSMASK[fCursorN div 2] := (hex2rbin(Data[i]) shl 4) or DataSMASK[fCursorN div 2]; + + DEC(fCursorN); + + INC(fLenSMASK); + INC(i); + +// DataSMASK[fCursor] := (hex2bin(Data[i]) shl 4) or hex2bin(Data[i+1]);; +// DataTDI [fCursor] := DataTDI[fCursor] and DataSMASK[fCursor]; +// +// DEC(fCursor); +// INC(fLenSMASK); +// +// INC(i, 2); + end; +end; + +// ================================================================================================ +// AddMASK +// ================================================================================================ +procedure TsvfAstScan.AddMASK( Data: AnsiString); +var + i: integer; + +begin + i := 1; + + if not Assigned( fDataMASK) then + begin + fLenMASK := 0; + fCursor := fBytes -1; + fCursorN := fNibbles -1; + fDataMASK := AllocMem( fBytes); + end; + + while i <= Length(Data) do + begin + if fCursorN mod 2 <> 0 + then DataMASK[fCursorN div 2] := hex2rbin(Data[i]) + else DataMASK[fCursorN div 2] := (hex2rbin(Data[i]) shl 4) or DataMASK[fCursorN div 2]; + + DEC(fCursorN); + + INC(fLenMASK); + INC(i); + +// DataMASK[fCursor] := (hex2bin(Data[i]) shl 4) or hex2bin(Data[i+1]);; +// +// DEC(fCursor); +// INC(fLenMASK); +// +// INC(i, 2); + end; +end; + +// ================================================================================================ +// AsText +// ================================================================================================ +function TsvfAstScan.AsText: AnsiString; + +const + spc = ' '; + + + function DumpData( PrefixLength: integer; + DataName : AnsiString; + Data : PByte; + DataLength : integer): AnsiString; + var + i : integer; + cnt: integer; + ptr: PByte; + b : byte; + s : AnsiChar; + + + begin + cnt := 0; + ptr := Data; + result := Format( '%-7s(',[DataName]); + + for i:= 0 to DataLength-1 do + begin + if i mod 2 = 0 + then b := (ptr^ shr 4) and $0f + else b := (ptr^ shr 0) and $0f; + + case b of + $0: s := '0'; $1: s := '1'; $2: s := '2'; $3: s := '3'; + $4: s := '4'; $5: s := '5'; $6: s := '6'; $7: s := '7'; + $8: s := '8'; $9: s := '9'; $a: s := 'A'; $b: s := 'B'; + $c: s := 'C'; $d: s := 'D'; $e: s := 'E'; $f: s := 'F'; + end; + + result := result +s; + + if cnt = 60 then + begin + result := result +#13#10+ Copy(spc,1,PrefixLength+8); + cnt := 0; + end; + + INC(cnt); + + if i mod 2 = 1 then + INC(ptr); + end; + + result := result +')'; + end; + + +var + s: AnsiString; + + + +begin + if fLenTDI > 0 + then result := Format('%3s %-8d',[fInst, fLength]) + else result := Format('%3s %d', [fInst, fLength]); + + if fLength > 0 then + begin + if fLenTDI > 0 then + result := result + DumpData( 12, 'TDI', fDataTDI, fLenTDI); + + if fLenSMASK > 0 then + begin + result := result + #13#10+ Copy( spc, 1, 12); + result := result + DumpData( 12, 'SMASK', fDataSMASK, fLenSMASK); + end; + + if fLenTDO > 0 then + begin + result := result + #13#10+ Copy( spc, 1, 12); + result := result + DumpData( 12, 'TDO', fDataTDO, fLenTDO); + end; + + if fLenMASK > 0 then + begin + result := result + #13#10+ Copy( spc, 1, 12); + result := result + DumpData( 12, 'MASK', fDataMASK, fLenMASK); + end; + end; + + result := result +';' +#13#10; +end; + +end. diff --git a/src.jtag/svf/jtag.svfAstState.pas b/src.jtag/svf/jtag.svfAstState.pas new file mode 100644 index 0000000..37b92dd --- /dev/null +++ b/src.jtag/svf/jtag.svfAstState.pas @@ -0,0 +1,168 @@ +unit jtag.svfAstState; + +interface +uses + jtag.svfAstNode; + +type + TsvfAstState = class( TsvfAstNode) + private + fStates : array[0..255] of byte; + fCursor : integer; + fAllowData : boolean; + + function GetStateCount: integer; + function GetState(i:integer): byte; + + public + constructor Create; + + public + function AsText: AnsiString; override; + + procedure BeginData; + procedure EndData; + + procedure AddState( State: byte); + + public + property StateCount : integer read GetStateCount; + property States[i:integer] : byte read GetState; + end; + +implementation +uses + jtag.svfProgram; + +{ TsvfAstState } + +// @@@: Constructor/destructor ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// Constructor/destructor +// +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ====================================================================================== +// Constructor +// ====================================================================================== +constructor TsvfAstState.Create; +begin + fCursor := 0; + fAllowData := false; +end; + +// @@@: Property Handlers +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// Property Handlers +// +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ====================================================================================== +// GetStateCount +// ====================================================================================== +function TsvfAstState.GetStateCount: integer; +begin + result := fCursor; +end; + +// ====================================================================================== +// GetState +// ====================================================================================== +function TsvfAstState.GetState(i:integer): byte; +begin + if (i>=0) and (i; + + TAnsiCharSet = set of AnsiChar; + + TsvfMode = ( SVF, HEX); + + TsvfLEX = class + private + fBuffer : PAnsiChar; + fStart : PAnsiChar; + fForward : PAnsiChar; + + fToken : TsvfToken; + fMode : TsvfMode; + + fLiterals: TTokenMap; + + private + procedure InitLiterals; + function CheckLiteral( ttext: AnsiString; ttype: TTokenType): TTokenType; + + function MakeToken( ttype : TTokenType; + ttext : AnsiString): TsvfToken; + + + public + function NextToken : TsvfToken; + + + + public + constructor Create( Stream: TStream); + destructor Destroy; override; + end; + +implementation +uses + WinAPI.Windows, + System.SysUtils; + +{ TsvfLEX } + +// ================================================================================================ +// Constructor +// ================================================================================================ +constructor TsvfLEX.Create(Stream: TStream); +var + size : Int64; + token : TsvfToken; + +begin + InitLiterals; + + if Assigned( Stream) then + begin + size := Stream.Size - Stream.Position; + fBuffer := GetMemory(size+1); + + Stream.Read(fBuffer^, size); + + fMode := SVF; + fStart := fBuffer; + fForward := fBuffer; + fBuffer[size] := #0; + end +end; + +destructor TsvfLEX.Destroy; +begin + FreeAndNil(fLiterals); + inherited; +end; + + + +// @@@: Internals +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// Internals +// +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ================================================================================================ +// MakeToken +// ================================================================================================ +function TsvfLEX.MakeToken(ttype: TTokenType; ttext: AnsiString): TsvfToken; +begin + result := TsvfToken.Create; + + with result do + begin + TokenType := ttype; + + if TokenType in [TT_COMMENT,TT_STRING] + then TokenText := ttext + else TokenText := UpperCase(ttext); + end +end; + +// ================================================================================================ +// InitLiterals +// ================================================================================================ +procedure TsvfLEX.InitLiterals; +begin + fLiterals := TTokenMap.Create; + + fLiterals.Add('HIR', LT_HIR ); + fLiterals.Add('HDR', LT_HDR ); + fLiterals.Add('TIR', LT_TIR ); + fLiterals.Add('TDR', LT_TDR ); + fLiterals.Add('SIR', LT_SIR ); + fLiterals.Add('SDR', LT_SDR ); + fLiterals.Add('TDI', LT_TDI ); + fLiterals.Add('TDO', LT_TDO ); + fLiterals.Add('MASK', LT_MASK ); + fLiterals.Add('SMASK', LT_SMASK ); + + fLiterals.Add('FREQUENCY', LT_FREQUENCY ); + fLiterals.Add('HZ', LT_HZ ); + + fLiterals.Add('PIO', LT_PIO ); + fLiterals.Add('PIOMAP', LT_PIOMAP ); + + fLiterals.Add('RUNTEST', LT_RUNTEST ); + fLiterals.Add('TCK', LT_TCK ); + fLiterals.Add('SCK', LT_SCK ); + fLiterals.Add('SEC', LT_SEC ); + fLiterals.Add('MAXIMUM', LT_MAXIMUM ); + fLiterals.Add('ENDSTATE', LT_ENDSTATE ); + + fLiterals.Add('ENDIR', LT_ENDIR ); + fLiterals.Add('ENDDR', LT_ENDDR ); + fLiterals.Add('STATE', LT_STATE ); + + fLiterals.Add('RESET', LT_RESET ); + fLiterals.Add('IDLE', LT_IDLE ); + + fLiterals.Add('DRSELECT', LT_DRSELECT ); + fLiterals.Add('DRCAPTURE', LT_DRCAPTURE ); + fLiterals.Add('DRSHIFT', LT_DRSHIFT ); + fLiterals.Add('DRUPDATE', LT_DRUPDATE ); + fLiterals.Add('DRPAUSE', LT_DRPAUSE ); + fLiterals.Add('DREXIT1', LT_DREXIT1 ); + fLiterals.Add('DREXIT2', LT_DREXIT2 ); + + fLiterals.Add('IRSELECT', LT_IRSELECT ); + fLiterals.Add('IRCAPTURE', LT_DRCAPTURE ); + fLiterals.Add('IRSHIFT', LT_IRSHIFT ); + fLiterals.Add('IRUPDATE', LT_IRUPDATE ); + fLiterals.Add('IRPAUSE', LT_IRPAUSE ); + fLiterals.Add('IREXIT1', LT_IREXIT1 ); + fLiterals.Add('IREXIT2', LT_IREXIT2 ); + + fLiterals.Add('IN', LT_IN ); + fLiterals.Add('OUT', LT_OUT ); + fLiterals.Add('INOUT', LT_INOUT ); + + fLiterals.Add('TRST', LT_TRST ); + fLiterals.Add('ON', LT_ON ); + fLiterals.Add('OFF', LT_OFF ); + fLiterals.Add('Z', LT_Z ); + fLiterals.Add('ABSENT', LT_ABSENT ); + + fLiterals.Add('PRINT', LT_PRINT ); +end; + +// ================================================================================================ +// CheckLiteral +// ================================================================================================ +function TsvfLEX.CheckLiteral(ttext: AnsiString; ttype: TTokenType): TTokenType; +begin + result := ttype; + fLiterals.TryGetValue(ttext, result); +end; + + + +// @@@: Interface +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// Interface +// +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ================================================================================================ +// NextToken +// ================================================================================================ +function TsvfLEX.NextToken: TsvfToken; + + function GetTokenText: AnsiString; + begin + SetLength( result, fForward-fStart); + MoveMemory( @result[1], fStart, fForward-fStart); + end; + +var + ttext : AnsiString; + ttype : TTokenType; + +begin + while true do + begin + result := nil; + fForward := fStart; + + if fMode = HEX then + case fForward^ of + // ---------------------------------------------------- + // HEX digits + // ---------------------------------------------------- + '0'..'9','a'..'f','A'..'F': + begin + INC(fForward); + + while fForward^ in ['0'..'9','a'..'f','A'..'F'] do + INC(fForward); + + result := MakeToken( TT_HEX, GetTokenText); + fStart := fForward; + end; + + // ---------------------------------------------------- + // HEX end + // ---------------------------------------------------- + ')': + begin + fMode := SVF; + INC(fForward); + + result := MakeToken( TT_RPAREN, ''); + fStart := fForward; + end; + + // ---------------------------------------------------- + // SPACE,TAB + // ---------------------------------------------------- + #32, #9: INC(fStart); + + // ---------------------------------------------------- + // CR/LF + // ---------------------------------------------------- + #13,#10: + begin + INC(fStart); + + while fStart^ in [#13,#10] do + INC(fStart) + end; + + // ---------------------------------------------------- + // Invalid char + // ---------------------------------------------------- + else + ; + end + + else + case fForward^ of + // ---------------------------------------------------- + // String + // ---------------------------------------------------- + '"': + begin + INC(fForward); + + while not (fForward^ in ['"',#13,#10]) do + INC(fForward); + + if fForward^ = '"' then + INC(fForward); + + result := MakeToken( TT_STRING, GetTokenText); + fStart := fForward; + end; + + // ---------------------------------------------------- + // semicolon + // ---------------------------------------------------- + ';': + begin + INC(fForward); + + result := MakeToken( TT_SEMI, ';'); + fStart := fForward; + end; + + // ---------------------------------------------------- + // comment + // ---------------------------------------------------- + '!','/': + begin + if fForward^ = '/' then + begin + INC(fForward); + + if fForward^ <> '/' then + ; //raise + end; + + INC(fForward); + + while not (fForward^ in [#13,#10]) do + INC(fForward); + + result := MakeToken( TT_COMMENT, GetTokenText); + fStart := fForward; + end; + + // ---------------------------------------------------- + // id + // ---------------------------------------------------- + 'a'..'z','A'..'Z': + begin + INC(fForward); + + while fForward^ in ['a'..'z','A'..'Z'] do + INC(fForward); + + ttext := GetTokenText; + ttype := CheckLiteral( ttext, TT_ID); + result := MakeToken( ttype, ttext); + fStart := fForward; + end; + + // ---------------------------------------------------- + // number + // ---------------------------------------------------- + '0'..'9': + begin + INC(fForward); + + while fForward^ in ['0'..'9'] do + INC(fForward); + + if fForward^ = '.' then + begin + INC(fForward); + + while fForward^ in ['0'..'9'] do + INC(fForward) + end; + + if fForward^ in ['e','E'] then + begin + INC(fForward); + + if fForward^ in ['+','-'] then + begin + INC(fForward); + + if fForward^ in ['0'..'9'] then + begin + INC(fForward); + + while fForward^ in ['0'..'9'] do + INC(fForward); + end + + else + // raise + end + else + ; // raise + + end; + + result := MakeToken( TT_NUMBER, GetTokenText); + fStart := fForward; + end; + + // ---------------------------------------------------- + // HEX start + // ---------------------------------------------------- + '(': + begin + fMode := HEX; + INC(fForward); + + result := MakeToken( TT_LPAREN, ''); + fStart := fForward; + end; + + // ---------------------------------------------------- + // WS,CR/LF + // ---------------------------------------------------- + #32, #9: INC(fStart); + + #13,#10: + begin + INC(fStart); + + while fStart^ in [#13,#10] do + INC(fStart) + end; + + // ---------------------------------------------------- + // EOF + // ---------------------------------------------------- + #0: + begin + result := MakeToken( TT_EOF, ''); + fStart := fForward; + end; + + // ---------------------------------------------------- + // invalid + // ---------------------------------------------------- + else + begin + fStart := 0; + break; + end; + end; + + + if Assigned(result) then + break; + end; +end; + + + +end. diff --git a/src.jtag/svf/jtag.svfPar.pas b/src.jtag/svf/jtag.svfPar.pas new file mode 100644 index 0000000..7d718d2 --- /dev/null +++ b/src.jtag/svf/jtag.svfPar.pas @@ -0,0 +1,424 @@ +unit jtag.svfPar; + +interface +uses + jtag.svfLex, + jtag.svfProgram; + +type + TsvfPar = class + private + fLex : TsvfLex; + fPrg : TsvfProgram; + + protected + function Match( ttype : TTokenType; dispose: boolean=true):TsvfToken; overload; + function Match( ttypes : TTokenTypes; dispose: boolean=true):TsvfToken; overload; + + public + function SvfProgram: TsvfProgram; + + public + constructor Create( Lex: TsvfLex); + destructor Destroy; override; + end; + +implementation +uses + System.SysUtils, + jtag.svfAstEndDR, + jtag.svfAstEndIR, + jtag.svfAstFreq, + jtag.svfAstRuntest, + jtag.svfAstScan, + jtag.svfAstState, + jtag.svfAstPrint, + jtag.svfAstComment; + + +{ TsvfPar } + +constructor TsvfPar.Create(Lex: TsvfLex); +begin + inherited Create; + + fLex := Lex; + fPrg := TsvfProgram.Create; +end; + +destructor TsvfPar.Destroy; +begin + inherited; +end; + +// ================================================================================================ +// Match token +// ================================================================================================ +function TsvfPar.Match( ttype: TTokenType; dispose: boolean):TsvfToken; +var + t: TsvfToken; + +begin + t := fLex.NextToken; + + if t.TokenType = ttype then + if dispose + then t.Free + else result := t + else + raise Exception.Create('Unexpected token'); +end; + +// ================================================================================================ +// Match tokens +// ================================================================================================ +function TsvfPar.Match(ttypes: TTokenTypes; dispose: boolean): TsvfToken; +var + token: TsvfToken; + +begin + result := nil; + token := fLex.NextToken; + + if token.TokenType in ttypes then + if dispose + then token.Free + else result := token + else + raise Exception.Create('Unexpected token'); +end; + + +// ================================================================================================ +// SVF Program +// ================================================================================================ +function TsvfPar.SvfProgram : TsvfProgram; + + function EndState( ttype: TTokenType): byte; + begin + case ttype of + LT_IDLE : result := stIDLE; + LT_RESET : result := stRESET; + LT_IRPAUSE : result := stIRPAUSE; + LT_DRPAUSE : result := stDRPAUSE; + + else + raise Exception.Create('Invalid end state'); + end; + end; + + function RunState( ttype: TTokenType): byte; + begin + case ttype of + LT_IDLE : result := stIDLE; + LT_RESET : result := stRESET; + LT_IRPAUSE : result := stIRPAUSE; + LT_DRPAUSE : result := stDRPAUSE; + + else + raise Exception.Create('Invalid run state'); + end; + end; + + function GenState( ttype: TTokenType): byte; + begin + case ttype of + LT_RESET : result := stRESET; + LT_IDLE : result := stIDLE; + + LT_DRSELECT : result := stDRSELECT; + LT_DRCAPTURE: result := stDRCAPTURE; + LT_DRSHIFT : result := stDRSHIFT; + LT_DREXIT1 : result := stDREXIT1; + LT_DRPAUSE : result := stDRPAUSE; + LT_DREXIT2 : result := stDREXIT2; + LT_DRUPDATE : result := stDRUPDATE; + + LT_IRSELECT : result := stIRSELECT; + LT_IRCAPTURE: result := stIRCAPTURE; + LT_IRSHIFT : result := stIRSHIFT; + LT_IREXIT1 : result := stIREXIT1; + LT_IRPAUSE : result := stIRPAUSE; + LT_IREXIT2 : result := stIREXIT2; + LT_IRUPDATE : result := stIRUPDATE; + + else + raise Exception.Create('Invalid run state'); + end; + end; + +var + cmd: TsvfToken; + p1 : TsvfToken; + p2 : TsvfToken; + p3 : TsvfToken; + + f : double; + scan : TsvfAstScan; + run : TsvfAstRuntest; + st : TsvfAstState; + + tt1 : TTokenTypes; + tt2 : TTokenTypes; + tt1s : TTokenTypes; + +begin + result := nil; + scan := nil; + + tt1 := [LT_DRSELECT .. LT_DRPAUSE]; + tt2 := [LT_RESET .. LT_DRPAUSE]; + tt1s := [LT_DRSELECT .. LT_DRPAUSE,TT_SEMI]; + + + if Assigned(fLex) then + begin + while true do + begin + p1 := nil; + p2 := nil; + p3 := nil; + cmd := fLex.NextToken; + + case cmd.TokenType of + // ---------------------------------------------------------------- + // PRINT + // ---------------------------------------------------------------- + LT_PRINT: + begin + p1 := Match(TT_STRING, false); + fPrg.AddStatement( TsvfAstPrint.Create(p1.TokenText)); + p1.Free + end; + + + // ---------------------------------------------------------------- + // ENDIR, ENDDR + // ---------------------------------------------------------------- + LT_ENDIR,LT_ENDDR: + begin + p1 := Match([LT_RESET,LT_IDLE,LT_DRPAUSE,LT_IRPAUSE],false); + Match(TT_SEMI); + + case cmd.TokenType of + LT_ENDIR: fPrg.AddStatement( TsvfAstEndIR.Create(EndState(p1.TokenType))); + LT_ENDDR: fPrg.AddStatement( TsvfAstEndDR.Create(EndState(p1.TokenType))); + end; + + p1.Free + end; + + // ---------------------------------------------------------------- + // FREQUENCY + // ---------------------------------------------------------------- + LT_FREQUENCY: + begin + f := 1E6; + p1 := Match([TT_NUMBER,TT_SEMI],false); + + if p1.TokenType <> TT_SEMI then + begin + Match(LT_HZ); + Match(TT_SEMI); + + f := StrToFloat(p1.TokenText); + end; + + fPrg.AddStatement( TsvfAstFreq.Create( f)); + + p1.Free + end; + + // ---------------------------------------------------------------- + // HIR,HDR,TIR,TDR,SIR,SDR + // ---------------------------------------------------------------- + LT_HIR,LT_HDR,LT_TIR,LT_TDR,LT_SIR,LT_SDR: + begin + p1 := Match( TT_NUMBER, false); + p2 := Match( [LT_TDI,LT_TDO,LT_MASK,LT_SMASK,TT_SEMI], false); + + scan := TsvfAstScan.Create(cmd.TokenText, p1.TokenText); + + while p2.TokenType <> TT_SEMI do + begin + Match(TT_LPAREN); + + scan.BeginData; + + while true do + begin + p3 := Match( [TT_HEX,TT_RPAREN],false); + + if p3.TokenType = TT_RPAREN then + begin + scan.EndData; + + p3.Free; + break; + end; + + case p2.TokenType of + LT_TDI : scan.AddTDI( p3.TokenText); + LT_TDO : scan.AddTDO( p3.TokenText); + LT_MASK : scan.AddMASK( p3.TokenText); + LT_SMASK : scan.AddSMASK( p3.TokenText); + end; + + p3.Free; + end; + + p2.Free; + p2 := Match( [LT_TDI,LT_TDO,LT_MASK,LT_SMASK,TT_SEMI], false); + end; + + FreeAndNil(p2); + FreeAndNil(p1); + + fPrg.AddStatement(scan); + end; + + // ---------------------------------------------------------------- + // RUNTEST + // ---------------------------------------------------------------- + LT_RUNTEST: + begin + run := TsvfAstRuntest.Create; + + p1 := nil; + p2 := fLex.NextToken; + + if p2.TokenType <> TT_NUMBER then + begin + p1 := p2; + p2 := Match( TT_NUMBER, false); + end; + + if Assigned(p1) then + run.RunState:= RunState(p1.TokenType); + + p3 := Match( [LT_SCK,LT_TCK,LT_SEC], false); + + if p3.TokenType in [LT_SCK,LT_TCK] then + begin + run.RunClock := p3.TokenText; + run.RunCount := p2.TokenText; + end + + else begin + run.MinTime := p2.TokenText; + end; + + FreeAndNil(p3); + FreeAndNil(p2); + FreeAndNil(p1); + + p1 := Match( [TT_NUMBER,LT_MAXIMUM,LT_ENDSTATE,TT_SEMI], false); + + if p1.TokenType = TT_NUMBER then + begin + Match(LT_SEC); + run.MinTime := p1.TokenText; + + FreeAndNil(p1); + p1 := Match([LT_MAXIMUM,LT_ENDSTATE,TT_SEMI],false) + end; + + if p1.TokenType = LT_MAXIMUM then + begin + Match(LT_SEC); + run.MaxTime := p1.TokenText; + + FreeAndNil(p1); + p1 := Match([LT_ENDSTATE,TT_SEMI],false); + end; + + if p1.TokenType = LT_ENDSTATE then + begin + p2 := Match(tt2,false); + run.EndState := EndState(p2.TokenType); + + FreeAndNil(p2); + FreeAndNil(p1); + + p1 := Match(TT_SEMI, false); + end; + + FreeAndNil(p1); + + fPrg.AddStatement(run); + end; + + + // ---------------------------------------------------------------- + // STATE + // ---------------------------------------------------------------- + LT_STATE: + begin + st := TsvfAstState.Create; + p1 := Match( tt1,false); + + st.BeginData; + + while p1.TokenType <> TT_SEMI do + begin + st.AddState(GenState(p1.TokenType)); + + // stable state can be followed with SEMI + if p1.TokenType in tt2 then + begin + p1.Free; + p1 := Match( tt1s,false); + end + + else begin + p1.Free; + p1 := Match( tt1,false); + end; + end; + + FreeAndNil(p1); + + st.EndData; + fPrg.AddStatement(st); + end; + + // ---------------------------------------------------------------- + // TRST + // ---------------------------------------------------------------- + LT_TRST: + begin + p1 := Match( [LT_ON,LT_OFF,LT_Z,LT_ABSENT],false); + Match(TT_SEMI); + + // ... + + p1.Free + end; + + // ---------------------------------------------------------------- + // Comment + // ---------------------------------------------------------------- + TT_COMMENT: + begin + fPrg.AddStatement( TsvfAstComment.Create(cmd.TokenText)); + end; + + + // ---------------------------------------------------------------- + // End Of File + // ---------------------------------------------------------------- + TT_EOF: + begin + cmd.Free; + break; + end; + end; + + cmd.Free; + end; + + result := fPrg; + end; +end; + +end. diff --git a/src.jtag/svf/jtag.svfProgram.pas b/src.jtag/svf/jtag.svfProgram.pas new file mode 100644 index 0000000..ba722d5 --- /dev/null +++ b/src.jtag/svf/jtag.svfProgram.pas @@ -0,0 +1,155 @@ +unit jtag.svfProgram; + +interface +uses + jtag.svfAstNode, + System.Contnrs; + +const + stRESET = 0; + stIDLE = 1; + + stDRSELECT = 2; + stDRCAPTURE = 3; + stDRSHIFT = 4; + stDRPAUSE = 5; + stDREXIT1 = 6; + stDREXIT2 = 7; + stDRUPDATE = 8; + + stIRSELECT = 9; + stIRCAPTURE = 10; + stIRSHIFT = 11; + stIRPAUSE = 12; + stIREXIT1 = 13; + stIREXIT2 = 14; + stIRUPDATE = 15; + + stNONDEF = $ff; + +type + TsvfProgram = class + private + fStatements : TObjectList; + + function GetStatementCount : integer; + function GetStatement(i: integer): TsvfAstNode; + + public + procedure AddStatement( Stmt: TsvfAstNode); + + public + constructor Create; + destructor Destroy; override; + + procedure Dump( FileName: string); + + public + property StatementCount : integer read GetStatementCount; + property Statements[i: integer] : TsvfAstNode read GetStatement; + + end; + +implementation +uses + System.Classes; + +{ TsvfProgram } + +// @@@: Constructor/destructor ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// Constructor/destructor +// +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ====================================================================================== +// Constructor +// ====================================================================================== +constructor TsvfProgram.Create; +begin + inherited; + fStatements := TObjectList.Create( true); +end; + +// ====================================================================================== +// Destructor +// ====================================================================================== +destructor TsvfProgram.Destroy; +begin + fStatements.Free; + inherited; +end; + +// @@@: Interface +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// Interface +// +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ====================================================================================== +// AddStatement +// ====================================================================================== +procedure TsvfProgram.AddStatement(Stmt: TsvfAstNode); +begin + fStatements.Add( Stmt); +end; + +// ================================================================================================ +// Dump +// ================================================================================================ +procedure TsvfProgram.Dump(FileName: string); +var + i : integer; + s : AnsiString; + stm : TMemoryStream; + + +begin + stm := TMemoryStream.Create; + + for i:=0 to StatementCount -1 do + begin + s := Statements[i].AsText; + stm.Write(s[1], Length(s)); + end; + + stm.SaveToFile(FileName); + stm.Free +end; + + +// @@@: Property Handlers +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// +// Property Handlers +// +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +// ====================================================================================== +// GetStatementCount +// ====================================================================================== +function TsvfProgram.GetStatementCount: integer; +begin + result := fStatements.Count; +end; + +// ====================================================================================== +// GetStatement +// ====================================================================================== +function TsvfProgram.GetStatement(i: integer): TsvfAstNode; +begin + if (i>=0) and (i fSIR_TDOData[i] then + begin + bits := 0; + end; + end; + + writeln( Format('SIR(mr): %s', [reverse(fSIR_TDIData,bytes)])); + writeln( Format('SIR(mo): %s', [reverse(fSIR_TDOData,bytes)])); + end; + end; + + writeln; + end; + + SCAN_SDR: + begin + writeln( Format('SDR(s) : %s', [reverse(fSDR_TDIData,bytes)])); + fJTAG.sdr( fSDR_TDIData, bits); + writeln( Format('SDR(r) : %s', [reverse(fSDR_TDIData,bytes)])); + + if dtTDOData in fDataSDR then + begin + writeln( Format('SDR(o) : %s', [reverse(fSDR_TDOData,bytes)])); + + if dtMASKData in fDataSDR then + begin + writeln( Format('SDR(m) : %s', [reverse(fSDR_MASKData,bytes)])); + + for i:=0 to bytes -1 do + begin + fSDR_TDIData[i] := fSDR_TDIData[i] and fSDR_MASKData[i]; + fSDR_TDOData[i] := fSDR_TDOData[i] and fSDR_MASKData[i]; + end; + + sTDI := reverse(fSDR_TDIData,bytes); + sTDO := reverse(fSDR_TDOData,bytes); + + writeln( Format('SDR(mr): %s', [sTDI])); + writeln( Format('SDR(mo): %s', [sTDO])); + end; + + s := ''; + + for i:=1 to Length(sTDI) do + if sTDI[i] <> sTDO[i] + then s := s + '^' + else s := s + ' '; + + if Trim(s) <> '' then + writeln( Format(' %s', [s])); + + end; + + writeln; + end; + end; + end; + end; +end; + + +// ================================================================================================ +// ENDIR/ENDDR +// ================================================================================================ +function TjtagSVF.svfENDxR: TsvfReturnCode; +var + state : AnsiChar; + tmp : AnsiString; + +begin + result := SVF_InvalidFile; + state := '0'; + tmp := ''; + + if (fBuffer[fBufferIdx+4] = 'R') and (fBuffer[fBufferIdx+5] in [#32,#9]) then + begin + INC(fBufferIdx,5); + + // skip whitespaces + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in [#32,#9]) do + INC(fBufferIdx); + + if fBufferIdx = fBufferSize then + exit; + + if not (fBuffer[fBufferIdx] in ['I','D','R']) then + exit; + + // read state name + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in ['A'..'Z']) do + begin + tmp := tmp + fBuffer[fBufferIdx]; + INC(fBufferIdx); + end; + + // check state name + if tmp = 'IRPAUSE' then else + if tmp = 'DRPAUSE' then else + if tmp = 'RESET' then else + if tmp = 'IDLE' then else exit; + + // skip whitespaces + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in [#32,#9]) do + INC(fBufferIdx); + + if fBufferIdx = fBufferSize then + exit; + + if fBuffer[fBufferIdx] = ';' then + begin + inc( fBufferIdx); + result := SVF_OK + end; + end; +end; + +// ================================================================================================ +// FREQUENCY +// ================================================================================================ +function TjtagSVF.svfFreq: TsvfReturnCode; +var + tmp: AnsiString; + +begin + result := SVF_InvalidFile; + tmp := ''; + + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in ['A'..'Z']) do + begin + tmp := tmp + fBuffer[fBufferIdx]; + inc(fBufferIdx); + end; + + if fBufferIdx = fBufferSize then + exit; + + if tmp = 'FREQUENCY' then + begin + // just skip for now + while (fBufferIdx < fBufferSize) and not (fBuffer[fBufferIdx] in [#13,#10]) do + inc(fBufferIdx); + end; +end; + +// ================================================================================================ +// RUNTEST +// ================================================================================================ +function TjtagSVF.svfRun: TsvfReturnCode; +var + tmp: AnsiString; + + tck : integer; + int : integer; + frc : integer; + exp : integer; + + state : TJTAGState; + save : cardinal; + + pulses: cardinal; + burst : WORD; + +label + pulse; + +begin + result := SVF_InvalidFile; + tmp := ''; + tck := 0; + pulses := 0; + + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in ['A'..'Z']) do + begin + tmp := tmp + fBuffer[fBufferIdx]; + inc(fBufferIdx); + end; + + if fBufferIdx = fBufferSize then + exit; + + if tmp = 'RUNTEST' then + begin + // skip whitespaces + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in [#32,#9]) do + INC(fBufferIdx); + + if fBufferIdx = fBufferSize then + exit; + + // get optional state + state := UNDEF; + + if fBuffer[fBufferIdx] in ['I','D','R'] then + begin + tmp := ''; + + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in ['A'..'Z']) do + begin + tmp := tmp + fBuffer[fBufferIdx]; + INC(fBufferIdx); + end; + + if tmp = 'DRPAUSE' then state := DRPAUSE else + if tmp = 'IRPAUSE' then state := IRPAUSE else + if tmp = 'RESET' then state := RESET else + if tmp = 'IDLE' then state := IDLE else exit; + end; + + // skip whitespaces + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in [#32,#9]) do + INC(fBufferIdx); + + if (fBufferIdx = fBufferSize) or not (fBuffer[fBufferIdx] in ['0'..'9']) then + exit; + + save := fBufferIdx; // remember position + + // get number of TCK pulses or integer part of mintime + int := 0; + frc := 0; + exp := 0; + tmp := ''; + + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in ['0'..'9']) do + begin + int := int * 10 + integer(fBuffer[fBufferIdx]) - ord('0'); + tmp := tmp + fBuffer[fBufferIdx]; + INC(fBufferIdx); + end; + + if fBufferIdx = fBufferSize then + exit; + + // "run_count run_clk" case + if fBuffer[fBufferIdx] <> '.' then + begin + // skip whitespaces + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in [#32,#9]) do + INC(fBufferIdx); + + if fBufferIdx = fBufferSize then + exit; + + // read 'TCK' or 'SCK' + if (fBuffer[fBufferIdx+0] in ['T','S']) and + (fBuffer[fBufferIdx+1] = 'C') and + (fBuffer[fBufferIdx+2] = 'K') then + begin + tck := int; + int := 0; + inc(fBufferIdx,3); + + // skip whitespaces + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in [#32,#9]) do + INC(fBufferIdx); + + if fBufferIdx = fBufferSize then + exit; + + if fBuffer[fBufferIdx] = ';' then + begin + result := SVF_OK; + inc(fBufferIdx); + goto pulse; + end; + end + + else + exit; + end + + else + fBufferIdx := save; + + // read mintime + int := 0; + frc := 0; + exp := 0; + tmp := ''; + + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in ['0'..'9']) do + begin + int := int * 10 + integer(fBuffer[fBufferIdx]) - ord('0'); + tmp := tmp + fBuffer[fBufferIdx]; + INC(fBufferIdx); + end; + + if (fBufferIdx = fBufferSize) or (fBuffer[fBufferIdx] <> '.') then + exit; + + tmp := tmp + fBuffer[fBufferIdx]; + inc(fBufferIdx); + + if (fBufferIdx = fBufferSize) or not (fBuffer[fBufferIdx] in ['0'..'9']) then + exit; + + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in ['0'..'9']) do + begin + frc := frc + integer(fBuffer[fBufferIdx]) - ord('0'); + tmp := tmp + fBuffer[fBufferIdx]; + INC(fBufferIdx); + end; + + // match exponent letter: 'E' + if (fBufferIdx = fBufferSize) or (fBuffer[fBufferIdx] <> 'E') then + exit; + + tmp := tmp + fBuffer[fBufferIdx]; + inc(fBufferIdx); + + // match optional sign: ('+' | '-') + if fBuffer[fBufferIdx] in ['-','+'] then + begin + tmp := tmp + fBuffer[fBufferIdx]; + inc(fBufferIdx); + end; + + // match exponent: ('0'..'9')+ + if (fBufferIdx = fBufferSize) or not (fBuffer[fBufferIdx] in ['0'..'9']) then + exit; + + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in ['0'..'9']) do + begin + exp := exp + integer(fBuffer[fBufferIdx]) - ord('0'); + tmp := tmp + fBuffer[fBufferIdx]; + INC(fBufferIdx); + end; + + // skip WS: (' ' | '\t')* + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in [#32,#9]) do + INC(fBufferIdx); + + if fBufferIdx = fBufferSize then + exit; + + pulses := Round(StrToFloat(tmp) / 1e-6); + + // match second mark: 'SEC' + if (fBufferIdx = fBufferSize) or (fBuffer[fBufferIdx] <> 'S') then + exit; + + tmp := ''; + + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in ['S','E','C']) do + begin + tmp := tmp + fBuffer[fBufferIdx]; + INC(fBufferIdx); + end; + + if tmp <> 'SEC' then + exit; + + // skip WS: (' ' | '\t')* + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in [#32,#9]) do + INC(fBufferIdx); + + if fBufferIdx = fBufferSize then + exit; + + // TODO:maxtime, endstate.... + + + // match instruction terminator: ';' + if fBuffer[fBufferIdx] <> ';' then + exit; + + inc(fBufferIdx); + + result := SVF_OK; + + // ------------------------------------------------------------ + // execute command + // ------------------------------------------------------------ +pulse: + if Assigned( fJTAG) then + begin + pulses := pulses + tck; + + while(pulses > 0) do + begin + if pulses > 50000 then + begin + burst := 50000; + pulses := pulses - 50000 + end + + else begin + burst := pulses; + pulses := 0 + end; + + fJTAG.run(state,burst); + end; + end; + + end; +end; + + +// ================================================================================================ +// STATE +// ================================================================================================ +function TjtagSVF.svfState : TsvfReturnCode; +var + tmp : AnsiString; + state : TJTAGState; + +begin + result := SVF_InvalidFile; + state := UNDEF; + tmp := ''; + + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in ['A'..'Z']) do + begin + tmp := tmp + fBuffer[fBufferIdx]; + inc(fBufferIdx); + end; + + if fBufferIdx = fBufferSize then + exit; + + if tmp = 'STATE' then + begin + while true do + begin + tmp := ''; + + // skip whitespaces + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in [#32,#9]) do + INC(fBufferIdx); + + // read state name + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in ['A'..'Z']) do + begin + tmp := tmp + fBuffer[fBufferIdx]; + INC(fBufferIdx); + end; + + // check state name + if tmp = 'IRPAUSE' then state := IRPAUSE else + if tmp = 'DRPAUSE' then state := DRPAUSE else + if tmp = 'RESET' then state := RESET else + if tmp = 'IDLE' then state := IDLE else exit; + + // skip whitespaces + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in [#32,#9]) do + INC(fBufferIdx); + + if fBufferIdx = fBufferSize then + exit; + + if Assigned(JTAG) then + JTAG.state(state); + + if fBuffer[fBufferIdx] = ';' then + begin + inc( fBufferIdx); + result := SVF_OK; + + break; + end; + end; + end; +end; + +// ================================================================================================ +// svfData +// ================================================================================================ +function TjtagSVF.svfData(buf: PBYTE; bits: cardinal): TsvfReturnCode; +var + tmp : AnsiString; + bytes : cardinal; + count : cardinal; + b : byte; + i : integer; + + function Reverse( c: AnsiChar): BYTE; + var + b: BYTE; + + begin + Result := 0; + + case c of + '0'..'9': b := ord(c) - ord('0'); + 'A'..'F': b := ord(c) - ord('A') + 10; + 'a'..'f': b := ord(c) - ord('a') + 10; + end; + + if b and $08 = $08 then Result := Result + $01; + if b and $04 = $04 then Result := Result + $02; + if b and $02 = $02 then Result := Result + $04; + if b and $01 = $01 then Result := Result + $08; + end; + +begin + result := SVF_InvalidFile; + bytes := (bits + 7) div 8; + + // skip whitespaces + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in [#32,#9]) do + INC(fBufferIdx); + + if fBufferIdx = fBufferSize then + exit; + + if fBuffer[fBufferIdx] <> '(' then + exit; + + inc( fBufferIdx); + + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in [#32,#9]) do + INC(fBufferIdx); + + if fBufferIdx = fBufferSize then + exit; + + if not (fBuffer[fBufferIdx] in ['0'..'9','A'..'F','a'..'f']) then + exit; + + tmp := ''; + + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in ['0'..'9','A'..'F','a'..'f',#32,#9,#13,#10]) do + begin + if fBuffer[fBufferIdx] in ['0'..'9','A'..'F','a'..'f'] then + tmp := tmp + fBuffer[fBufferIdx]; + + inc(fBufferIdx); + end; + + if length(tmp) < (bits + 3) div 4 then + exit; + + bytes := 0; + count := 0; + + for i:=length(tmp) downto 1 do + begin + b := Reverse(tmp[i]); + + if count mod 2 = 0 + then buf[bytes] := b shl 4 + else buf[bytes] := buf[bytes] + b; + + if count mod 2 = 1 then + inc(bytes); + + inc(count); + + if count * 4 >= bits then + break; + end; + + + if fBufferIdx = fBufferSize then + exit; + + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in [#32,#9]) do + INC(fBufferIdx); + + if fBufferIdx = fBufferSize then + exit; + + if fBuffer[fBufferIdx] <> ')' then + exit; + + inc( fBufferIdx); + + while (fBufferIdx < fBufferSize) and (fBuffer[fBufferIdx] in [#32,#9,#13,#10]) do + INC(fBufferIdx); + + if fBufferIdx = fBufferSize then + exit; + + result := SVF_OK +end; + +// ================================================================================================ +// svfMemManager +// ================================================================================================ +procedure TjtagSVF.svfMemManager( scan: TScan; bits: cardinal); +var + bytes: cardinal; +begin + bytes := (bits + 7) div 8; + + case scan of + SCAN_HIR: + begin + if (bits = 0) or (bits > fHIRSize) then + begin + if Assigned(fHIR_TDIData) then FreeMemory(fHIR_TDIData); + if Assigned(fHIR_TDOData) then FreeMemory(fHIR_TDOData); + if Assigned(fHIR_MASKData) then FreeMemory(fHIR_MASKData); + if Assigned(fHIR_SMASKData) then FreeMemory(fHIR_SMASKData); + + if bits = 0 then + begin + fHIR_TDIData := nil; + fHIR_TDOData := nil; + fHIR_MASKData := nil; + fHIR_SMASKData := nil + end + + else begin + fHIR_TDIData := GetMemory(bytes); + fHIR_TDOData := GetMemory(bytes); + fHIR_MASKData := GetMemory(bytes); + fHIR_SMASKData := GetMemory(bytes) + end + end; + + if fHIRSize <> bits then + begin + fHIRSize := bits; + fDataHIR := [] + end + end; + + SCAN_HDR: + begin + if (bits = 0) or (bits > fHDRSize) then + begin + if Assigned(fHDR_TDIData) then FreeMemory(fHDR_TDIData); + if Assigned(fHDR_TDOData) then FreeMemory(fHDR_TDOData); + if Assigned(fHDR_MASKData) then FreeMemory(fHDR_MASKData); + if Assigned(fHDR_SMASKData) then FreeMemory(fHDR_SMASKData); + + if bits = 0 then + begin + fHDR_TDIData := nil; + fHDR_TDOData := nil; + fHDR_MASKData := nil; + fHDR_SMASKData := nil + end + + else begin + fHDR_TDIData := GetMemory(bytes); + fHDR_TDOData := GetMemory(bytes); + fHDR_MASKData := GetMemory(bytes); + fHDR_SMASKData := GetMemory(bytes) + end + end; + + if fHDRSize <> bits then + begin + fHDRSize := bits; + fDataHDR := [] + end + end; + + SCAN_TIR: + begin + if (bits = 0) or (bits > fTIRSize) then + begin + if Assigned(fTIR_TDIData) then FreeMemory(fTIR_TDIData); + if Assigned(fTIR_TDOData) then FreeMemory(fTIR_TDOData); + if Assigned(fTIR_MASKData) then FreeMemory(fTIR_MASKData); + if Assigned(fTIR_SMASKData) then FreeMemory(fTIR_SMASKData); + + if bits = 0 then + begin + fTIR_TDIData := nil; + fTIR_TDOData := nil; + fTIR_MASKData := nil; + fTIR_SMASKData := nil + end + + else begin + fTIR_TDIData := GetMemory(bytes); + fTIR_TDOData := GetMemory(bytes); + fTIR_MASKData := GetMemory(bytes); + fTIR_SMASKData := GetMemory(bytes) + end + end; + + if fTIRSize <> bits then + begin + fTIRSize := bits; + fDataTIR := [] + end + end; + + SCAN_TDR: + begin + if (bits = 0) or (bits > fTDRSize) then + begin + if Assigned(fTDR_TDIData) then FreeMemory(fTDR_TDIData); + if Assigned(fTDR_TDOData) then FreeMemory(fTDR_TDOData); + if Assigned(fTDR_MASKData) then FreeMemory(fTDR_MASKData); + if Assigned(fTDR_SMASKData) then FreeMemory(fTDR_SMASKData); + + if bits = 0 then + begin + fTDR_TDIData := nil; + fTDR_TDOData := nil; + fTDR_MASKData := nil; + fTDR_SMASKData := nil + end + + else begin + fTDR_TDIData := GetMemory(bytes); + fTDR_TDOData := GetMemory(bytes); + fTDR_MASKData := GetMemory(bytes); + fTDR_SMASKData := GetMemory(bytes) + end + end; + + if fTDRSize <> bits then + begin + fTDRSize := bits; + fDataTDR := [] + end + end; + + SCAN_SIR: + begin + if (bits = 0) or (bits > fSIRSize) then + begin + if Assigned(fSIR_TDIData) then FreeMemory(fSIR_TDIData); + if Assigned(fSIR_TDOData) then FreeMemory(fSIR_TDOData); + if Assigned(fSIR_MASKData) then FreeMemory(fSIR_MASKData); + if Assigned(fSIR_SMASKData) then FreeMemory(fSIR_SMASKData); + + if bits = 0 then + begin + fSIR_TDIData := nil; + fSIR_TDOData := nil; + fSIR_MASKData := nil; + fSIR_SMASKData := nil + end + + else begin + fSIR_TDIData := GetMemory(bytes); + fSIR_TDOData := GetMemory(bytes); + fSIR_MASKData := GetMemory(bytes); + fSIR_SMASKData := GetMemory(bytes) + end + end; + + if fSIRSize <> bits then + begin + fSIRSize := bits; + fDataSIR := [] + end + end; + + SCAN_SDR: + begin + if (bits = 0) or (bits > fSDRSize) then + begin + if Assigned(fSDR_TDIData) then FreeMemory(fSDR_TDIData); + if Assigned(fSDR_TDOData) then FreeMemory(fSDR_TDOData); + if Assigned(fSDR_MASKData) then FreeMemory(fSDR_MASKData); + if Assigned(fSDR_SMASKData) then FreeMemory(fSDR_SMASKData); + + if bits = 0 then + begin + fSDR_TDIData := nil; + fSDR_TDOData := nil; + fSDR_MASKData := nil; + fSDR_SMASKData := nil + end + + else begin + fSDR_TDIData := GetMemory(bytes); + fSDR_TDOData := GetMemory(bytes); + fSDR_MASKData := GetMemory(bytes); + fSDR_SMASKData := GetMemory(bytes) + end + end; + + if fSDRSize <> bits then + begin + fSDRSize := bits; + fDataSDR := [] + end + end; + end; +end; + + +end. diff --git a/src.jtag/vme/jtag.vme.pas b/src.jtag/vme/jtag.vme.pas new file mode 100644 index 0000000..2173f51 --- /dev/null +++ b/src.jtag/vme/jtag.vme.pas @@ -0,0 +1,2900 @@ +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. diff --git a/src.jtag/vme/jtag.vme.tools.pas b/src.jtag/vme/jtag.vme.tools.pas new file mode 100644 index 0000000..8b62865 --- /dev/null +++ b/src.jtag/vme/jtag.vme.tools.pas @@ -0,0 +1,46 @@ +unit jtag.vme.tools; + +interface + +function FlipByte( Data: byte): byte; +function FlipWord( Data: word): word; + +implementation + +function FlipByte( Data: byte): byte; +var + i: integer; + +begin + result := 0; + + for i:=0 to 7 do + begin + result := result shl 1; + + if Data and $01 = $01 then + result := result or $1; + + Data := Data shr 1; + end; +end; + +function FlipWord( Data: word): word; +var + i: integer; + +begin + result := 0; + + for i:=0 to 15 do + begin + result := result shl 1; + + if Data and $01 = $01 then + result := result or $1; + + Data := Data shr 1; + end; +end; + +end.