Просмотр полной версии : Если бы у Медноногова был БК ?..
Oleg N. Cher
08.12.2021, 19:09
Очень сырой скрин процесса портирования :)
76618
Oleg N. Cher
16.12.2021, 07:21
Первый более или менее годный скриншот :) Ловите также бинарь. 76670
https://i2.piccy_.info/i9/e19f8cbe64a45cbec98f091e8177c5cd/1639628242/399838/1320134/DurakBK.png
К сожалению, для реализации всех фич оригинального Медноноговского "Дурака" на десятой Бэкашке недостаточно памяти. Постараюсь добавить то, что наиболее важно для передачи оригинального геймплея.
Полную версию можно будет позже выпустить для БК11(M) и УКНЦ.
К сожалению, для реализации всех фич оригинального Медноноговского "Дурака" на десятой Бэкашке недостаточно памяти.
А можно узнать, на что не хватает, и почему? Должно хватать, и даже с запасом.
А можно узнать, на что не хватает, и почему? Должно хватать, и даже с запасом.Паскаль съедает?
Oleg N. Cher
16.12.2021, 17:04
А можно узнать, на что не хватает, и почему? Должно хватать, и даже с запасом.Я думаю, не хватит на анимацию, мини-игры и музыку. Музыкой и заморачиваться не очень хочется. Я не спец по этому делу)
"Паскаль съедает"? Оригинальная игра весит под 40 Кб, в ней под 7 Кб графики. Понятно же, что "15 Кб Бэкашки хватит на всё" (почти Бил Гейтц)
- - - Добавлено - - -
В оригинальной игре также 2 Кб музыки, шрифт 768 байт и наверно килобайта 2-3 текстовых сообщений. А на Бэкашке графику надо растягивать (блок 8x8 становится 8x10). Иначе некрасиво получается.
ZX_NOVOSIB
16.12.2021, 17:04
Если б у Медного был БК, он бы спился от горя и скуки.
Oleg N. Cher
16.12.2021, 17:05
Кстати, ИИ тоже весит прилично, не один килобайт. Я думаю, тут даже переписывание на асм мало что даст. GCC для PDP-11 даёт очень недурной код, намного лучше, чем SDCC. Факт.
Oleg N. Cher
16.12.2021, 18:00
SDCC отличный компилятор, так что не надо. А ZSDCC с расширенным набором правил peephole-оптимизатора - ещё лучше.
Z80 просто не слишком оптимизирован для Си.
А что лучше SDCC? z88dk? Нет. Hitech C? Смешно.
Оригинальная игра весит под 40 Кб
так она на LaserBasic и сама программа скорее ~20Kb
Oleg N. Cher
16.12.2021, 18:02
Возможно. Если не считать ресурсов. Но ей же интерпретатор нужен с графической библиотекой. Так что ~20 Кб это некорректное число.
> SDCC отличный компилятор
Ничего отличного в нём нет.
> А что лучше SDCC? z88dk?
Оба мусор.
> Hitech C
Не знаю, этот не тестировал.
> Z80 просто не слишком оптимизирован для Си.
И это не отменяет того факта, что SDCC - мусор. Есть компилятор, которым можно пользоваться на Z80. Это IAR.
Oleg N. Cher
16.12.2021, 18:25
IAR закрытая платная устаревшая и мёртвая хрень. А по кодогенерации тоже не слишком важный компилятор. Он даже не умеет байтовые параметры на стек ложить. И по-уродски работает с индексными регистрами.
Знаете что грустно? Что вот есть люди с упоротым очень ценным мнением, которые просто где-то прочитали, что IAR лучший компилер. Но сами им не пользовались. А SDCC я пользуюсь уже лет 10, и он только хорошеет.
а зачем использовать Паскаль если на БК есть бейсик ?
> IAR закрытая платная устаревшая и мёртвая хрень
Всё, чем мы занимаемся, есть устаревшая и мёртвая хрень. Весьма глупо ожидать каких-то мощных оптимизаций новых продуктов под устаревшие и мёртвые платформы. Поэтому, есть то, что есть. Ничего лучше не будет.
> Он даже не умеет байтовые параметры на стек ложить.
Байтовые параметры на стек ложить не может сам Z80.
> И по-уродски работает с индексными регистрами.
Он нормально работает с индексными регистрами.
> Знаете что грустно? Что вот есть люди с упоротым очень ценным мнением
Да. Именно это и грустно.
> и он только хорошеет.
Он вообще не меняется. Там 0 прогресса. Как 10 лет назад генерил нерабочий уродский код, таким и остался.
Oleg N. Cher
16.12.2021, 19:39
3 причины не пользоваться IAR. Даже если закрыть глаза на то, что вам придётся хрензна откуда его скачивать и долго крякать.
1. Есть в IAR регистровые параметры? Нет. В SDCC есть. Кстати, появились за последние 10 лет.
2. Есть там разные модели вызова? Нет. В SDCC есть ещё три модели вызова, помимо родной __cdecl
3. IAR ложит два байтовых параметра в виде двух слов. SDCC в виде двух байтов.
Всё это весьма, знаете ли, важно, когда стыкуешь Си с ассемблером. Где важно экономить, особенно скорость, которая и так невелика.
Весьма глупо ожидать каких-то мощных оптимизаций новых продуктов под устаревшие и мёртвые платформы. Поэтому, есть то, что есть. Ничего лучше не будет.SDCC улучшают постоянно. Вы просто не следите. Ваше очень ценное мнение зафиксировано 10 лет назад и с тех пор не пересматривалось. Но это, согласитесь, Ваша проблема.
Байтовые параметры на стек ложить не может сам Z80.Одной командой не может, а двумя запросто.
PUSH AF
INC SP
Но главное: IAR ложит два байтовых параметра как два слова. Это уродски.
Да. Именно это и грустно.А я о чём. УМХО. Упоротое мнение хрен оспоришь.
Он вообще не меняется. Там 0 прогресса. Как 10 лет назад генерил нерабочий уродский код, таким и остался.Опять же, это ложь. Хотя я поглядел бы на человечка, который бы сам запилил оптимизирующий компилятор. Если бы сумел. Срать в душу легко, трудно качественно делать. Так-то.
Кстати, уверен, что Вы не сделали никакого вклада в развитие SDCC. Складывается впечатление, что весь Ваш вклад в развитие компайлеров Си свёлся к тому, что Вы просто спёрли IAR и собрали им три хелоуорлда.
- - - Добавлено - - -
а зачем использовать Паскаль если на БК есть бейсик ?1. Бейсик был не на всех БК, на некоторых был прошит Фокал.
2. Даже если делать на Бейсике и закрыть глаза на то, что на части БК работать не будет, всё равно не обойтись без кодовых вставок. Бейсик жрёт доп. память и снижает скорость работы программы.
3. Тогда как скомпилированный GCC машкод рулит на всю мощь. И я настолько стараюсь обойти несовместимости разных моделей БК, что не юзаю ПЗУ вообще.
Хватит причин?
Аргумент про авторское право, про кряки, про скачку с левых сайтов был бы весьма сильным, если бы это был другой сайт. Ребята, здесь весь сайт про нелегально выпускаемые компьютеры, про крякнутые игрушки и другое ПО к ним, про то, как их отреверсить и незаконно модифицировать. Если вы такой поборник морали. Ну, сколько игр для ZX-Spectrum у вас в коллекции и сколько из них вы купили за бабки? Вот после ответа на этот вопрос, продолжим дискуссию о том, насколько морально крякать мертвый компилятор. Либо шляпу снимите, либо штаны оденьте. Нет, я тоже против пиратства, но есть понятие abandonware. Есть дискуссия на эту тему.
Oleg N. Cher
16.12.2021, 20:52
Вы по сути ответьте. Что есть возразить по поводу тех фич, что есть в SDCC, но нету в IAR? Важных фич, я бы даже сказал, первостепенных для такой слабой платформы, как Z80. И втягивать в дискуссию про мораль меня не нужно. Речь не об этом.
> Код:
PUSH AF
INC SP
Вместе с автором SDCC, вы не знаете язык С. Так делать нельзя. Будет лажа при несовпадении разрядности аргументов функции и передаваемых параметров.
Oleg N. Cher
16.12.2021, 21:09
Так делать можно и нужно. Не сочтите за труд и дайте пример Вашему несвязному обвинению. Разрядность чего не совпадёт с разрядностью чего? А то: не знал к чему придраться, но придрался. Просто из вредности.
Никакого несовпадения разрядности не будет. На момент передачи параметров таким образом компилятор прекрасно знает список параметров и их разрядность.
- - - Добавлено - - -
Да, очень рад за Вас, что Вы прекрасно знаете Си. Поучите меня сирого, а то не знал к кому податься)
> Никакого несовпадения разрядности не будет. На момент передачи параметров таким образом компилятор прекрасно знает список параметров и их разрядность.
Может не знать. Тело функции может быть в совершенно другом модуле, скомпилированным даже не этим компилятором. Передача параметров через стек в С абсолютно стандартна и подобных фокусов не допускает. Более того, экономия одного байта на стеке весьма сомнительна относительно разрастанию кода и уменьшению быстродействия. Ни один компилятор так не делает.
Oleg N. Cher
16.12.2021, 21:45
Хых. Знаете ли, уважаемый, если Вы перепутаете количество и последовательность параметров, то у Вас любая программа на этом вылетит. Это не недостаток SDCC и уж точно не недостаток такого способа передачи.
Если придерживаться "стандартных" для PDP-11 способов вызова, то надо забыть про Z80 и про подходы для улучшения оптимальности. Напрочь. Но я понимаю, Вы выступаете в защиту сишного бардака. С этим я спорить не буду, бардака конечно хватает.
Дело, кстати, не в экономии байта на стеке. Дело больше в экономии кода и улучшении скорости при снятии параметров.
Сожалею, что Вас задел. Идите с миром.
IAR код в 2 раза более компактный генерирует
1854 j = c1 = c2 = c3 = c4 = c5 = c8 = 0;
\ 382B 010000 LD BC,0
\ 382E 69 LD L,C
\ 382F 60 LD H,B
\ 3830 221201 LD (?0010+274),HL
\ 3833 ED431401 LD (?0010+276),BC
\ 3837 220E01 LD (?0010+270),HL
\ 383A ED431001 LD (?0010+272),BC
\ 383E 220A01 LD (?0010+266),HL
\ 3841 ED430C01 LD (?0010+268),BC
\ 3845 220601 LD (?0010+262),HL
\ 3848 ED430801 LD (?0010+264),BC
\ 384C 220201 LD (?0010+258),HL
\ 384F ED430401 LD (?0010+260),BC
\ 3853 22FE00 LD (?0010+254),HL
\ 3856 ED430001 LD (?0010+256),BC
\ 385A 221A01 LD (?0010+282),HL
\ 385D ED431C01 LD (?0010+284),BC
\ 3861
// 54 байта
14528 ;bank2.c:1844: j = c1 = c2 = c3 = c4 = c5 = c8 = 0;
006160 AF [ 4]14529 xor a, a
006161 DD 77 CD [19]14530 ld -51 (ix), a
006164 DD 77 CE [19]14531 ld -50 (ix), a
006167 DD 77 CF [19]14532 ld -49 (ix), a
00616A DD 77 D0 [19]14533 ld -48 (ix), a
00616D AF [ 4]14534 xor a, a
00616E DD 77 D1 [19]14535 ld -47 (ix), a
006171 DD 77 D2 [19]14536 ld -46 (ix), a
006174 DD 77 D3 [19]14537 ld -45 (ix), a
006177 DD 77 D4 [19]14538 ld -44 (ix), a
00617A AF [ 4]14539 xor a, a
00617B DD 77 D5 [19]14540 ld -43 (ix), a
00617E DD 77 D6 [19]14541 ld -42 (ix), a
006181 DD 77 D7 [19]14542 ld -41 (ix), a
006184 DD 77 D8 [19]14543 ld -40 (ix), a
006187 AF [ 4]14544 xor a, a
006188 DD 77 D9 [19]14545 ld -39 (ix), a
00618B DD 77 DA [19]14546 ld -38 (ix), a
00618E DD 77 DB [19]14547 ld -37 (ix), a
006191 DD 77 DC [19]14548 ld -36 (ix), a
006194 AF [ 4]14549 xor a, a
006195 DD 77 DD [19]14550 ld -35 (ix), a
006198 DD 77 DE [19]14551 ld -34 (ix), a
00619B DD 77 DF [19]14552 ld -33 (ix), a
00619E DD 77 E0 [19]14553 ld -32 (ix), a
0061A1 AF [ 4]14554 xor a, a
0061A2 DD 77 E1 [19]14555 ld -31 (ix), a
0061A5 DD 77 E2 [19]14556 ld -30 (ix), a
0061A8 DD 77 E3 [19]14557 ld -29 (ix), a
0061AB DD 77 E4 [19]14558 ld -28 (ix), a
0061AE AF [ 4]14559 xor a, a
0061AF DD 77 E5 [19]14560 ld -27 (ix), a
0061B2 DD 77 E6 [19]14561 ld -26 (ix), a
0061B5 DD 77 E7 [19]14562 ld -25 (ix), a
0061B8 DD 77 E8 [19]14563 ld -24 (ix), a
14564 ;bank2.c:1845: do
0061BB
// 91 байт
Oleg N. Cher
16.12.2021, 22:53
Любите синтетические тесты, по которым Java превосходит Rust в стопицот раз? Угомонитесь уже.
Кстати, я именно это называл уродской работой с индексными регистрами.
- - - Добавлено - - -
; ---------------------------------
; Function _Abc
; ---------------------------------
_Abc:
ld hl,0x0000
ld (_c8),hl
ld (_c5),hl
ld (_c4),hl
ld (_c3),hl
ld hl,0x0000
ld (_c2),hl
ld (_c1),hl
ld (_j),hl
ret
SECTION code_compiler
; ---------------------------------
28 байт
Может тогдв сделать порт Laser Basic на БК, а потом уже перетаскивать дурака ? Их кстати было 2 версии, вторая от New Hakers Krowait System'94:
https://vtrd.in/release.php?r=d8d1faac5bf55bc24e376207559297e6
Oleg N. Cher
16.12.2021, 22:58
Это выхлоп ZSDCC с опциями -SO3 --opt-code-size --max-allocs-per-node100000
Код такой:
static int j, c1, c2, c3, c4, c5, c8;
static void Abc (void) {
j = c1 = c2 = c3 = c4 = c5 = c8 = 0;
}
- - - Добавлено - - -
По порядку:
Может тогдв сделать порт Laser Basic на БК, а потом уже перетаскивать дурака ?Такой порт несомненно бы был хорош и полезен. Но в полном объёме это не понадобится для Дурака. Буду заниматься этим посильно.
Их кстати было 2 версии, вторая от New Hakers Krowait System'94:Это просто хак под джойстик. И копирайты Славы выпилены. Я их сравнивал.
1. Есть в IAR регистровые параметры? Нет. В SDCC есть. Кстати, появились за последние 10 лет.
SDCC, вплоть до версии 4.1.0 не умеет "в стоке", без использования "соглашений" использовать регистровые параметры. только снапшот 4.1.12 этому научился. IAR это умеет 20 лет как без всяких соглашений. почитай мануал хоть к нему, чтоли. там всё расписано.
В SDCC есть ещё три модели вызова, помимо родной __cdecl
начиная с 4.1.12 он автоматом применяет новую модель вызовов и то, только к генерируемым функциям. функции в его родной либе всё ещё в старой модели. хоть 10 моделей пусть будет, это без толку, т.е. его родная либа это кошмар! банальный mul/div long для Z80 написан на СИ(!!!), какая уж там оптимизация?!
3. IAR ложит два байтовых параметра в виде двух слов. SDCC в виде двух байтов.
IAR, как и любой компилятор сей/паскалей для Z80 всегда делает PUSH RR, где RR какая то регистровая пара. НО, IAR, если параметры не динамические, сначала будет юзать регистры и только потом стек. опять таки - RTFM.
PUSH AF
INC SP
ОООЙ, это так важно, положить 1 байт на стек и и потратить потом ещё 6 тактов на inc sp. что за чушь?
SDCC улучшают постоянно. Вы просто не следите.
я могу с вами поспорить, что кодогенерация между 3.4.0 и 4.1.0 байт в байт одинаковая! так где изменения и улучшения?
но, во всём этом самое забавное то, что старый Solid C, написанный ещё в 1995 году для MSX и портированный под Спринтер в 2004 году, выдаёт код более компактный и быстрый, чем SDCC, хотя местами и есть у Солида затупы, но какой си без затупов то?!)))
а пресловутый пипхоле - чего там, чего? если посмотреть в его исходники, то становится очевидно, что вся оптимизация сводится к перебору шаблонов которые вкомпилированы. и можно задавать хоть 2000000 глубину этой пипки, результата не будет, а время компиляции растягивается на несколько минут.
я тут сижу над FatFS, переделки там кое какие, оптимизации. так вот, sdcc, Solid-C, IAR участвуют в этом. на текущий момент, SDCC даёт самый худший результат (и это на 4.1.12). даже Солид, у коиторого отродясь нет лонгов, путём вкарячивания "внешней" имитации умудряется обгонять SDCC. При этом, у SDCC весьма странная любовь к индексным регистрам, не смотря на попытку использовать static. А вот IAR и Solid весьма легко от индексных регистров отказываются.
который бы сам запилил оптимизирующий компилятор
оптимизатор может быть внешним, в виде отдельного ехешника. почти все существовавшие компиляторы (большая их часть) сей для z80 имели именно отдельные оптимизаторы. IAR, SDCC, Solid как раз те, в которых оптимизатор внутренний.
Любите синтетические тесты, по которым Java превосходит Rust в стопицот раз? Угомонитесь уже.
Кстати, я именно это называл уродской работой с индексными регистрами.
- - - Добавлено - - -
; ---------------------------------
; Function _Abc
; ---------------------------------
_Abc:
ld hl,0x0000
ld (_c8),hl
ld (_c5),hl
ld (_c4),hl
ld (_c3),hl
ld hl,0x0000
ld (_c2),hl
ld (_c1),hl
ld (_j),hl
ret
SECTION code_compiler
; ---------------------------------
28 байт
; 229. static void Abc (void)
Abc:
; 230. {
; 231. static int j, c1, c2, c3, c4, c5, c8;
; 232.
LD HL,0
LD (?0099),HL
LD (?0098),HL
LD (?0097),HL
LD (?0096),HL
LD (?0095),HL
LD (?0094),HL
LD (?0093),HL
; 233. j = c1 = c2 = c3 = c4 = c5 = c8 = 0;
RET
; 234. }
IAR 4.06a с опцией -z9, 25 байт.
> Кстати, я именно это называл уродской работой с индексными регистрами.
Кстати, я тоже это назвал бы уродской работой с индексными регистрами. Это - выхлоп SDCC, внезапно. IAR индексные регистры в каждую дырку не засовывает.
> Любите синтетические тесты, по которым Java превосходит Rust в стопицот раз?
Люблю синтетические тесты. Но что тут синтетического ? Не вижу тут ничего синтетического.
Я выбираю компиляторы для своей работы.
Вот полный тест с исходником и результатами компиляции (http://www.sanarin.ru/files/sdtcc-test/)
Как видите, SDCC нагенерировал 28582 байта кода, IAR - 16270 байт. Разница - 2 раза. Это абсолютно неприемлемо.
При этом, код SDCC - нерабочий. Разбирайтесь, вам с афтором работы на 50 лет. Этот фрагмент сверху - вырезка оттуда.
Кстати, написать оптимизирующиий компилятор для убогого 8-и битного процессора - вполне реально. Это не для VLIW писать, тут всё проще.
Не за год, конечно, не за 2. Но за 5-10 лет - вполне. Они так все и писались, собственно.
Автор SDCC трудится уже лет 20? Чем он занимается, и где результат - остаётся только догадываться.
IAR код в 2 раза более компактный генерирует
1854 j = c1 = c2 = c3 = c4 = c5 = c8 = 0;
\ 382B 010000 LD BC,0
\ 382E 69 LD L,C
\ 382F 60 LD H,B
\ 3830 221201 LD (?0010+274),HL
\ 3833 ED431401 LD (?0010+276),BC
\ 3837 220E01 LD (?0010+270),HL
\ 383A ED431001 LD (?0010+272),BC
\ 383E 220A01 LD (?0010+266),HL
\ 3841 ED430C01 LD (?0010+268),BC
\ 3845 220601 LD (?0010+262),HL
\ 3848 ED430801 LD (?0010+264),BC
\ 384C 220201 LD (?0010+258),HL
\ 384F ED430401 LD (?0010+260),BC
\ 3853 22FE00 LD (?0010+254),HL
\ 3856 ED430001 LD (?0010+256),BC
\ 385A 221A01 LD (?0010+282),HL
\ 385D ED431C01 LD (?0010+284),BC
\ 3861
// 54 байта
зачем тут 32 битные данные?
Oleg N. Cher
26.12.2021, 13:59
У меня нет никакого желания общаться с господами, засравшими мою тему по игрушке для БК своими обширными простынями с облизываниями IAR, уже не говоря про то, что облизывать IAR было бы несколько более уместно в более тематических разделах. Как можно доказать что-то людям, которые не понимают разницу между мёртвым закрытым и живым открытым компилятором? "Поместите Minix в свободный доступ, и одна из моих главных претензий к ней отпадёт" (c) Линус Торвальдс
И уже не говоря про то, что разрабатывать драйвер FAT для Z80 на Си это уродство. Моё мнение в этом не поменяется. Драйвер - критичная часть системы, он должен быть максимально компактным и работать максимально быстро. Идёте по шаткому пути била гейца, господа.
- - - Добавлено - - -
У меня практический вопрос к кодерам БК. Я разработал процедуры горизонтального циклического скроллинга прямоугольного окна влево на 4 и 8 пикселей. Теперь нужно сделать на 1 пиксель, надо юзать два битовых сдвига. Подскажите, плз, как это сделать наиболее оптимально? Может есть готовые какие-то подпрограммы?
void _Laser2_XYtoScr (int dummy, int r2, int r3,
int x, int y, int len, int hgt)
{ /* R0 - screen address */
asm("\
MOV %4, R0 // y \n\
MOV R0, R1 \n\
ASL R0 \n\
ASL R0 \n\
ADD R1, R0 \n\
SWAB R0 // * 640 \n\
ROR R0 \n\
ADD $041000, R0 \n\
ADD %3, R0 \n\
ADD %3, R0 // + 2*x \n\
MOVB %5, R2 // len \n\
MOVB %6, R3 // hgt \n"
::"g"(dummy), "g"(r2), "g"(r3),
"g"(x), "g"(y), "g"(len), "g"(hgt)
);
} // _Laser2_XYtoScr
void Laser2_WL4V (int x, int y, int len, int hgt)
{
asm("\
JSR PC, __Laser2_XYtoScr \n\
ASL R2 // 2*x \n\
MOV R4, -(SP) \n\
MOV R5, -(SP) \n\
OUTLN4: MOV R0, R1 \n\
MOV R2, R4 \n\
MOVB @R1, R5 \n\
OUTWR4: MOVB 1(R1), (R1)+ \n\
SOB R4, OUTWR4 \n\
MOVB R5, @R1 \n\
ADD $0100, R0 \n\
SOB R3, OUTLN4 \n\
MOV (SP)+, R5 \n\
MOV (SP)+, R4 \n"
:::"r2", "r3"
);
} // Laser2_WL4V
void Laser2_WL8V (int x, int y, int len, int hgt)
{
asm("\
JSR PC, __Laser2_XYtoScr \n\
MOV R4, -(SP) \n\
MOV R5, -(SP) \n\
OUTLN5: MOV R0, R1 \n\
MOV R2, R4 \n\
MOV @R1, R5 \n\
OUTWR5: MOV 2(R1), (R1)+ \n\
SOB R4, OUTWR5 \n\
MOV R5, @R1 \n\
ADD $0100, R0 \n\
SOB R3, OUTLN5 \n\
MOV (SP)+, R5 \n\
MOV (SP)+, R4 \n"
:::"r2", "r3"
);
} // Laser2_WL8V
Теперь нужно сделать на 1 пиксель, надо юзать два битовых сдвига. Подскажите, плз, как это сделать наиболее оптимально? Может есть готовые какие-то подпрограммы?Окно фиксированного размера или каждый раз разное? Универсальная процедура под любой размер окна будет тормознутей.
Oleg N. Cher
26.12.2021, 14:20
Окно заданного шириной len размера. Ширина в словах или в байтах, как удобнее.
Тут часть проблемы - перенос двух битов, его придётся делать через логические операции. Но если бы хотя бы не делать эту операцию для каждого байта/слова.
Может крутить строку пикселей на 1 бит, но два раза подряд? Не будут нехарактерные цвета проскакивать? (что теоретически возможно)
Откуда 640 взялось? У БК 512/256 пикселей ширина экрана. 64. (0100) байт.
Да, если сдвигать по одному биту прямо в экранной памяти, то возможно мерцание при попадании под луч. Надо по два. Это можно без дополнительной памяти, регистров хватает.
Oleg N. Cher
26.12.2021, 14:34
Откуда 640 взялось?y задаётся не в пикселях, а в "знакоместах" по типу Спековских, а высота "знакоместа" на Бэкашке - 10 точек, так что это просто 64*10.
Непринципиальный момент, вычисление координат работает же)
Регистров хватит для чего? А если в линии экрана, допустим, 20 слов (20*8 пикселей)?
Может крутить строку пикселей на 1 бит, но два раза подряд? Не будут нехарактерные цвета проскакивать? (что теоретически возможно)Я так и сделал. Может, и проскакивают лишние цвета, но только в одной строке при попадании под луч. Надо смотреть на конкретной картинке. На рандомных точках незаметно. В крайнем случае, можно делать это в буфере, а потом копировать сдвинутый результат.
Бинарник и исходник: 76745
W = 32. ; width in bytes
H = 28. ; height in rows
Addr = 60040-H*100-W/2
CALL DrawNoise
1: MOV #Addr,R0
CALL ScrollRight
MOV #Addr+4000,R0
CALL ScrollLeft
BR 1
HALT
; R0 - screen address
ScrollRight:
PUSH R1
MOV #H,R1
1: CLC
.Repeat W/2 ; scroll row
{
ROL (R0)+
}
ADC -W(R0)
SUB #W,R0
INC PC ; repeat twice
BR 1
ADD #100,R0 ; next row
SOB R1,1
POP R1
RET
; R0 - screen address
ScrollLeft:
PUSH R1
ADD #(H-1)*100,R0 ; right low corner
MOV #H,R1
1: ADD #W,R0
CLC
.Repeat W/2 ; scroll row
{
ROR -(R0)
}
BCC 2
BIS #100000,W-2(R0)
2: INC PC ; repeat twice
BR 1
SUB #100,R0 ; next row
SOB R1,1
POP R1
RET
DrawNoise:
MOV #Addr,R3
MOV #100000,R2
MOV #H,R1
1: MOV #W/2,R0
2: MOV (R2),4000(R3)
MOV (R2)+,(R3)+
SOB R0,2
ADD #100-W,R3
SOB R1,1
RET
Регистров хватит для чего? А если в линии экрана, допустим, 20 слов (20*8 пикселей)?
Длина строки как раз не важна. Идея в том, что два бита сдвигами запихиваем в два регистра, а на следующем слове их опять тасуем обратно. Примерно так:
mov @r1, r0
asr r4
ror r0
ror r4
asr r5
ror r0
ror r5
; мы провернули r0 на два бита и держим их в r4/r5
mov r0, (r1)+
mov @r1, r0
asl r4
ror r0 ; запихали запасённый бит, и взяли новый в флаг C
rol r5 ; сохранили C в r5 и выдали обратно сохранённый
ror r0
rol r4 ; почти та же петрушка со вторым битом
mov r0, (r1)+
; теперь r4/r5 поменялись чётностью, надо писать код с переставленными регистрами ...
Вот как-то так. Почти все команды -- регистровые, поэтому на БК это будет побыстрее, чем два (а то и три) раза память вращать да копировать.
Длина строки как раз не важна. Идея в том, что два бита сдвигами запихиваем в два регистра, а на следующем слове их опять тасуем обратно.
Почти все команды -- регистровые, поэтому на БК это будет побыстрее, чем два (а то и три) раза память вращать да копировать.А запили тест с теми же параметрами, что у меня. Сравним быстродействие. Что-то навскидку не кажется, что твой способ быстрей – слишком много обращений к памяти при чтении инструкций.
Oleg N. Cher
27.12.2021, 13:35
Спасибо за помощь. Не надо соревноваться в скорости. Оба способа хороши, каждый на своём месте. Я, скорее всего, возьму способ Manwe, просто потому, что при разработке для БК10 надо очень сильно экономить.
Спасибо за помощь. Не надо соревноваться в скорости. Оба способа хороши, каждый на своём месте. Я, скорее всего, возьму способ Manwe, просто потому, что при разработке для БК10 надо очень сильно экономить.Смотря что экономить. Вот этот код
.Repeat W/2 ; scroll row
{
ROL (R0)+
}
означает несколько инструкций ROL (R0)+ подряд. Столько, сколько ширина окна в словах.
Так что это не самый короткий код. Хотя, думаю, у него хорошее соотношение размер/скорость.
переименовать бы тему в "карточная игра" или как-то так
Oleg N. Cher
28.12.2021, 04:50
Вот этот код означает несколько инструкций ROL (R0)+ подряд. Столько, сколько ширина окна в словах.
Так что это не самый короткий код. Хотя, думаю, у него хорошее соотношение размер/скорость.Ну, я же всё равно сделаю этот ROL внутри цикла SOB, т.к. мне нужна возможность работать с произвольной шириной окна.
Ну, я же всё равно сделаю этот ROL внутри цикла SOB, т.к. мне нужна возможность работать с произвольной шириной окна.Ну смотри, в скорости потеряешь вдвое.
Для произвольной ширины я бы сделал иначе: перед последовательностью команд ROL поставить BR, чтобы он прыгал вперёд на нужное число слов, пропуская ненужные ROLы. Просто перед началом записываешь в младший байт по адресу команды BR число сколько ROLов надо пропустить. Самомодифицирующийся код.
Исходник и бинарник: 76771
; R0 - screen address
; R1 - width in words
; R2 - height in rows
ScrollRight:
MOVB #32.,RB ; default offset
SUB R1,RB
ASL R1 ; width in bytes
MOV R1,Of1+2
NEG Of1+2
R: CLC
RB: BR Of1
2: .Repeat 32.
{
ROL (R0)+ ; scroll row
}
Of1: ADC -32.(R0)
SUB R1,R0
INC PC ; repeat twice
BR R
ADD #100,R0 ; next row
SOB R2,R
RET
; R0 - screen address
; R1 - width in words
; R2 - height in rows
ScrollLeft:
MOVB #32.,LB ; default offset
SUB R1,LB
ASL R1 ; width in bytes
MOV R1,Of2-2
SUB #2,Of2-2
L: ADD R1,R0
CLC
LB: BR Of2:
2: .Repeat 32.
{
ROR -(R0) ; scroll row
}
BCC Of2
BIS #100000,-2(R0)
Of2: INC PC ; repeat twice
BR L
ADD #100,R0 ; next row
SOB R2,L
RET
записываешь в младший байт по адресу команды BR число сколько ROLов надо пропустить. Самомодифицирующийся код.
По аналогии со Спектрумом предложу еще один вариант, для БК он даже больше подойдет, как как PC такой же регистр, как и остальные:
ADD смещение,PC
как оно точно записывается в ассемблере PDP, вам лучше знать =) Зато избавимся от команд BR и команды модификации кода,
плюс при таком варианте длина прыжка не имеет ограничения, имеющегося для команды BR - можно хоть 500 команд перепрыгнуть.
По аналогии со Спектрумом предложу еще один вариант, для БК он даже больше подойдет, как как PC такой же регистр, как и остальные:
ADD смещение,PC
как оно точно записывается в ассемблере PDP, вам лучше знать =) Зато избавимся от команд BR и команды модификации кода,
плюс при таком варианте длина прыжка не имеет ограничения, имеющегося для команды BR - можно хоть 500 команд перепрыгнуть.К сожалению, по аналогии со Спектрумом не получится, потому что у него инструкции 8-битные, а тут 16-битные. То есть не получится прибавлять нечётные числа – они в середину команды будут указывать.
Хотя... Я же там потом ширину умножаю на 2. Надо попробовать!
Update: попробовал. Пришлось задействовать ещё один регистр. Команда ADD работает чуть дольше, чем BRanch. Размер процедуры не сократился. Так что лучше оставить с BR. Всё-таки для PDP-11 самомодифицирующийся код – часто наилучшее решение.
Размер процедуры не сократился
По идее, должен сократиться, сейчас сижу сочиняю процедуру)) хотя тут двоякая задача: максимальная скорость и размер не сильно раздувать.
И еще пара вопросов, все же PDP не моя стихия. Как понимаю, переход для SOB ограничен 128-ю байтами назад?
То бишь нас спасает только то, что работаем словами - 64 команды сдвига не влезли бы в переход. Не в конкретно данном примере, а вообще, где понадобятся 64 двухбайтовых команды.
И второе: объясните фокус с однократным повтором кода через INC PC. Каким образом это первый раз срабатывает, а на втором проходе нет.
с однократным повтором кода через INC PC
Скорей, CALL (PC)
Скорей, CALL (PC)
неа, именно inc PC и только на процах, которые допускают чтение слов по нечётным адресам. Это совсем другая фича и работает по-другому.
объясните фокус с однократным повтором кода через INC PC
Когда выполняется первый раз команда INC PC, то счётчик команд становится нечётным, но при этом всё равно выполняется команда, следующая за INC PC, т.к. по нечётному адресу всё равно читаются слова, которые читались бы и по чётному. А вот при втором выполнении, нечётный PC становится чётным, при этом значение счётчика команд становится +2 к значению счётчика команд после выполнения INC PC и следующая команда за INC PC пропускается и выполнение программы идёт дальше. Немного сумбурно, но всё это легко пронаблюдать в любом отладчике даже на самой БКшке. У этого метода один минус - нельзя использовать относительную адресацию для байтового доступа к памяти внутри участка, который повторно выполняется с нечётным счётчиком команд.
Oleg N. Cher
28.12.2021, 14:21
Как понимаю, переход для SOB ограничен 128-ю байтами назад?Не совсем так. Поскольку адреса команд могут быть только чётные, то в байте хранится смещение, которое потом удваивается процессором, т.е. переход возможен до 256 байт назад и 254 вперёд. Если я конечно правильно понял логику проца PDP-11.
- - - Добавлено - - -
Кстати, команда SOB не портит флаги?
т.е. переход возможен до 256 байт назад и 254 вперёд
Для SOB - нет.
По идее, должен сократиться, сейчас сижу сочиняю процедуру))Я проверил, тот же размер получается.
; R0 - screen address
; R1 - width in bytes
; R2 - height in rows
ScrollRight:
MOV #64.,R3 ; default offset
SUB R1,R3
MOV R1,Of1+2
NEG Of1+2
R: CLC
ADD R3,PC
2: .Repeat 32.
{
ROL (R0)+ ; scroll row
}
Of1: ADC -32.(R0)
SUB R1,R0
INC PC ; repeat twice
BR R
ADD #100,R0 ; next row
SOB R2,R
RET
- - - Добавлено - - -
Как понимаю, переход для SOB ограничен 128-ю байтами назад?
Кстати, команда SOB не портит флаги?Не портит.
Переход возможен на 255 слов назад
Переход возможен на 255 слов назад
Согласно последним постановлениям ВЦСПС - нет
при этом всё равно выполняется команда, следующая за INC PC
Мудрено =) Догадывался о такой механике, но стоило прояснить для себя. А на регистр SP это тоже распространяется или нет? Или он всегда изменяется на 2 командами INC/DEC?
Если же нет, то что происходит при работе с нечетным стеком? Трап, как и в остальных подобных ситуациях?
Если я конечно правильно понял логику проца PDP-11.
Не, у SOB переходы только назад, но вот описание команды не сходится с этим:
Переход возможен на 255 слов назад
А теперь смотрим описание команд процессора:
https://i.ibb.co/M58p3xj/SOB-jump.jpg (https://ibb.co/BK4jS57)
число nn - это 6 бит, 64 варианта. Значит, максимальное значение - минус 128. Поэтому максимум можно обработать 63 двухбайтовых команды (учитывая +2 байта к PC от SOB)
Значит, максимальное значение - минус 128
А учитывая, что PC у нас указывает на следующую ЗА SOB команду - реальный диапазон - -126 байт от текущей. Кроме того попытка сделать команду 077R00 (смещение 0) - даст ошибку как минимум при компиляции
реальный диапазон - -126 байт от текущей
Да, это и имел в виду, говоря "63 двухбайтовых команды". А вот переход с нулевым смещением на Спектруме работает нормально =) Т.е. JR $+2 или DJNZ $+2 у Z80 это "бесполезные" команды, в общем.
А теперь смотрим описание команд процессораа, про Rn я забыл :)
А на регистр SP это тоже распространяется или нет? Или он всегда изменяется на 2 командами INC/DEC?
Так же распространяется. INC/DEC меняет на единицу, а инкрементные/декрементные адресации - всегда на 2, независимо от того, словная или байтовая команда. Для PC это тоже так, см. например адресации 27, 37.
что происходит при работе с нечетным стеком?
На 1801ВМ1 всё работает как ни в чём не бывало, так же как и с чётным стеком. (имеется в виду, что производятся стандартные операции помещения в стек/извлечения из стека). Байтовая операция доступа к памяти с относительной адресацией, где индексируемый регистр - стек и его значение нечётно, даёт доступ к нечётному байту, т.е. MOVB (SP),R0, если SP=0775 выдаст в R0 содержимое байта из ячейки 0775
реальный диапазон - -126 байт от текущей
если текущей считается сама команда SOB, то даже 124., т.к. 77R01 - это переход команды на саму себя.
Кроме того попытка сделать команду 077R00 (смещение 0) - даст ошибку как минимум при компиляции
Однако выполнение этой команды на 1801ВМ1 равнозначно команде DEC R при этом флаги-признаки вообще не меняются, т.к. выполняется уменьшение на 1 содержимого регистра и, если он не равен 0, то переход по смещению 0 - на адрес, следующий за командой SOB, если равен 0, то прекращение ветвления и переход на адрес, следующий за командой SOB.
INC/DEC меняет на единицу, а инкрементные/декрементные адресации - всегда на 2
Хорошо, а команды типа CALL (JSR) и RET (RTI) будут корректно работать с нечетным стеком?
переход по смещению 0 - на адрес, следующий за командой SOB, если равен 0, то прекращение ветвления
А если поставить команду SOB PC,nn? Тут вопрос даже не в нулевом смещении, а в изменении PC самой командой.
Я проверил, тот же размер получается
Неа, у меня сократилось аж на 16 байт =) Правда, тоже задействовал один дополнительный регистр, зато ощутимый выигрыш по объему.
Заработало с первого раза без багов, хотя в асме БК я вообще нубас =) Настрочил в блокнотике, скомпилил - ура, работает.
В плане быстродействия где-то одинаково за счет того, что внутри цикла (основного) нет адресаций через память.
А если задействовать еще один регистр под хранение числа #100, то и перед SOB можно убрать выборку из памяти, а размер будет тот же.
Кстати, команда CLC не нужна, т.к. ADD reg,PC в любом случае обнулит флаг переноса.
76773
Вложил оба варианта: первоначальный от Manwe и свой. Внутри исходники + готовый код. Ниже под спойлером текст исходника, если кому лень загружать файл.
Скроллится кусочек вверху экрана, время около 18 сек, можно перезапустить командой S монитора. Удобно запускать прямо в эмуляторе.
Развернул команды скролла, т.к. компилер BKTurbo8 не понимает этой конструкции с копиями. Как в нем задать повтор куска кода?
.LA 1000
MOV #1000,R5
SCRL: MOV #40000,R0
MOV #30,R1
MOV #100,R2
CALL ScrollRight
SOB R5,SCRL
HALT
; R0 - screen address
; R1 - width in words
; R2 - height in rows
ScrollRight:
ASL R1
NEG R1
ADD #100,R1 ;R1=64-(width*2)
ROLL: MOV R0,R3 ;save scr addr
ROLL1: ADD R1,PC
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+
ROL (R0)+ ; scroll row
ROL (R0)+
ROL (R0)+
ROL (R0)+
MOV R3,R0 ; restore scr addr
ADC (R0) ; shift from last word to 1st
INC PC
BR ROLL1
ADD #100,R0
SOB R2,ROLL
RET
.END
да, CLC осталась от прошлого варианта без ADD, можно смело убирать
а команды типа CALL (JSR) и RET (RTI) будут корректно работать с нечетным стеком?
Разумеется, да. Я выше специально в скобках уточнил про стандартные операции помещения/извлечения - они подразумеваются словными. CALL (JSR) и RET (RTI) оперируют словами.
вот MOVB ss,-(SP) и MOVB (SP)+,dd если в одном случае стек чётный, а в другом - нет, уже будут обращаться к разным байтам и поместится в стек одно, а извлечётся другое.
А если поставить команду SOB PC,nn?
Давайте посмотрим. После того, как инструкция прочитается микроавтоматом для разбора и выполнения, PC будет указывать на ячейку за командой SOB. Затем начинается разбор и выполнение инструкции, PC уменьшается на 1, и начинает указывать на старший байт команды SOB, поскольку значение регистра не 0, то выполнится переход, но не на метку, а на старший байт предыдущего слова, т.е. фактически будет выполняться инструкция в слове перед меткой. Далее, снова доходим до команды SOB, но имеем в виду, что PC у нас нечётный (если где-то в теле цикла его не выравнивают по слову). PC снова уменьшается на 1, и становится чётным, и в данный момент станет указывать на слово за командой, т.е. получится нормальная ситуация. Снова будет переход, но уже точно по метке, и так бесконечно.
- - - Добавлено - - -
SOB PC,00 (опкод 077700) приведёт к тому, что эта команда выполнится дважды, а потом продолжится обычное выполнение программы
нужно сделать на 1 пиксель, надо юзать два битовых сдвига. Подскажите, плз, как это сделать наиболее оптимально? Может есть готовые какие-то подпрограммы?Кстати, в 256 байт:
https://content.pouet.net/files/screenshots/00087/00087557.gif (https://www.pouet.net/prod.php?which=87557)
Powered by vBulletin® Version 4.2.5 Copyright © 2026 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot