{
    Copyright (c) 2014 by Florian Klaempfl

    Symbol table overrides for i8086

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

 ****************************************************************************
}
unit symcpu;

{$i fpcdefs.inc}

interface

uses
  globtype,
  symconst,symtype,symdef,symsym,symx86,symi86;

type
  { defs }
  tcpufiledef = class(tfiledef)
  end;
  tcpufiledefclass = class of tcpufiledef;

  tcpuvariantdef = class(tvariantdef)
  end;
  tcpuvariantdefclass = class of tcpuvariantdef;

  tcpuformaldef = class(tformaldef)
  end;
  tcpuformaldefclass = class of tcpuformaldef;

  tcpuforwarddef = class(tforwarddef)
  end;
  tcpuforwarddefclass = class of tcpuforwarddef;

  tcpuundefineddef = class(tundefineddef)
  end;
  tcpuundefineddefclass = class of tcpuundefineddef;

  tcpuerrordef = class(terrordef)
  end;
  tcpuerrordefclass = class of tcpuerrordef;

  tcpupointerdef = class(tx86pointerdef)
    class function default_x86_data_pointer_type: tx86pointertyp; override;
    function pointer_arithmetic_int_type:tdef; override;
    function pointer_subtraction_result_type:tdef; override;
  end;
  tcpupointerdefclass = class of tcpupointerdef;

  tcpurecorddef = class(trecorddef)
  end;
  tcpurecorddefclass = class of tcpurecorddef;

  tcpuimplementedinterface = class(timplementedinterface)
  end;
  tcpuimplementedinterfaceclass = class of tcpuimplementedinterface;

  tcpuobjectdef = class(tobjectdef)
  end;
  tcpuobjectdefclass = class of tcpuobjectdef;

  tcpuclassrefdef = class(tclassrefdef)
  end;
  tcpuclassrefdefclass = class of tcpuclassrefdef;

  { tcpuarraydef }

  tcpuarraydef = class(tarraydef)
   private
    huge: Boolean;
   protected
    procedure ppuload_platform(ppufile: tcompilerppufile); override;
    procedure ppuwrite_platform(ppufile: tcompilerppufile); override;
   public
    constructor create_from_pointer(def:tpointerdef);override;
    function getcopy: tstoreddef; override;
    function GetTypeName:string;override;
    property is_huge: Boolean read huge write huge;
  end;
  tcpuarraydefclass = class of tcpuarraydef;

  tcpuorddef = class(torddef)
  end;
  tcpuorddefclass = class of tcpuorddef;

  tcpufloatdef = class(tfloatdef)
  end;
  tcpufloatdefclass = class of tcpufloatdef;

  { tcpuprocvardef }

  tcpuprocvardef = class(ti86procvardef)
    constructor create(level:byte);override;
    function is_far:boolean;
  end;
  tcpuprocvardefclass = class of tcpuprocvardef;

  { tcpuprocdef }

  tcpuprocdef = class(ti86procdef)
   private
    { returns whether the function is far by default, i.e. whether it would be
      far if _all_ of the following conditions are true:
      - we're in a far code memory model
      - it has no 'near' or 'far' specifiers
      - it is compiled in a $F- state }
    function default_far:boolean;
   public
    constructor create(level:byte);override;
    function address_type:tdef;override;
    procedure declared_far;override;
    procedure declared_near;override;
    function is_far:boolean;
  end;
  tcpuprocdefclass = class of tcpuprocdef;

  tcpustringdef = class(tstringdef)
  end;
  tcpustringdefclass = class of tcpustringdef;

  tcpuenumdef = class(tenumdef)
  end;
  tcpuenumdefclass = class of tcpuenumdef;

  tcpusetdef = class(tsetdef)
  end;
  tcpusetdefclass = class of tcpusetdef;

  { syms }
  tcpulabelsym = class(tlabelsym)
  end;
  tcpulabelsymclass = class of tcpulabelsym;

  tcpuunitsym = class(tunitsym)
  end;
  tcpuunitsymclass = class of tcpuunitsym;

  tcpunamespacesym = class(tnamespacesym)
  end;
  tcpunamespacesymclass = class of tcpunamespacesym;

  tcpuprocsym = class(tprocsym)
  end;
  tcpuprocsymclass = class of tcpuprocsym;

  tcputypesym = class(ttypesym)
  end;
  tcpuypesymclass = class of tcputypesym;

  tcpufieldvarsym = class(tfieldvarsym)
  end;
  tcpufieldvarsymclass = class of tcpufieldvarsym;

  tcpulocalvarsym = class(tlocalvarsym)
  end;
  tcpulocalvarsymclass = class of tcpulocalvarsym;

  tcpuparavarsym = class(tparavarsym)
  end;
  tcpuparavarsymclass = class of tcpuparavarsym;

  tcpustaticvarsym = class(tstaticvarsym)
  end;
  tcpustaticvarsymclass = class of tcpustaticvarsym;

  tcpuabsolutevarsym = class(ti86absolutevarsym)
   protected
    procedure ppuload_platform(ppufile: tcompilerppufile); override;
    procedure ppuwrite_platform(ppufile: tcompilerppufile); override;
   public
    addrsegment : aword;
  end;
  tcpuabsolutevarsymclass = class of tcpuabsolutevarsym;

  tcpupropertysym = class(tpropertysym)
  end;
  tcpupropertysymclass = class of tcpupropertysym;

  tcpuconstsym = class(tconstsym)
  end;
  tcpuconstsymclass = class of tcpuconstsym;

  tcpuenumsym = class(tenumsym)
  end;
  tcpuenumsymclass = class of tcpuenumsym;

  tcpusyssym = class(tsyssym)
  end;
  tcpusyssymclass = class of tcpusyssym;


const
   pbestrealtype : ^tdef = @s80floattype;


  function is_proc_far(p: tabstractprocdef): boolean;

  {# Returns true if p is a far pointer def }
  function is_farpointer(p : tdef) : boolean;

  {# Returns true if p is a huge pointer def }
  function is_hugepointer(p : tdef) : boolean;

implementation

  uses
    globals, cpuinfo, verbose, fmodule;


  function is_proc_far(p: tabstractprocdef): boolean;
  begin
    if p is tcpuprocdef then
      result:=tcpuprocdef(p).is_far
    else if p is tcpuprocvardef then
      result:=tcpuprocvardef(p).is_far
    else
      internalerror(2014041301);
  end;

  { true if p is a far pointer def }
  function is_farpointer(p : tdef) : boolean;
    begin
      result:=(p.typ=pointerdef) and (tcpupointerdef(p).x86pointertyp=x86pt_far);
    end;

  { true if p is a huge pointer def }
  function is_hugepointer(p : tdef) : boolean;
    begin
      result:=(p.typ=pointerdef) and (tcpupointerdef(p).x86pointertyp=x86pt_huge);
    end;

{****************************************************************************
                               tcpuarraydef
****************************************************************************}

  constructor tcpuarraydef.create_from_pointer(def: tpointerdef);
    begin
      if tcpupointerdef(def).x86pointertyp=x86pt_huge then
        begin
          huge:=true;
          { use -1 so that the elecount will not overflow }
          self.create(0,high(asizeint)-1,s32inttype);
          arrayoptions:=[ado_IsConvertedPointer];
          setelementdef(def.pointeddef);
        end
      else
        begin
          huge:=false;
          inherited create_from_pointer(def);
        end;
    end;


  function tcpuarraydef.getcopy: tstoreddef;
    begin
      result:=inherited;
      tcpuarraydef(result).huge:=huge;
    end;


  function tcpuarraydef.GetTypeName: string;
    begin
      Result:=inherited;
      if is_huge then
        Result:='Huge '+Result;
    end;


  procedure tcpuarraydef.ppuload_platform(ppufile: tcompilerppufile);
    begin
      inherited;
      huge:=(ppufile.getbyte<>0);
    end;


  procedure tcpuarraydef.ppuwrite_platform(ppufile: tcompilerppufile);
    begin
      inherited;
      ppufile.putbyte(byte(huge));
    end;


{****************************************************************************
                             tcpuprocdef
****************************************************************************}

  constructor tcpuprocdef.create(level: byte);
    begin
      inherited create(level);
      if (current_settings.x86memorymodel in x86_far_code_models) and
         ((cs_huge_code in current_settings.moduleswitches) or
          (cs_force_far_calls in current_settings.localswitches)) then
        procoptions:=procoptions+[po_far];
    end;


  function tcpuprocdef.address_type: tdef;
    begin
      if is_far then
        result:=voidfarpointertype
      else
        result:=voidnearpointertype;
    end;


  procedure tcpuprocdef.declared_far;
    begin
      if current_settings.x86memorymodel in x86_far_code_models then
        include(procoptions,po_far)
      else
        inherited declared_far;
    end;


  procedure tcpuprocdef.declared_near;
    begin
      if (current_settings.x86memorymodel in x86_far_code_models) and
         not (cs_huge_code in current_settings.moduleswitches) then
        exclude(procoptions,po_far)
      else
        inherited declared_near;
    end;


  function tcpuprocdef.default_far: boolean;
    begin
      if proctypeoption in [potype_proginit,potype_unitinit,potype_unitfinalize,
                            potype_constructor,potype_destructor,
                            potype_class_constructor,potype_class_destructor,
                            potype_propgetter,potype_propsetter] then
        exit(true);
      if (procoptions*[po_classmethod,po_virtualmethod,po_abstractmethod,
                       po_finalmethod,po_staticmethod,po_overridingmethod,
                       po_external,po_public,po_interrupt])<>[] then
        exit(true);
      if is_methodpointer then
        exit(true);
      result:=not (visibility in [vis_private,vis_hidden]);
    end;


  function tcpuprocdef.is_far: boolean;
    begin
      result:=(current_settings.x86memorymodel in x86_far_code_models) and
        ((po_far in procoptions) or default_far);
    end;

{****************************************************************************
                             tcpuprocvardef
****************************************************************************}

  constructor tcpuprocvardef.create(level: byte);
    begin
      inherited create(level);
      { procvars are always far in the far code memory models }
      if current_settings.x86memorymodel in x86_far_code_models then
        procoptions:=procoptions+[po_far];
    end;


  function tcpuprocvardef.is_far: boolean;
    begin
      { procvars are always far in the far code memory models }
      result:=current_settings.x86memorymodel in x86_far_code_models;
    end;

{****************************************************************************
                             tcpupointerdef
****************************************************************************}

    class function tcpupointerdef.default_x86_data_pointer_type: tx86pointertyp;
      begin
        if current_settings.x86memorymodel in x86_far_data_models then
          result:=x86pt_far
        else
          result:=inherited;
      end;


    function tcpupointerdef.pointer_arithmetic_int_type:tdef;
      begin
        if x86pointertyp=x86pt_huge then
          result:=s32inttype
        else
          result:=inherited;
      end;


    function tcpupointerdef.pointer_subtraction_result_type:tdef;
      begin
        case x86pointertyp of
          x86pt_huge:
            result:=s32inttype;
          x86pt_far:
            result:=u16inttype;
          else
            result:=inherited;
        end;
      end;


{****************************************************************************
                             tcpuabsolutevarsym
****************************************************************************}

  procedure tcpuabsolutevarsym.ppuload_platform(ppufile: tcompilerppufile);
    begin
      inherited;
      if absseg then
        addrsegment:=ppufile.getaword;
    end;


  procedure tcpuabsolutevarsym.ppuwrite_platform(ppufile: tcompilerppufile);
    begin
      inherited;
      if absseg then
        ppufile.putaword(addrsegment);
    end;

begin
  { used tdef classes }
  cfiledef:=tcpufiledef;
  cvariantdef:=tcpuvariantdef;
  cformaldef:=tcpuformaldef;
  cforwarddef:=tcpuforwarddef;
  cundefineddef:=tcpuundefineddef;
  cerrordef:=tcpuerrordef;
  cpointerdef:=tcpupointerdef;
  crecorddef:=tcpurecorddef;
  cimplementedinterface:=tcpuimplementedinterface;
  cobjectdef:=tcpuobjectdef;
  cclassrefdef:=tcpuclassrefdef;
  carraydef:=tcpuarraydef;
  corddef:=tcpuorddef;
  cfloatdef:=tcpufloatdef;
  cprocvardef:=tcpuprocvardef;
  cprocdef:=tcpuprocdef;
  cstringdef:=tcpustringdef;
  cenumdef:=tcpuenumdef;
  csetdef:=tcpusetdef;

  { used tsym classes }
  clabelsym:=tcpulabelsym;
  cunitsym:=tcpuunitsym;
  cnamespacesym:=tcpunamespacesym;
  cprocsym:=tcpuprocsym;
  ctypesym:=tcputypesym;
  cfieldvarsym:=tcpufieldvarsym;
  clocalvarsym:=tcpulocalvarsym;
  cparavarsym:=tcpuparavarsym;
  cstaticvarsym:=tcpustaticvarsym;
  cabsolutevarsym:=tcpuabsolutevarsym;
  cpropertysym:=tcpupropertysym;
  cconstsym:=tcpuconstsym;
  cenumsym:=tcpuenumsym;
  csyssym:=tcpusyssym;

  cPtrDefHashSet:=tx86PtrDefHashSet;
end.

