nabbla (nabbla1) wrote,
nabbla
nabbla1

Транслятор QuatCore: Delphi рулит!

Вот нравится мне этот язык/среда разработки. Не знаю уж, эффект утёнка или что, но очень быстро всё получается и работает фактически с первого раза.

Так описывается класс команды процессора QuatCore:

TCommandPlace = (cpDest, cpSrc);
TCommandPlaces = set of TCommandPlace;
TCommandResource = (crAcc, crC, crX, crY, crZ, crSP, cri, crj, crk, crInv,crMemBus);
TCommandResources = set of TCommandResource;
TCommandDataType = (dtNumeric, dtAbsJump, dtRelJump);

TQuatCoreCommand = class (TStreamingClass)
    private
      fKey: string;
      fCode: Byte;
      fDescription: string;
      fPlace: TCommandPlaces;
      fResources: TCommandResources;
      fDataType: TCommandDataType;
      fAddrMask: Byte;
    public
      constructor Create(aOwner: TComponent); override;
    published
      property Key: string read fKey write fKey;
      property Code: Byte read fCode write fCode;
      property Mask: Byte read fAddrMask write fAddrMask default 255;
      property Description: string read fDescription write fDescription;
      property Place: TCommandPlaces read fPlace write fPlace;
      property Resources: TCommandResources read fResources write fResources;
      property DataType: TCommandDataType read fDataType write fDataType;
end;


Конструктор очень простой, он присваивает маске значение по умолчанию, 0xFF:
(*
    TQuatCoreCommand
                            *)
constructor TQuatCoreCommand.Create(aOwner: TComponent);
begin
  inherited Create(aOwner);
  SetDefaultProperties;
end;


(а точнее, вообще всем свойствам даёт значения, прописанные директивой default)

Затем создаётся класс TQuatCoreTranslator, "внутри которого" лежат все эти команды, и ещё кое-какая дополнительная информация, и теперь всю эту структуру данных можно одной строкой сохранить в файл вроде такого:


UTF8object TQuatCoreTranslator
  RelJumpLatency = 2
  object TQuatCoreCommand
    Key = 'OUT'
    Code = 0
    Mask = 224
    Description = 'Sends value to chosen output'
    Place = [cpDest]
    Resources = []
    DataType = dtNumeric
  end
  object TQuatCoreCommand
    Key = 'SIO'
    Code = 32
    Mask = 224
    Description = 'Selects I/O device'
    Place = [cpDest]
    Resources = []
    DataType = dtNumeric
  end
  object TQuatCoreCommand
    Key = 'ERL'
    Code = 64
    Mask = 240
    Description = 'Sets lower 16 bits of external memory register'
    Place = [cpDest]
    Resources = []
    DataType = dtNumeric
  end

...

  object TQuatCoreCommand
    Key = 'JNO'
    Code = 190
    Mask = 254
    Description = 'If no signed overflow, jump by relative address from value. Otherwise, do nothing'
    Place = [cpDest]
    Resources = []
    DataType = dtRelJump
  end
  object TQuatCoreCommand
    Key = '[X+1]'
    Code = 192
    Description = 'Write to memory [X+1]'
    Place = [cpDest]
    Resources = [crMemBus]
    DataType = dtNumeric
  end
  object TQuatCoreCommand
    Key = '[X+1]'
    Code = 192
    Description = 'Read from memory [X+1]'
    Place = [cpSrc]
    Resources = [crX,crMemBus]
    DataType = dtNumeric
  end
  object TQuatCoreCommand
    Key = '[X+2i+1]'
    Code = 193
    Description = 'Access memory [X+2i+1]'
    Place = [cpDest]
    Resources = [crMemBus]
    DataType = dtNumeric
  end
  object TQuatCoreCommand
    Key = '[X+2i+1]'
    Code = 193
    Description = 'Access memory [X+2i+1]'
    Place = [cpSrc]
    Resources = [crX,cri,crMemBus]
    DataType = dtNumeric
  end
...
end


И самое главное, из такого файла можно ЗАГРУЗИТЬ конфигурацию, по сути не написав ни строчки парсинга. Просто-напросто:

  transl := TQuatCoreTranslator.Create(self);
  transl.LogLines := txtLog.Lines;
  transl.LoadFromFile('translatorConfig.txt');


Создали объект, привязали к нему текстовое поле, куда будут выводиться сообщения - и загрузили из файла. Сколько нужно объектов автоматически создаётся, все поля заполняются, в том числе множества (sets).

Притом, если что-то в файле не так, любая опечатка - уже при загрузке укажет, что не так, и это тоже на автомате. Я понимаю, что есть JSON, есть XML, всякие DOM (Document Object Model), куда можно запихивать что угодно, произвольную иерархическую структуру. И тоже загрузить "в одну строку", но потом всё равно нужно долго и муторно проверять, что там загрузилось, приводить к нашим типам данных.

И это всё в КОМПИЛИРУЕМОМ языке, притом в нормальный машинный код, не для виртуальной машины а вполне себе "железной". Просто изначально заложено достаточно "интроспекции", и мне кажется, очень удачно. Само по себе множество (set), если не ошибаюсь - просто битовое поле, на каждый признак выделяется по одному биту. Но каждый упомянутый тип описан, и это описание уходит в runtime - и там прописано, как называется каждый признак. А для каждого класса там определён метакласс, который в одном экземпляре также уходит в runtime - и там указывается тип каждого property, что и позволяет в итоге всю эту загрузку произвести вообще "без участия программиста" - автоматически всё "подцепится" и инициализируется как надо.

Потом всё-таки нам самим нужно проверить, что разные команды не имеют одного и того же кода (в том числе, с учётом "маски", показывающей, когда декодеры QuatCore игнорируют отдельные биты), и наоборот, нет совсем незадействованных кодов. Да пожалуйста:

procedure TQuatCoreTranslator.Loaded;
var i,j: Integer;
    cmd: TQuatCoreCommand;
    startAddr: Byte;
    streak: Boolean;
begin
  BeginUpdate;
  Log('Загружаем файл конфигурации транслятора');
  for i := 0 to ComponentCount-1 do begin
    cmd := Components[i] as TQuatCoreCommand;
    if cpDest in cmd.Place then begin
      for j := 0 to 255 do
        if (j and cmd.Mask) = cmd.Code then begin
          if Assigned(DestByAdr[j]) then
            Log(Format('ПРЕДУПРЕЖДЕНИЕ: DestAddr=%x занят одновременно командами %s и %s',[j,DestByAdr[j].Key,cmd.Key]))
          else
            DestByAdr[j] := cmd;
        end;
      DestNames.AddObject(cmd.Key,cmd);
    end;
    if cpSrc in cmd.Place then begin
      for j := 0 to 255 do
        if (j and cmd.Mask) = cmd.Code then begin
          if Assigned(SrcByAdr[j]) then
            Log(Format('ПРЕДУПРЕЖДЕНИЕ: SrcAddr=%x занят одновременно командами %s и %s',[j,SrcByAdr[j].Key,cmd.Key]))
          else
            SrcByAdr[j] := cmd;
        end;
      SrcNames.AddObject(cmd.Key,cmd);
    end;
  end;

  streak := false;
  startAddr := 0; //успокоить компилятор
  for i := 0 to 255 do
    if Not Assigned(DestByAdr[i]) then begin
      if not streak then begin
        streak := true;
        startAddr := i;
      end;
    end
    else begin
      if streak then begin
        Log(Format('ИНФОРМАЦИЯ: ни одна команда не назначена на DestAddr=%x..%x', [startAddr, i-1]));
        streak := false;
      end;
    end;

  streak := false;
  startAddr := 0;
  for i := 0 to 255 do
    if Not Assigned(SrcByAdr[i]) then begin
      if not streak then begin
        streak := true;
        startAddr := i;
      end;
    end
    else begin
      if streak then begin
        Log(Format('ИНФОРМАЦИЯ: ни одна команда не назначена на SrcAddr=%x..%x', [StartAddr,i-1]));
        streak := false;
      end;
    end;

  Log('Файл конфигурации прочитан, готовы к работе');

  EndUpdate;
end;


Эта штука реально помогла - ошибся пару раз, когда эти команды "забивал", и тут же получил информативные предупреждения об этом, исправил - теперь вроде бы всё в порядке.

Сейчас вот умиляюсь множествам (sets): для них уже сразу определён оператор *, который означает пересечение, так что и проверка этих Hazard'ов получится практически самоочевидной, причём скомпилится это в обычный AND (да чуть ли не TEST), так что всё очень шустро. Скажем так, мой компьютер на Intel Atom D510 всю трансляцию делает в полпинка, самая долгая операция - вывести на экран результаты :)

Наверное, это не должно шибко удивлять, всё-таки транслятор ассемблера - штука изначально простая, но ведь и её можно умудриться засрать. У меня выполняется ровно в один проход - все неизвестные метки заносятся в отдельный список FixUps, с указанием строк, где эти метки используются, и под конец оно "разрешается".
Tags: ПЛИС, программки, работа, странные девайсы
Subscribe

  • Так есть ли толк в ковариационной матрице?

    Задался этим вопросом применительно к своему прибору чуть более 2 недель назад. Рыл носом землю с попеременным успехом ( раз, два, три, четыре),…

  • Big Data, чтоб их ... (4)

    Наконец-то стряхнул пыль с компьютерной модели сближения, добавил в неё код, чтобы мы могли определить интересующие нас точки, и выписать…

  • Потёмкинская деревня - 2

    В ноябре 2020 года нужно было сделать скриншот несуществующей программы рабочего места под несуществующий прибор, чтобы добавить его в документацию.…

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 5 comments