+536.57
Рейтинг
1489.62
Сила
  • avatar aa-dav
  • 0
А есть на примете какие-нибудь русскоязычные руководства в том духе о котором я пишу — чтобы от установки Nesicide и по каждому аспекту отдельно и нудно проходилось? Просто чтобы не писать одно и то же, а как то изменить точку зрения по сравнению с существующими аналогами.
  • avatar aa-dav
  • 2
Начал сам знакомится с программированием на ассемблере через Nesicide уже пару вечеров и уже начало получаться и начала складываться картинка как оно вообще происходит, что за куски памяти и сегменты описываются в одном файле, судя по всему начинаю уже догадываться как их натягивать на мапперы и на экране символ уже инкрементируется в цикле, после GBA в принципе это уже конечно детали и тонкости.
И вот тут возникает вопрос — есть смысл писать на русском введение в программирование на NES по лекалам как я написал про GBA — от скачивания среды и через поэтапную реализацию всех нужных техник для создания игры или что-то такое уже есть? Есть ли на английском даже — и то вопрос?
  • avatar aa-dav
  • 0
наоборот — у процессов разные стеки и регистры, а вот память как программ так и глобальных данных общая, поэтому нельзя модифицировать код или полагаться в работе на перезаписываемые глобальные переменные.
  • avatar aa-dav
  • 0
я просто хочу протестировать наколенную реализацию вытесняющей многопоточности и для этого нужно выполнить требования выше — чтобы два потока могли исполнять один и тот же код синхронно. а всё что гуглится либо для скорости оптимизировано до нарушающих многопоточные принципы оптимизаций либо не гуглится вовсе.
  • avatar aa-dav
  • 0
P.S. пункт (г) не означает что режим записи должен быть входным параметром в алгоритм — можно добиваться этого просто модификацией кода или созданием трёх разных процедур. главное сама принципиальная возможность — почему это вообще важно, потому что уже упомянутый fast divide & conquer line часто пишет пиксель по два раза и поэтому на инвертированную линию без серьёзных модификаций просто не способен. тут важная сама принципиальная способность делать это точечными изменениями кода.
  • avatar aa-dav
  • 0
Господа, тут такое оживлённое было обусждение сверхбыстрого алгоритма рисования линии, что осмелюсь тут спросить: ни у кого не завалялся исходный код рисующий линию по брезенхему удовлетворяющий следующим условиям:
а) рисует линию от начала до конца (а не легко гуглящийся fast divide & conquer)
б) не использует глобальных переменных кроме констант типа предрассчитанных таблиц
в) на самом деле то же самое что и (б) — не использует самомодификацию кода
г) способен писать как 0 так и 1 так и инверсию
д) легко скопипастить в другую программу
Суперскорость не особо нужна, думал легко найду, но ни на русском ни на английском гугл как ни мучаю — ничего подходящего не вижу…
  • avatar aa-dav
  • 1
В статье упоминается, что Zilog сперва хотела продвигать другую архитектуру — дело в том, что в 1979 (всего через год после выхода в продажу Intel 8086) году фирма выпускает еще один процессор Z8000 уже несовместимый с Z80 с продвинутой 16–битной архитектурой: 16 регистров общего назначения, множество режимов адресации и до 8 Мб сегментированной памяти. Интересно, что когда IBM захотела покусится на нишу персональных компьютеров и создала IBM PC Z8000 уже был на рынке и гипотетически мог быть выбран в качестве сердца новой машины, но IBM выбрала процессор Intel и если верить википедии:
Федерико Фаджин, тогда исполнительный директор Zilog, считает, что причиной тому было то, что владельцем Zilog преимущественно был один инвестор — Exxon Enterprises, фирма которая имела амбиции конкурировать с IBM. Поэтому когда IBM начала проект PC она рассматривала Zilog как конкурента и выбрала Intel 8088, а не Z8000 потому что не видела в Intel конкурента на рынке компьютеров.
Позднее Z8000 обзаводится 32–битным наследником Z80000, но это уже не помогает — звезда Zilog на рынке персональных компьютеров закатилась окончательно и сейчас фирма занимается микроконтроллерами.
Интересно каким был бы современный мир домашних компьютеров если тогда давным давно IBM сделал бы выбор в пользу Z8000. :)
  • avatar aa-dav
  • 0
У меня у одного когда вижу логотип «Code Masters» в голове выстреливает «Ghost Busters»-ты-ды-ды-ды-дыдыдым?
  • avatar aa-dav
  • 0
Тогда еще добавка из последнего:
Добавил поддержку локальных меток — начинаются с точки и по факту разворачиваются внутри парсера в lastGlobalLabel.thisLocalLabel таким образом можно обратится к метке из любой точки программы по полному имени, но в пределах одной процедуры можно обращаться по короткому имени. При этом создание символов через = не засчитывается как глобальная метка после которой локальные будут соединятся с ней — только прямые объявления меток.
Добавил ключевое слово ds x [ y ] которое создаёт массив размером x слов заполненных значением y (если не указано — 0).
Для краткости и понятности вызова процедур ввёл 4 псевдоинструкции:

call arg
; эквивалентно следующему:
[ sp ] =+2 pc
pc = arg

ret
; эквивалентно
pc = [ sp ]

; а так же для быстрых вызовов:

qcall arg
; эквивалентно
r4 =+2 pc
pc = arg

qret
; эквивалентно
pc = r4

В силу того как парсером обрабатываются коды условий типа @nz @z — их можно присовокуплять к этим инструкциям точно так же как к обычным. Однако надо помнить, что если адрес процедуры есть не прямая метка (addr16), а содержимое регистра, то call (как и qcall) неприменима, т.к. первой инструкцией в ней должна быть [ sp ] =+1 pc, поэтому косвенные переходы по крайней мере пока надо расписывать полностью.
Так же PORT_CONSOLE теперь еще работает на ввод возвращая или 0 или символ последней нажатой клавиши (пока по сути обёртка над kbhit/getch без учёта какой то виртуальной архитектуры).
Так же еще кучу багов вымел как в виртуальной машине так и в ассемблере.
В общем теперь возможно написать такую программу:

PORT_CONSOLE    = $FFFF
    sp  = $FF00

    pc  = start

; string_input
; in: r0 - string buffer
;     r1 - max buffer size
; out: 
string_input  r3  = r0    ; remember beginning
.loop    r2  =? [ PORT_CONSOLE ]
    pc  = .loop @z
    r2  <?> 13
    pc  = .end @z  ; if CR
    r2  <?> 8
    pc  = .backsp @z  ; if BS
    r1  =? r1
    pc  = .overfl @z  ; if buffer overflow
    ; accept symbol
    [ PORT_CONSOLE ] = r2
    r1  =-1 r1
    [ r0 ]  = r2
    r0  =+1 r0
    pc  = .loop    ; continue input
    ; backspace
.backsp    r0  <?> r3
    pc  = .loop @z  ; ignore del at start of line
    [ PORT_CONSOLE ] = r2
    [ PORT_CONSOLE ] = 32  ; erase prev symbol at (windows) console...
    [ PORT_CONSOLE ] = r2
    r1  =+1 r1
    r0  =-1 r0
    pc  = .loop
    ; overflow
.overfl    pc  = .loop ; just continue
    ; end
.end    [ r0 ]  = 0
    ret

; string_print
; in: r0 - string buffer
string_print  r1  =? [ r0 ]
    ret @z
    r0  =+1 r0
    [ PORT_CONSOLE ] = r1
    pc  = string_print

; string_len  
; in:  r0 - string buffer
; out:  r0 - length of the string
string_len  r1  = 0
.loop    r2  = [ r0 ]
    pc  = .end @z
    r0  =+1 r0
    r1  =+1 r1
    pc  = .loop
.end    r0  = r1
    ret

start    
    r0  = msg1
    call  string_print
    r0  = buf
    r1  = 10
    call  string_input
    [ PORT_CONSOLE ] = 10

    r0  = msg2
    call   string_print
    r0  = buf
    call  string_print
    r0  = CrLf
    call  string_print

    dw  0
buf    ds  12 $AAAA
msg1    dw  "Enter command: " 0
msg2    dw  "You entered this text: " 0
CrLf    dw  13 10 0

Программа выведет приглашение ввести с клавиатуры текст в буфер ограниченный десятью символами и выведет потом введённый текст в консоль же.
В принципе это уже приближается к реальному машинописанию на реальном ассемблере, можно писать достаточно сложные программы и почувствовать отклик от них.

И ощущения от архитектуры двоякие.
С одной стороны сам ассемблерный код несмотря на сильно упрощенный синтаксис и крайнюю схожесть с человекочитаемыми операторами из сишечки всё равно выглядит как стена ассемблерного и плохосчитываемого кода. :D Какой то революции человекочитаемого ассемблера не случилось.
С другой стороны мозг реально разгружен когда _пишешь_ на этом ассемблере по сравнению с классикой — не нужно как в Z80 на том же спектруме постоянно задумываться над тем как и куда перекинуть результаты из аккумулятора или HL, во что развернуть проверку регистровой пары на достижение нуля, какие там есть двухбайтовые инструкции на которых можно сэкономить и т.п.

8<=============

А виртуальной машины пока еще нет чтобы эффектами меряться. Да и много чего нет — инструкции в АЛУ даже вводятся по мере того как появляются в них потребности. Это в свою очередь интересно тем, что как только видно что какая то инструкция часто нужна, то берешь и вводишь её — например move with flags update которая пишется в этом синтаксисе как =? и перемещает данное обновляя флаги S и Z обычно не встречается, но тут сразу попросилась разгружать циклы для asciiz-строк.
  • avatar aa-dav
  • 1
круто, у меня тоже был Кворум 64к и я даже уже знал про то что он совместим с CP/M за счёт дополнительных 16Кб ОЗУ и особых режимов памяти, но техническую информацию об этом так и не смог найти в своё время. спасибо за ссылку!
  • avatar aa-dav
  • 1
Сильно переработал код виртуальной машины и ассемблера — разделил собственно классы на Машину и Ассемблер и кроме того теперь виртуальная машина умеет выводить символы в консоль, а ассемблер поддерживает строки и множество данных в одном ключевом слове dw.
Программа теперь может выглядеть так:

PORT_CONSOLE    =         $FFFF   ; символ для порта ввода-вывода консоли
                sp        = $0050 ; настроим стек

                r0        = str1
                [ sp ]    =+2 pc  ; запоминаем в стеке pc для возврата
                pc        = print ; вместе с предыдущей инструкцией - CALL

                r0        = str2
                [ sp ]    =+2 pc
                pc        = print ; т.е. два раза вызвали процедуру print разных строк

exit            dw        0        ; STOP полный останов программы
        
                ; процедура print, на входе r0 - указатель на ASCIIZ-строку
print           r1        =? [ r0 ]    ; MOV с обновлением FLAGS (carry и zero)
                pc        = [ sp ] @z  ; если флаг нуля, то совершаем выход
                [ PORT_CONSOLE ] = r1  ; в порт консоли выводим очередной символ 
                r0        =+1 r0       ; увеличиваем указатель на строку
                pc = print             ; цикл на начало процедуры

                org $0050              ; начало данных для вывода
str1            dw "Hello, world!" 13 10 0
str2            dw "That's it." 13 10 0

и выводит она следующее (включая дамп памяти и регистров после выполнения):

Hello, world!
That's it.
R0:006C  R1:0000  R2:0000  R3:0000  R4:0000  SP:0050  PC:000C  FL:0001
0000:005E  0010:FFFF  0020:0000  0030:0000  0040:0000  0050:0048  0060:0054  0070:0000
0001:0050  0011:2000  0021:0000  0031:0000  0041:0000  0051:0065  0061:0068  0071:0000
0002:000E  0012:006E  0022:0000  0032:0000  0042:0000  0052:006C  0062:0061  0072:0000
0003:0050  0013:000D  0023:0000  0033:0000  0043:0000  0053:006C  0063:0074  0073:0000
0004:40D6  0014:0000  0024:0000  0034:0000  0044:0000  0054:006F  0064:0027  0074:0000
0005:006E  0015:0000  0025:0000  0035:0000  0045:0000  0055:002C  0065:0073  0075:0000
0006:000D  0016:0000  0026:0000  0036:0000  0046:0000  0056:0020  0066:0020  0076:0000
0007:000E  0017:0000  0027:0000  0037:0000  0047:0000  0057:0077  0067:0069  0077:0000
0008:0060  0018:0000  0028:0000  0038:0000  0048:0000  0058:006F  0068:0074  0078:0000
0009:40D6  0019:0000  0029:0000  0039:0000  0049:0000  0059:0072  0069:002E  0079:0000
000A:006E  001A:0000  002A:0000  003A:0000  004A:0000  005A:006C  006A:000D  007A:0000
000B:000D  001B:0000  002B:0000  003B:0000  004B:0000  005B:0064  006B:000A  007B:0000
000C:0000  001C:0000  002C:0000  003C:0000  004C:0000  005C:0021  006C:0000  007C:0000
000D:1018  001D:0000  002D:0000  003D:0000  004D:0000  005D:000D  006D:0000  007D:0000
000E:026D  001E:0000  002E:0000  003E:0000  004E:0000  005E:000A  006E:0000  007E:0000
000F:00F1  001F:0000  002F:0000  003F:0000  004F:000C  005F:0000  006F:0000  007F:0000

Единственный пока порт ввода-вывода замаплен на адрес $FFFF (и вообще все порты ввода-вывода будут замаплены на последние ячейки памяти) и при записи в себя выводит символ в консоль.
Ключевое слово dw теперь может принимать строки в кавычках и много данных в одной строке программмы — они даже не разделяются запятыми, а только пробельными символами, так парсер даже проще.
Заодно демонстрация того как CALL имитируется двумя инструкциями — сперва в стек пишется адрес возврата через инструкцию inc_by_two и уже потом совершается переход.
RET в программе условный.
  • avatar aa-dav
  • 1
Пытались неоднократно. К сожалению, потеря анонимности голосования обычно снижает кол-во голосующих в полтора-два раза
А почему собственно? Может те кто отсеивается отсеиваются как раз потому что желают быть необъективными?
Ну и тот же КВН вон меньше чем в 10 судей судят и норм.
  • avatar aa-dav
  • 2
По моему надо завязывать с анонимностью при голосовании. И даже если какое то внешнее голосование, то через фейсбучную учётку.
  • avatar aa-dav
  • 2
Даёшь неделю «making of...»! :D
  • avatar aa-dav
  • 0
«Среднее неадекватно, потому что при 20 голосующих одна единственная единица от недоброжелателя хоронит все шансы на победу.»

Не понимаю. Как?
  • avatar aa-dav
  • 1
«Извини, ничего личного, но сразу видно, что ты никогда не выставлялся на пати.»

Лично и не надо — я выше писал что не более года чем тут на ресурсе и демо на пати никогда не писал и авторитетом каким то подавляющим не являюсь.
Поэтому мне дваджы, трижы, десятикратно непонятно как можно не понимать что среднее арифметическое есть объективный показатель?
Приведи примеры, за что ты топишь? Почему считаешь адвекватным?
  • avatar aa-dav
  • 0
«при воздержании авторов.» => " при воздержании авторов от собственных работ"
!
Блин. Действительно круче всех работы могут оценить только сами демомейкеры и поэтому их точно нельзя отстранять. Это то что я выше говорил.
  • avatar aa-dav
  • 0
«как раз авторы стараются голосовать не предвзято»

Авторы хороши не только в создании работ, но именно еще и в их оценке — ведь они понимают что золото а что не очень лучше всех вокруг.
Поэтому тут да, замкнутый круг — и мне кажется лучшая стратегия: среднее при воздержании авторов.
Можно придумывать разные случаи. И видимо годами ранее всё это проходилось. Эх.
Имхо — среднее наиболее адекватно.
  • avatar aa-dav
  • 0
«Ну вот 10 человек сделают демо...»

Вообще если совсем уж пытаться добиться непредвзятости, то авторы вообще не должны иметь права принимать в голосовании. Вообще. Они не только потенциально могут в силу предвзятости поднимать свои работы, но могут и «топить» чужие опять же в силу той же изначальной очевидной предвзятости.
Но это по всей видимости в нашем случае не выход тоже.
В общем продолжаю считать что среднее — лучший вариант.
  • avatar aa-dav
  • 0
Я на этом ресурсе как раз не больше года. :)
Так или иначе мой пойнт изначально именно в том, что система среднего не имеет никаких подобных проблем — она позволяет правильно и не влияя на оценки воздерживаться и считает всё правильно. Чего же боле?