Доступ к периферийным регистрам из Паскаля
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:37 am (UTC)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 с адресами регистров.
no subject
Date: 2019-06-04 12:58 am (UTC)no subject
Date: 2019-06-04 01:22 am (UTC)У некоторых линкеров бывают флаги для объявления таких меток: --defsym SYMBOL=EXPRESSION.
no subject
Date: 2019-06-04 01:31 am (UTC)no subject
Date: 2019-06-04 01:54 am (UTC)no subject
Date: 2019-06-04 02:19 am (UTC)no subject
Date: 2019-06-04 02:44 am (UTC)Подобно сделано в nios: с помощью мастера делается текстовый файл с метками для linker'а и текстовый файл с #define для стандартной библиотеки Си.
no subject
Date: 2019-06-04 02:49 am (UTC)на самом деле большой вопросСтало любопытно, существует ли какое общее соглашение по передаче параметров из разных языков при вызове процедур? (calling convention, __fastcall, _stdc, FFI и т.д.)
no subject
Date: 2019-06-04 03:29 am (UTC)https://github.com/besm6/besm6.github.io/blob/master/wiki/Madlen.md#14-%D0%BF%D1%80%D0%B0%D0%B2%D0%B8%D0%BB%D0%B0-%D0%BE%D1%84%D0%BE%D1%80%D0%BC%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F-%D0%B0%D0%B2%D1%82%D0%BE%D0%BA%D0%BE%D0%B4%D0%BD%D1%8B%D1%85-%D0%BF%D0%BE%D0%B4%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC
no subject
Date: 2019-06-04 10:03 am (UTC)Код:
{=P- Disable debug information and crash dump} {=T- Disable range checks} {=S8 Disable checking for stack overflow} program uart_pas(); const tx_done = 35; rx_empty = 36; type union = record case integer of 0: (i:integer); 1: (s:set of 0..47) end; var uart_data, uart_ctrl, uart_cset: @integer; procedure uart_init(baud_rate: integer); begin uart_data := ptr(77740B); uart_ctrl := ptr(77747B); uart_cset := ptr(77746B); (* set baud rate *) uart_ctrl@ := 50000000 div (baud_rate * 16); (* enable loopback mode *) uart_cset@ := 16777216; (* enable RX TX *) uart_cset@ := 1000B; end; function uart_recv: integer; var tmp: union; begin (* blocking read *) repeat tmp.i := uart_ctrl@; until not(rx_empty in tmp.s); uart_recv := uart_data@; end; procedure uart_tx_wait; var tmp: union; begin repeat tmp.i := uart_ctrl@; until tx_done in tmp.s; end; procedure uart_send(value: integer); var tmp: union; begin (* wait for previous send *) uart_tx_wait; uart_data@ := value; end; begin uart_init(115200); uart_send(85); (* 01010101 *) repeat uart_send(uart_recv); until false; end.Если посмотреть трейс (усеченный):
видно что пролазит экспонента. Как всё-таки "красиво" с побитовыми операциями работать? Как задавить лишнее?
Я еще тот паскалист, конечно :)
no subject
Date: 2019-06-04 02:24 pm (UTC)Иначе вылазит:
Error 2: Identifier already defined 00001 7 1 src_bignam, src_bignam2: @integer; ^^^^^ 0 IN 14 LINES 1 ERRORSno subject
Date: 2019-06-05 07:35 am (UTC)no subject
Date: 2019-06-05 07:37 am (UTC)Вдруг будет нужда линковаться со старым кодом на БЭСМ.
no subject
Date: 2019-06-06 09:36 pm (UTC)Побродил по исходникам компилятора - там всё непросто, с наскока не разобраться.
no subject
Date: 2019-06-05 05:09 am (UTC)y = x << i; где i заранее неизвестное переменное целое число
no subject
Date: 2019-06-05 07:32 am (UTC)no subject
Date: 2019-06-05 07:34 am (UTC)no subject
Date: 2019-06-06 09:22 pm (UTC)Кто бы взялся доработать компилятор, добавить побитовые операторы для целых чисел, типа &, |, ^, ~, <<, >>. Получился бы вполне практичный Паскаль.
no subject
Date: 2019-06-05 04:41 pm (UTC)При достижении конца программы, она перезапускается.
С ком-портом нормально, а вот для vga нужны битовые операции, а с ними какие-то странности.
Пользуюсь тем хитрым типом union
type union = record case integer of 0: (i:integer); 1: (s:set of 0..47) end;Вот такой процедурой пытаюсь выдать точку:
procedure plot_xy(x,y: integer); var addr, bit: integer; pix: union; begin addr := (x div 8) + 40 * y; bit := 40 + x mod 8; vga_al@ := addr; pix.i := vga_data@; pix.s := pix.s + [bit]; vga_al@ := addr; vga_data@ := pix.i; end;Но ставятся биты как-то странно, с "дырками" когда перебираешь x от 0 до 7.
Завтра буду смотреть внимательно еще раз.
В первом приближении показалось, что при определенных вызовах этой процедуры из разных мест кода (из цикла, не из цикла, из под условия) как-то целые аргументы портятся. Буду изучать.
no subject
Date: 2019-06-06 05:05 am (UTC)вот такое выражение считается неправильно, где bit и x integer
bit := 40 + (x mod 8);
Причем bit := x mod 8;
no subject
Date: 2019-06-06 09:38 am (UTC)Дело в том, что у целых чисел в экспоненте стоит всегда 064 (в старших разрядах), поэтому в этом выражении:
bit := 40 + (x mod 8)
когда X приходил из ком-порта в старших разрядах был 0-лик до той поры пока к нему не применить операцию сложения или вычитания. Как применишь так в ответе мусор.
Любопытно что операции умножения эти биты не трогают.
Переделал немного UART чтобы при чтении байта читалось 064 в старших разрядах а принтяй байт в младших и все сразу же заработало.
Из питона посылаются случайные координаты:
Там где линии алгоритм Брезенхейма (точнее его частный случай, но на Паскале)
Пример №1 https://youtu.be/1qtg4VCXjYU
Пример №2 https://youtu.be/62jhjpRayWc
Любопытно, но похоже в нашем Паскале нет "else".
no subject
Date: 2019-06-06 09:28 pm (UTC)В Паскале if-else есть, как же без него. Только перед else нельзя ставить точку с запятой.
no subject
Date: 2019-06-07 03:34 am (UTC)plotLine(x0,y0, x1,y1) if abs(y1 - y0) < abs(x1 - x0) if x0 > x1 plotLineLow(x1, y1, x0, y0) else plotLineLow(x0, y0, x1, y1) end if else if y0 > y1 plotLineHigh(x1, y1, x0, y0) else plotLineHigh(x0, y0, x1, y1) end if end ifи сходу не получилось... ну это ладно попробую еще раз.
Добавление 064 можно избежать, если сделать например на мадлене те самые peek/poke c AOX , а на оборудовании не использовать биты с 40 по 48-й.
no subject
Date: 2019-06-07 04:57 am (UTC)procedure pltln(x0, y0, x1, y1: integer); begin if abs(y1 - y0) < abs(x1 - x0) then if x0 > x1 then pltlo(x1, y1, x0, y0) else pltlo(x0, y0, x1, y1) else if y0 > y1 then plthi(x1, y1, x0, y0) else plthi(x0, y0, x1, y1) end;no subject
Date: 2019-06-07 05:05 am (UTC)Как можно инициализировать массив:
Ошибку выдает.
Error 103: Required token not found: SEMICOLON
00001 23 1 data: array[0..9] of integer = (10,20,30,40,50,60,71,80,90,91);
^^^^^ 0
IN 216 LINES 1 ERRORS
no subject
Date: 2019-06-07 06:14 am (UTC)Вот так:
program test(output); var data: array[0..9] of integer; begin writeln(data[0], data[1], data[2], data[3], data[9]); end.data data[0] = 10; data[1] = 20; data[2] = 30; data[3] = 40; data[4] = 50; data[5] = 60; data[6] = 71; data[7] = 80; data[8] = 90; data[9] = 91; endno subject
Date: 2019-06-07 06:16 am (UTC)no subject
Date: 2019-06-07 06:21 am (UTC)https://github.com/besm6/mesm6/blob/master/toolchain/pascompl/test/pascompl/pascompl.pas#L8555