Информация об изменениях

Сообщение Re[4]: Золотое время АйТи от 29.12.2016 13:22

Изменено 29.12.2016 21:34 IID

Здравствуйте, vfedosov, Вы писали:

IID>>Z80 + 41кб памяти + 7кб экран (совершенно маразматической структуры с т.з. программиста) == Wolfenstein с играбельным FPS


V>Структура экрана была не так плоха: при такой структуре для того, чтобы перейти к следующей строке, с сохранением координаты x надо было прибавить к адресу 256 (в большинстве случаев) = инкремент старшего байта адреса, что для 8ми битового проца куда быстрее, чем добавлять 32 (размер строки).


Это, строго говоря, неправда. Т.к. переходить так можно только если младшие 3 бита координаты Y находятся в диапазое [000...110], в случае [111] необходима специальная обработка.

вот как выглядит переход на следующую Y координату в псевдокоде:

word IncY(word addr)
{
  if (((addr >> 8) & 0x03) < 7)
    return addr + 0x100;

  if (((addr + 0x20) & 0xFF) < 0x20)
    return addr + 0x100;

  return addr + 0x20 - 0x700;
}


На ассемблере:

; assume screen addr in DE register pair
PROC IncY
  inc d
  ld a, d
  and 7
  ret nz      ; в реальном коде процедура инланится и тут не возврат а переход jp nz
  ld a, e
  add a, 0x20
  ld e, a
  ret c       ; в реальном коде процедура инлайнится и тут не возврат а переход jp c
  ld a, d
  sub 8
  ld d, a
  ret         ; в реальном коде процедура инлайнится и тут внешний код


Скорость выполнения 25/50/65 тактов плюс всегда портится аккумулятор.

V>Это неплохо ускоряло работу со спрайтами, вывод символов.


Это ускоряло ТОЛЬКО вывод символов и ТОЛЬКО в Y позициях кратных 8.
Для спрайтов все делали табличку экранных адресов. И получали адрес нужной Y координаты лукапом в этой табличке. Переход вверх-вниз инкремент-декремент индекса. Табличка типичная для 16 битных адресоов в 8 битках: первые 256 байт это младшие байты, следующие 256 это старшие байты. Лукап змейкой, чтобы сэкономить на паре инкремента-декремента старшего байта. Итого стабильные 7 + 4 + 7 = 18 тактов на получение экранного адреса. Как вариант можно было ставить на табличку стек, и получать адрес за 10 тактов, но так не поступали, потому что выгоднее было стеком забирать данные спрайтов, ведь их больше.

V>Вроде бы и алгоритмы отрисовки линий тоже можно было сделать быстрее, правда тут не уверен.


Нет.
Re[4]: Золотое время АйТи
Здравствуйте, vfedosov, Вы писали:

IID>>Z80 + 41кб памяти + 7кб экран (совершенно маразматической структуры с т.з. программиста) == Wolfenstein с играбельным FPS


V>Структура экрана была не так плоха: при такой структуре для того, чтобы перейти к следующей строке, с сохранением координаты x надо было прибавить к адресу 256 (в большинстве случаев) = инкремент старшего байта адреса,


Это, строго говоря, неправда. Т.к. переходить так можно только если младшие 3 бита координаты Y находятся в диапазое [000...110], в случае [111] необходима специальная обработка.

V>что для 8ми битового проца куда быстрее, чем добавлять 32 (размер строки).


Это тоже неправда. Z-80 умеет в 16 битное сложение и у него достаточно регистровых пар чтобы сделать красивый иннер-луп вида
  rept N
  pop de : ld a, (hl): and e : or d : ld (hl), a : inc l
  endr
  pop de : ld a, (hl): and e : or d : ld (hl), a
  add hl, bc

  rept N
  pop de : ld a, (hl): and e : or d : ld (hl), a : dec l
  endr
  pop de : ld a, (hl): and e : or d : ld (hl), a
  add hl, bc


Добавить 32 к адресу это одно сложение регистровых пар == 11 тактов. Как видно ниже, это быстрее любых других вариантов. И не требует доп. памяти на таблицы.
Учитывая что типичное значение N это 2-3, а количество инкрементов Y порядка 24-32 то экономия получается существенной.

вот как выглядит переход на следующую Y координату в псевдокоде:

word IncY(word addr)
{
  if (((addr >> 8) & 0x03) < 7)
    return addr + 0x100;

  if (((addr + 0x20) & 0xFF) < 0x20)
    return addr + 0x100;

  return addr + 0x20 - 0x700;
}


На ассемблере:

; assume screen addr in DE register pair
PROC IncY
  inc d
  ld a, d
  and 7
  ret nz      ; в реальном коде процедура инланится и тут не возврат а переход jp nz
  ld a, e
  add a, 0x20
  ld e, a
  ret c       ; в реальном коде процедура инлайнится и тут не возврат а переход jp c
  ld a, d
  sub 8
  ld d, a
  ret         ; в реальном коде процедура инлайнится и тут внешний код


Скорость выполнения 25/50/65 тактов плюс всегда портится аккумулятор.

V>Это неплохо ускоряло работу со спрайтами, вывод символов.


Это ускоряло ТОЛЬКО вывод символов и ТОЛЬКО в Y позициях кратных 8.
Для спрайтов все делали табличку экранных адресов. И получали адрес нужной Y координаты лукапом в этой табличке. Переход вверх-вниз инкремент-декремент индекса. Табличка типичная для 16 битных адресоов в 8 битках: первые 256 байт это младшие байты, следующие 256 это старшие байты. Лукап змейкой, чтобы сэкономить на паре инкремента-декремента старшего байта. Итого стабильные 7 + 4 + 7 = 18 тактов на получение экранного адреса. Как вариант можно было ставить на табличку стек, и получать адрес за 10 тактов, но так не поступали, потому что выгоднее было стеком забирать данные спрайтов, ведь их больше.

V>Вроде бы и алгоритмы отрисовки линий тоже можно было сделать быстрее, правда тут не уверен.


Нет.