Доступ к периферийным регистрам из Паскаля
Jun. 3rd, 2019 04:16 pmСейчас к периферийным регистрам можно обращаться из Паскаля через указатели. К примеру, код:
Есть более эффективный способ, если чуть улучшить линкер в юниксном стиле. Объявляем внешнюю структуру, которая по адресам сооветствует расположению периферийных регистров. Обращение к полям этой структуры будет превращаться в чтение/запись регистров. При этом будет использоваться команда UTC, чуть более эффективная, и не нужна дополнительная память на указатели. Пример:
program test();превращается в:
var
src, dst: @integer;
begin
src := ptr(77755B);
dst := ptr(77756B);
repeat
dst@ := src@
until false;
end.
c2: 10 010 0000 xta (8) ; =77755
01 000 0050 atx 050(1) ; src
c3: 10 010 0001 xta 1(8) ; =77756
01 000 0051 atx 051(1) ; dst
c4: 01 23 00050 wtc 050(1) ; src@
00 010 0000 xta
c5: 01 23 00051 wtc 051(1) ; dst@
00 000 0000 atx
c6: 00 30 00004 uj 4
00 22 00000 utc
Команда WTC выполняет косвенное обращение к периферийному регистру через указатель. При этом нужно выделять память на указатели.Есть более эффективный способ, если чуть улучшить линкер в юниксном стиле. Объявляем внешнюю структуру, которая по адресам сооветствует расположению периферийных регистров. Обращение к полям этой структуры будет превращаться в чтение/запись регистров. При этом будет использоваться команда UTC, чуть более эффективная, и не нужна дополнительная память на указатели. Пример:
program test(gpio);Результат:
var
gpio: record { периферийные регистры блока GPIO }
unused0, { 77750 - на будущее }
unused1, { 77751 }
unused2, { 77752 }
unused3, { 77753 }
CNEN, { 77754 - маска отслеживаемых пинов }
CNIE, { 77755 - вкл. прерывание по изменению сигнала }
PORT, { 77756 - запись - выдача, чтение - прием }
TRIS: integer { 77757 - направление данных }
end;
begin
repeat
gpio.PORT := gpio.CNIE
until false;
end.
c2: 00 22 77750 utc 77750
00 010 0005 xta 5 ; gpio.CNIE
c3: 00 22 77750 utc 77750
00 000 0006 atx 6 ; gpio.PORT
c4: 00 30 00002 uj 2
00 22 00000 utc
Надо только научить линкер привязывать внешние common-блоки к фиксированным адресам, но это нетрудно.
no subject
Date: 2019-06-04 12:55 am (UTC)Паскаль успешно загружает в регистр значение указателя, а после этого всё равно генерит WTC, игнорируя только что установленный регистр.
Исходник:
program test(); type gpio_regs = { периферийные регистры блока GPIO } record reserved0, { 77750...77753 - на будущее } CNEN, { 77754 - маска отслеживаемых пинов } CNIE, { 77755 - вкл. прерывание по изменению сигнала } PORT, { 77756 - запись - выдача, чтение - прием } TRIS: integer { 77757 - направление данных } end; var gpio: @gpio_regs; begin gpio := ptr(77750B); with gpio@ do begin repeat PORT := CNIE until false; end end.Результат:c2: 10 010 0000 xta (8) 01 000 0050 atx 050(1) c3: 01 23 00050 wtc 050(1) 03 24 00000 vtm (3) c4: 01 23 00050 wtc 050(1) 00 010 0002 xta 2 c5: 01 23 00050 wtc 050(1) 00 000 0003 atx 3 c6: 00 30 00004 uj 4 00 22 00000 utcno subject
Date: 2019-06-04 01:10 am (UTC)no subject
Date: 2019-06-04 02:33 am (UTC)no subject
Date: 2019-06-04 03:39 am (UTC)type union = record case integer of 0: (c:char); 1: (s:set of 0..47) end;
var u:union;
Тест наличия конкретного бита или набора битов (0-старший, 47-младший) делается с помощью выражения [N] <= u.s - так дешевле, чем
N in u.s. А если номер бита переменный, то лучше N in u.s.
Несмотря на то, что поле c - типа char, преобразование ord(u.c) сделает integer из всех 40 разрядов мантиссы, просто добавив целый порядок.
И наоборот, присваивание u.c := chr(i) отрежет только порядок.
no subject
Date: 2019-06-04 06:18 am (UTC)А как вот такое Сишное выражение написать tmp = a & 0x3; ?
no subject
Date: 2019-06-04 07:07 am (UTC)Ну или для a типа char, соответственно, ord(a) mod 4.
В общем виде, используя битовые множества и переменные типа union, будет
tmp.s := a.s * MASK; (для битовых множеств операции сложения, умножения и вычитания понимаются в булевском смысле: OR, AND и AND-NOT); в данном случае MASK будет [46,47].
no subject
Date: 2019-06-04 02:19 am (UTC)Но лучше, наверное, как-то статически все метки настраивать во время линковки/сборки, по принципу библиотек .h файлов для Arduino где есть куча #define с адресами регистров.