![]() |
1 Attachment(s)
Обещал в среду, поэтому выкладываю что есть. Я сегодня, внезапно, опять с нуля переписал кодогенератор. Переписать до конца не успел и некоторые вещи компилируется не оптимально.
При этом синтаксисом Си почти не занимался, там то же есть масса косяков. Косяки все не перечисляю, поскольку их там несколько десятков. Но основное это: 1) Преобразование типов криво написано. Никакого автоматического преобразования нет. То есть signed -> unsigned, short -> char и т.п. При вычитании указателей деление на размер может не производится. Сравнение указателя с нулем не реализовано. Я просто не успел. 2) Инициализация статических данных написана в самом простом варианте и не совсем корректно. ( uchar code[4] = { 1,2,3,4 }; ) 3) #define действует на #define :) 4) Переменные и функции не контролируются на дубликаты. 5) switch реализован криво. Забыл. (Два или более подряд идущих CASE быть не должно. Перед CASE должен быть BREAK, иначе поведение не определено) И по оптимизации основное: 1) Операции && и || и ! работают крайне медленно. Хотя и корректно. Не успел дописать оптимизацию. 2) Дублирующиеся бесполезные команды ассемблера будут удаляться на следующем этапе компиляции, который я еще не дописал. 3) Размеры структур должны быть кратны степени двойки (но об этом и так вам сообщит компилятор) 4) Не все варианты команд реализованы, есть вероятность схватить ошибку типа "pokeHL 12" P.S. Можете добавить в список, но у меня пока дел хватает и ошибки я правлю когда они сильно мешают жить. Во вложении компилятор и исходники игрушки. Игрушка тормозит не по детски, не синхронизируется с кадровой разверткой, но вроде работает. Для цветного Апогея. |
Пример кода
Code:
;--- drawSprite ----------------------------------------------------------------- |
В следующей версии будет часть ошибок поправлена и оптимизатор-удалятор подключен. Он так же сможет формировать программу в мненониках 8080.
|
Работа проделана огромная! Молодец! Будем следить!
|
Присоединяюсь. Браво! Даже не ожидал, что в наше время возможна разработка проекта такой сложности на чистом энтузиазме.
Сравнительно просто можно реализовать в Вашем компиляторе оптимизацию, которая встречается редко в каком компиляторе, сделанном не большой фирмой за финансирование. Способ основан на отслеживании кодогенератором состояния процессора: флагов, регистров и т.д. Имея и актуализируя после генерации каждой команды набор такой информации, легко встроить различные оптимизации: загрузки адресов, значений, опора на состояние флагов (ну раз значение точно известно) и т.д. Заведите “слово состояния процессора”, представляющее собой запись (структуру в Си-терминологии) состояния различных флагов, регистров и т.п., что будет выглядеть примерно так: Code:
TYPECode:
IF regA & (regA_val = 0) THENCode:
IF regHL & (regHL_val = varA_addr) THENP.S. Игру в эмуле Башкирия-2М запустить удалось только в ч/б. Выбираю при старте цветной Апогей, но после открытия файла он упрямо переключается на ч/б (буковка Ц пропадает из заголовка). Что я делаю не так? |
Quote:
|
В игре есть "баг" или "фича": если при движении вниз человечка не отпускать кнопку движения, он проходит немного вправо (если открыт путь). Влево же такого поведения не наблюдается. Заметил: редко-редко при нажатии кнопки движения человечек делает шажок не в ту сторону, но потом сам возвращается. Управлять легко, не зацепляется за края стен. Удобно. Осталось поправить мерцание спрайтов.
|
Quote:
Но пока я делаю страшную вещь... Прошлая версия компилятора собирала любую команду в три этапа: загрузка первого аргумента в HL, загрузка второго аргумента в DE, работа с регистрами. Этот подход работает, но код не оптимален и сложно поддается оптимизации. Например ushort &= register uchar* ;oSAnd pConstStrRef16 pBCRef8 ld a, (bc) ld e, c ld d, 0 ld hl, (name1) ld a, l and e ld l, a ld a, h and d ld h, a ld (name1), hl Я объединил эти три действия в одно и получил под тысячу вариантов команд. И сейчас сижу описываю более оптимальные варианты ld hl, name1 ld a, (bc) and (hl) ld (hl), a inc hl ld (hl), 0 ---------- Post added at 23:11 ---------- Previous post was at 22:58 ---------- Quote:
|
Вот это это выглядит. Код для 8 битного вычитания.
Для команд & | ^ + > < <= >= != == будет подобный вариант, но там команды будут проще, так как там слогаемые можно переставлять: case pC, pA: w.ld_d_a().ld_a_c().alu_d(op); break; заменится на case pC, pA: w.alu_с(op); break; Code:
void cmd_alu(AluOp op, bool self, bool flags) { |
vinxru, тебе ещё все предстоит в очередной раз переделывать, когда будешь вести по каждой переменной её состояние, и в зависимости от этого код будет разный. Приблизительный пример.
Твой код, сейчас: Code:
; 54 for(y=0; y<8; y++)Code:
; 54 for(y=0; y<8; y++)Нужно на каждую переменную вести её последнее значение, на этапе компиляции анализировать условия (y<8 в данном случае). И в зависимости от этого анализа условия компилятор выбирает нужную ветку. Ты молодец, много сделал, но тут ещё копать и копать. И боюсь, ещё не раз придётся всё переписать... |
Замена for(a;b;c) на a; do ... c; while(b); ? Я не думал об этом, так как это может сделать программист, но сделаем.
---------- Post added at 01:15 ---------- Previous post was at 01:10 ---------- Quote:
Можно было бы давно оставить в покое кодогенератор, добить синтаксис Си, добавить оптимизатор. Но хочется, что бы потом пальцем не показывали, что бы компилятор работал на уровне или даже лучше компиляторов для Z80. ---------- Post added at 01:31 ---------- Previous post was at 01:15 ---------- Quote:
А уже потом, несколько алгоритмов оптимизации будут сверху-вниз и снизу-верх обрабатывать программу. ---------- Post added at 03:18 ---------- Previous post was at 01:31 ---------- Добавил замену команды LD A на INC A, DEC A в зависимости от состояния A. Вам очень этого хотелось :) Еще добавлю CPL туда же и для всех регистров сделаю. Сделал нормальную поддержку операторов && || ! Надо еще расписать все варианты для 16-битной арифметики. Code:
startGame: |
В op_shr надо CP A перенести после op_shr_2.
Возможно в memcpy и memset стоит сделать две ветки - одна для счетчика >255 (как сейчас), вторая для <=255? Сделал оба пункта, printKeyb раскомментил - бомберман не сломался. Процедуры/функции, которые никто не "трогает", наверно лучше не компилировать и не включать в .asm? |
Quote:
Quote:
Quote:
Quote:
Более того, надо продумать более грамотное подключение библиотек функций. Что бы не компилировать весь код. Что то типа: uchar getch() = stdlib.c; uchar setPixel(uchar x, uchar y, uchar c) = apogey/graph.c; |
1 Attachment(s)
Quote:
В качестве оффтопа - сделал тупой немигающий вариант бомбера. Просто копирую (pop shld, почти 80000 тактов :o) из бэкбуффера в ВОЗУ, хотя на апогее надо конечно менять базовый адрес отрисовки и переключать адреса ВОЗУ. Quote:
|
Восьмибитное умножение можно немного оптимизировать
Code:
; Умножение A на D, результат в HL. BC не трогаемCode:
op_mul:В прошлом посте я сначала случайно выложил mem.h без pop, потом исправился. |
Начал писать оптимизатор.
1) Выбрасываются бессмысленные команды MOV; MVI; LDA; LDAX. 2) LDA, STA заменяется на MOV A, M, MOV M, A, LDAX, STAX если HL, BC, DE содержит соответствующее значение. 3) LHLD + MVI H, 0 заменяется на MOV L, R, MVI H, 0 если R содержит соответствующее значение. 4) MVI заменяется на INC, DEC в зависимости от значения регистра. 5) MVI A заменяется на XOR A, ADD A, CMA в зависимости от значения регистра A. 6) OR A уничтожается в последовательности команд типа: ANI 16; OR A; JZ 7) Два подряд идущих ANI, ORI, XRI, ADI, SBI... объединяются. 8) Конструкции JC $+4 + RET; JC $+6 + CALL; JC $+6 + JP заменяются на одну команду типа RNC, CNC, JNC. 9) Бесполезные переходы JP $+3 убираются. Помимо этого в самом кодогенераторе 1) Условные операторы, типа X = A<B, теперь рассчитываются используя команду SBC вместо перехода: LDA 1; CP 2; SBC A 2) Из за недоработки компилятор выдавал последовательность команд XOR A, MOV M, A в некоторых случаях. Теперь всегда будет MVI M, 0. 3) Для 16 битного сравнения и вычитания, если один из аргументов константа, используется команда ADD HL, DE. Исключение составляют 4 оператора для знакового типа SHORT: <, >, <=, =>, для которых вызывается подпрограмма. ---------- Post added at 13:42 ---------- Previous post was at 12:40 ---------- В ближайшее время займусь доработкой синтаксиса Си. Какие нибудь программы Си покомпилирую. Например Трубо-Кальк из примеров к Трубо-Си. А то как в первый день я сделал наброски, так больше и не трогал. ---------- Post added at 14:14 ---------- Previous post was at 13:42 ---------- Прикинул, какие команды я не использую: EI, DI, DAA, CMC, STC, DCX D, HLT, SPHL, PUSH D, IN, OUT, RST, LXI SP, NOP JP, JPO, JPE, JM CP, CPO, CPE, CM RP, RPO, RPE, RM, RLC, RRC, RAL Еще некоторые комбинации регистров в MOV, ADD, ADC, SBC, OR, AND, XOR, CP не используются. |
Quote:
Quote:
---------- Post added at 15:25 ---------- Previous post was at 15:20 ---------- Quote:
|
Quote:
А посоветуйте компилятор ассемблера для 8080, я бы сразу его прикрутил. ---------- Post added at 14:35 ---------- Previous post was at 14:33 ---------- Quote:
Так же будут работать float, double, long double и т.д. Все операторы внешние. ---------- Post added at 14:36 ---------- Previous post was at 14:35 ---------- Quote:
---------- Post added at 14:41 ---------- Previous post was at 14:36 ---------- Quote:
|
Quote:
Могу ещё предложить консольный эмулятор CP/M для i8080, недавно тестировал в нём работу C80,M80,L80. Вроде всё работает. Ещё я использовал FASM :) У него мощный препроцессор, я сделал файл с макросами, так он и i8080 компилировал, хотя и не поддерживает этот процессор. |
1 Attachment(s)
Quote:
Quote:
Quote:
|
Quote:
Но что бы рассчитать, какие переменные располагать вместе, надо построить дерево вызовов функций. И жестко определить адрес для каждой переменной. Возможно относительный адрес, то есть memset_dest EQU variables_area + 100 memset_c EQU variables_area + 102 memcpy_dest EQU variables_area + 100 memcpy_src EQU variables_area + 102 То есть потребуется анализ всех исходников и переформирование OBJ файлов каждый раз. Либо свой линкер. |
1 Attachment(s)
выход компилятора для 8080 (просто текст программы, есть пара комяков. НАпример перепутал mvi m и shld)
|
Quote:
Ну хрен с ним, пусть переменные не будут определены одна поверх другой - баловство все это. Не надо ничего экономить в памяти переменных, экономия получится за счет компактного кода. |
Quote:
---------- Post added at 19:05 ---------- Previous post was at 18:52 ---------- Я добавил оператор $. Это 8-битное умножение. Работает быстрее. ---------- Post added at 19:06 ---------- Previous post was at 19:05 ---------- Аналогично (uchar)(a*b), только быстрее и короче. Использовать не обязательно. ---------- Post added at 19:39 ---------- Previous post was at 18:06 ---------- Ух ты блин. Эмулятор b2m подхватил названия переменных из LST файла, который генерирует tasm http://s017.radikal.ru/i443/1209/50/73899f5f3dd1.png |
Quote:
|
Сделал сумматор тактов всех команд программы. И замерял результат до работы оптимизатора и после. Пока получается оптимизация 90%. (стало/было*100)
Но в оптимизаторе нет самого главного. Он не умеет работать с ветвлениями и циклами. Сегодня добавлю их. ---------- Post added at 16:07 ---------- Previous post was at 14:12 ---------- Сделал, несколько команд пропало. Оценка 89%. Красные - это поправки (удаления) Code:
test: |
Версии компилятора буду выкладывать на LJ, меня сейчас тут забанят.
|
Quote:
---------- Post added at 23:06 ---------- Previous post was at 21:23 ---------- Quote:
|
| All times are GMT +4. The time now is 01:08. |
Powered by vBulletin® Version 3.8.3
Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.