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.