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

8-битный "компьютер мечты" (21 стр)

Страницы: 117 18 19 20 21 22 Следующая »
#300
21:51, 1 ноя. 2019

}:+()___ [Smile]
> Я, когда придумывал свой язык, «^» использовал для степени,
> а для xor задействовал бинарный оператор «~».
> Получилось аналогично «+» и «−»: +a = 0 + a, −a = 0 − a, ~a = 0 ~ a.
И у меня тоже был «~», так как волной инвертируются биты и визуально это более обосновано под XOR…
A вот «^» я задействовал под OR, так как визуально стрелка «^» поднимает биты…
Но потом всё-таки решил не изощряться и вернуться к Си-классике.


#301
23:18, 5 ноя. 2019

Уф... кажется победил виртуальный Z80 и таки запустил (мне так кажется) симуляцию. К сожалению Icarus Verilog не понимает vhdl, а нормальное ядро Z80 именно на нём сделано. Пришлось попутно осваивать запуск другого симулятора, с поддержкой смешанных (Verilog/VHDL) проектов

Изображение

теперь нужно сделать арбитраж между CPU/видеоконтроллером и  работу с внешней RAM'ой. Забавно, но без передёргивания сигнала RESET, на старте, виртуальный Z80 не запускается (а документацию, конечно же, я не читал)

#302
(Правка: 14:34) 14:33, 24 ноя. 2019

Проапгрейдил эмулятор/ассемблер для Simpleton и теперь виртуальная машина умеет выводить символы в консоль, а ассемблер поддерживает строки и множество данных в одном ключевом слове dw.
Программа теперь может выглядеть так:

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

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

                r0        = str2
                [ sp ]    =+2 pc
                pc        = 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 в программе условный.

#303
(Правка: 8:47) 8:22, 27 ноя. 2019

Добавил поддержку локальных меток - начинаются с точки и по факту разворачиваются внутри парсера в 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, во что развернуть проверку регистровой пары на достижение нуля, какие там есть двухбайтовые инструкции на которых можно сэкономить и т.п.

#304
(Правка: 13:34) 12:46, 27 ноя. 2019
Какой то революции человекочитаемого ассемблера не случилось.
С другой стороны мозг реально разгружен когда _пишешь_ на этом ассемблере по сравнению с классикой - не нужно как в Z80 на том же спектруме постоянно задумываться над тем как и куда перекинуть результаты из аккумулятора или HL, во что развернуть проверку регистровой пары на достижение нуля, какие там есть двухбайтовые инструкции на которых можно сэкономить и т.п.

Это отчасти происходит в силу "неоднородности-фрагментированности" синтаксиса через классическую форму  присваивания и работу с регистровой моделью.

P.S. Например, синтаксис Форт языка сглаживает такие моменты, но требует некоторого привыкания к его стилю программирования и некоторых накладных расходов по использованию стеков языка.
Интересно как решили проблему дизайна системного языка в проекте Gigatron компьютера.
Форт для данного компьютера тоже делают на форуме. :)
Factor язык, 8th ... - тоже интересны варианты дизайна.

Здесь вообще https://github.com/Anding/N.I.G.E.-Machine почти полный Форт компьютер сделан на FPGA плате. Видео: https://www.youtube.com/watch?v=PRltE8q62dA

Достал с полки плату с FPGA (такую как в видео выше) есть некоторый интерес детального изучения её программирования (на плате, правда, уже "древний" Spartan 3E - 500 :)
Прошивка заливается через драйвер использованного контроллера на популярной микросхеме CY7C68013A (достаточно интересный USB 2.0 контроллер на 51-м ядре - используется в народных логических анализаторах, с загрузкой при старте из внешней флэш памяти, кое как нашёл нужный драйвер для неё программы Adept старой версии от  Digilent)

#305
13:35, 27 ноя. 2019

Думаю когда нибудь на пенсии дойду до того чтобы реализовать и Simpleton на FPGA xD. К тому времени подкоплю для него софт из эмулятора и сразу заряжу пушку... :D

#306
22:01, 27 ноя. 2019

Мне тут ютуб в рекомендации подсунул...

https://www.youtube.com/user/eaterbc/videos

#307
22:53, 12 дек. 2019

Periwinkle: процессор с одной инструкцией
https://habr.com/ru/post/480024/

#308
4:54, 13 дек. 2019

KPG

Ооочень многословный и неоптимальный, имхо, при том еще что слово 32-битное и поэтому для хранения литералов команда 40-битная и это еще сверху добивается тем, что если перемещение из регистра-в-регистр, то подавляющая часть бит команды остаётся неиспользованной. К тому же такие вещи как сложение реализуются совсем сложно - в один и тот же регистр надо 2 раза записать операнды чтобы сработав порт ввода-вывода в двухкомпонентный буфер который запускает операцию над своим содержимым когда число элементов в нём станет 2 - это машина состояний внутри машины состояний...
Как говорится: не об этом я мечтал. :D

#309
(Правка: 17:46) 17:45, 13 дек. 2019

KPG
> процессор с одной инструкцией

Вроде бы, согласно викистатье это OISC с Transport triggered architecture. С другой стороны - фактически точно также можно считать, что в команде есть несколько битов кода команды, просто каждая команда жестко работает только с конкретным регистром. Типа избавились от декодера команд, но зато либо нафигачили упрощенные АЛУ в нескольких экземплярах, либо оставили такой же универсальный АЛУ, просто, как написали в комментарии, вместо нормального доступа к операциям сделали его через зад.

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

Цель непонятна. Ни фана, ни простоты. Уж тогда сделал бы Bit-manipulating machine, чтоб хоть фан был и еще большая аппаратная простота. Ну и до кучи реализовав это на одной однобитной микросхеме динамической памяти из 80-х :)

#310
(Правка: 18:51) 18:49, 13 дек. 2019

Dmitry_Milk
> Цель непонятна.

Человек просто изучал само понятие микропроцессоров и железной архитектуры. Просто фан на тот момент для себя самого.
Непонятно больше почему это стало предметом статьи в 2019-ом когда оно всё было придумано в 2016-ом.

А вообще реально "одноиструкторность" иногда путается с "одноформатностью".
Есть реально одноинструкторные эзотерические процессоры где по всем статьям только одна инструкция и звучит она по смыслу типа "вычесть ячейку А из Б и если получилось меньше нуля, то перейти на В, а иначе на Г". Полные по Тьюрингу. Ну собственно выше было уже.
Тот же мой Simpleton по сути своей не однокомандный, но одноформатный - есть только один формат инструкций, все битовые поля всегда парсятся декодером инструкций совершенно одинаково. Но это не означает что в его АЛУ одна только команда зашита - наоборот, тут богатый спектр. Просто формат инструкции всегда делает одно и то же инструкция за инструкцией - берет два операнда, пихает их в АЛУ и результат записывает во второй операнд. Единственная схема/формат работы.

#311
(Правка: 23:33) 23:32, 13 дек. 2019

=A=L=X=
> А вообще реально "одноиструкторность" иногда путается с "одноформатностью".
Просто потому, что между ними нету четкой границы.

Вот, команды add и sub — это разные?
А по факту это a + ((0 - imm) ^ b) + imm — одна команда с однобитным immediate и в железе выполняется так же.
#312
8:41, 14 дек. 2019

}:+()___ [Smile]
> Вот, команды add и sub — это разные?
> А по факту это a + ((0 - imm) ^ b) + imm — одна команда с однобитным immediate
> и в железе выполняется так же.

Конечно разные - имея на входе одинаковые аргументы они выдают разные результаты, а то что там _частично_ используется один и тот же блок двоичного сумматора вообще никакой роли не играет - повторное использование всегда хорошо и приветствуется.

#313
8:53, 14 дек. 2019

=A=L=X=
> Конечно разные - имея на входе одинаковые аргументы они выдают разные результаты
В этом случае любая команда с n-битным immediate — это 2^n разных команд.

#314
9:48, 14 дек. 2019

}:+()___ [Smile]
> В этом случае любая команда с n-битным immediate — это 2^n разных команд.
Во первых - а почему "в этом случае" то? При чём тут принцип разности команд на основании разности их результатов от одних и тех же аргументов?
Во вторых - ну это уже передёргивание. Мы всё-таки отделяем команду от её аргументов, хотя иногда разница может быть зыбкой, но выбор обычно нетруден.

Страницы: 117 18 19 20 21 22 Следующая »
ФлеймФорумЖелезо