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

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

Страницы: 116 17 18 19 20 21
#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

Страницы: 116 17 18 19 20 21
ФлеймФорумЖелезо