Speccy - наш выбор!

Speccy - наш выбор! (http://zx-pk.ru/index.php)
-   Разное (http://zx-pk.ru/forumdisplay.php?f=90)
-   -   Кросскомпилятор Си под 8080 (http://zx-pk.ru/showthread.php?t=20018)

vinxru 13th September 2012 17:32

LD DE, 0000 + ADD HL, DE = 10+4 = 14 тактов
LD A,H + OR L = 5+4 = 9 тактов

Но если DE загружать вне цикла, то покатит.

b2m 13th September 2012 17:37

LXI 10 тактов. DAD тоже. Итого 20.

---------- Post added at 17:37 ---------- Previous post was at 17:36 ----------

Давай будем разговаривать в мнемониках i8080 :)

vinxru 13th September 2012 17:39

http://www.emuverse.ru/wiki/Intel_80...B0%D0%BD%D0%B4

DAD = 4 такта

---------- Post added at 15:39 ---------- Previous post was at 15:38 ----------

А в Intel_8080_ASM_Lang_Manual.pdf написано 10

b2m 13th September 2012 17:42

Quote:

Originally Posted by vinxru (Post 539432)

Опечатка. Даташит не врёт :)

predatoralpha 14th September 2012 01:21

Я тут просматривал код:
Code:

  ; for(x=0; x<64; x+=16) {
  xor a
  ld (main_x), a
l10:
  ld d, 64
  ld a, (main_x)
  call l_uchar
  or a
  jp z, l11
  jp l12
l13:
  ld a, (main_x)
  add 16
  ld (main_x), a
  jp l10
l12:


  ; }
  jp l13
l11:

И подумал - а не стоит ли переменные засовывать прямо в код, для циклов? Выделенную строчку заменить на две:
main_x_var:
ld a,0
нолик, соответственно, место где хранится переменная, она же теперь часть кода. Соответственно, обращаться к переменной теперь не ld a, (main_x), а ld a, (main_x_var+1). Код на байт короче, байт экономится на глобальной переменной, 6 тактов на каждой итерации цикла. Правда 2 минуса - нужно следить за обращением к x, он теперь на новом месте, и такой код нельзя зашить в ROM.

vinxru 14th September 2012 04:23

Хм, сделаю и такой режим :) Но когда переменные лежат одним блоком, легко реализовать рекурсию. Просто этот блок переменных копировать в стек.

Выхожу на финишную прямую с кодогенератором. Сделал операции < > <= >= == != для uchar. Сделал #define #undef (как полагается с параметрами).

Code:

print_return ds 0
print_x ds 1
print_y ds 1
print_text ds 2
print_dest ds 2
print:
  push bc
  ld (print_text), hl
  ; 10 dest = (uchar*)(0xE1D5 + x + y*78);
  ld hl, (print_x)
  ld h, 0
  ld de, 57813
  add hl, de
  push hl
  ld d, 78
  ld a, (print_y)
  call mul_uchar
  pop de
  add hl, de
  ld bc, hl
  ; 11 while(*text) { *dest = *text; dest++; text++; }
l2:
  ld hl, (print_text)
  ld a, (hl)
  or a
  jp z, l3
  ; 11 *dest = *text; dest++; text++; }
  ld hl, (print_text)
  ld a, (hl)
  ld (bc), a
  ; 11 dest++; text++; }
  inc bc
  ; 11 text++; }
  ld hl, (print_text)
  inc hl
  ld (print_text), hl
  jp l2
l3:
l1:
  pop bc
  ret
;----------------------------------
clrscr_return ds 0
clrscr_dest ds 2
clrscr_c ds 2
clrscr:
  push bc
  ; 17 dest = (uchar*)0xE1D0-1;
  ld hl, 57807
  ld (clrscr_dest), hl
  ; 18 c = 78*25;
  ld bc, 1950
  ; 19 do *++dest = 0; while(c--);
l5:
  ; 19 *++dest = 0; while(c--);
  ld hl, (clrscr_dest)
  inc hl
  ld (clrscr_dest), hl
  xor a
  ld hl, (clrscr_dest)
  ld (hl), a
  dec bc
  ld a, b
  or c
  jp nz, l5
l4:
  pop bc
  ret
;----------------------------------
get:
  ; 23 return 23;
  ld hl, 23
  jp l6
l6:
  ret
;----------------------------------
atoi_return ds 0
atoi_str1 ds 2
atoi_a ds 2
atoi_str ds 2
atoi_c ds 1
atoi:
  push bc
  ld (atoi_a), hl
  ; 31 str = str1;
  ld hl, (atoi_str1)
  ld bc, hl
  ; 32 do {
l8:
  ; 33 c = ((uchar)a & 15) + 48;
  ld a, (atoi_a)
  and 15
  add 48
  ld (atoi_c), a
  ; 34 if('9' < c) c += 7;
  ld a, (atoi_c)
  cp 57
  jp c, l10
  ; 34 c += 7;
  ld a, (atoi_c)
  add 7
  ld (atoi_c), a
l10:
  ; 35 *str = c; str++;
  ld a, (atoi_c)
  ld (bc), a
  ; 35 str++;
  inc bc
  ; 36 a = a >> 4;
  ld de, 4
  ld hl, (atoi_a)
  call shr_ushort
  ld (atoi_a), hl
  ld hl, (atoi_a)
  ld a, l
  or h
  jp nz, l8
  ; 38 *str = 0;
  xor a
  ld (bc), a
l7:
  pop bc
  ret
;----------------------------------
main_return ds 0
main_i ds 1
main_x ds 1
main_buf ds 32
main:
  push bc
  ; 47 clrscr();
  call clrscr
  ; 48 print(0, 0, "HELLO");
  xor a
  ld (print_x), a
  xor a
  ld (print_y), a
  ld hl, string0
  call print
  ; 49 atoi(buf, 0x12AB);
  ld hl, main_buf
  ld (atoi_str1), hl
  ld hl, 4779
  call atoi
  ; 51 print(1, 1, buf);
  ld a, 1
  ld (print_x), a
  ld a, 1
  ld (print_y), a
  ld hl, main_buf
  call print
  ; 53 i=5;
  ld b, 5
  ; 55 for(x=0; x<64; x+=XYZ(12)) {
  ld c, 0
l12:
  ld a, c
  cp 64
  jp nc, l13
l12:
  ; 56 print(x, i, "12345678.123");
  ld a, c
  ld (print_x), a
  ld a, b
  ld (print_y), a
  ld hl, string1
  call print
  ld a, c
  add 14
  ld c, a
  jp l12
l13:
  ; 59 while(1) {
l15:
  ; 60 if(getch() == '1') clrscr();
  call getch
  cp 49
  jp nz, l18
  ; 60 clrscr();
  call clrscr
l18:
  jp l15
l16:
l11:
  pop bc
  ret

В этом коде еще убрать дублирующиеся присваивания переменных (ld a, 1 ld (print_x), a ld a, 1) или (ld (atoi_a), hl, ld hl, (atoi_a)) и т.д. Эта уборка будет отключатся словом volatile. Объединить XOR A и LD (HL), A, например (xor a ld hl, (clrscr_dest) ld (hl), a). И убрать лишние переходы, например jp $+3 или jp на другой jp.

1888 строк 54 Кб.

---------- Post added at 03:23 ---------- Previous post was at 02:47 ----------

Мне написали, что есть компиляторы Си для 8080.

https://github.com/begoon/smallc-scc3, https://github.com/begoon/smallc-85

и работают они так

Code:

main() {
static char a;
for (a = '\0'; a < '\10'; ++a) {
a = a + '\1';
}
}

(специально использовал char везде) генерит адъ типа:

;main() {
main:
; static char a;
dseg
?2: ds 1
cseg
; for (a = '\0'; a < '\10'; ++a) {
lxi h,?2
push h
lxi h,0
pop d
call ?pchar
?3:
lxi h,?2
call ?gchar
push h
lxi h,12592
pop d
call ?lt
mov a,h
ora l
jnz ?5
jmp ?6
?4:
lxi h,?2
push h
call ?gchar
inx h
pop d
call ?pchar
jmp ?3
?5:
; a = a + '\1';
lxi h,?2
push h
lxi h,?2
call ?gchar
push h
lxi h,49
pop d
dad d
pop d
call ?pchar
; }
jmp ?4
?6:
;}
?1:
ret

мой

main:
  push bc
  ; 3 for (a = 0; a < 10; ++a) {
  ld b, 0
l1:
  ld a, b
  cp 10
  jp nc, l2
l1:
  ; 4 a = a + 1;
  ld a, b
  inc a
  ld b, a
  inc b
  jp l1
l2:
l0:
  pop bc
  ret


predatoralpha 14th September 2012 14:15

Quote:

Originally Posted by vinxru (Post 539519)
Хм, сделаю и такой режим :) Но когда переменные лежат одним блоком, легко реализовать рекурсию. Просто этот блок переменных копировать в стек.

Ну далеко не всегда нужно все переменные копировать в стек. В идеале нужно вести время жизни переменных. Часть переменных уже не используется, часть ещё не присвоены, часть будут безусловно проинициализированы после вызова, и текущее значение не нужно.

А это зачем?
ld hl, (clrscr_dest)
ld (hl), a

Регистр а можно прямо поместить по нужному адресу.

Кстати, 0xE1D5 + x можно ещё оптимальнее
Вместо
ld hl, (print_x)
ld h, 0
ld de, 57813 // 0xE1D5
add hl, de

Сделать
ld hl, (print_x)
ld de, 0x0СD5 // d=E1-D5=0C
ld h, е // На байт короче, на 3 такта быстрее
add hl, de


А вот здесь у тебя неверный код, вроде
while(c--);
dec bc
ld a, b
or c
jp nz, l5

У тебя код не постдекрементный, а преддекрементный. Т.е. для случая while(--c), а не while(c--).

Error404 14th September 2012 15:19

Переменные на стеке нужны для реентабельности процедур. Это не только рекурсия, но и второе в хождение в ту же процедуру из обработчика перерывания. Соответственно, в случае работы системы с прерываниями, копировать глобальные переменные на стек бессмысленно - остается вероятность что по прерыванию будет повторное вхождение пока переменные еще не скопированы. Ну и если будет такое копирование, всякий выигрыш теряется (что про времени выполнения, что по размеру кода). Тогда уж сразу надо делать на стеке.

predatoralpha 14th September 2012 15:30

Quote:

Originally Posted by Error404 (Post 539595)
Переменные на стеке нужны для реентабельности процедур. Это не только рекурсия, но и второе в хождение в ту же процедуру из обработчика перерывания. Соответственно, в случае работы системы с прерываниями, копировать глобальные переменные на стек бессмысленно - остается вероятность что по прерыванию будет повторное вхождение пока переменные еще не скопированы. Ну и всякий выигрыш теряется (что про времени выполнения, что по размеру кода) если будет такое копирование: тогда уж сразу надо делать на стеке.

Насчёт реентабельности по прерываниям - да, абсолютно верно, такие процедуры нереентабельные. А вот с "Ну и всякий выигрыш теряется (что про времени выполнения, что по размеру кода)" я не согласен. Для 8080 (не Z80) операции со стеком весьма и весьма мудоёмкие, сжирающие как минимум одну из трёх регистровых пар (HL), которая весьма незаменима, а это постоянные прологи из двух-пяти команд для каждого обращения к стеку. Выигрыш весьма существенный. Особенно в тех случаях, когда возможен анализ кода, есть ли возможность рекурсии при вызове некой функции.
-
Проблема нереентабельности по прерываниям, как по мне, несущественная. Обработчик обычно пишется на ассемблере, если какие-то сишные функции и будут вызываться - то обычно это не те, что выполняются вне прерывания. Этот факт нужно отразить в документации, и принять его "как есть".
-
Более серьёзная проблема, как по мне - это передача ссылки на локальную переменную в некую функцию. Если создаются копии локальных переменных в стеке, то ссылка на локальную переменную "повиснет". А если ещё добавить, что вызываемая функция эту ссылку может сохранить в глобальной переменной, и другая вызываемая функция (из базовой функции) эту ссылку может оттуда поднять... Тут весьма сложный момент. И врядли он будет сделан в соответствии со стандартами языка. Я не хочу сейчас грузить vinxru этой проблемой. Он и так молодец.

vinxru 14th September 2012 16:37

Quote:

Originally Posted by predatoralpha (Post 539575)
ld hl, (clrscr_dest)
ld (hl), a

В ячейке clrscr_dest хранится адрес, который предыдущей строкой увеличивается.

Нет на 8080 команды ld ((clrscr_dest)), A

А вот на PDP-11 есть.

---------- Post added at 14:31 ---------- Previous post was at 14:30 ----------

Quote:

Originally Posted by predatoralpha (Post 539575)
А вот здесь у тебя неверный код, вроде
while(c--);
dec bc
ld a, b
or c
jp nz, l5
У тебя код не постдекрементный, а преддекрементный. Т.е. для случая while(--c), а не while(c--).

Да, я пока одну версию операторов написал. Сегодня поправлю, а то забуду.

---------- Post added at 14:34 ---------- Previous post was at 14:31 ----------

Quote:

Originally Posted by Error404 (Post 539595)
Ну и если будет такое копирование, всякий выигрыш теряется (что про времени выполнения, что по размеру кода). Тогда уж сразу надо делать на стеке.

Чисто арифметически выигрыш есть. Копируем мы переменную один раз на входе, один на выходе. Причем, копирование всех переменных можно делать за один присест.

А обращаться к переменной мы будем много раз, может быть что 1000 раз.

---------- Post added at 14:35 ---------- Previous post was at 14:34 ----------

Quote:

Originally Posted by predatoralpha (Post 539598)
Проблема нереентабельности по прерываниям, как по мне, несущественная. Обработчик обычно пишется на ассемблере, если какие-то сишные функции и будут вызываться - то обычно это не те, что выполняются вне прерывания. Этот факт нужно отразить в документации, и принять его "как есть".

Можно продублировать функцию вызываемую из прерывания и из основного кода.

---------- Post added at 14:37 ---------- Previous post was at 14:35 ----------

Quote:

Originally Posted by predatoralpha (Post 539598)
Более серьёзная проблема, как по мне - это передача ссылки на локальную переменную в некую функцию. Если создаются копии локальных переменных в стеке, то ссылка на локальную переменную "повиснет". А если ещё добавить, что вызываемая функция эту ссылку может сохранить в глобальной переменной, и другая вызываемая функция (из базовой функции) эту ссылку может оттуда поднять...

Это компромисс между
1) Программой, которая умеет рекурсию.
2) И программой, которая работает в 3 раза быстрее.

predatoralpha 14th September 2012 17:50

Quote:

Originally Posted by vinxru (Post 539609)
В ячейке clrscr_dest хранится адрес, который предыдущей строкой увеличивается.
Нет на 8080 команды ld ((clrscr_dest)), A

Извиняюсь, просмотрел, что тут двойной доступ.

Quote:

Да, я пока одну версию операторов написал. Сегодня поправлю, а то забуду.
Догадываюсь, что код сильно усложнится. Прединкремент/преддекремент работает быстрее, и код короче. Конкретно здесь, поскольку переменная с в теле не используется, его стОит оставить, только увеличить на единицу BC (или сразу загрузить в него увеличенную на 1 константу, как в этом случае). Впрочем, анализ циклов сложное дело, и я понимаю, что сейчас оно не на времени.


Quote:

Originally Posted by vinxru (Post 539609)
Можно продублировать функцию вызываемую из прерывания и из основного кода.

Безусловно. Кому надо - продублирует.

Quote:

Originally Posted by vinxru (Post 539609)
Это компромисс между
1) Программой, которая умеет рекурсию.
2) И программой, которая работает в 3 раза быстрее.

Полностью поддерживаю. Компилятор прежде всего будет использоваться любителями старых компов, типа Львова, а там абсолютный приоритет - быстродействие.
Единственно замечу, что это проблема не только рекурсии. В том примере, что я привёл, это возможно при вызове из функции двух функций, которые никак рекурсию не производят. Просто отразить в документации - если хочешь иметь корректный указатель на лок.перем. между вызовами разных функций - используй указатель на static или volatile переменную.

b2m 14th September 2012 19:26

Quote:

Originally Posted by vinxru (Post 539609)
Это компромисс между
1) Программой, которая умеет рекурсию.
2) И программой, которая работает в 3 раза быстрее.

Так надо ввести опцию компилятора: все переменные статические - да/нет. А компилятор делать классически, с поддержкой локальных переменных в стеке. Кому не нравится глобальная переменная, поставит перед декларацией register.

---------- Post added at 19:26 ---------- Previous post was at 19:23 ----------

И в тексте программы учитывать:
#pragma static_variable on
#pragma static_variable off

predatoralpha 14th September 2012 19:36

Quote:

Originally Posted by b2m (Post 539657)
Так надо ввести опцию компилятора: все переменные статические - да/нет. А компилятор делать классически, с поддержкой локальных переменных в стеке. Кому не нравится глобальная переменная, поставит перед декларацией register.

Ээээ... ничего что стандарт C99 позволяет указатели на регистровые локальные переменные? И это как раз такой случай, что она должна располагаться в стеке, если конечно компилятор не соптимизирует обращение к переменной, и есть гарантия, что доступа к адресу не будет.
Так что вопрос несколько сложнее, и просто register это не решает.
Здесь планируется несколько более, чем просто статические переменные. Их можно использовать как и автоматические, для рекурсии. Можно сказать, что локальные переменные просто кешируются в памяти по конкретным адресам.

vinxru 14th September 2012 22:27

У меня нельзя будет получить адрес регистровой переменной. Как раз сейчас сообщений об ошибках придумывал.

case pVar8: p.logicError_("Нельзя получить адрес переменной преобразованной из 8 бит"); break; // &(ushort)a;
case pA: case pHl: case pStack: p.logicError_("Нельзя получить адрес временного значения"); break;
case pB: case pC: case pBC: p.logicError_("Нельзя получить адрес регистровой переменной"); break;
case pConst: p.logicError_("Нельзя получить адрес константы"); break;

---------- Post added at 19:42 ---------- Previous post was at 19:40 ----------

Кстати первая ошибка - это косяк оптимизации, потом сделаю обход.

Когда мы преобразовываем значение

char a;
short b = (short)a + 0x1234;

Сразу А не преобразуется. Просто функции чтения забивают старшие 8 бит нулями. Это работает везде кроме

short* b = &(short)a;

Оно и так не должно выполняться. А если выполнится, то будет идентично

short* b = (short*)&a;

---------- Post added at 19:43 ---------- Previous post was at 19:42 ----------

Чё я торможу. Это ошибка "Нельзя получить адрес временного значения"

---------- Post added at 20:34 ---------- Previous post was at 19:43 ----------

Сейчас мой мозг вытечет через ухо

Есть абстрактные команды

moNot, moNeg, moAddr, moDeAddr, moPostInc, moPostDec, moInc, moDec
oDiv, oMod, oMul, oAdd, oSub, oShl, oShr, oL, oG, oLE, oGE, oE, oNE, oAnd, oXor, oOr, oLAnd, oLOr, oIf, oSet, oSAdd, oSSub, oSMul, oSDiv, oSMod, oSShl, oSShr, oSAnd, oSXor, oSOr

И такой набор команд на каждый тип данных char, short, long, ulong.

У них несколько значений на входе. Причем значения могут быть:

pConst - это просто число
pConstRef - адрес в памяти
pVar - какая то переменная
pVar8 - переменная, причем используются только 8 нижних бит
pRef - переменная содержащая адрес в памяти
pArray - переменная, но компилятор должен подставлять её адрес в программу вместо значения.
pHl, pA, pB, pC, pBC - регистры
pStack - верхушка стека
pBCRef, pHLRef - в регистрах лежит адрес значения в памяти.

И при этом регистры A, DE, HL используются для временного хранения переменных и их иногда можно использовать, а иногда нельзя.

И при этом, команды должны сваливать результат в

pConstRef - адрес в памяти
pVar - какая то переменная
pRef - переменная содержащая адрес в памяти
pHl, pA, pB, pC, pBC - регистры
pStack - верхушка стека
pBCRef, pHLRef - в регистрах лежит адрес значения в памяти.

---------- Post added at 20:38 ---------- Previous post was at 20:34 ----------

Ой, да. Команды при этом еще объединяются и упрощаются. Например сравнение и переход.

---------- Post added at 21:27 ---------- Previous post was at 20:38 ----------

А чем отличается RAL от ADС A, кроме изменяемых флагов?

b2m 14th September 2012 22:44

У ADC A справа нулевой бит добавляется, а RAL - берёт флаг переноса.

vinxru 14th September 2012 22:45

У разве не у ADD нулевой бит добавляется?

b2m 14th September 2012 22:51

Фу-ты, попутал. Значит ничем :)

vinxru 14th September 2012 23:27

Команды RAL вообще мне не пригодились

16 битный сдвиг DAD H
8 битный сдвиг ADD A
8 бит в другую сторону CP A + RAR

16 бит вправо самая сложная

MOV A, H/B
CP A
RAR
MOV H, A
MOV A, L/C
RAR
MOV L, A

ivagor 14th September 2012 23:32

Quote:

Originally Posted by vinxru (Post 539699)
16 бит вправо самая сложная
MOV A, H/B
CP A

Можно скинуть 1 такт, если первые 2 команды заменить на
xra a (или sub a)
ora h/b

vinxru 14th September 2012 23:46

И еще я что то не могу сообразить, как сравнивать знаковые числа. Беззнаковые просто, по флагам Z и C. А знаковые я только придумал

(n1+80h) < (n2+80h)

MOV A, N1
XRI 0x80
MOV D, A
MOV A, N2
XRI 0x80
CP D

А дальше так же по флагам C, Z

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

b2m 15th September 2012 01:07

А если просто вычесть и знак результата проверить?
MOV A,N1
MOV B,N2
SUB B
JM less

vinxru 15th September 2012 01:40

Ааа... спать надо больше. Точно ведь. А мне лень даже в яндекс вбить слово.

---------- Post added at 00:39 ---------- Previous post was at 00:33 ----------

У меня получилось, что myFunction(1, myFuction(2, 3)) некорректно работает

mvi a, 1
sta myFunction_paramA
mvi a, 2
sta myFunction_paramA
mvi a, 3
call myFunction
call myFunction

Но это можно обойти

---------- Post added at 00:40 ---------- Previous post was at 00:39 ----------

В среду дам первую версию. Эта еще сырая очень.

2100 строк 66 Кб

PPC 15th September 2012 01:41

Quote:

Originally Posted by vinxru (Post 539609)
Это компромисс между
1) Программой, которая умеет рекурсию.
2) И программой, которая работает в 3 раза быстрее.

И всё-таки по причинам реентерабельности, стоит подумать о размещении локальных переменных на стеке. Дело здесь не только в interrupt функциях, для которыз кстати надо ещё PUSHALL делать. Просто, если компилятор будет использоваться для написания оконных интерфейсов, почти неизбежны локальные стеки и переключения контекстов.

Возможно, Вы подумаете о чём-нибудь типа
#pragma recursion:ON/OFF

Также пожелание поддерживать несколько calling conventions, по крайей мере extern "C" / _stdcall, _pascal, _memblock (это-Ваш вариант) и _fast (передача до 2х параметров в регистрах)

vinxru 15th September 2012 02:36

Сделаю рекурсию. Добавлю модификаторы _static, _stack. Пока не до этого, пока у меня даже комментарии не поддерживаются. :)

---------- Post added at 01:22 ---------- Previous post was at 00:52 ----------

Прикольно. Написал

x=32; y=15;

while(1) {
i=getch();

print(x, y, "+");

if(i==0x19) { if(y>0) --y; } else
if(i==0x08) { if(x>0) --x; } else
if(i==0x1A) { if(y<24) ++y; } else
if(i==0x18) { if(x<63) ++x; }

print(x, y, "O");
}

сижу рисую. :) Теперь жизнь станет проще, а программы круче.

---------- Post added at 01:36 ---------- Previous post was at 01:22 ----------

Code:

Программа

struct File {
  ushort some1, size;
  uchar name[11];
  uchar some2;
};

File files[24];

void main() {
  register uchar i;
  File* f;

  clrscr();

  for(f=files, i=0; i<24; ++i, ++f)
    itoa(f->name, i);

  for(i=0; i<16; ++i)
    print(0, i, files[i].name);

  while(1);
}


files ds 384
main_f ds 2
main:
  push bc
  ; 49 clrscr();
  call clrscr
  ; 51 for(f=files, i=0; i<24; ++i, ++f)
  ld hl, files
  ld (main_f), hl
  ld b, 0
l12:
  ld a, b
  cp 24
  jp nc, l13
  ; 52 atoi(f->name, i);
  ld hl, (main_f)
  inc hl
  inc hl
  inc hl
  inc hl
  ld (atoi_str1), hl
  ld l, b
  ld h, 0
  call atoi
  inc b
  ld hl, (main_f)
  ld de, 16
  add hl, de
  ld (main_f), hl
  jp l12
l13:
  ; 54 for(i=0; i<16; ++i)
  ld b, 0
l15:
  ld a, b
  cp 16
  jp nc, l16
  ; 55 print(0, i, files[i].name);
  xor a
  ld (print_x), a
  ld a, b
  ld (print_y), a
  ld l, b
  ld h, 0
  add hl, hl
  add hl, hl
  add hl, hl
  add hl, hl
  ld de, files
  add hl, de
  inc hl
  inc hl
  inc hl
  inc hl
  call print
  inc b
  jp l15
l16:
  ; 57 while(1);
l18:
  jp l18
l19:
l11:
  pop bc
  ret


predatoralpha 15th September 2012 03:06

Quote:

Originally Posted by b2m (Post 539722)
А если просто вычесть и знак результата проверить?
MOV A,N1
MOV B,N2
SUB B
JM less

Если сравнивать только положительные или только отрицательные - то да.
Например.
10-8 = 2. бит 7 нулевой. 10>8
(-1)-(-2)=255-254=1. бит 7 нулевой. -1>-2
А вот если одни с другими...
127 - (-2) = 127 - 254 = -127 = 0х81 бит 7 ненулевой. 127<-2. Но это неверно!
Тут надо не только знак учитывать, но и флаг переполнения. И если есть переполнение - реверсировать результат.

MOV A,N1
MOV B,N2
SUB B
MOV B,A
RRA
XOR B
JM less
В коде не совсем уверен, сейчас несколько нетрезв.

ivagor 15th September 2012 09:00

Возможно пригодится - сравнение 16 битных знаковых чисел
Code:

;DE и HL - знаковые 16 битные целые
;Портит A и B
CmpDEHL:        mov        a,d
                xra        h
                jm        DiffSigns
                mov        a,e
                sub        l
                mov        b,a
                mov        a,d
                sbb        h
                rc                        ;DE<HL (CY=1)
                ora        b
                ret                        ;или DE>HL (CY=0;Z=0) или DE=HL (CY=0;Z=1)
DiffSigns:        xra        h
                rp                        ;DE>HL (CY=0;Z=0)
                stc
                ret                        ;DE<HL (CY=1)

Чуть измененный вариант из книги
Григорьев В.Л. Программное обеспечение микропроцессорных систем. М.: Энергоатомиздат, 1983 (с. 173-174)

Mick 15th September 2012 09:16

Если автор топика задумал написть свой компилятор Си под ВМ80, то может ему пригодится книга "Компилятор Си для микроЭВМ" Д.Хендрикс. В ней описывается Смолл-Си.

Вот ссылки из инета.
http://net.lg.ua/~cray/compilers/jhc.djvu
http://net.lg.ua/~cray/compilers/smallc21.rar

b2m 15th September 2012 12:02

Quote:

Originally Posted by predatoralpha (Post 539745)
Тут надо не только знак учитывать, но и флаг переполнения. И если есть переполнение - реверсировать результат.

Согласен. Про переполнение я уже потом подумал, когда выключил комп :)

ivagor 15th September 2012 12:33

8-битное сравнение из 16-битного варианта вроде тоже неплохо получается:
Code:

;A и E - знаковые 8 битные целые
;Кроме флагов ничего не портит
CmpAE:        xra        e
        jm        DiffSigns
        xra        e
        cmp        e
        ret                ;A<E (CY=1) или A>E (CY=0;Z=0) или A=E (CY=0;Z=1)
DiffSigns:
        xra        e
        rp                ;A>E (CY=0;Z=0)
        stc
        ret                ;A<E (CY=1)


predatoralpha 15th September 2012 15:32

Мой вариант сравнения с инверсией флага переноса неверен.
vinxru, используй свою версию с +80. Похоже, на 7-й бит нельзя опираться.

svofski 15th September 2012 16:41

Вчера, засыпая, отправил не в тот тред. На всякий случай повторюсь:

Ускоренные умножения и деления, вдруг пригодится:
http://www.cirsovius.de/CPM/Projekte...IV/MULDIV.html

b2m 15th September 2012 21:58

Quote:

Originally Posted by predatoralpha (Post 539837)
vinxru, используй свою версию с +80.

И я того же мне ни я.

vinxru 17th September 2012 03:08

Реализовал break, continue, return, switch, default, do {} while, union, typedef, extern, sizeof. Реализовано описание внешних функций и переменных. Функции сравнения + перехода оптимизированы. Реализован #define

---
Осталось:

Оптимизировать умножение и деление на константу.

Switch - это пока просто последовательность if, т.е. без таблицы переходов

Вставки ассемблера не реализованы.

Препроцессор не реализован: #include, #ifdef, #ifndef, #endif

Инициализации статических переменных нет Например: char data[] = { 0x10, 0x20 }; FileInfo files[] = { { "abc", 1 }, { "def", 2 } };

Контроля рекурсии нет и необходимый размер стека не определяется.

Сделать постоптимизатор ассемблера, который в том числе будет переводить программу в мненоники 8080, комплировать в BIN файл.

Режима стековых переменных нет.

vinxru 17th September 2012 14:01

В структурах нельзя будет описывать многомерные массивы. В моём компиляторе двухмерный массив - это массив указателей на одномерные массивы.

int a[5][10] - это

int* a[5];
int b[50];
a[0] = b;
a[1] = b+10;
a[2] = b+20;
a[3] = b+30;
a[4] = b+40;

Еще не сделал вычитание указателя из указателя. И с преобразованием типов не все впорядке.

---------- Post added at 12:01 ---------- Previous post was at 11:57 ----------

Так же в этой документации описано, что перед любой арифметической операцией надо 8 битные типы данных приводить к 16 битным.

в моем же случае любая операция между 8 битными значениями даст 8 битный результат. Кроме умножения, оно дает 16 бит.

А любое сравнение или операция НЕ дает 8 битный результат.

vinxru 18th September 2012 01:03

Команда XTHL пригодилась.

predatoralpha 18th September 2012 12:52

Quote:

Originally Posted by vinxru (Post 540555)
Команда XTHL пригодилась.

А на каком коде? Не хватало регистров?

vinxru 18th September 2012 12:56

На команде загрузить в HL значение с верхушки стека. Но перед тем как использовать HL, надо его прошлое значение сохранить в стек.

Что то типа

POP DE
PUSH HL
EX HL, DE

И даже команда DEC SP пригодилась. Для варианта

PUSH DE

...

INC SP
POP AF
DEC SP

predatoralpha 18th September 2012 13:00

Quote:

Originally Posted by vinxru (Post 540656)
На команде загрузить в HL значение с верхушки стека. Но перед тем как использовать HL, надо его прошлое значение сохранить в стек.

Я понимаю что делает команда. А на каком сишном коде она "всплыла"?

vinxru 18th September 2012 13:05

Сейчас сказать не могу.

vinxru 19th September 2012 05:27

Ради отладки компилятора переписал с JS игру. Почти полностью на Си.

http://s019.radikal.ru/i615/1209/b9/3875185eea1d.png


All times are GMT +4. The time now is 01:08.

Powered by vBulletin® Version 3.8.3
Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.