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 20th September 2012 00:51

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. Можете добавить в список, но у меня пока дел хватает и ошибки я правлю когда они сильно мешают жить.

Во вложении компилятор и исходники игрушки. Игрушка тормозит не по детски, не синхронизируется с кадровой разверткой, но вроде работает. Для цветного Апогея.

vinxru 20th September 2012 00:57

Пример кода

Code:

;--- drawSprite -----------------------------------------------------------------
drawSprite_x ds 1
drawSprite_y ds 1
drawSprite_s ds 2
drawSprite_v ds 2
drawSprite_a ds 1
drawSprite:
  ld (drawSprite_s), hl
  ; 8 a = (uchar)(x/SPRITE_WIDTH*5);
  ld a, (drawSprite_x)
  rra
  rra
  and 3Fh
  ld d, 5
  call op_mul
  ld a, l
  ld (drawSprite_a), a
  ; 9 v = (uchar*)(0xA009 + 94*6 + a + y*94);
  ld hl, (drawSprite_a)
  ld h, 0
  ld de, 41533
  add hl, de
  push hl
  ld d, 94
  ld a, (drawSprite_y)
  call op_mul
  pop de
  add hl, de
  ld (drawSprite_v), hl
  ; 11 switch(x % SPRITE_WIDTH) {
  ld a, (drawSprite_x)
  and 3
  cp 0
  jp nz, l24
  ; 12 drawImage (v, CYAN, s); break;
  ld hl, (drawSprite_v)
  ld (drawImage_to), hl
  ld a, 129
  ld (drawImage_color), a
  ld hl, (drawSprite_s)
  call drawImage
  ; 12 break;
  jp l23
l24:
  cp 1
  jp nz, l25
  ; 13 drawImage1(v, CYAN, s); break;
  ld hl, (drawSprite_v)
  ld (drawImage1_to), hl
  ld a, 129
  ld (drawImage1_color), a
  ld hl, (drawSprite_s)
  call drawImage1
  ; 13 break;
  jp l23
l25:
  cp 2
  jp nz, l26
  ; 14 drawImage2(v, CYAN, s); break;
  ld hl, (drawSprite_v)
  ld (drawImage2_to), hl
  ld a, 129
  ld (drawImage2_color), a
  ld hl, (drawSprite_s)
  call drawImage2
  ; 14 break;
  jp l23
l26:
  cp 3
  jp nz, l27
  ; 15 drawImage3(v, CYAN, s); break;
  ld hl, (drawSprite_v)
  ld (drawImage3_to), hl
  ld a, 129
  ld (drawImage3_color), a
  ld hl, (drawSprite_s)
  call drawImage3
  ; 15 break;
  jp l23
l23:
l27:
  ; 18 a = (uchar)((y/SPRITE_WIDTH)*MAP_WIDTH+(x/SPRITE_HEIGHT));
  ld a, (drawSprite_y)
  rra
  rra
  and 3Fh
  ld h, 0
  ld l, a
  add hl, hl
  add hl, hl
  add hl, hl
  add hl, hl
  ld a, (drawSprite_x)
  rra
  rra
  and 3Fh
  ld e, a
  ld d, 0
  add hl, de
  ld a, l
  ld (drawSprite_a), a
  ; 19 map1[a]=0xFF;
  ld hl, (drawSprite_a)
  ld h, 0
  ld de, map1
  add hl, de
  ld a, 255
  ld (hl), a
  ; 20 if(x%MAP_WIDTH) {
  ld a, (drawSprite_x)
  and 0Fh
  or a
  jp z, l28
  ; 21 map1[a+1] = 0xFF;
  ld a, (drawSprite_a)
  add 1
  ld h, 0
  ld l, a
  ld de, map1
  add hl, de
  ld a, 255
  ld (hl), a
  ; 22 if(y%MAP_WIDTH) {
  ld a, (drawSprite_y)
  and 0Fh
  or a
  jp z, l29
  ; 23 map1[a+MAP_WIDTH]=0xFF;
  ld a, (drawSprite_a)
  add 16
  ld h, 0
  ld l, a
  ld de, map1
  add hl, de
  ld a, 255
  ld (hl), a
  ; 24 map1[a+(MAP_WIDTH+1)]=0xFF;
  ld a, (drawSprite_a)
  add 17
  ld h, 0
  ld l, a
  ld de, map1
  add hl, de
  ld a, 255
  ld (hl), a
l29:
  jp l30
l28:
  ; 27 if(y%MAP_WIDTH) {
  ld a, (drawSprite_y)
  and 0Fh
  or a
  jp z, l31
  ; 28 map1[a+MAP_WIDTH]=0xFF;
  ld a, (drawSprite_a)
  add 16
  ld h, 0
  ld l, a
  ld de, map1
  add hl, de
  ld a, 255
  ld (hl), a
l31:
l30:
l22:
  ret
;--- redrawTiles -----------------------------------------------------------------
redrawTiles_v ds 2
redrawTiles_a ds 1
redrawTiles_addr ds 1
redrawTiles:
  push bc
  ; 39 for(m = map1; m - (map1+MAP_WIDTH*MAP_HEIGHT); ++m) {
  ld bc, map1
l33:
  ld hl, -((map1)+(208))
  add hl, bc
  ld a, l
  or h
  jp z, l34
  ; 40 if(!*m) continue;
  ld a, (bc)
  or a
  jp nz, l37
  ; 40 continue;
  jp l35
l37:
  ; 41 *m = 0;
  xor a
  ld (bc), a
  ; 43 addr = (uchar)(m - map1);
  ld hl, -(map1)
  add hl, bc
  ld a, l
  ld (redrawTiles_addr), a
  ; 44 a = map[addr];
  ld hl, (redrawTiles_addr)
  ld h, 0
  ld de, map
  add hl, de
  ld a, (hl)
  ld (redrawTiles_a), a
  ; 45 v = (uchar*)(0xA009 + 94*6 + (addr/MAP_WIDTH)*(94*4) + 5*(addr%MAP_WIDTH));
  ld a, (redrawTiles_addr)
  rra
  rra
  rra
  rra
  and 0Fh
  ld de, 376
  ld h, 0
  ld l, a
  call op_mul16
  ld de, 41533
  add hl, de
  ld a, (redrawTiles_addr)
  and 0Fh
  push hl
  ld d, a
  ld a, 5
  call op_mul
  pop de
  add hl, de
  ld (redrawTiles_v), hl
  ; 46 if(a==0) {
  ld a, (redrawTiles_a)
  cp 0
  jp nz, l39
  ; 47 drawEmptyImage(v);
  ld hl, (redrawTiles_v)
  call drawEmptyImage
  jp l40
l39:
  ; 49 if(a >= 0x80) a=2;
  ld a, (redrawTiles_a)
  cp 128
  jp c, l42
  ; 49 a=2;
  ld a, 2
  ld (redrawTiles_a), a
l42:
  ; 50 a--;
  ld hl, redrawTiles_a
  ld a, (hl)
  dec (hl)
  ; 51 drawImage(v, tilesColors[a], tiles + a*16);
  ld hl, (redrawTiles_v)
  ld (drawImage_to), hl
  ld hl, (redrawTiles_a)
  ld h, 0
  ld de, tilesColors
  add hl, de
  ld a, (hl)
  ld (drawImage_color), a
  ld hl, (redrawTiles_a)
  ld h, 0
  add hl, hl
  add hl, hl
  add hl, hl
  add hl, hl
  ld de, tiles
  add hl, de
  call drawImage
l40:
l35:
  inc bc
  jp l33
l34:
l32:
  pop bc
  ret
;--- redrawScreen -----------------------------------------------------------------
redrawScreen_i ds 1
redrawScreen_s ds 2
redrawScreen:
  push bc
  ; 61 redrawTiles();
  call redrawTiles
  ; 63 s = enemySprite + enemyAnimation[(ticks/4)%4];
  ld a, (ticks)
  rra
  rra
  and 3Fh
  and 3
  ld h, 0
  ld l, a
  ld de, enemyAnimation
  add hl, de
  ld l, (hl)
  ld h, 0
  ld de, enemySprite
  add hl, de
  ld (redrawScreen_s), hl
  ; 64 for(e=enemies, i=0; i<enemyCount; ++i, ++e)
  ld bc, enemies
  xor a
  ld (redrawScreen_i), a
l44:
  ld hl, enemyCount
  ld a, (redrawScreen_i)
  cp (hl)
  jp nc, l45
  ; 65 drawSprite(e->x, e->y, s);
  ld a, (bc)
  ld (drawSprite_x), a
  ld hl, bc
  inc hl
  ld a, (hl)
  ld (drawSprite_y), a
  ld hl, (redrawScreen_s)
  call drawSprite
l46:
  ld hl, redrawScreen_i
  inc (hl)
  inc bc
  inc bc
  inc bc
  inc bc
  jp l44
l45:
  ; 67 if(playerDir==1 || playerDir==2) s = playerSprite + 16 + 16*(1 + (ticks / 2)&1); else
  ld a, (playerDir)
  cp 1
  ld a, 1
  jp z, l48
  dec a
l48:
  push af
  ld a, (playerDir)
  cp 2
  ld a, 1
  jp z, l49
  dec a
l49:
  ld d, a
  pop af
  or d
  or a
  jp z, l50
  ; 67 s = playerSprite + 16 + 16*(1 + (ticks / 2)&1); else
  ld a, (ticks)
  cp a
  rra
  add 1
  and 1
  ld d, a
  ld a, 16
  call op_mul
  ld de, (playerSprite)+(16)
  add hl, de
  ld (redrawScreen_s), hl
  jp l51
l50:
  ; 68 if(playerDir==3 || playerDir==4) s = playerSprite + 16*3 + 16*(1 + (ticks / 2)&1);
  ld a, (playerDir)
  cp 3
  ld a, 1
  jp z, l52
  dec a
l52:
  push af
  ld a, (playerDir)
  cp 4
  ld a, 1
  jp z, l53
  dec a
l53:
  ld d, a
  pop af
  or d
  or a
  jp z, l54
  ; 68 s = playerSprite + 16*3 + 16*(1 + (ticks / 2)&1);
  ld a, (ticks)
  cp a
  rra
  add 1
  and 1
  ld d, a
  ld a, 16
  call op_mul
  ld de, (playerSprite)+(48)
  add hl, de
  ld (redrawScreen_s), hl
  jp l55
l54:
  ; 69 s = playerSprite;
  ld hl, playerSprite
  ld (redrawScreen_s), hl
l55:
l51:
  ; 70 drawSprite(playerX, playerY, s);
  ld a, (playerX)
  ld (drawSprite_x), a
  ld a, (playerY)
  ld (drawSprite_y), a
  ld hl, (redrawScreen_s)
  call drawSprite
l43:
  pop bc
  ret
;--- getKeybFire -----------------------------------------------------------------
getKeybFire:
  ; 2 *(uchar*)0xED00 = ~(1<<7); 
  ld a, 127
  ld (60672), a
  ; 3 return !(*(uchar*)0xED01 & 0x80); 
  ld a, (60673)
  and 128
  or a
  ld a, 0
  jp nz, l57
  inc a
l57:
  jp l56
l56:
  ret
;--- getKeybArrows -----------------------------------------------------------------
getKeybArrows:
  ; 7 *(uchar*)0xED00 = ~(1<<1); 
  ld a, 253
  ld (60672), a
  ; 8 return ~(*(uchar*)0xED01); 
  ld a, (60673)
  cpl
  jp l58
l58:
  ret
lvd:
  db 35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,32
  db 35,32,32,32,55,32,32,50,32,32,32,32,32,32,35,32
  db 35,32,35,32,35,32,35,50,35,32,35,32,35,32,35,32
  db 35,32,32,32,32,54,50,50,32,32,32,50,32,32,35,32
  db 35,32,35,32,35,50,35,32,35,32,35,50,35,32,35,32
  db 35,52,50,54,50,50,32,32,32,54,50,50,50,32,35,32
  db 35,32,35,64,35,50,35,32,35,50,35,32,35,32,35,32
  db 35,32,50,32,32,50,64,32,32,32,50,32,32,32,35,32
  db 35,50,35,50,35,50,35,54,35,50,35,32,35,32,35,32
  db 35,32,32,32,32,50,32,32,32,50,32,64,54,32,35,32
  db 35,50,35,32,35,32,35,50,35,50,35,50,35,32,35,32
  db 35,32,50,32,32,32,50,64,32,32,32,32,32,32,35,32
  db 35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,32
;--- printKeyb -----------------------------------------------------------------
printKeyb:
  push bc
  ; 52 for(x=0; x<8; x++) {
  ld b, 0
l60:
  ld a, b
  cp 8
  jp nc, l61
  ; 53 *(uchar*)0xED00 = ~(1<<x); 
  ld d, b
  ld a, 1
  call op_shl
  cpl
  ld (60672), a
  ; 54 for(y=0; y<8; y++)
  ld c, 0
l64:
  ld a, c
  cp 8
  jp nc, l65
  ; 55 ((uchar*)0xA000+94*y)[x] = (*(uchar*)0xED01 >> y) & 1;
  ld d, c
  ld a, 94
  call op_mul
  ld de, 40960
  add hl, de
  ld e, b
  ld d, 0
  add hl, de
  ld d, c
  ld a, (60673)
  call op_shr
  and 1
  ld (hl), a
l66:
  ld a, c
  inc c
  jp l64
l65:
l62:
  ld a, b
  inc b
  jp l60
l61:
l59:
  pop bc
  ret
moveBonus:  ds 1
moveExit:  ds 1
moveDead:  ds 1


vinxru 20th September 2012 15:31

В следующей версии будет часть ошибок поправлена и оптимизатор-удалятор подключен. Он так же сможет формировать программу в мненониках 8080.

predatoralpha 20th September 2012 15:37

Работа проделана огромная! Молодец! Будем следить!

Oleg N. Cher 21st September 2012 21:49

Присоединяюсь. Браво! Даже не ожидал, что в наше время возможна разработка проекта такой сложности на чистом энтузиазме.

Сравнительно просто можно реализовать в Вашем компиляторе оптимизацию, которая встречается редко в каком компиляторе, сделанном не большой фирмой за финансирование. Способ основан на отслеживании кодогенератором состояния процессора: флагов, регистров и т.д. Имея и актуализируя после генерации каждой команды набор такой информации, легко встроить различные оптимизации: загрузки адресов, значений, опора на состояние флагов (ну раз значение точно известно) и т.д. Заведите “слово состояния процессора”, представляющее собой запись (структуру в Си-терминологии) состояния различных флагов, регистров и т.п., что будет выглядеть примерно так:
Code:

TYPE
  FlagStatus = SET; (* Off, On, Unknown *)

VAR
  cpuStat = RECORD
    flagZ, flagC, flagM ... : FlagStatus; (* Статус флагов *)
    regA, regB, regC ... : BOOLEAN; (* Есть ли в регистре точно известное значение? *)
    regA_val, regB_val, regC_val ... : INTEGER; (* Если оно есть, то значение RegX_val имеет смысл *)
  END;

Теперь, допустим, нам по коду надо обнулить переменную var1. Делать мы это решили через засылку значения в неё из регистра A. Проверяем, а может в A уже ноль?
Code:

IF regA & (regA_val = 0) THEN
  (* Можно не генерировать обнуление, т.к. в A остался ноль, сформированный предыдущим кодом... *)
ELSE
  Gen("XRA A");
  (* Теперь скорректируем состояние процессора, вызванное командой XRA A *)
  cpuStat.flagZ := On; cpuStat.regA := TRUE; cpuStat.regA_val := 0; ...
END;
Gen("STA var1");

Или надо загрузить в HL адрес переменной varB, а там загружен адрес varA, которые идут подряд (отличаются единичкой):
Code:

IF regHL & (regHL_val = varA_addr) THEN
  (* Можно не генерировать установку адреса, он уже там... *)
ELSIF regHL & (regHL_val = varA_addr + 1) THEN (* Адрес в HL, но он на единицу меньше, чем надо *)
  Gen("INX H");
ELSIF regHL & (regHL_val = varA_addr - 1) THEN (* Адрес в HL, но он на единицу больше, чем надо *)
  Gen("DCX H");
ELSE (* Что ни пробовали, но таки надо грузить адрес в HL... *)
  Gen("LXI H, varA");
END;

Извиняюсь, если где перепутал мнемонику, давно для РК-86 не кодил. :)

P.S. Игру в эмуле Башкирия-2М запустить удалось только в ч/б. Выбираю при старте цветной Апогей, но после открытия файла он упрямо переключается на ч/б (буковка Ц пропадает из заголовка). Что я делаю не так?

ivagor 21st September 2012 22:23

Quote:

Originally Posted by Oleg N. Cher (Post 541816)
Выбираю при старте цветной Апогей, но после открытия файла он упрямо переключается на ч/б (буковка Ц пропадает из заголовка).

Вы наверно через File->Open открываете, а при этом, в соответствии с EMU.ext запускается конфиг Apogee. Можно или EMU.ext изменить или грузить в конфиге цветного апогея командой I -> появится диалог, выбираете test_ok.rka и G.

Oleg N. Cher 21st September 2012 23:31

В игре есть "баг" или "фича": если при движении вниз человечка не отпускать кнопку движения, он проходит немного вправо (если открыт путь). Влево же такого поведения не наблюдается. Заметил: редко-редко при нажатии кнопки движения человечек делает шажок не в ту сторону, но потом сам возвращается. Управлять легко, не зацепляется за края стен. Удобно. Осталось поправить мерцание спрайтов.

vinxru 22nd September 2012 00:11

Quote:

Originally Posted by Oleg N. Cher (Post 541816)
P.S. Игру в эмуле Башкирия-2М запустить удалось только в ч/б. Выбираю при старте цветной Апогей, но после открытия файла он упрямо переключается на ч/б (буковка Ц пропадает из заголовка). Что я делаю не так?

Да, спасибо больше. Я так и собираюсь делать. И еще много будет всяких оптимизаций. Например замена JMP, который переходит на JMP. Замена PUSH H, POP H на XCHG, XCHG. Поиск одинаковых фрагментов кода и вынесение из в функцию.

Но пока я делаю страшную вещь... Прошлая версия компилятора собирала любую команду в три этапа: загрузка первого аргумента в 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:

Originally Posted by Oleg N. Cher (Post 541874)
Осталось поправить мерцание спрайтов.

Алгоритм отрисовки неправильный выбран. Но это потому что эта игра перенесена в JS. При перемещении спрайтов надо просто закрашивать лишнее черным не перерисовывая всю карту.

vinxru 22nd September 2012 00:27

Вот это это выглядит. Код для 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) {
  Stack& a = stack[stack.size()-2];
  Stack& b = stack[stack.size()-1];

  Place ap = simpleArg8(a.place);
  Place bp = simpleArg8(b.place);

  Writer& w = bc();

  if(ap!=pA && bp!=pA)
    useA();

  switch(ap) {
    case pA:
      switch(bp) {
        case pB:                          w.alu_b(op); break;
        case pC:                          w.alu_c(op); break;
        case pHL:                        w.alu_l(op); break;
        case pConst:                      w.alu(op, b); break;
        case pConstRef8:        useHL(); w.ld_hl(b).alu_HL(op); break;
        case pConstStrRefRef8:  useHL(); w.ld_hl_ref(b).alu_HL(op); break;
        case pHLRef8:                    w.alu_HL(op); break;
        case pBCRef8:            useHL(); w.ld_hl_bc().alu_HL(op); break;
        case pStack8:                    w.pop_de().alu_d(op); break;
        case pStack16:                    w.pop_de().alu_e(op); break;
        case pStackRef8:        chkHL(); w.pop_hl().alu_HL(op); break;
        default: cmd_alu_raise(ap, bp);
      }
      break;
    case pB:
      switch(bp) {
        case pA:                          w.ld_d_a().ld_a_b().alu_d(op); break;
        case pB:                          w.ld_a_b().alu_b(op); break;
        case pC:                          w.ld_a_b().alu_c(op); break;
        case pHL:                        w.ld_a_b().alu_l(op); break;
        case pConst:                      w.ld_a_b().alu(op, b); break;
        case pConstRef8:                  w.ld_a_b().ld_hl(b).alu_HL(op); break;
        case pConstStrRefRef8:  useHL(); w.ld_a_b().ld_hl_ref(b).alu_HL(op); break;
        case pHLRef8:                    w.ld_a_b().alu_HL(op); break;
        case pBCRef8:                    w.ld_a_BC().ld_d_a().ld_a_b().alu_d(op); break;
        default: cmd_alu_raise(ap, bp);
      }
      break;
    case pC:
      switch(bp) {
        case pA:                          w.ld_d_a().ld_a_c().alu_d(op); break;
        case pB:                          w.ld_a_c().alu_b(op); break;
        case pC:                          w.ld_a_c().alu_c(op); break;
        case pHL:                        w.ld_a_c().alu_l(op); break;
        case pConst:                      w.ld_a_c().alu(op, b); break;
        case pConstRef8:                  w.ld_a_c().ld_hl(b).alu_HL(op); break;
        case pConstStrRefRef8:  useHL(); w.ld_a_c().ld_hl_ref(b).alu_HL(op); break;
        case pHLRef8:                    w.ld_a_c().alu_HL(op); break;
        case pBCRef8:                    w.ld_a_BC().ld_d_a().ld_a_b().alu_d(op); break;
        default: cmd_alu_raise(ap, bp);
      }
      break;
    case pHL:
      switch(bp) {
        case pA:                          w.ld_d_a().ld_a_l().alu_d(op); break;
        case pB:                          w.ld_a_l().alu_b(op); break;
        case pC:                          w.ld_a_l().alu_c(op); break;
        case pConst:                      w.ld_a_l().alu(op, b); break;
        case pConstRef8:                  w.ld_a_l().ld_hl(b).alu_HL(op); break;
        case pConstStrRefRef8:            w.ld_a_l().ld_hl_ref(b).alu_HL(op); break;
        case pBCRef8:                    w.ld_a_BC().ld_d_a().ld_a_l().alu_d(op); break;
        default: cmd_alu_raise(ap, bp);
      }
      break;
    case pConst:
      switch(bp) {
        case pA:                          w.ld_d_a().ld_a(a).alu_d(op); break;
        case pB:                          w.ld_a(a).alu_b(op); break;
        case pC:                          w.ld_a(a).alu_c(op); break;
        case pHL:                        w.ld_a(a).alu_l(op); break;
        case pConstRef8: if(lastHL==-1) { w.ld_hl(b).ld_a(a).alu_HL(op); break; } // 10+7+7=24
                                          w.ld_a_ref(b).ld_d_a().ld_a(a).alu_d(op); break; // 13+5+7+7=32
        case pConstStrRefRef8:  useHL(); w.ld_hl_ref(b).ld_a(a).alu_HL(op); break;
        case pHLRef8:                    w.ld_a(a).alu_HL(op); break;
        case pBCRef8:                    w.ld_a_BC().ld_d_a().ld_a(a).alu_d(op); break; // это 7+5+7+4=23, против ld_hl_bc().ld_a(a).alu_HL(op), которым еще нужен HL
        default: cmd_alu_raise(ap, bp);
      }
      break;
    case pConstRef8:
      switch(bp) {
        case pA:                          w.ld_d_a().ld_a_ref(a).alu_d(op); break;
        case pB:                          w.ld_a_ref(a).alu_b(op); break;
        case pC:                          w.ld_a_ref(a).alu_c(op); break;
        case pHL:                        w.ld_a_ref(a).alu_l(op); break;
        case pConst:                      w.ld_a_ref(a).alu(op, b); break;
        case pConstRef8: if(lastHL==-1) { w.ld_hl(b).ld_a_ref(a).alu_HL(op); break; } // 10+13+7=30
                                          w.ld_a_ref(b).ld_d_a().ld_a_ref(a).alu_d(op); break; // 13+5+13+4=35
        case pConstStrRefRef8:  useHL(); w.ld_hl_ref(b).ld_a_ref(a).alu_HL(op); break; // 16+13+7=36
        case pHLRef8:                    w.ld_a_ref(a).alu_HL(op); break;
        case pBCRef8:                    w.ld_a_BC().ld_d_a().ld_a_ref(a).alu_d(op); break;
        default: cmd_alu_raise(ap, bp);
      }
      break;
    case pConstStrRefRef8:
      switch(bp) {
        case  pA:              useHL(); w.ld_d_a()                        .ld_hl_ref(a).ld_a_HL().alu_d(op); break;
        case  pB:              useHL(); w                                  .ld_hl_ref(a).ld_a_HL().alu_b(op); break;
        case  pC:              useHL(); w                                  .ld_hl_ref(a).ld_a_HL().alu_c(op); break;
        case  pHL:                      w.ld_d_l()                        .ld_hl_ref(a).ld_a_HL().alu_d(op); break;
        case  pConst:          useHL(); w                                  .ld_hl_ref(a).ld_a_HL().alu(op,b); break;
        case  pConstRef8:      useHL(); if(self) { w.ld_hl(a)    .ld_d_HL().ld_hl_ref(a).ld_a_HL().alu_d(op); break; } // 10+7+16+7+4 = 44
                                w.ld_hl_ref(a).ld_a_HL().ld_hl(b).alu_HL(op); break;                                    // 16+7+10+7  = 40
        case  pConstStrRefRef8: useHL(); if(self) { w.ld_hl_ref(a).ld_d_HL().ld_hl_ref(a).ld_a_HL().alu_d(op); break; } // 16+7+16+7+4 = 50
                                w.ld_hl_ref(a).ld_a_HL().ld_hl_ref(b).alu_HL(op); break;                                // 16+7+16+7  = 46
        case  pHLRef8:                  w.ld_d_HL()                        .ld_hl_ref(a).ld_a_HL().alu_d(op); break;
        case  pBCRef8:          useHL(); w.ld_a_BC().ld_d_a()              .ld_hl_ref(a).ld_a_HL().alu_d(op); break;
        default: cmd_alu_raise(ap, bp);
      }
      a.place = a.place==pConstStrRefRef8 ? pHLRef8 : pHLRef16; // Оптимизация
      lastHL = stack.size()-2;
      break;
    case pHLRef8: // Если self, то HL изменять нельзя
      switch(bp) {
        case pA:                        w.ld_d_a()              .ld_a_HL().alu_d(op); break;
        case pB:                        w                      .ld_a_HL().alu_b(op); break;
        case pC:                        w                      .ld_a_HL().alu_c(op); break;
        case pConst:                    w                      .ld_a_HL().alu(op,b); break;
        case pConstRef8:                w.ld_a_ref(b).ld_d_a()  .ld_a_HL(); break;
        case pConstStrRefRef8:if(self){ w.ex_hl_de().ld_hl_ref(b).ld_h_HL().ex_hl_de().ld_a_HL().alu_d(op); break; }
                                        w.ld_a_HL().ld_hl_ref(b).alu_HL(op); break;
        case pBCRef8:                  w.ld_a_BC().ld_d_a()    .ld_a_HL().alu_d(op); break;
        default: cmd_alu_raise(ap, bp);
      }
      break;
    case pBCRef8:
      switch(bp) {
        case pA:                        w.ld_d_a()              .ld_a_BC().alu_d(op);  break;
        case pB:                        w                      .ld_a_BC().alu_b(op);  break;
        case pC:                        w                      .ld_a_BC().alu_c(op);  break;
        case pHL:                      w                      .ld_a_BC().alu_l(op);  break;
        case pConst:                    w                      .ld_a_BC().alu(op,b);  break;
        case pConstRef8:if(lastHL==-1){ w.ld_hl(b)              .ld_a_BC().alu_HL(op); break; } // 10+7+7 = 24
                                        w.ld_a_ref(b).ld_d_a()  .ld_a_BC().alu_d(op);  break; // 13+5+7+4 = 29                           
        case pConstStrRefRef8: useHL(); w.ld_hl_ref(b)          .ld_a_BC().alu_HL(op); break;
.... Съедено сайтом ...
    default: cmd_alu_raise(ap, bp);
  }
  if(self) {
    switch(a.place) {
      case pConstStrRef8:
      case pConstRef8: w.ld_ref_a(a); break;
      case pHLRef8:    w.ld_HL_a();  break;
      case pBCRef8:    w.ld_BC_a();  break;
      default: cmd_alu_self_raise(a.place, bp);
    }
    asm_pop();
    if(flags) raise("flags!");
  } else {
    asm_pop();
    asm_pop();
    if(flags) stack.push_backr().place = pFlags;
        else popTmpA();
  }
}


predatoralpha 22nd September 2012 01:55

vinxru, тебе ещё все предстоит в очередной раз переделывать, когда будешь вести по каждой переменной её состояние, и в зависимости от этого код будет разный. Приблизительный пример.
Твой код, сейчас:
Code:

  ; 54 for(y=0; y<8; y++)
  ld c, 0
l64:
  ld a, c
  cp 8
  jp nc, l65
...

l66:
  ld a, c
  inc c
  jp l64
l65:

Тут есть два варианта - если условие по старту верное (как в этом коде), то такой код неоптимален, и лучше что-то типа:

Code:

  ; 54 for(y=0; y<8; y++)
  ld c, 0
l64:
...


  ld a, c
  inc c
  cp 7
  jp c, l64

а вот если условие неопределённое, то нужен такой код как есть.
Нужно на каждую переменную вести её последнее значение, на этапе компиляции анализировать условия (y<8 в данном случае). И в зависимости от этого анализа условия компилятор выбирает нужную ветку.

Ты молодец, много сделал, но тут ещё копать и копать. И боюсь, ещё не раз придётся всё переписать...

vinxru 22nd September 2012 04:18

Замена for(a;b;c) на a; do ... c; while(b); ? Я не думал об этом, так как это может сделать программист, но сделаем.

---------- Post added at 01:15 ---------- Previous post was at 01:10 ----------

Quote:

Originally Posted by predatoralpha (Post 541917)
И боюсь, ещё не раз придётся всё переписать...

Слово переписывтаь не совсем корректное. Я сейчас подключаю новые блоки поверх простых конструкций. Расширяем :)

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

---------- Post added at 01:31 ---------- Previous post was at 01:15 ----------

Quote:

Originally Posted by predatoralpha (Post 541917)
Нужно на каждую переменную вести её последнее значение, на этапе компиляции анализировать условия (y<8 в данном случае).

Это будет отдельный блок компилятора. Сначала программа сваливается в буфер. Я для этого удобный способ офомил: w.ld_hl_ref(b).ld_d_HL().ld_a_c();

А уже потом, несколько алгоритмов оптимизации будут сверху-вниз и снизу-верх обрабатывать программу.

---------- Post added at 03:18 ---------- Previous post was at 01:31 ----------

Добавил замену команды LD A на INC A, DEC A в зависимости от состояния A. Вам очень этого хотелось :) Еще добавлю CPL туда же и для всех регистров сделаю. Сделал нормальную поддержку операторов && || !

Надо еще расписать все варианты для 16-битной арифметики.

Code:

startGame:
  push bc
  ; 375 enemyCount    = 0;
  xor a
  ld (enemyCount), a
  ; 376 playerX        = SPRITE_WIDTH;
  ld a, 4
  ld (playerX), a
  ; 377 playerY        = SPRITE_HEIGHT;
  ;o a=4
  ld (playerY), a
  ; 378 gameOver      = 0;
  xor a
  ld (gameOver), a
  ; 379 fireSize      = 2;
  ld a, 2
  ld (fireSize), a
  ; 380 fireMax        = 2;
  ;o a=2
  ld (fireMax), a
  ; 381 bombCount      = 0;
  xor a
  ld (bombCount), a
  ; 382 prevFire      = 1;
  inc a ;o a=1
  ld (prevFire), a
  ; 383 gameOver      = 0;
  xor a
  ld (gameOver), a
  ; 385 memset(map1, 0xFF, MAP_WIDTH*MAP_HEIGHT);
  ld hl, map1
  ld (memset_dest), hl
  dec a ;o a=255
  ld (memset_v), a
  ld hl, 208
  call memset
  ; 386 memcpy(map, lvd, MAP_WIDTH*MAP_HEIGHT);
  ld hl, map
  ld (memcpy_dest), hl
  ld hl, lvd
  ld (memcpy_src), hl
  ld hl, 208
  call memcpy
  ; 387 memset(times, 0, MAP_WIDTH*MAP_HEIGHT);
  ld hl, times
  ld (memset_dest), hl
  xor a
  ld (memset_v), a
  ld hl, 208
  call memset
  ; 389 p = map;


ivagor 22nd September 2012 13:32

В op_shr надо CP A перенести после op_shr_2.
Возможно в memcpy и memset стоит сделать две ветки - одна для счетчика >255 (как сейчас), вторая для <=255?
Сделал оба пункта, printKeyb раскомментил - бомберман не сломался.
Процедуры/функции, которые никто не "трогает", наверно лучше не компилировать и не включать в .asm?

vinxru 22nd September 2012 16:51

Quote:

Originally Posted by ivagor (Post 541976)
В op_shr надо CP A перенести после op_shr_2.

Ага, я уже заметил.

Quote:

Originally Posted by ivagor (Post 541976)
Возможно в memcpy и memset стоит сделать две ветки - одна для счетчика >255 (как сейчас), вторая для <=255?

Ага. И наверное еще сделать копирование стековыми командами. Я такое недавно видел в исходниках CP/M BIOS-а Корвета. И вообще не редкость.

Quote:

Originally Posted by ivagor (Post 541976)
Сделал оба пункта, printKeyb раскомментил - бомберман не сломался.

printKeyb - это я сделал, что бы подсмотреть сканкоды клавиш.

Quote:

Originally Posted by ivagor (Post 541976)
Процедуры/функции, которые никто не "трогает", наверно лучше не компилировать и не включать в .asm?

Да, конечно. Я построю дерево вызовов и по этому дереву станет ясно, какая функция нужна, а какая нет. И по ней же я рассчитаю и размещу в общей памяти переменные функций, которые одновременно не вызываются.

Более того, надо продумать более грамотное подключение библиотек функций. Что бы не компилировать весь код. Что то типа:

uchar getch() = stdlib.c;
uchar setPixel(uchar x, uchar y, uchar c) = apogey/graph.c;

ivagor 22nd September 2012 17:51

1 Attachment(s)
Quote:

Originally Posted by vinxru (Post 542020)
И наверное еще сделать копирование стековыми командами.

Как вариант - Attachment 37493. Можно еще для size>=2 memset с push сделать, но не уверен, стоит ли. Со стеком надо аккуратно. Для машин с прерываниями надо (наверно на условной компиляции) di до и ei после поставить (или использовать пару типовых mem.h для машин с прерываниями/без).
В качестве оффтопа - сделал тупой немигающий вариант бомбера. Просто копирую (pop shld, почти 80000 тактов :o) из бэкбуффера в ВОЗУ, хотя на апогее надо конечно менять базовый адрес отрисовки и переключать адреса ВОЗУ.

Quote:

Originally Posted by vinxru (Post 542020)
printKeyb - это я сделал, что бы подсмотреть сканкоды клавиш.

Мне понравилось, как показывает printKeyb. Про него я упомянул в связи с тем, что в бомбере вроде только в этой процедуре используется shr.

ivagor 22nd September 2012 21:43

Восьмибитное умножение можно немного оптимизировать
Code:

; Умножение A на D, результат в HL. BC не трогаем
op_mul:
  ex hl, de
  ld l, 0
  ld e, a
  ld d, l
  ld a, 8
op_mul1:
  add hl, hl
  jp nc, op_mul2
    add hl, de
op_mul2:
  dec a
  jp nz, op_mul1
  ret

Если памяти не жалко, то еще быстрее
Code:

op_mul:
  ex hl, de
  ld l, 0
  ld e, a
  ld d, l
  DUP 7
  add hl, hl
  jp nc, $+4
  add hl, de
  EDUP
  add hl, hl
  ret nc
  add hl, de
  ret

Кажется такой или подобный вариант был в "Микропроцессорных средствах и системах", только номер не помню.

В прошлом посте я сначала случайно выложил mem.h без pop, потом исправился.

vinxru 24th September 2012 16:14

Начал писать оптимизатор.

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 не используются.

Error404 24th September 2012 16:25

Quote:

Originally Posted by vinxru (Post 542020)
Ага. И наверное еще сделать копирование стековыми командами. Я такое недавно видел в исходниках CP/M BIOS-а Корвета.

ни в коем случае! При выполенини таких процедур придется гасить прерывания, а это суксь. Нужна скорость - гоните процессор (а лучше поменять его на Z80).


Quote:

Originally Posted by vinxru (Post 542020)
Более того, надо продумать более грамотное подключение библиотек функций. Что бы не компилировать весь код. Что то типа:

uchar getch() = stdlib.c;
uchar setPixel(uchar x, uchar y, uchar c) = apogey/graph.c;

Надо делать обычные extern объявления (чтобы компилер мог только проверить синтаксис вызываемых внешних процедур), а связыванием должен заниматься линкер (компилеру знать про то, что где лежит, не надо): ассеблерный выхлоп компилятора будет помодульно компилироваться в объектник и далее линковаться либо включаться в библиотеки. Улилиты для этого уже есть: М80/L80/LIB80. :) Кстати, понимают оба типа мненмоник - и вменяемые, и от i8080. :)

---------- Post added at 15:25 ---------- Previous post was at 15:20 ----------

Quote:

Originally Posted by vinxru (Post 542345)
3) Для 16 битного сравнения и вычитания,

Будут ли 32-битные арифметические операции ?

vinxru 24th September 2012 16:41

Quote:

Originally Posted by Error404 (Post 542381)
Надо делать обычные extern объявления (чтобы компилер мог только проверить синтаксис вызываемых внешних процедур), а связыванием должен заниматься линкер (компилеру знать про то, что где лежит, не надо): ассеблерный выхлоп компилятора будет помодульно компилироваться в объектник и далее линковаться либо включаться в библиотеки. Улилиты для этого уже есть: М80/L80/LIB80. Кстати, понимают оба типа мненмоник - и вменяемые, и от i8080.

extern уже есть. Но вроде бы компилятор SJASM не позволяет создавать OBJ файлы.

А посоветуйте компилятор ассемблера для 8080, я бы сразу его прикрутил.

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

Quote:

Originally Posted by Error404 (Post 542381)
Будут ли 32-битные арифметические операции ?

Будут. Я большинство из них вынесу во внешние функции, только параметры будут передаваться как адреса.

Так же будут работать float, double, long double и т.д. Все операторы внешние.

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

Quote:

Originally Posted by Error404 (Post 542381)
ни в коем случае! При выполенини таких процедур придется гасить прерывания, а это суксь.

На РК-86 нет прерываний.

---------- Post added at 14:41 ---------- Previous post was at 14:36 ----------

Quote:

Originally Posted by vinxru (Post 542387)
Цитата:
Сообщение от Error404 Посмотреть сообщение
Надо делать обычные extern объявления (чтобы компилер мог только проверить синтаксис вызываемых внешних процедур), а связыванием должен заниматься линкер (компилеру знать про то, что где лежит, не надо): ассеблерный выхлоп компилятора будет помодульно компилироваться в объектник и далее линковаться либо включаться в библиотеки. Улилиты для этого уже есть: М80/L80/LIB80. Кстати, понимают оба типа мненмоник - и вменяемые, и от i8080.
extern уже есть. Но вроде бы компилятор SJASM не позволяет создавать OBJ файлы.

А посоветуйте компилятор ассемблера для 8080, я бы сразу его прикрутил.

При использовании OBJ файлов нельзя разместить аргументы функций в общей памяти. Нельзя рассчитать дерево вызовов и вывести предупреждения при возникновении рекурсии.

b2m 24th September 2012 17:01

Quote:

Originally Posted by vinxru (Post 542387)
А посоветуйте компилятор ассемблера для 8080, я бы сразу его прикрутил.

Есть, например, такой ассемблер TASM.
Могу ещё предложить консольный эмулятор CP/M для i8080, недавно тестировал в нём работу C80,M80,L80. Вроде всё работает.
Ещё я использовал FASM :) У него мощный препроцессор, я сделал файл с макросами, так он и i8080 компилировал, хотя и не поддерживает этот процессор.

Error404 24th September 2012 18:19

1 Attachment(s)
Quote:

Originally Posted by vinxru (Post 542387)
extern уже есть. Но вроде бы компилятор SJASM не позволяет создавать OBJ файлы.

А посоветуйте компилятор ассемблера для 8080, я бы сразу его прикрутил

Если для МС-ДОС, то я пользовался таким (во вложении - MA80/MLINK) - оно совместимо с олдскульным микрософтовским M80 по входному синтаксису асссемблера. Объектники между L80 и MLINK не совместимы, но это и не особенно нужно - главное что общая идеология раздельной компиляции.

Quote:

Originally Posted by vinxru (Post 542387)
На РК-86 нет прерываний.

Значит, по-хорошему - надо сделать 2 набора либ: со стековыми функциями (ни в одном компиляторе не видел таких реализаций, к примеру, memset, хотя не думаю что авторы не знали про такие способы заполнения памяти) и с обычными циклами. Все же универсальность куда полезнее съэкономленного такта.

Quote:

Originally Posted by vinxru (Post 542387)
При использовании OBJ файлов нельзя разместить аргументы функций в общей памяти. Нельзя рассчитать дерево вызовов и вывести предупреждения при возникновении рекурсии.

С чего это? Пременную в любом ассемблере можно как явно положить в память по абсолютному адресу при помощи EQU, так и отдать на откуп линкеру на этапе сборки. В обоих случаях в исходнике обращение к ней идет по символическому имени. Или общая память это нечто отличающееся от обычной оперативной? Не понимаю.

vinxru 24th September 2012 18:54

Quote:

Originally Posted by Error404 (Post 542423)
С чего это? Пременную в любом ассемблере можно как явно положить в память по абсолютному адресу при помощи EQU, так и отдать на откуп линкеру на этапе сборки. В обоих случаях в исходнике обращение к ней идет по символическому имени. Или общая память это нечто отличающееся от обычной оперативной? Не понимаю.

Сейчас аргументы и переменные функций располагаются в общей памяти. И это не очень оптимально, так как одновременно memset и memcpy выполняться не могут. Логично разместить их аргументы и переменные в одной области памяти.

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

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 файлов каждый раз. Либо свой линкер.

vinxru 24th September 2012 19:30

1 Attachment(s)
выход компилятора для 8080 (просто текст программы, есть пара комяков. НАпример перепутал mvi m и shld)

Error404 24th September 2012 19:31

Quote:

Originally Posted by vinxru (Post 542427)
Сейчас аргументы и переменные функций располагаются в общей памяти. И это не очень оптимально, так как одновременно memset и memcpy выполняться не могут. Логично разместить их аргументы и переменные в одной области памяти.

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

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 файлов каждый раз. Либо свой линкер.

Я правильно понимаю - весь этот гемор оттого чтобы не передавать параметры стеком (который автоматически утилизирует память увеличением вершины стека после возврата из функции), но получить похожее удобство пользования?

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

vinxru 24th September 2012 21:39

Quote:

Originally Posted by Error404 (Post 542432)
Я правильно понимаю - весь этот гемор оттого чтобы не передавать параметры стеком (который автоматически утилизирует память увеличением вершины стека после возврата из функции), но получить похожее удобство пользования?

Ага

---------- 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

b2m 24th September 2012 23:14

Quote:

Originally Posted by vinxru (Post 542438)
Ух ты блин. Эмулятор b2m подхватил названия переменных из LST файла, который генерирует tasm

Дык для tasm и делал! :)

vinxru 25th September 2012 18:07

Сделал сумматор тактов всех команд программы. И замерял результат до работы оптимизатора и после. Пока получается оптимизация 90%. (стало/было*100)

Но в оптимизаторе нет самого главного. Он не умеет работать с ветвлениями и циклами. Сегодня добавлю их.

---------- Post added at 16:07 ---------- Previous post was at 14:12 ----------

Сделал, несколько команд пропало. Оценка 89%.

Красные - это поправки (удаления)

Code:

test:
  push b
  ; 4 c = 100;
  mvi b, 100
  ; 5 x = (uchar*)0xA000;
  lxi h, 40960
  shld test_x
  ; 6 do { *x = 0; ++x; } while(--c);
l0:
  ; 6 *x = 0; ++x; } while(--c);
  lhld test_x
  mvi m, 0
  ; 6 ++x; } while(--c);
  lhld test_x
  inx h
  shld test_x
  dcr b
  mov a, b
  ora a

  jnz l0
l1:
  pop b
  ret


vinxru 27th September 2012 23:18

Версии компилятора буду выкладывать на LJ, меня сейчас тут забанят.

begoon 10th October 2012 01:06

Quote:

Originally Posted by vinxru (Post 542387)
А посоветуйте компилятор ассемблера для 8080, я бы сразу его прикрутил.

Пока ничего удобнее http://john.ccac.rwth-aachen.de:8000/as/ не встречал. Продвинутая макро-поддержка, работает на Windows, Mac и Linux.

---------- Post added at 23:06 ---------- Previous post was at 21:23 ----------

Quote:

Originally Posted by vinxru (Post 543318)
Версии компилятора буду выкладывать на LJ, меня сейчас тут забанят.

А почему бы не создать проект на github/bitbucket/googlecode/etc?


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

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