(*
说明:全志A20的地址映射封装类。
单例,请勿在程序中使用。
作者:tjCFeng
邮箱:tjCFeng@163.com
更新日期:2014.12.06
*)

unit A20;

{$mode objfpc}{$H+}

interface

uses Unix, BaseUnix, SysUtils;

type
  TGROUP1_REG = ^LongWord;
  TGROUP2_REG = array [0..1] of ^LongWord;
  TGROUP4_REG = array [0..3] of ^LongWord;
  TGROUP5_REG = array [0..4] of ^LongWord;
  TGROUP6_REG = array [0..5] of ^LongWord;
  TGROUP16_REG = array [0..15] of ^LongWord;

type
  TA20 = class
  private
    class var FInstance: TA20;
    class function GetInstance: TA20; static;
  public
    class procedure Release;
    class property Instance: TA20 read GetInstance;

  private
    FhMEM: Integer;
    constructor Create;
    destructor Destroy; override;
  public
    function GetMMap(BaseAddr: LongWord): PLongWord;
    function BaseOffset(BaseAddr: LongWord): LongWord;
    procedure FreeMMap(MMapAddr: PLongWord);
  end;

implementation

const
  PAGE_SIZE = 4096;
  BLOCK_SIZE = 4096;

class function TA20.GetInstance: TA20;
begin
  if FInstance = nil then FInstance:= TA20.Create;
  Result:= FInstance;
end;

class procedure TA20.Release;
begin
  FreeAndNil(FInstance);
end;

constructor TA20.Create;
begin
  inherited Create;

  FhMEM:= fpopen('/dev/mem', O_RdWr);
  if (FhMEM < 0) then Exit;
end;

destructor TA20.Destroy;
begin
  fpclose(FhMEM);

  inherited Destroy;
end;

function TA20.GetMMap(BaseAddr: LongWord): PLongWord;
var MEM: LongWord;
begin
  MEM:= (BaseAddr and $FFFFF000) div PAGE_SIZE;
  Result:= fpMmap(nil, PAGE_SIZE, PROT_READ or PROT_WRITE, MAP_SHARED, FhMem, MEM);
end;

function TA20.BaseOffset(BaseAddr: LongWord): LongWord;
begin
  Result:= (BaseAddr and $00000FFF);
end;

procedure TA20.FreeMMap(MMapAddr: PLongWord);
begin
  if (MMapAddr <> nil) then fpMUnmap(MMapAddr, PAGE_SIZE);
end;


finalization
  TA20.Instance.Release;

end.