nedoPC.org

Community of electronics hobbyists established in 2002

...
Atom Feed | View unanswered posts | View active topics It is currently 13 Nov 2018 10:47



Reply to topic  [ 13 posts ] 
Компилятор Pascal для i8048 (msc-48) 
Author Message
Doomed

Joined: 18 Nov 2013 03:38
Posts: 588
Location: Москва
Reply with quote
Рано или поздно всплывает на форумах вопрос, почему нет компилятора языка высокого уровня для MSC-48? Отвечают практически всегда одно и то-же - мол, мало памяти, стек не прозрачный и тд. Но мне кажется, что некий "упрощенный" вариант Паскаля/Си реализовать можно.

Сначала я смотрел в сторону SDCC - Small Device C Compiler. Но немного повтыкав в сорцы кодогенератора для 8051 удалил их, поняв что я ничего не понимаю. Может для кого-то он конечно и "easy portable to another architecture", но явно не для меня.

А потом вспомнил, что я, давным давно, читал замечательную статью Let's Build a Compiler, by Jack Crenshaw, она же, внезапно на русском в PDF. А потом вдобавок ко всему нашел еще и сорцы некого Power Pascal for OS/2. Эта вещь написана явно под влиянием вышеупомянутой статьи. Генерирует ASM-листинг для x86. Собирается хоть Turbo Pascal, хоть FreePascal с небольшими правками, и что удивительно, в принципе работает. Тем более Паскаль как бы мне более "родной", чем Си (хотя в последнее время пишу почти всегда на Си, но не суть).

Итак, Паскаль. Конечно, памяти маловато. На классическом 8048 имеем два банка 8-битных регистров R0 - R7 (16 байт), восьмиуровневый 16-битный стек (16 байт), остальные 32 байта на пользовательские переменные.
В контроллере есть внешнее прерывание и таймер. И вектора обработчиков от них по адресам .org 3 и .org 7.

Поэтому решено сделать пока так - в основной программе работаем только с первым банком регистров R0 - R7, не трогая второй банк. Второй банк регистров использовать только в обработчиках прерываний. Таким образом не нужно морочиться с сохранением/восстановлением текущих регистров в обработчиках прерываний. Дальше, A - акуумулятор, в него помещается текущее значение с которым работаем. R0 - операнд. R1 - для временного хранения аккумулятора, если с ним производятся логические действия. С R2 по R7 находятся значения в "стеке". Если "стека" из регистров не хватит, писать в пользовательскую память, если там есть место. Переменные хранятся в памяти начиная с адреса .org 32. Всего 32 байта.

Ну и первый простой тест на операции сложения/вычитания:
Code:
Var
   x,y : byte;
Begin
   x := 6;
   y := 2;
   x := x + y;
    y := y - 3;
End.


Дает такой вот листинг:
Code:
;;    MSC-48 PASCAL
;;    Tronix (c) 2017

      .org 0         ; reset vector
      dis   i
      jmp   MAIN

      .org 3         ; external interrupt vector--trap
      retr

      .org 7         ; timer interrupt vector
      retr
MAIN:
      mov   a,6         ; load const
      mov   r0,_X      ; store variable
      mov   @r0,a
      mov   a,2         ; load const
      mov   r0,_Y      ; store variable
      mov   @r0,a
      mov   r0,_X      ; load variable
      mov   a,@r0
      mov   r2,a      ; push to stack
      mov   r0,_Y      ; load variable
      mov   a,@r0
      mov   r1,a      ; save V0->V1, get V0 from stack
      mov   a,r2
      add   a,r1      ; make addiction
      mov   r0,_X      ; store variable
      mov   @r0,a
      mov   r0,_Y      ; load variable
      mov   a,@r0
      mov   r2,a      ; push to stack
      mov   a,3         ; load const
      mov   r1,a      ; save V0->V1, get V0 from stack
      mov   a,r2
      xch   a,r1      ; make substraction
      cpl   a
      inc   a
      add   a,r1
      mov   r0,_Y      ; store variable
      mov   @r0,a
_PEND:
      jmp  _PEND      ; end program
; ***** Library Code *****
; ***** Library Ends *****
; Variable Area
.equ   _Y   32
.equ   _X   33
; String constants



Немного подзастрял пока на логических операциях. Но думаю, победим мы его.


14 May 2017 00:35
Profile
God

Joined: 02 Jan 2006 03:28
Posts: 1371
Location: Abakan
Reply with quote
Здорово! :kruto:
Книжку на досуге почитаю.


14 May 2017 01:53
Profile
Doomed

Joined: 08 Apr 2013 05:04
Posts: 441
Location: 213.247.249.139
Reply with quote
готов потестить на своей платке.
Кроссплатформенная версия будет или wanacryptor-only? :)


Quote:
Поэтому решено сделать пока так - в основной программе работаем только с первым банком регистров R0 - R7, не трогая второй банк. Второй банк регистров использовать только в обработчиках прерываний.

да, так обычно и делают, причем во 2 наборе 1 рег убивается сразу и навсегда для схоронения в него А во время входа.
Еще есть такая жопа, что из прерывания моюно только проецедуры первых 2к вызывать, вторые 2к недоступны вообще (от момента входа до выполнения retr)


14 May 2017 02:03
Profile
Doomed

Joined: 08 Apr 2013 05:04
Posts: 441
Location: 213.247.249.139
Reply with quote
вычитание в интеловом аппноте рекомендуют делать так:
Code:
    cpl a
    add a,r4
    cpl a   ; a=a-r4


14 May 2017 02:10
Profile
Doomed

Joined: 08 Apr 2013 05:04
Posts: 441
Location: 213.247.249.139
Reply with quote
А еще кстати, прерывания от таймера и внешние независимо запрещаются. Чтобы запретить все, надо 2 команды:

Code:
    dis i
    dis tcnti


14 May 2017 02:17
Profile
Doomed

Joined: 18 Nov 2013 03:38
Posts: 588
Location: Москва
Reply with quote
angry_troll wrote:
вычитание в интеловом аппноте рекомендуют делать так:
Code:
    cpl a
    add a,r4
    cpl a   ; a=a-r4


Что за апноут? Я читаю какой-то, там так:
Code:
Subtract 8-bit subtrahend from 8-bit minuend using two's complement addition and store difference in register 7.
SUB8: MOV A,#5UBHND
CPL A ;ONE'S COMPLEMENT A
INC A ;TWO'S COMPLEMENT A
ADD A,#MINEND
MOV R7,A


Но ваше решение попроще, попробую.
UPD: Попробовал, работает. Спасибо.
Насчет таймера - где-то вроде видел что по умолчанию он выключен. Но можно конечно dis tcnti воткнуть.


14 May 2017 02:57
Profile
Doomed

Joined: 08 Apr 2013 05:04
Posts: 441
Location: 213.247.249.139
Reply with quote
Tronix wrote:
Что за апноут? Я читаю какой-то, там так:

Мды, с аппноутом я погорячился. Сейчас посмотрел, вот тут https://github.com/AngryTroll/i8048_board/blob/master/pdf/mcs48/1980_MCS-48_Users_Manual.pdf на странице 133, например, упоминается. Ну и вообще моя подборка док: https://github.com/AngryTroll/i8048_board/tree/master/pdf/mcs48


Quote:
Насчет таймера - где-то вроде видел что по умолчанию он выключен. Но можно конечно dis tcnti воткнуть.

Ну и внешнее прерывание после ресета тоже выключено.
Я рассуждаю так -- если вдруг придётся программно рестартовать контрольник переходом на 0, то тогда смысл запрещать ВСЕ прерывания есть.


14 May 2017 03:40
Profile
Supreme God
User avatar

Joined: 21 Oct 2009 09:08
Posts: 7777
Location: Россия
Reply with quote
Tronix wrote:
решение попроще, попробую.
UPD: Попробовал, работает.

Что-то мне на взгляд кажется, что дополнение до двух (TWO'S COMPLEMENT) теряется...
Нет ошибки на единицу?

_________________
iLavr


14 May 2017 03:48
Profile
Doomed

Joined: 18 Nov 2013 03:38
Posts: 588
Location: Москва
Reply with quote
Lavr wrote:
Что-то мне на взгляд кажется, что дополнение до двух (TWO'S COMPLEMENT) теряется...
Нет ошибки на единицу?


Да не, нормально. Чуть разобрался с условиями < > =. Правда пока не сделал <= и >=. Прикрутил основные циклы (for/while/repeat). Набросал небольшой тест. Внутренняя процедура Debug(N) просто выставляет число N в порт 1 и уходит на бесконечный цикл.
Code:
{MSC-48 PASCAL exerciser}
Var
   x,y : byte;
   i   : byte;
Begin

   x := 2;
   y := 253;

   {Do IF...THEN..ELSE tests}
   If (x+y) = 255 then
      Begin
         If (x+y) <> 255 then
            Debug(1);            {Error 1 - not equal false}


         If (x+y) < 255 then
            Debug(2);            {Error 2 - less false}

         y := y - 1;

         If (x+y) > 254 then
            Debug(3);            {Error 3 - greater false}
      End
   Else
      Debug(4);                  {Error 4 - equal false}


   x := 0;
   
   {Do FOR test}
   For i := 1 to 200 do
     x := x + 1;

   If x <> 200 then
      Debug(10);                 {Error 10 - FOR loop failed}

   {Do WHILE test}
   While x > 1 do
      x := x - 1;
   
   If x <> 1 then
      Debug(11);                 {Error 11 - WHILE loop failed}
     
   x := 0;
   
   {Do REPEAT..UNTIL test}
   Repeat
      x := x + 1;
   Until x < 123;
   
   If x <> 123 then
      Debug(12);                 {Error 12 - REPEAT loop failed}
     
   {All test's passed}
   Debug($5A);
End.


 Кодогенерация:
Code:
;;    MSC-48 PASCAL
;;    Tronix (c) 2017

      .org 0                       ; reset vector
      dis   i
      jmp   MAIN

      .org 3                       ; external interrupt vector--trap
      retr

      .org 7                       ; timer interrupt vector
      retr
MAIN:
      dis   tcnti
      mov   a,2                    ; load const
      mov   r0,_X                  ; store variable
      mov   @r0,a
      mov   a,253                  ; load const
      mov   r0,_Y                  ; store variable
      mov   @r0,a
      mov   r0,_X                  ; load variable
      mov   a,@r0
      mov   r2,a                   ; push to stack
      mov   r0,_Y                  ; load variable
      mov   a,@r0
      mov   r1,a                   ; save R0->R1, get R0 from stack
      mov   a,r2
      add   a,r1                   ; make addiction
      mov   r2,a                   ; push to stack
      mov   a,255                  ; load const
      mov   r1,a                   ; save R0->R1, get R0 from stack
      mov   a,r2
      cpl   a                      ; make substraction A-R1
      add   a,r1
      cpl   a
      jnz    L0                    ; if NOT jump to
      mov   r0,_X                  ; load variable
      mov   a,@r0
      mov   r2,a                   ; push to stack
      mov   r0,_Y                  ; load variable
      mov   a,@r0
      mov   r1,a                   ; save R0->R1, get R0 from stack
      mov   a,r2
      add   a,r1                   ; make addiction
      mov   r2,a                   ; push to stack
      mov   a,255                  ; load const
      mov   r1,a                   ; save R0->R1, get R0 from stack
      mov   a,r2
      cpl   a                      ; make substraction A-R1
      add   a,r1
      cpl   a
      jz     L2                    ; if jump to
      mov   a,1                    ; load const
      outl  p1,a                   ; !!! DEBUG. Set P1 and forever loop !!!
      jmp   _PEND
L2:
L3:
      mov   r0,_X                  ; load variable
      mov   a,@r0
      mov   r2,a                   ; push to stack
      mov   r0,_Y                  ; load variable
      mov   a,@r0
      mov   r1,a                   ; save R0->R1, get R0 from stack
      mov   a,r2
      add   a,r1                   ; make addiction
      mov   r2,a                   ; push to stack
      mov   a,255                  ; load const
      mov   r1,a                   ; save R0->R1, get R0 from stack
      mov   a,r2
      cpl   a                      ; make substraction A-R1
      add   a,r1
      cpl   a
      jz     L4                    ; logical less
      jnc    L4
      mov   a,2                    ; load const
      outl  p1,a                   ; !!! DEBUG. Set P1 and forever loop !!!
      jmp   _PEND
L4:
L5:
      mov   r0,_Y                  ; load variable
      mov   a,@r0
      mov   r2,a                   ; push to stack
      mov   a,1                    ; load const
      mov   r1,a                   ; save R0->R1, get R0 from stack
      mov   a,r2
      cpl   a                      ; make substraction A-R1
      add   a,r1
      cpl   a
      mov   r0,_Y                  ; store variable
      mov   @r0,a
      mov   r0,_X                  ; load variable
      mov   a,@r0
      mov   r2,a                   ; push to stack
      mov   r0,_Y                  ; load variable
      mov   a,@r0
      mov   r1,a                   ; save R0->R1, get R0 from stack
      mov   a,r2
      add   a,r1                   ; make addiction
      mov   r2,a                   ; push to stack
      mov   a,254                  ; load const
      mov   r1,a                   ; save R0->R1, get R0 from stack
      mov   a,r2
      cpl   a                      ; make substraction A-R1
      add   a,r1
      cpl   a
      jz     L6                    ; logical greater
      jc     L6
      mov   a,3                    ; load const
      outl  p1,a                   ; !!! DEBUG. Set P1 and forever loop !!!
      jmp   _PEND
L6:
L7:
      jmp   L1
L0:
      mov   a,4                    ; load const
      outl  p1,a                   ; !!! DEBUG. Set P1 and forever loop !!!
      jmp   _PEND
L1:
      mov   a,0                    ; load const
      mov   r0,_X                  ; store variable
      mov   @r0,a
      mov   a,1                    ; load const
      mov   r0,_I                  ; store variable
      mov   @r0,a
      mov   a,200                  ; load const
      mov   r0,Lim_I               ; store variable
      mov   @r0,a
L8:
      mov   r0,_X                  ; load variable
      mov   a,@r0
      mov   r2,a                   ; push to stack
      mov   a,1                    ; load const
      mov   r1,a                   ; save R0->R1, get R0 from stack
      mov   a,r2
      add   a,r1                   ; make addiction
      mov   r0,_X                  ; store variable
      mov   @r0,a
      mov   r0,_I                  ; load variable
      mov   a,@r0
      mov   r2,a                   ; push to stack
      mov   r0,Lim_I               ; load variable
      mov   a,@r0
      mov   r1,a                   ; save R0->R1, get R0 from stack
      mov   a,r2
      cpl   a                      ; make substraction A-R1
      add   a,r1
      cpl   a
      jz     L9                    ; logical less
      jnc    L9
      mov   r0,_I                  ; increase var by 1
      mov   a,@r0
      inc   a
      mov   @r0,a
      jmp   L8
L9:
      mov   r0,_X                  ; load variable
      mov   a,@r0
      mov   r2,a                   ; push to stack
      mov   a,200                  ; load const
      mov   r1,a                   ; save R0->R1, get R0 from stack
      mov   a,r2
      cpl   a                      ; make substraction A-R1
      add   a,r1
      cpl   a
      jz     L10                   ; if jump to
      mov   a,10                   ; load const
      outl  p1,a                   ; !!! DEBUG. Set P1 and forever loop !!!
      jmp   _PEND
L10:
L11:
L12:
      mov   r0,_X                  ; load variable
      mov   a,@r0
      mov   r2,a                   ; push to stack
      mov   a,1                    ; load const
      mov   r1,a                   ; save R0->R1, get R0 from stack
      mov   a,r2
      cpl   a                      ; make substraction A-R1
      add   a,r1
      cpl   a
      jz     L13                   ; if jump to
      mov   r0,_X                  ; load variable
      mov   a,@r0
      mov   r2,a                   ; push to stack
      mov   a,1                    ; load const
      mov   r1,a                   ; save R0->R1, get R0 from stack
      mov   a,r2
      cpl   a                      ; make substraction A-R1
      add   a,r1
      cpl   a
      mov   r0,_X                  ; store variable
      mov   @r0,a
      jmp   L12
L13:
      mov   r0,_X                  ; load variable
      mov   a,@r0
      mov   r2,a                   ; push to stack
      mov   a,1                    ; load const
      mov   r1,a                   ; save R0->R1, get R0 from stack
      mov   a,r2
      cpl   a                      ; make substraction A-R1
      add   a,r1
      cpl   a
      jz     L14                   ; if jump to
      mov   a,11                   ; load const
      outl  p1,a                   ; !!! DEBUG. Set P1 and forever loop !!!
      jmp   _PEND
L14:
L15:
      mov   a,0                    ; load const
      mov   r0,_X                  ; store variable
      mov   @r0,a
L16:
      mov   r0,_X                  ; load variable
      mov   a,@r0
      mov   r2,a                   ; push to stack
      mov   a,1                    ; load const
      mov   r1,a                   ; save R0->R1, get R0 from stack
      mov   a,r2
      add   a,r1                   ; make addiction
      mov   r0,_X                  ; store variable
      mov   @r0,a
      mov   r0,_X                  ; load variable
      mov   a,@r0
      mov   r2,a                   ; push to stack
      mov   a,123                  ; load const
      mov   r1,a                   ; save R0->R1, get R0 from stack
      mov   a,r2
      cpl   a                      ; make substraction A-R1
      add   a,r1
      cpl   a
      jnz    L16                   ; if NOT jump to
      mov   r0,_X                  ; load variable
      mov   a,@r0
      mov   r2,a                   ; push to stack
      mov   a,123                  ; load const
      mov   r1,a                   ; save R0->R1, get R0 from stack
      mov   a,r2
      cpl   a                      ; make substraction A-R1
      add   a,r1
      cpl   a
      jz     L17                   ; if jump to
      mov   a,12                   ; load const
      outl  p1,a                   ; !!! DEBUG. Set P1 and forever loop !!!
      jmp   _PEND
L17:
L18:
      mov   a,90                   ; load const
      outl  p1,a                   ; !!! DEBUG. Set P1 and forever loop !!!
      jmp   _PEND
_PEND:
      jmp  _PEND                   ; end program
; ***** Library Code *****
; ***** Library Ends *****
; Variable Area
.equ   _Y   32
.equ   _X   33
.equ   _I   34
.equ   Lim_I   35
; String constants



Без оптимизации 309 байт. Однако.
Вот думаю, какой-бы реальный простенький пример можно реализовать.. Не знаю, число ПИ там вычислить или еще чего. Есть идеи? С ПИ немного сложно, потому что пока нет 16-битных чисел. 8 бит онли.


14 May 2017 08:33
Profile
Senior

Joined: 30 Mar 2017 01:55
Posts: 137
Reply with quote
Уххх!

Tronix, спасибо за ссылку на книжку!

Там как раз под 68К !! :)


15 May 2017 16:12
Profile
Doomed

Joined: 25 Aug 2009 08:02
Posts: 361
Location: Москва
Reply with quote
У меня к сочетанию Паскаль и М68К какое-то недоверие и настороженность. Зимой развлекался дизассемблированием ПЗУшки процессора с телефонной станции AXE-10, там уж очень симпатичная керамическая с золотом PGAшная микросхема системного контроллера, дизассемблировал на тему ее реверс-инжиниринга с прицелом применить в своих целях, уж больно красива, в сочетании с PGAшным же TMP68HC000. По результатам работы - к большому сожалению, микросхема сильно заточена на специфику архитектуры AXE, в системе общего назначения неприменима. Но более всего я намучился разбирать логику кода, который, по признакам передачи параметров и еще каким-то, как я понял, был сгенерен с Паскаля. Получился ассемблерный ужос, все как-то неоптимально, медленно, куча лишних назначений, пересылок и т.п. Сочетание M68K и C выглядело гораздо лучше, тоже был опыт.


15 May 2017 16:57
Profile
Senior

Joined: 30 Mar 2017 01:55
Posts: 137
Reply with quote
Ничего страшного. Всё хорошо.
Ассемблер 68-го, к которому у меня очень особенное и близкое отношение, никуда же не делся ;)
Во-многом из-за его удобства я и выбрала этот процессор для нашей "левой" системы ;)

Но вариант с языком - тоже интересен, пусть даже там куча лишнего кода, да еще наверное пересылки в стеке и всё такое... Есть же всякие применения, где это уместно. Например, какой-нибудь редактор паттернов в секвенсоре или что-то подобное интерактивное - удобней закодить на языке. А вот отрисовка графики и генерация MIDI в достаточно жестком реальном времени - пусть себе крутится на асме по прерываниям, а частично даже хардварно в плисах. И всё будет замечательно:)

Mixa, да наверное эти специализированные чипы лучше просто оставить "в музее" и не мучиться с ними...Пусть лежат в ящичке, как фетиш :)
А вот сам PGAшный 68К -это уже прикольно :)

(извиняюсь за оффтоп):)


15 May 2017 18:03
Profile
Supreme God
User avatar

Joined: 21 Oct 2009 09:08
Posts: 7777
Location: Россия
Reply with quote
Tronix wrote:
Рано или поздно всплывает на форумах вопрос, почему нет компилятора языка высокого уровня для MSC-48?
...
Но мне кажется, что некий "упрощенный" вариант Паскаля/Си реализовать можно.

А я вот тут призадумался - не реализовать ли более интересную штуку, раз уж ты взялся,
с учетом ограниченности ресурсов MSC-48.

Короче, был давно такой "якобы BASIC", который назывался ASIC... :wink:
Ко мне он попал довольно поздно и пользы от него я уже не поимел,
поскольку программировать научился уже совершенно по-другому.

Но суть следующая (в общем-то идея напоминает немного С ): это язык программирования,
который сочетает простоту и синтаксис BASIC с возможностью прямого использования
ассемблерного кода, где это надо, причем генерит (как говорят) весьма хороший код!

Примерно так:
Code:
FOR I=0 TO 99
...
' здесь пишем на ассемблере
...
NEXT I

То есть ASIC удачно сочетает конструкции языка высокого уровня с ассемблерным синтаксисом.

Я полистал интернет, что про ASIC на сей день известно... на русском - практически ничего.
Есть вот такие ссылки которые еще не протухли:
https://en.wikipedia.org/wiki/ASIC_programming_language
http://www.atarimagazines.com/compute/issue126/64_Basic_is_back.php


Я на что намекаю - может и в твоем "микро-Паскале_48" реализовать похожий подход?

_________________
iLavr


16 May 2017 10:25
Profile
Display posts from previous:  Sort by  
Reply to topic   [ 13 posts ] 

Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group
Designed by ST Software.