425 lines
12 KiB
ObjectPascal
425 lines
12 KiB
ObjectPascal
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.
|