Ignore:
Timestamp:
May 1, 2019, 9:48:46 PM (6 years ago)
Author:
chronos
Message:
  • Added: Assembler labels reference address calculation.
  • Fixed: Displaying address/data hex numbers in opcode and instruction.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/virtualcpu4/UAssembler.pas

    r184 r185  
    2020    Text: string;
    2121    procedure Expect(Text: string);
     22    function IsOperator(C: Char): Boolean;
     23    function IsWhiteSpace(C: Char): Boolean;
    2224    function ReadNext: string;
    2325    function EndOfText: Boolean;
     
    2527  end;
    2628
     29  TLabelRef = class
     30    Address: QWord;
     31    BitWidth: TBitWidth;
     32    Relative: Boolean;
     33  end;
     34
     35  { TLabel }
     36
    2737  TLabel = class
    2838    Name: string;
    2939    Address: QWord;
    30   end;
     40    Refs: TFPGList<TLabelRef>;
     41    constructor Create;
     42    destructor Destroy; override;
     43  end;
     44
     45  { TLabels }
    3146
    3247  TLabels = class(TFPGObjecTList<TLabel>)
    33 
     48    function SearchByName(Name: string): TLabel;
    3449  end;
    3550
     
    4055    FOnError: TErrorEvent;
    4156    OpcodeDefs: TOpcodeDefs;
     57    InstructionIP: QWord;
    4258    procedure Error(Text: string);
    4359    procedure ParseParam(Param: TOpcodeParam);
     60    procedure WriteRefAddr(Name: string; Relative: Boolean = False);
     61    procedure WriteRefData(Name: string);
     62    procedure UpdateLabelRef;
     63    procedure ParseInstruction;
    4464  public
    4565    Parser: TParser;
     
    5676implementation
    5777
     78{ TLabels }
     79
     80function TLabels.SearchByName(Name: string): TLabel;
     81var
     82  I: Integer;
     83begin
     84  I := 0;
     85  while (I < Count) and (Items[I].Name <> Name) do Inc(I);
     86  if I < Count then Result := Items[I]
     87    else Result := nil;
     88end;
     89
     90{ TLabel }
     91
     92constructor TLabel.Create;
     93begin
     94  Refs := TFPGList<TLabelRef>.Create;
     95end;
     96
     97destructor TLabel.Destroy;
     98begin
     99  Refs.Free;
     100  inherited Destroy;
     101end;
     102
    58103{ TParser }
    59104
     
    72117end;
    73118
     119function TParser.IsOperator(C: Char): Boolean;
     120begin
     121  Result := (C = ',') or (C = ';');
     122end;
     123
     124function TParser.IsWhiteSpace(C: Char): Boolean;
     125begin
     126  Result := (C = ' ') or (C = #8);
     127end;
     128
    74129function TParser.ReadNext: string;
    75130var
     
    78133  Text := Trim(Text);
    79134  P := 1;
    80   if (Length(Text) > 0) and (Text[P] = ',') then begin
     135  if (Length(Text) > 0) and IsOperator(Text[P]) then begin
    81136    Result := Text[P];
    82137    Delete(Text, 1, 1);
    83138  end else begin
    84     while (P <= Length(Text)) and (Text[P] <> ' ') and (Text[P] <> ',') do Inc(P);
     139    while (P <= Length(Text)) and not IsWhiteSpace(Text[P]) and not IsOperator(Text[P]) do Inc(P);
    85140    Result := Copy(Text, 1, P - 1);
    86141    Delete(Text, 1, P - 1);
     
    103158var
    104159  Reg: TRegIndex;
    105   Addr: QWord;
     160  Addr: Int64;
    106161  Next: string;
    107162begin
     
    115170  if Param = prData then begin
    116171    Next := Parser.ReadNext;
    117     InstructionWriter.WriteData(StrToInt(Next));
     172    if TryStrToInt64(Next, Addr) then
     173      InstructionWriter.WriteData(Addr)
     174      else WriteRefData(Next);
    118175  end else
    119176  if Param = prAddr then begin
    120177    Next := Parser.ReadNext;
    121     InstructionWriter.WriteAddress(StrToInt(Next));
     178    if TryStrToInt64(Next, Addr) then
     179      InstructionWriter.WriteAddress(Addr)
     180      else WriteRefAddr(Next);
    122181  end else
    123182  if Param = prAddrRel then begin
    124183    Next := Parser.ReadNext;
    125     InstructionWriter.WriteAddress(StrToInt(Next));
    126   end;
     184    if TryStrToInt64(Next, Addr) then
     185      InstructionWriter.WriteAddress(InstructionWriter.IP + Addr)
     186      else WriteRefAddr(Next, True);
     187  end;
     188end;
     189
     190procedure TAssembler.WriteRefAddr(Name: string; Relative: Boolean = False);
     191var
     192  L: TLabel;
     193  NewRef: TLabelRef;
     194begin
     195  L := Labels.SearchByName(Name);
     196  if Assigned(L) then begin
     197    if Relative then
     198      InstructionWriter.WriteAddressSigned(InstructionWriter.GetRelativeAddr(
     199        InstructionWriter.AddrSize, InstructionIP, L.Address))
     200      else InstructionWriter.WriteAddress(L.Address);
     201  end else begin
     202    L := TLabel.Create;
     203    L.Name := Name;
     204    NewRef := TLabelRef.Create;
     205    NewRef.Address := InstructionWriter.IP;
     206    NewRef.BitWidth := InstructionWriter.AddrSize;
     207    if Relative then NewRef.Relative := True;
     208    L.Refs.Add(NewRef);
     209    Labels.Add(L);
     210    InstructionWriter.WriteAddress(0);
     211  end;
     212end;
     213
     214procedure TAssembler.WriteRefData(Name: string);
     215var
     216  L: TLabel;
     217  NewRef: TLabelRef;
     218begin
     219  L := Labels.SearchByName(Name);
     220  if Assigned(L) then begin
     221    InstructionWriter.WriteData(L.Address);
     222  end else begin
     223    L := TLabel.Create;
     224    L.Name := Name;
     225    NewRef := TLabelRef.Create;
     226    NewRef.Address := InstructionWriter.IP;
     227    NewRef.BitWidth := InstructionWriter.DataSize;
     228    L.Refs.Add(NewRef);
     229    Labels.Add(L);
     230    InstructionWriter.WriteData(0);
     231  end;
     232end;
     233
     234procedure TAssembler.UpdateLabelRef;
     235var
     236  I: Integer;
     237  R: Integer;
     238begin
     239  for I := 0 to Labels.Count - 1 do
     240  with TLabel(Labels[I]) do begin
     241    for R := 0 to Refs.Count - 1 do
     242    begin
     243      InstructionWriter.IP := Refs[R].Address;
     244      InstructionWriter.AddrSize := Refs[R].BitWidth;
     245      if Refs[R].Relative then InstructionWriter.WriteAddressSigned(InstructionWriter.GetRelativeAddr(
     246        InstructionWriter.AddrSize, InstructionWriter.IP - 1, Address))
     247        else InstructionWriter.WriteAddress(Address);
     248    end;
     249  end;
     250end;
     251
     252procedure TAssembler.ParseInstruction;
     253var
     254  Next: string;
     255  LabelName: string;
     256  NewLabel: TLabel;
     257  OpcodeDef: TOpcodeDef;
     258begin
     259  Next := Parser.ReadNext;
     260  if Next = '' then Exit;
     261  if (Length(Next) > 0) and (Next[Length(Next)] = ':') then begin
     262    LabelName := Copy(Next, 1, Length(Next) - 1);
     263    NewLabel := Labels.SearchByName(LabelName);
     264    if not Assigned(NewLabel) then begin
     265      NewLabel := TLabel.Create;
     266      NewLabel.Name := LabelName;
     267      Labels.Add(NewLabel);
     268    end;
     269    NewLabel.Address := InstructionWriter.IP;
     270    Next := Parser.ReadNext;
     271  end;
     272  if Next = '' then Exit;
     273  OpcodeDef := OpcodeDefs.SearchByName(Next);
     274  if Assigned(OpcodeDef) then begin
     275    if OpcodeDef.Prefix then InstructionWriter.Prefix := True;
     276    if OpcodeDef.Opcode = opDataPrefix16 then InstructionWriter.DataSize := bw8
     277    else if OpcodeDef.Opcode = opDataPrefix16 then InstructionWriter.DataSize := bw16
     278    else if OpcodeDef.Opcode = opDataPrefix32 then InstructionWriter.DataSize := bw32
     279    else if OpcodeDef.Opcode = opDataPrefix64 then InstructionWriter.DataSize := bw64
     280    else if OpcodeDef.Opcode = opAddrPrefix8 then InstructionWriter.AddrSize := bw8
     281    else if OpcodeDef.Opcode = opAddrPrefix16 then InstructionWriter.AddrSize := bw16
     282    else if OpcodeDef.Opcode = opAddrPrefix32 then InstructionWriter.AddrSize := bw32
     283    else if OpcodeDef.Opcode = opAddrPrefix64 then InstructionWriter.AddrSize := bw64;
     284    InstructionIP := InstructionWriter.IP;
     285    InstructionWriter.Write8(Byte(OpcodeDef.Opcode));
     286    ParseParam(OpcodeDef.Param1);
     287    if OpcodeDef.Param2 <> prNone then begin
     288      Parser.Expect(',');
     289      ParseParam(OpcodeDef.Param2);
     290      if OpcodeDef.Param3 <> prNone then begin
     291        Parser.Expect(',');
     292        ParseParam(OpcodeDef.Param3);
     293      end;
     294    end;
     295    if not OpcodeDef.Prefix then begin
     296      InstructionWriter.DataSize := InstructionWriter.DataSizeBase;
     297      InstructionWriter.AddrSize := InstructionWriter.AddrSizeBase;
     298    end;
     299  end else
     300  if Next = 'STRING' then begin
     301    Next := Parser.ReadNext;
     302    if (Length(Next) >= 2) and (Next[1] = '''') and (Next[Length(Next)] = '''') then
     303      InstructionWriter.WriteString(Copy(Next, 2, Length(Next) - 2));
     304  end else
     305  Error('Unknown instruction ' + Next);
    127306end;
    128307
     
    130309var
    131310  I: Integer;
    132   NewLabel: TLabel;
    133311  Next: string;
    134   OpcodeDef: TOpcodeDef;
    135312begin
    136313  InstructionWriter.Init;
     
    138315  for I := 0 to Source.Count - 1 do begin
    139316    Parser.Text := Source[I];
    140     Next := Parser.ReadNext;
    141     if (Length(Next) > 0) and (Next[Length(Next)] = ':') then begin
    142       NewLabel := TLabel.Create;
    143       NewLabel.Name := Copy(Next, 1, Length(Next) - 1);
    144       //NewLabel.Address := ;
    145       Labels.Add(NewLabel);
     317    ParseInstruction;
     318    repeat
    146319      Next := Parser.ReadNext;
    147     end;
    148     OpcodeDef := OpcodeDefs.SearchByName(Next);
    149     if Assigned(OpcodeDef) then begin
    150       InstructionWriter.Write8(Byte(OpcodeDef.Opcode));
    151       ParseParam(OpcodeDef.Param1);
    152       if OpcodeDef.Param2 <> prNone then begin
    153         Parser.Expect(',');
    154         ParseParam(OpcodeDef.Param2);
    155         if OpcodeDef.Param3 <> prNone then begin
    156           Parser.Expect(',');
    157           ParseParam(OpcodeDef.Param3);
    158         end;
    159       end;
    160     end else Error('Unknown instruction ' + Next);
    161   end;
     320      if (Next = '') or (Next <> ';') then Break;
     321      ParseInstruction;
     322    until False;
     323  end;
     324  UpdateLabelRef;
    162325end;
    163326
Note: See TracChangeset for help on using the changeset viewer.