Войти
ФлеймФорумЖелезо

А если ли у нас ностальгирующие по MOS 6502? (11 стр)

Страницы: 18 9 10 11 12 13 Следующая »
#150
11:42, 15 янв. 2018

Осмелюсь продолжить оффтоп про CGA Composite mode.
Посмотрите, какие чудеса творит в этом режиме Дэйвид Мюррей : https://youtu.be/szhv6fwx7GY?t=644


#151
10:48, 16 янв. 2018

ZeebaEata
> Посмотрите, какие чудеса творит в этом режиме Дэйвид Мюррей :
> https://youtu.be/szhv6fwx7GY?t=644

Ну почему чудеса - оно и предполагается что так должно работать же, 16 цветов при вдвое пониженном разрешении.

#152
11:34, 16 янв. 2018

=A=L=X=
Только абсолютное большинство игр в CGA режиме предпочитали разрешение экрана разрешению цветовому.

#153
11:55, 16 янв. 2018

Dexus
> предпочитали разрешение экрана разрешению цветовому

Выше видео про это было - никто ничего не предпочитал, а просто мониторы полностью перешли на RGB-сигнал и перестали понимать это тюльпановое подключение, которое эксплойтило наложение сигналов в тракте цветодекодирования NTSC.
Это был намеренный хак и эти вырвиглазные четыре цвета CGA-графики намеренно такие какие есть - чтобы в результате запаздывания в декодере цвета получились красивые чёткие цвета как на видео выше. Но работало это только по тюльпанам, которые просто отмерли и с ними отмерли правильные цвета CGA-графики.
Огромное количество программистов даже не понимало наверное что это за вырвиглазная жесть да и шансов не имели увидеть правильные цвета.

#154
6:50, 17 янв. 2018

В принципе вырвиглазная палитра CGA-графики по RGBI имеет право существовать на каких нибудь "высококонтрастных" интерфейсах станков ЧПУ и типа того - видимо поэтому его и реализовали.
Но если бы они хоть на минутку хотели бы чтобы в этом режиме рисовали игры они бы сделали или программируемую или более вменяемую встроенную палитру.

#155
5:18, 27 фев. 2018

Наткнулся тут на хладную историю как чуваки из CGA выжали графику на 1024 цвета в картинке: http://8088mph.blogspot.ru/2015/04/cga-in-1024-colors-new-mode-illustrated.html
Заодно там есть некоторые детали - что вообще происходит с этим цветоперемешиванием в режиме композитного NTSC.
Суть такова, что в цветном телевидении цветовая информация передавалась в заметно меньшем разрешении, чем яркостная - для экономии канала.
Так в NTSC получалось ровно 160 периодов выдачи цвета на строку, то есть 160 цветных пикселей по горизонтали.
Цветовая информация при этом как бы пробегала по кругу на каждом цикле:
Изображение
И вот подача в нужное время сигнала в цветовом канале приводила как я понял к накапливанию информации о цвете который потом и выводился.
Например включив черно-белое разрешение 640x200 и включив режим цветного NTSC (Color Burst Bit) получалось что группы по 4 пикселя укладывались ровно в один цветовой пиксель.
При этом их паттерн просто "попадал" в эту периодическую окружность в определенных точках порождая нужные цвета и их смешения.
Вот какая итоговая таблица паттернов получалась:
Изображение
Суть такова, что цветовой цикл пикселя начинается в круге с отметки "Burst" и далее начинают выстреливать по окружности наши выставленные биты.
Обратите внимание - первый цвет зеленый, потому что 0001 от отметки Burst единица попадает на зеленую часть как раз.
Далее 0010 попадает единицей в синюю часть круга - и так далее, а что главное - выстреливают так же и смешения.
В общем в тракте NTSC графическая информация так начинает превращаться в цветовую и абсолютно тем же самым трюком пользовался Стив Возняк в Apple II.

Прошло более 1 года
#156
(Правка: 12:04) 12:03, 1 мая 2019

Наткнулся тут на таблицу набора инструкций сабжа: https://www.masswerk.at/6502/6502_instruction_set.html
Не, это всё-таки даже в систематизированном табличном виде как то странно выглядит.
Стабильная система просматривается только в столбцах 01, 05, 09 и 0D - это базисные инструкции сохранения и загрузки аккумулятора LDA/STA и арифметико-логические команды ORA,AND,EOR,ADC,CMP и SBC представленные с разными режимами адресации второго аргумента. Единственное исключение тут проскакивает в инструкции с кодом $89 - как бы сохранение аккумулятора в immediate операнд, что, очевидно, невозможно.
Всё. Это единственная простыня из четырёх столбцов (то есть четверти всех возможных опкодов инструкций) занятая ровными и логично-систематичными рядами.
Но вот со всем остальным уже какая то лажа и нисистематичность.
Например инструкция LDX # "выстреливает" единственной в столбце 02 и больше в этом столбце инструкций нет вообще.
Ну и по остальным столбцам видна сильная нисистематичность.
Даже интересно что они там внутри навинтили такого, чтобы такая система команд была проста изнутри схемотехнически.

#157
13:40, 1 мая 2019

Я когда-то проверял на работоспособность эти незадействованные операции, кое-что ограниченно работало, например, там есть:

LDA X,ind
LDA ind,Y
Но я нашёл и
LDA ind, X
LDA Y, ind
Но они не видели старших двух или трёх бит индексного регистра. Но в диапазоне от 0 до 31 (или до 63, не помню), работали корректно.

#158
13:48, 1 мая 2019

=A=L=X=
> Даже интересно что они там внутри навинтили такого, чтобы такая система команд
> была проста изнутри схемотехнически.
Ну как бы известно в общем что при синтезе логических функций если тебя интересует не не все множество аргументов, а только некоторое подмножество то можно сэкономить на логических элементах

#159
16:15, 1 мая 2019

Mikle
> Но они не видели старших двух или трёх бит индексного регистра.

Это вообще выносит мозг. :)

Tonal
> можно сэкономить на логических элементах

Ну вот навскидку - как помогло сэкономить количество логических элементов то, что режим адресации "zpg,Y" возможен только в ровно двух командах во всём множестве - STX и LDX (с соответствующим режимом адресации)?
Как вообще программист должен об этом помнить?

#160
18:14, 1 мая 2019

=A=L=X=
> Ну вот навскидку - как помогло сэкономить количество логических элементов то,
> что режим адресации "zpg,Y" возможен только в ровно двух командах во всём
> множестве - STX и LDX (с соответствующим режимом адресации)?
это могло быть сделано как целенаправленно, так и просто побочным эффектом при минимизации, в обоих случаях очевидно преследовалась минимзация

> Как вообще программист должен об этом помнить?
это навряд ли было приоритетом

Прошло более 9 месяцев
#161
(Правка: 10:38) 10:34, 6 фев. 2020

=A=L=X=
> И вы знаете - всегда когда с ним сталкиваюсь меня вот пронзает ощущение
> глубокого сочувствия и сострадания к тем героям прошлых лет, которые на нём
> программировали
> Ужасно по моему всё. Он 8-битный настолько насколько это вообще возможно. Даже цикл длиннее 256 итерацией не делали.
(это из первопоста)

Забавно, сейчас уже несколько вечеров разбираясь с программированием для Famicom/NES/Денди на ассемблере я всё больше и больше проникаюсь философией процессора MOS 6502.
Несмотря на тотальную 8-битность и отсутствие 16-битных РОН в нём одни костыли оказываются подпёрты другими таким образом, что на практике действительно много задач 8-битного толка решаются не особо сложно.
Регистров общего назначения всего три - A, X и Y и все три исключительно 8-битные, при этом весь спектр арифметико-логических команд доступен только с A (аккумулятором), а вот X и Y служат как бы индексными регистрами и счётчиками.
Поэтому для X и Y доступны операции инкремента/декремента (а вот у аккумулятора - нет!), а так же сравнения. Это забавно, т.к. сравнение это и есть по сути вычитание без сохранения результата, только флаги выставляются как надо.
Так как регистров общего назначения такое вот скудное количество, то почти все операции которые требуют второго аргумента берут его из памяти в одном из многочисленных режимов адресации.
Очень важную роль в 6502 играют первые 256 байт памяти которые называются zero page и для которой доступна адресация всего одним байтом, в то время как для полной адресации оставшихся 64Кб нужен двухбайтовый адрес.
После старта Famicom состояние памяти неизвестно и желательно занулить zero page. Сделать это можно, например, таким кодом:

        lda # $00       ; a = 0
        ldx # $00       ; x = 0
loop1:  sta $00, x      ; [ $00 + x ] = a
        inx             ; x++
        bne loop1       ; if ( x != 0 ) goto loop1
Операции lda, ldx и ldy грузят байт в соответствующий регистр из памяти, а sta, stx и sty соответственно сохраняют. Что нетипично - команды загрузки обновляют флаги нуля и знака, так что с ними надо осторожнее в длинных цепочках условий. Если загружается непосредственное данное указанное в инструкции, то его надо обязательно предварять символом # иначе число будет воспринято лишь как адрес в памяти откуда грузить (и если оно уместится в 1 байт, то будет применена сокращённая однобайтовая форма загрузки из zero page). Таким образом мы сперва занулили регистры "a" и "x", а потом идём в цикле.
"sta $00, x" сохраняет "a" по адресу в zero page "указанное байтовое смещение + x" при этом адрес проворачивается вокруг нуля и никогда не выходит за пределы zero page.
(интересно, что единственные две команды где доступен такой же вариант адресации только с "y" в качестве индекса - это ldx и stx, а вот с "x" в качестве индекса в zero page доступны все основные инструкции)
Инструкции inx и iny инкрементируют "x" и "y" соответственно, а dex и dey их же декрементируют.
Здесь мы инкрементируем "x" и зацикливаемся в "branch if not equal" (т.е. флаг нуля не 1).
Это довольно простой цикл и 8-битный индекс конечно же полностью покрывает потребности зануления одной страницы. Но что если надо занулить больше памяти?

А тоже по ситуации и разумению. В Денди при старте желательно так же занулить память вне zero-page от $2000 до $7FFF.
Мой подход был следующий:

        lda # $00
        sta arg0w + 0           ; little-endian
        lda # $02
        sta arg0w + 1           ; [ arg0w ] = $0200 (слово в zero page)
        lda # $00               ; a = 0
        ldx # $08               ; рубеж
        ldy # $00               ; y = 0
loop2:  sta (arg0w), y          ; [ temp_addr + y ] = a
        iny                     ; y++
        bne loop2               ; if ( y != 0 ) goto loop2
        inc arg0w + 1           ; (high arg0w)++
        cpx arg0w + 1           ; if ( high arg0w != x )...
        bne loop2               ; ...goto loop2
В zero page выделено слово arg0w и мы в его младший (+0) и старший (+1) байты сохраняем начало куска памяти - $0200, а в x прописываем $08, ибо цикл должен остановится когда верхний байт этого итератора станет равным $08.
Здесь используется более хитрая и одна из двух максимально мощных косвенных индексаций в процессоре - за неимением 16-битных регистров он тупо не может индексировать память по полному косвенному адресу никак иначе кроме как через слово хранимое в двух байтах zero page!
И здесь используется форма sta (arg0w), y - т.е. из zero-page по однобайтовому адресу (метка arg0w) извлекается слово которое воспринимается как адрес к которому прибавляется байт y (без знака, но с нормальным преодолением границ страниц с +1 тактом на инструкцию за факт такового) и уже в полученный адрес сохраняется аккумулятор.
Здесь образуется внутренний цикл - y через iny и bne по той же схеме что и в коде выше пробегает 256 байт и очищает одну страницу, а вот по выходу из этого внутреннего цикла мы командой inc zero-page-addr инкрементируем старший байт нашего адреса - прямо в памяти - это тоже логичная команда - сразу инкрементирующая байт в памяти для этого процессора, ибо иначе было бы тяжело.
И вот сверяя эту ячейку памяти с порогом в $08 отложенным заранее в "x" мы и выходим из цикла.
Замысловато, но работает. И, признаться, не так уж и страшно. Манипулируя тем что очистку нужно сделать по границам страниц можно один костыль косвенной адресации подпереть другим костылём инкремента сразу ячейки памяти и сравнения её же с индексом - в общем действительно индексные регистры тут хоть и не знают произвольных арифметико-логических операций, но всё что нужно ввиду имеют.

Из любопытства залез в другой пример как зануляют эти же 2Кб без хвостика другие люди и заулыбался.
Код взят отсюда: https://github.com/bbbradsmith/NES-ca65-example/blob/master/example.s

        lda #0
        ldx #0
loop:
        sta $0000, x
        sta $0100, x
        sta $0200, x
        sta $0300, x
        sta $0400, x
        sta $0500, x
        sta $0600, x
        sta $0700, x
        inx
        bne loop
Ах тыж хитрая ты жопа, использовал двухбайтовую адресацию с индексацией по x! (кстати, в отличие от однобайтовой, двухбайтовая адресация с индексацией доступна и по "y" во всех командах во всей широте спектра как и по "x", и таких асимметрий в этом процессоре - вагон)
И тупо перечислил все страницы которые захотел занулить.
Ну вариант!

#162
12:13, 6 фев. 2020

=A=L=X=
> sta $0000, x
это типа
mov ($0000+x), a

#163
(Правка: 12:36) 12:34, 6 фев. 2020

Tonal
> это типа
> mov ($0000+x), a

Ну да, база двухбайтовый immediate, а индекс - однобайтовый без знака "x".
Т.к. первый аргумент инструкции всегда зашит в её код (lda, stx и т.п.), то всё что после мнемоники инструкции описывает некую адресацию.
Вторым аргументом регистр быть не может, к примеру, он тогда тоже просто в код инструкции зашивается, например tax - это transfer a to x.

#164
13:23, 6 фев. 2020

=A=L=X=
> таких асимметрий в этом процессоре - вагон
Это ещё что! Помню, экспериментально нашёл недокументированные инструкции, что-то типа "sty imm, x" и "stx imm, y", и они работали, но не при всех значениях imm, на сколько помню сейчас, воспринималось 5 бит в imm из 8-ми.
Инструкции нашёл не перебором, а анализируя биты в кодах имеющихся инструкций.

Страницы: 18 9 10 11 12 13 Следующая »
ФлеймФорумЖелезо