![]() |
LD DE, 0000 + ADD HL, DE = 10+4 = 14 тактов
LD A,H + OR L = 5+4 = 9 тактов Но если DE загружать вне цикла, то покатит. |
LXI 10 тактов. DAD тоже. Итого 20.
---------- Post added at 17:37 ---------- Previous post was at 17:36 ---------- Давай будем разговаривать в мнемониках i8080 :) |
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 |
Quote:
|
Я тут просматривал код:
Code:
; for(x=0; x<64; x+=16) {main_x_var: ld a,0 нолик, соответственно, место где хранится переменная, она же теперь часть кода. Соответственно, обращаться к переменной теперь не ld a, (main_x), а ld a, (main_x_var+1). Код на байт короче, байт экономится на глобальной переменной, 6 тактов на каждой итерации цикла. Правда 2 минуса - нужно следить за обращением к x, он теперь на новом месте, и такой код нельзя зашить в ROM. |
Хм, сделаю и такой режим :) Но когда переменные лежат одним блоком, легко реализовать рекурсию. Просто этот блок переменных копировать в стек.
Выхожу на финишную прямую с кодогенератором. Сделал операции < > <= >= == != для uchar. Сделал #define #undef (как полагается с параметрами). Code:
print_return ds 01888 строк 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() { |
Quote:
А это зачем? 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--). |
Переменные на стеке нужны для реентабельности процедур. Это не только рекурсия, но и второе в хождение в ту же процедуру из обработчика перерывания. Соответственно, в случае работы системы с прерываниями, копировать глобальные переменные на стек бессмысленно - остается вероятность что по прерыванию будет повторное вхождение пока переменные еще не скопированы. Ну и если будет такое копирование, всякий выигрыш теряется (что про времени выполнения, что по размеру кода). Тогда уж сразу надо делать на стеке.
|
Quote:
- Проблема нереентабельности по прерываниям, как по мне, несущественная. Обработчик обычно пишется на ассемблере, если какие-то сишные функции и будут вызываться - то обычно это не те, что выполняются вне прерывания. Этот факт нужно отразить в документации, и принять его "как есть". - Более серьёзная проблема, как по мне - это передача ссылки на локальную переменную в некую функцию. Если создаются копии локальных переменных в стеке, то ссылка на локальную переменную "повиснет". А если ещё добавить, что вызываемая функция эту ссылку может сохранить в глобальной переменной, и другая вызываемая функция (из базовой функции) эту ссылку может оттуда поднять... Тут весьма сложный момент. И врядли он будет сделан в соответствии со стандартами языка. Я не хочу сейчас грузить vinxru этой проблемой. Он и так молодец. |
Quote:
Нет на 8080 команды ld ((clrscr_dest)), A А вот на PDP-11 есть. ---------- Post added at 14:31 ---------- Previous post was at 14:30 ---------- Quote:
---------- Post added at 14:34 ---------- Previous post was at 14:31 ---------- Quote:
А обращаться к переменной мы будем много раз, может быть что 1000 раз. ---------- Post added at 14:35 ---------- Previous post was at 14:34 ---------- Quote:
---------- Post added at 14:37 ---------- Previous post was at 14:35 ---------- Quote:
1) Программой, которая умеет рекурсию. 2) И программой, которая работает в 3 раза быстрее. |
Quote:
Quote:
Quote:
Quote:
Единственно замечу, что это проблема не только рекурсии. В том примере, что я привёл, это возможно при вызове из функции двух функций, которые никак рекурсию не производят. Просто отразить в документации - если хочешь иметь корректный указатель на лок.перем. между вызовами разных функций - используй указатель на static или volatile переменную. |
Quote:
---------- Post added at 19:26 ---------- Previous post was at 19:23 ---------- И в тексте программы учитывать: #pragma static_variable on #pragma static_variable off |
Quote:
Так что вопрос несколько сложнее, и просто register это не решает. Здесь планируется несколько более, чем просто статические переменные. Их можно использовать как и автоматические, для рекурсии. Можно сказать, что локальные переменные просто кешируются в памяти по конкретным адресам. |
У меня нельзя будет получить адрес регистровой переменной. Как раз сейчас сообщений об ошибках придумывал.
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, кроме изменяемых флагов? |
У ADC A справа нулевой бит добавляется, а RAL - берёт флаг переноса.
|
У разве не у ADD нулевой бит добавляется?
|
Фу-ты, попутал. Значит ничем :)
|
Команды 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 |
Quote:
xra a (или sub a) ora h/b |
И еще я что то не могу сообразить, как сравнивать знаковые числа. Беззнаковые просто, по флагам Z и C. А знаковые я только придумал
(n1+80h) < (n2+80h) MOV A, N1 XRI 0x80 MOV D, A MOV A, N2 XRI 0x80 CP D А дальше так же по флагам C, Z Но конструкция получается тормозная и большая. Такую не жалко в подпрограмму вынести, что бы зря размер кода не увеличивать. |
А если просто вычесть и знак результата проверить?
MOV A,N1 MOV B,N2 SUB B JM less |
Ааа... спать надо больше. Точно ведь. А мне лень даже в яндекс вбить слово.
---------- 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 Кб |
Quote:
Возможно, Вы подумаете о чём-нибудь типа #pragma recursion:ON/OFF Также пожелание поддерживать несколько calling conventions, по крайей мере extern "C" / _stdcall, _pascal, _memblock (это-Ваш вариант) и _fast (передача до 2х параметров в регистрах) |
Сделаю рекурсию. Добавлю модификаторы _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:
Программа |
Quote:
Например. 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 В коде не совсем уверен, сейчас несколько нетрезв. |
Возможно пригодится - сравнение 16 битных знаковых чисел
Code:
;DE и HL - знаковые 16 битные целыеГригорьев В.Л. Программное обеспечение микропроцессорных систем. М.: Энергоатомиздат, 1983 (с. 173-174) |
Если автор топика задумал написть свой компилятор Си под ВМ80, то может ему пригодится книга "Компилятор Си для микроЭВМ" Д.Хендрикс. В ней описывается Смолл-Си.
Вот ссылки из инета. http://net.lg.ua/~cray/compilers/jhc.djvu http://net.lg.ua/~cray/compilers/smallc21.rar |
Quote:
|
8-битное сравнение из 16-битного варианта вроде тоже неплохо получается:
Code:
;A и E - знаковые 8 битные целые |
Мой вариант сравнения с инверсией флага переноса неверен.
vinxru, используй свою версию с +80. Похоже, на 7-й бит нельзя опираться. |
Вчера, засыпая, отправил не в тот тред. На всякий случай повторюсь:
Ускоренные умножения и деления, вдруг пригодится: http://www.cirsovius.de/CPM/Projekte...IV/MULDIV.html |
Quote:
|
Реализовал 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 файл. Режима стековых переменных нет. |
В структурах нельзя будет описывать многомерные массивы. В моём компиляторе двухмерный массив - это массив указателей на одномерные массивы.
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 битный результат. |
Команда XTHL пригодилась.
|
Quote:
|
На команде загрузить в HL значение с верхушки стека. Но перед тем как использовать HL, надо его прошлое значение сохранить в стек.
Что то типа POP DE PUSH HL EX HL, DE И даже команда DEC SP пригодилась. Для варианта PUSH DE ... INC SP POP AF DEC SP |
Quote:
|
Сейчас сказать не могу.
|
Ради отладки компилятора переписал с 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.