А есть на примете какие-нибудь русскоязычные руководства в том духе о котором я пишу — чтобы от установки Nesicide и по каждому аспекту отдельно и нудно проходилось? Просто чтобы не писать одно и то же, а как то изменить точку зрения по сравнению с существующими аналогами.
Начал сам знакомится с программированием на ассемблере через Nesicide уже пару вечеров и уже начало получаться и начала складываться картинка как оно вообще происходит, что за куски памяти и сегменты описываются в одном файле, судя по всему начинаю уже догадываться как их натягивать на мапперы и на экране символ уже инкрементируется в цикле, после GBA в принципе это уже конечно детали и тонкости.
И вот тут возникает вопрос — есть смысл писать на русском введение в программирование на NES по лекалам как я написал про GBA — от скачивания среды и через поэтапную реализацию всех нужных техник для создания игры или что-то такое уже есть? Есть ли на английском даже — и то вопрос?
наоборот — у процессов разные стеки и регистры, а вот память как программ так и глобальных данных общая, поэтому нельзя модифицировать код или полагаться в работе на перезаписываемые глобальные переменные.
я просто хочу протестировать наколенную реализацию вытесняющей многопоточности и для этого нужно выполнить требования выше — чтобы два потока могли исполнять один и тот же код синхронно. а всё что гуглится либо для скорости оптимизировано до нарушающих многопоточные принципы оптимизаций либо не гуглится вовсе.
P.S. пункт (г) не означает что режим записи должен быть входным параметром в алгоритм — можно добиваться этого просто модификацией кода или созданием трёх разных процедур. главное сама принципиальная возможность — почему это вообще важно, потому что уже упомянутый fast divide & conquer line часто пишет пиксель по два раза и поэтому на инвертированную линию без серьёзных модификаций просто не способен. тут важная сама принципиальная способность делать это точечными изменениями кода.
Господа, тут такое оживлённое было обусждение сверхбыстрого алгоритма рисования линии, что осмелюсь тут спросить: ни у кого не завалялся исходный код рисующий линию по брезенхему удовлетворяющий следующим условиям:
а) рисует линию от начала до конца (а не легко гуглящийся fast divide & conquer)
б) не использует глобальных переменных кроме констант типа предрассчитанных таблиц
в) на самом деле то же самое что и (б) — не использует самомодификацию кода
г) способен писать как 0 так и 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. :)
Тогда еще добавка из последнего:
Добавил поддержку локальных меток — начинаются с точки и по факту разворачиваются внутри парсера в 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-строк.
круто, у меня тоже был Кворум 64к и я даже уже знал про то что он совместим с CP/M за счёт дополнительных 16Кб ОЗУ и особых режимов памяти, но техническую информацию об этом так и не смог найти в своё время. спасибо за ссылку!
Сильно переработал код виртуальной машины и ассемблера — разделил собственно классы на Машину и Ассемблер и кроме того теперь виртуальная машина умеет выводить символы в консоль, а ассемблер поддерживает строки и множество данных в одном ключевом слове 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
и выводит она следующее (включая дамп памяти и регистров после выполнения):
Единственный пока порт ввода-вывода замаплен на адрес $FFFF (и вообще все порты ввода-вывода будут замаплены на последние ячейки памяти) и при записи в себя выводит символ в консоль.
Ключевое слово dw теперь может принимать строки в кавычках и много данных в одной строке программмы — они даже не разделяются запятыми, а только пробельными символами, так парсер даже проще.
Заодно демонстрация того как CALL имитируется двумя инструкциями — сперва в стек пишется адрес возврата через инструкцию inc_by_two и уже потом совершается переход.
RET в программе условный.
Пытались неоднократно. К сожалению, потеря анонимности голосования обычно снижает кол-во голосующих в полтора-два раза
А почему собственно? Может те кто отсеивается отсеиваются как раз потому что желают быть необъективными?
Ну и тот же КВН вон меньше чем в 10 судей судят и норм.
«Извини, ничего личного, но сразу видно, что ты никогда не выставлялся на пати.»
Лично и не надо — я выше писал что не более года чем тут на ресурсе и демо на пати никогда не писал и авторитетом каким то подавляющим не являюсь.
Поэтому мне дваджы, трижы, десятикратно непонятно как можно не понимать что среднее арифметическое есть объективный показатель?
Приведи примеры, за что ты топишь? Почему считаешь адвекватным?
«при воздержании авторов.» => " при воздержании авторов от собственных работ"
!
Блин. Действительно круче всех работы могут оценить только сами демомейкеры и поэтому их точно нельзя отстранять. Это то что я выше говорил.
«как раз авторы стараются голосовать не предвзято»
Авторы хороши не только в создании работ, но именно еще и в их оценке — ведь они понимают что золото а что не очень лучше всех вокруг.
Поэтому тут да, замкнутый круг — и мне кажется лучшая стратегия: среднее при воздержании авторов.
Можно придумывать разные случаи. И видимо годами ранее всё это проходилось. Эх.
Имхо — среднее наиболее адекватно.
Вообще если совсем уж пытаться добиться непредвзятости, то авторы вообще не должны иметь права принимать в голосовании. Вообще. Они не только потенциально могут в силу предвзятости поднимать свои работы, но могут и «топить» чужие опять же в силу той же изначальной очевидной предвзятости.
Но это по всей видимости в нашем случае не выход тоже.
В общем продолжаю считать что среднее — лучший вариант.
Я на этом ресурсе как раз не больше года. :)
Так или иначе мой пойнт изначально именно в том, что система среднего не имеет никаких подобных проблем — она позволяет правильно и не влияя на оценки воздерживаться и считает всё правильно. Чего же боле?
И вот тут возникает вопрос — есть смысл писать на русском введение в программирование на NES по лекалам как я написал про GBA — от скачивания среды и через поэтапную реализацию всех нужных техник для создания игры или что-то такое уже есть? Есть ли на английском даже — и то вопрос?
а) рисует линию от начала до конца (а не легко гуглящийся fast divide & conquer)
б) не использует глобальных переменных кроме констант типа предрассчитанных таблиц
в) на самом деле то же самое что и (б) — не использует самомодификацию кода
г) способен писать как 0 так и 1 так и инверсию
д) легко скопипастить в другую программу
Суперскорость не особо нужна, думал легко найду, но ни на русском ни на английском гугл как ни мучаю — ничего подходящего не вижу…
Позднее Z8000 обзаводится 32–битным наследником Z80000, но это уже не помогает — звезда Zilog на рынке персональных компьютеров закатилась окончательно и сейчас фирма занимается микроконтроллерами.
Интересно каким был бы современный мир домашних компьютеров если тогда давным давно IBM сделал бы выбор в пользу Z8000. :)
Добавил поддержку локальных меток — начинаются с точки и по факту разворачиваются внутри парсера в lastGlobalLabel.thisLocalLabel таким образом можно обратится к метке из любой точки программы по полному имени, но в пределах одной процедуры можно обращаться по короткому имени. При этом создание символов через = не засчитывается как глобальная метка после которой локальные будут соединятся с ней — только прямые объявления меток.
Добавил ключевое слово ds x [ y ] которое создаёт массив размером x слов заполненных значением y (если не указано — 0).
Для краткости и понятности вызова процедур ввёл 4 псевдоинструкции:
В силу того как парсером обрабатываются коды условий типа @nz @z — их можно присовокуплять к этим инструкциям точно так же как к обычным. Однако надо помнить, что если адрес процедуры есть не прямая метка (addr16), а содержимое регистра, то call (как и qcall) неприменима, т.к. первой инструкцией в ней должна быть [ sp ] =+1 pc, поэтому косвенные переходы по крайней мере пока надо расписывать полностью.
Так же PORT_CONSOLE теперь еще работает на ввод возвращая или 0 или символ последней нажатой клавиши (пока по сути обёртка над kbhit/getch без учёта какой то виртуальной архитектуры).
Так же еще кучу багов вымел как в виртуальной машине так и в ассемблере.
В общем теперь возможно написать такую программу:
Программа выведет приглашение ввести с клавиатуры текст в буфер ограниченный десятью символами и выведет потом введённый текст в консоль же.
В принципе это уже приближается к реальному машинописанию на реальном ассемблере, можно писать достаточно сложные программы и почувствовать отклик от них.
И ощущения от архитектуры двоякие.
С одной стороны сам ассемблерный код несмотря на сильно упрощенный синтаксис и крайнюю схожесть с человекочитаемыми операторами из сишечки всё равно выглядит как стена ассемблерного и плохосчитываемого кода. :D Какой то революции человекочитаемого ассемблера не случилось.
С другой стороны мозг реально разгружен когда _пишешь_ на этом ассемблере по сравнению с классикой — не нужно как в Z80 на том же спектруме постоянно задумываться над тем как и куда перекинуть результаты из аккумулятора или HL, во что развернуть проверку регистровой пары на достижение нуля, какие там есть двухбайтовые инструкции на которых можно сэкономить и т.п.
8<=============
А виртуальной машины пока еще нет чтобы эффектами меряться. Да и много чего нет — инструкции в АЛУ даже вводятся по мере того как появляются в них потребности. Это в свою очередь интересно тем, что как только видно что какая то инструкция часто нужна, то берешь и вводишь её — например move with flags update которая пишется в этом синтаксисе как =? и перемещает данное обновляя флаги S и Z обычно не встречается, но тут сразу попросилась разгружать циклы для asciiz-строк.
Программа теперь может выглядеть так:
и выводит она следующее (включая дамп памяти и регистров после выполнения):
Единственный пока порт ввода-вывода замаплен на адрес $FFFF (и вообще все порты ввода-вывода будут замаплены на последние ячейки памяти) и при записи в себя выводит символ в консоль.
Ключевое слово dw теперь может принимать строки в кавычках и много данных в одной строке программмы — они даже не разделяются запятыми, а только пробельными символами, так парсер даже проще.
Заодно демонстрация того как CALL имитируется двумя инструкциями — сперва в стек пишется адрес возврата через инструкцию inc_by_two и уже потом совершается переход.
RET в программе условный.
Ну и тот же КВН вон меньше чем в 10 судей судят и норм.
Не понимаю. Как?
Лично и не надо — я выше писал что не более года чем тут на ресурсе и демо на пати никогда не писал и авторитетом каким то подавляющим не являюсь.
Поэтому мне дваджы, трижы, десятикратно непонятно как можно не понимать что среднее арифметическое есть объективный показатель?
Приведи примеры, за что ты топишь? Почему считаешь адвекватным?
!
Блин. Действительно круче всех работы могут оценить только сами демомейкеры и поэтому их точно нельзя отстранять. Это то что я выше говорил.
Авторы хороши не только в создании работ, но именно еще и в их оценке — ведь они понимают что золото а что не очень лучше всех вокруг.
Поэтому тут да, замкнутый круг — и мне кажется лучшая стратегия: среднее при воздержании авторов.
Можно придумывать разные случаи. И видимо годами ранее всё это проходилось. Эх.
Имхо — среднее наиболее адекватно.
Вообще если совсем уж пытаться добиться непредвзятости, то авторы вообще не должны иметь права принимать в голосовании. Вообще. Они не только потенциально могут в силу предвзятости поднимать свои работы, но могут и «топить» чужие опять же в силу той же изначальной очевидной предвзятости.
Но это по всей видимости в нашем случае не выход тоже.
В общем продолжаю считать что среднее — лучший вариант.
Так или иначе мой пойнт изначально именно в том, что система среднего не имеет никаких подобных проблем — она позволяет правильно и не влияя на оценки воздерживаться и считает всё правильно. Чего же боле?