Флейм
GameDev.ru / Флейм / Форум / Меряемся придуманными машинными архитектурами (7 стр)

Меряемся придуманными машинными архитектурами (7 стр)

Страницы: 1 2 3 4 5 6 7
innuendoПостоялецwww26 мая 201814:19#90
Tonal
> ЗЫ:можно мерятся кто круче в столбик поделит на восьмибитке)

oooooooo, а можно просто DAA

TonalПостоялецwww26 мая 201816:08#91
innuendo
> oooooooo,
Да ладно, чт там страшного?) К тому же в примере деление длянных чисел 32:16, деление 8:8 выглядит значитель проще
;
R7 - DELIMOE
R3 - DELITEL
R0 - OSTATOK

FDIV8_8:mov     a,#8
divc: xch     a,R7
        rlc     a
        xch     a,R7
        xch     a,R1
        rlc     a
        clr     c
        subb    a,R3
        jnc     norez
        add     a,R3
norez:xch     a,R1
  cpl     c
        djnz    acc,divc
        xch     a,R7
        rlc     a
        xch     a,R7
        ret
innuendoПостоялецwww26 мая 201819:31#92
Tonal

я
не
спорю
что
можно
так
но DAA
по-моему
короче

=A=L=X=Постоялецwww26 мая 201819:40#93
CODE_L: ANL A, #0FH 
  ADD A, #90H 
  DA A 
  ADDC A, #40H 
  DA A
у меня аналогичный код на Z80 без DAA (т.е. на входе в аккумуляторе байт, на выходе - в нём же код 16-ричной цифры нижнего разряда в ASCII:
    and $0F
    cp $A
    jr nc, .alpha2
    add '0'
    jr .output2
.alpha2  add 'A'-$A
.output2  ...
Ну подлиннее, но ведь совсем чуть-чуть. Сказать чтобы DAA прямо зарулило до мурашек - я бы не сказал.
А вот с верхним разрядом - беда, из-за отсутствия аналога SWAP (выше по дискуссии) получается так:
    and $F0
    rrca
    rrca
    rrca
    rrca
    cp $A
    jr nc, .alpha1
    add '0'
    jr .output1
.alpha1    add 'A'-$A
.output1  ...
Вот эти 4 rrca портят малину, но дело тут не в DAA конечно.
=A=L=X=Постоялецwww26 мая 201819:50#94
А, его еще и короче на одну команду можно сделать и разницы не будет.
DexusУчастникwww26 мая 201822:02#95
Конвертация чисел в строку достаточно редкое действие (не только в плане необходимости, сколько в плане частоты вызовов), что заморачиваться на этом совершенно нерационально. И лучше бы это была операция деления (и она бы покрыла момент конвертации).

В своём муз.редакторе на zx я вообще делал конвертацию в строку путём последовательного вычитания 100 и 10, и не страдал из-за потери скорости. Вывод скорости адской не требует.

TonalПостоялецwww28 мая 20186:23#96
Мне тут костью в горле стало то что в диспплеях типа 1602 после отравки символа готовность к приему следующего наступает через ~1,5ms...
Естественно появилась идея выделить непосредственно работу с дисплеем в независимый поток, чтобы основная программа без ожиданий готовности скарливала пачку символов этому потоку.
А для упрощения кода все возможные задачи кодируются в один байт LCD_TASK
бит 7 - фоаг запроса на вывод
бит 6 - тип вывода(функция/текст)
бит 5 - резерв для меню
биты 0..4 номер функции/текста
Все строки текста упакованы в таблицу и адресуются короким номером(вместо полного адреса), функции это вывести время, какую либо отладочную информацию или определенный пункт меню.

Теперь:
- в произвольном месте программы по факту необходимисти вывести на экран одной командой формируется  байт LCD_TASK с встроенным флагом запроса на обработку
- в основном цикле программы каждые 25мс проверяется флаг запроса и управление передается функции вывода скармливающей без пачку символов потоку вывода в буфер FIFO без ожидания
- в основном цикле постоянно(один раз за цикл ~200мкс) проверяется готовность дисплея и при готовности отправляется очередной символ из FIFO.

Ожидание готовности диспелея не отбирает время у основной программы, ожидания как такового теперь вообще нет.
В основном цикле программы процессорор находится в состоянии пониженного энергопотребления Sleep, просыпается по прерыванию от таймера каждые 200мкс проверяет флаги/выполняет функции и опять переходит в Sleep

Правка: 28 мая 2018 7:03

0iStalkerМодераторwww3 июля 201814:44#97
Хм,... 8 команд и ни в чём себе не отказывай а нет, видео врёт, команд 16

https://gigatron.io/?page_id=482

Правка: 3 июля 2018 14:45

=A=L=X=Постоялецwww3 июля 201815:10#98
0iStalker
> а нет, видео врёт, команд 16

Мммм... это смотря в каком смысле рассматривать понятие команды.
Опкодов там, если я правильно считываю таблицу, 256 за вычетом одного невалидного бита.
В опкоде 3 бита отведено под код операции - то есть можно считать что концептуальных операций действительно всего 8 штук.
Но дальше операция уточняется тремя битами mode - в которых кодируется аргументы, адресация памяти или код условия перехода. А потом еще двумя битами какой то шины, вот тут сразу не могу понять о чём речь, потому что там один из вариантов - аккумулятор.
Поэтому в принципе нельзя сказать, что он какой то прямо ну дико аскетичный - вполне себе норм.

=A=L=X=Постоялецwww3 июля 201818:36#99
Блин, у этого гигатрона даже не расписаны толком как работают инструкции на сайте. Так и сказано - мол если хотите программировать на нём, то разбирайтесь в исходниках эмулятора и пишите ассемблер. xD
Исходник и правда небольшой, но блин, система команд немного запутанная. Немного разобрался в ней и решил описать что понял.

Единственный 16-битный регистр у процессора - счётчик инструкций (PC). Всё остальное восьмибитное - два регистра ввода-вывода IN и OUT, аккумулятор AC и два вспомогательных регистра X и Y, они чаще всего помогают формировать адрес.
Занятно, что регистр IN доступен только для чтения, а регистры X, Y и OUT - только для записи!
Архитектура гарвардская - программа располагается в отдельном банке ROM, причём банков этих два по 64Кб каждый - в одном содержатся 8-битные коды инструкций, а в другом 8-битные immediate данные к этим инструкциям. При каждом считывании кода инструкции из банка инструкций параллельно считывается данное из банка данных по тому же адресу и формирует значение еще одного регистра D.
RAM почему то всего 32Кб в отдельном банке.

Команды можно условно поделить на 4 больших группы - загрузка (LD), сохранение (ST), арифметика-логика (ADDA, SUBA, ANDA, ORA, XORA) и условные и безусловные переходы (JMP, BRA, BGT, BEQ, BGE, BLT, BNE, BLE).
Рассмотрим команду загрузки LD. В битовых полях кода инструкции mode и bus кодируются две вещи: в какой регистр будет производится запись загружаемого значения (AC, X, Y или OUT) и откуда будут браться данные для загрузки - D, AC, IN или память.
В синтаксисе ассемблера пишется "ld откуда,куда" - при этом если куда=AC, то этот параметр опускается.
например (в качестве непосредственного данного D использовано $01):

ld $01         ; AC  = D
ld $01,x       ; X   = D
ld ac,y        ; Y   = AC
ld in,out
Если загрузка производится из памяти, то возможны только следующие комбинации источников и приёмников:
ld [$01]       ; AC  = RAM[ D ]
ld [x]         ; AC  = RAM[ X ]
ld [y,$01]     ; AC  = RAM[ 256 * Y + D ]
ld [y,x]       ; AC  = RAM[ 256 * Y + X ]
ld [$01],x     ; X   = RAM[ D ]
ld [$01],y     ; Y   = RAM[ D ]
ld [$01],out   ; OUT = RAM[ D ]
ld [y,x++],out ; OUT = RAM[ 256 * Y + X++ ]
заметьте, что в последнем случае c пост-инкрементом X он не формирует неразрывного 16-битного адреса с Y, а "проворачивается" вокруг 256 байт, то есть процессор очень восьмибитный.

Арифметико-логические команды можно представить себе как LD который к данному для загрузки еще присовокупляет аккумулятор в заданной операции, в остальном режимы адресации, источники и приёмники данных - те же, так что можно даже LD воспринимать как "пустую" арифметико-логическую команду.
таким образом:

adda $01         ; AC  = AC + D
adda ac          ; AC  = AC + AC
adda ac,x        ; X   = AC + AC
adda [y,x++],out ; OUT = AC + RAM[ 256 * Y + X++ ]

Немного выбивается из общей схемы сохранение ST. Оно сохраняет в память только регистры D, AC или IN в адреса по вышеописанным вариантам RAM, но при этом при режиме адресации RAM[ D ] может еще параллельно скопировать AC содержимое в X или Y - такие вот странные какие то комбинации складываются в полях mode и bus. Зачем - не очень понятно.
Чаще всего синтаксис выглядит как "st что,куда", аккумулятор так же не пишется, но есть пара исключений.
Выглядит это так:

st [$01]         ; RAM[ D ] = AC
st $01,[$01]     ; RAM[ D ] = D
st in,[$01]      ; RAM[ D ] = IN
st [$01],x       ; RAM[ D ] = AC, X = AC
st [$01],y       ; RAM[ D ] = AC, Y = AC
st [y,x++]       ; RAM[ 256 * Y + X++ ] = AC
Обратите внимание, что вторая инструкция может записать только в адрес совпадающий с записываемым данным, так как D в инструкции только одно.
А в инструкциях с X и Y их наличие не означает того, что в них записывается первый аргумент, но лишь то, что параллельно сохранению в память AC он же еще копируется в X или Y.

С переходами тоже как то странно - границы страниц по 256 байт может пересекать только безусловный переход JMP при этом верхний байт адреса берется из Y, а нижний - на выбор из D, RAM[ D ], AC или IN. Условные же переходы могут только поменять нижний байт адреса PC на один из этих четырёх вариантов. Регистра флагов нет - все условия это те или иные сравнения аккумулятора с нулём или BRA (always). Но надо заметить, что при последовательном нарастании PC без переходов он пересекает границы страниц самостоятельно.

Та еще короче архитектурка, мдас...

Правка: 4 июля 2018 10:25

=A=L=X=Постоялецwww4 июля 20188:25#100
Почитал побольше у них на сайте что да как - презентацию посмотрел, не ну это лолище вообще.
Для тех кто плохо владеет инглишем что-то продублирую из видео 8-бит-гая:

Ну во первых Gigatron это минималистичный компьютер без микропроцессора, а реализованный на TTL-схемах. То есть процессор у него не реализован в одной микросхеме, а рассыпан по многим более простым микросхемам типа сумматоров и сдвигов по всей плате.
Минималистичность там серьёзно довлеет - так порт ввода только один 8-битный канал IN и вывода так же - один 8-битный канал OUT.
Хуже того - в системе отсутствует специализированный контроллер видео, поэтому видеовывод делается самим ЦП через порт OUT на VGA-разьём - в результате 8 бит этого порта определены как VSync, HSync и 3 RGB канала по 2 бита каждый - таким образом получается цветность в 64 RGB-оттенка (довольно грубых). Кроме того, чтобы пролезть по частотам и размерам видеопамяти картинка там имеет скромное разрешение 160x120 пикселей.
Так как процессор плотно занят на период генерации VGA-сигнала, то ему остаётся не так уж много времени чтобы обрабатывать программу - хуже того нужно выдерживать точные тайминги по обработке видеосигнала. И тут реально масса причудливых решений. xD
Во первых так как 120 строк по вертикали рендерятся выводом каждой строки 4 раза подряд, что даёт 480 строк VGA, то с одной стороны для "ретро-эффекта" вывод каждой четвертой строки можно подавить, тогда между сканлайнами появятся как бы телевизионные черные полоски - но это полдела - второе дело тут в том, что процессор в эти полоски как раз начинает дополнительно обрабатывать программный код и заметно ускоряется в своей работе.
Но для таких финтов нужно чётко контролировать исполняемые инструкции по тактам.
И делается это весьма комплексно и с фантазией.

Выше я описал нативный машинный код Гигатрона - он конечно трудится в сердцевине процесса. Это строго 8-битная RISC-машина гарвардской архитектуры, каждая инструкция имеет фиксированный размер в 1 байт инструкции и 1 байт immediate-данного (даже если оно не используется), исполняется любая инструкция за одно и то же время - вроде бы даже ровно за такт, при том что частота синхрогенератора 6,25 МГц. Инструкций сравнительно немного, даже, например, сдвиги делаются путём lookup-таблиц, всё остальное работает на ADD/SUB/AND/OR/XOR.
Ассемблер для нативного асма имеется, но основное ядро системы написано иначе - на python сделан генератор инструкций в следующем файле: https://github.com/kervinck/gigatron-rom/blob/master/Core/ROMv1.py
Если промотать чуть подальше, то видно как созидаются машинные инструкции (это программа на питоне):

# Simple RAM test and size check by writing to [1<<n] and see if [0] changes.
ld(1);                          C('RAM test and count')
label('.countMem0')
st([memSize], Y)
ld(255)
xora([Y,0])
st([Y,0])                       # Test if we can change and read back ok
st([0]) # Preserve (inverted) memory value in [0]
в результате в файле https://raw.githubusercontent.com/kervinck/gigatron-rom/master/ROMv1.asm генерируется асмолистинг в настоящем синтаксисе ассемблера:
              0003 0001  ld   $01         ;RAM test and count
.countMem0:   0004 d601  st   [$01],y
              0005 00ff  ld   $ff
              0006 6900  xora [y,$00]
              0007 ca00  st   [y,$00]
              0008 c200  st   [$00]
              0009 6900  xora [y,$00]
              000a ec0a  bne  $000a
              000b 00ff  ld   $ff
а в файле ROMv1.rom формируется бинарник к заливке на дейвас.
Теперь мы снова возвращаемся к вопросу - как выдерживать чёткие тайминги для VGA-вывода и в то же время выполнять программы. Делается это тем, что на Native Asm написано только корневое ядро системы - собственно код отсчитывающий тайминги, выводящий видеосигнал в VGA и... в перерывах интепретирующий виртуальный код 16-битного Virtual CPU (vCPU)!
vCPU обладает собственной системой команд, по моему похожей на семейство Motorola 6800, например вот так выглядит его код:
https://github.com/kervinck/gigatron-rom/blob/master/Contrib/at67… didemo64.vasm
                ; main loop 
erase           LDW     xPos
                DEEK
                ADDW    vbase
                STW     pixels
                LDI     0x00
                POKE    pixels
    
                CALL velocity
как видно уже есть стек, CALL и 16-битные команды.
Интерпретируя код на vCPU ядро способно как раз отслеживать сколько тактов потрачено на его выполнение и в нужные моменты прерываться на подпитку VGA.
Так же на vCPU написан какой то дикий язык высокого уровня - Gigatron Control Language (Gcl) и основная масса примеров и игр пользовательского софта написана уже на нём!
Синтаксис, имхо, какой то мозгоразрывающий гибрид лиспа с фортом:
https://github.com/kervinck/gigatron-rom/blob/master/Apps/Racer.gcl
[def { Wait -- Wait Delay number of frames (range 1..255) }
  \frameCount, Delay+ 255& tmp=
  [do \frameCount, tmp- if<>0loop]
  ret
] Wait=
Как я понял существует единый компилятор для нативного асма, vCpu и Gcl в одном - он там в исходниках лежит.

Тем не менее ядро генерируется (видимо исторически) программой на питоне которая генерирует код на нативном 8-битном машкоде, который интерпретирует виртуальный байткод 16-битного vCPU, который исполняет скомпилированные программы на языке высокого уровня GCL!

Изображение

Жгут, отстойщики, ай да жгут! xD

Правка: 4 июля 2018 8:27

TonalПостоялецwww4 июля 201813:28#101
=A=L=X=
красноглазненько)
TonalПостоялецwww4 июля 201813:55#102
В развитии темы из предыдущего сообщения я пошел еще дальше. Возникла необходимость сэкономить на размере FIFO буфера для потока вывода на дисплей - 32байта все таки жирновато будет...
Убеньшаем размер буфера до 4х байт, в результате натыкаемся на ту же проблемму, закинули в буфер 4 символа из 32 и надо ждать пока буффер освободится, а ждать нельзя!
Что делать? переделать основной цикл программы.
Main0:
  Call  Main1
  Jmp  Main0

Main1:
  Call  Proc0
  ...
  Call  ProcN
  Ret

ProcN:
  ...
  Call  Main1  ;!!!
  ...
  Ret

Теперь основной цикл стал процедурой и его можно вызывать из других процедур, в часности заполнив буфер вывода процедура вывода делает  Call  Main1, в Main1 выполняются как обычно все необходимые функции и постепенно опустошается буфер - по мере опустошения буфера управление возвращается в процедуру вывода, та подкидывает новые символы в буффер и процесс повторяется.
Этот же механизм теперь используется для задержек кратных времени пеиоду основного цикла -5мс, например при записи стринцы во Флэшь просто вызываем Main1, поле возрата управления мы знаем что прошло 5мс и можно писать следующкю страницу, и никто никого не ждет)
За кадром остался механихм семафоров регулирующий всю эту канитель и предотвращающий переполнение стека.

Правка: 4 июля 2018 14:11

EduardПостоялецwww11 июля 201820:27#103
Есть идея процессора с уменьшенной точностью арифметических вычислений. Любая арифметическая операция переводит операнд в аналоговую форму (ЦАП), операция производится, и сохраняется снова в цифровой форме (АЦП). Хотя эти преобразования займут время, зато выигрыш по скорости будет в сложных функциях. А время выполнения не будет зависеть от сложности операции.
Страницы: 1 2 3 4 5 6 7

/ Форум / Флейм / Железо

2001—2018 © GameDev.ru — Разработка игр