Автор |
Сообщение |
|
|
Заголовок сообщения: |
Re: Ну, очень смешной процессор... |
|
|
KPG писал(а): Интересно, что попробовав заход на местный сайт через плагин Websec Дотошно и пунктуально. Не знаю, хорошо это или плохо...
[quote="KPG"]Интересно, что попробовав заход на местный сайт через плагин Websec [/quote] Дотошно и пунктуально. Не знаю, хорошо это или плохо... :)
|
|
|
|
Добавлено: Пт дек 20, 2019 11:45 |
|
|
|
|
|
Заголовок сообщения: |
Re: Ну, очень смешной процессор... |
|
|
HishnikИнтересно, что попробовав заход на местный сайт через плагин Websec ( для браузера PaleeMoom на базе кода FireFox увмдел, что лобальные счётчики http://www4.clustrmaps.com/counter/maps ... nglion.ru/ - на главной странице форума- однозначно определили место захода на местный форум (со счётчиками от mail.ru не ясно какая ещё ситуация) P.S. Имеет ли смысл, при этом, сохранять на местном форуме эти и другие счётчмки посещений?
[b]Hishnik[/b] Интересно, что попробовав заход на местный сайт через плагин Websec ( для браузера PaleeMoom на базе кода FireFox увмдел, что лобальные счётчики http://www4.clustrmaps.com/counter/maps.php?url=http://fforum.winglion.ru/ - на главной странице форума- однозначно определили место захода на местный форум (со счётчиками от mail.ru не ясно какая ещё ситуация)
P.S. Имеет ли смысл, при этом, сохранять на местном форуме эти и другие счётчмки посещений?
|
|
|
|
Добавлено: Пт дек 20, 2019 03:13 |
|
|
|
|
|
Заголовок сообщения: |
Re: Ну, очень смешной процессор... |
|
|
Ой, прелесть какая. FPGA явно осталась от другого проекта - на таком монстре можно и 32-разрядные процессоры десятками объединять.
Ой, прелесть какая. FPGA явно осталась от другого проекта - на таком монстре можно и 32-разрядные процессоры десятками объединять.
|
|
|
|
Добавлено: Вт дек 17, 2019 01:16 |
|
|
|
|
|
Заголовок сообщения: |
Re: Ну, очень смешной процессор... |
|
|
Статья с Хабр. [url=https://habr.com/ru/post/480290/]Самодельный ноутбук ZedRipper на шестнадцати Z80[/url] (FPGA дизайн)
|
|
|
|
Добавлено: Пн дек 16, 2019 21:56 |
|
|
|
|
|
Заголовок сообщения: |
Re: Ну, очень смешной процессор... |
|
|
Ради интереса откомпилировал (последнюю версию) процессора в MAX-Plus II для EP1K30QC208-3
Результат: объем - 690LCELLs (40%), максимальная частота - 30MHz
Ради интереса откомпилировал (последнюю версию) процессора в MAX-Plus II для EP1K30QC208-3
Результат: объем - 690LCELLs (40%), максимальная частота - 30MHz
|
|
|
|
Добавлено: Вс окт 10, 2010 16:15 |
|
|
|
|
|
Заголовок сообщения: |
Re: Ну, очень смешной процессор... |
|
|
Quartus II не воспринимает com-файл как правильный для прошивки в ПЛИС. Ему нужно либо mif-файл (альтеровский формат), либо hex-файл (интеловский hex-формат). Не сильно раздумывая можно поступить двумя путями - 1. - Написать конвертор (или сразу целевой компилятор) на форте 2. - Использовать имеющийся конвертор форматов - bin2hex.exe Второе - явно проще и быстрее, поэтому именно этот способ и применен, так же как TASM для генерации бинарника. K TASM-у нужен еще и Link.exe. Таким образом, для первого эксперимента с процессором понадобятся следующие файлы: Tasm.exe - турбо-ассемблер Link.exe - линкер Exe2bin.exe - для преобразования получающегося exe-шника в bin-арник Bin2hex.exe - для преобразования bin-арника в hex-файл Чтобы не долго раздумывать, как это все связать, приведу здесь содержимое файла Work.bat : Код: rem @echo off echo ====================== echo TRANSCODE from *.ASM to *.HEX echo Writed by WingLion 2010 echo ====================== if '%1-' == '-' goto error c:\_asm\tasm %1.asm,%1,%1,%1 if exist %1.obj c:\_asm\link %1.obj,%1,%1,, if not exist %1.exe goto error if '%2-' == '-' goto label1 CALL c:\_asm\exe2bin %1.exe %2 GOTO LABEL2 :label1 CALL c:\_asm\exe2bin %1.exe %1.bin CALL Bin2hex.exe %1.bin :LABEL2 DEL %1.XRF DEL %1.EXE REM DEL %1.LST DEL %1.MAP DEL %1.OBJ EXIT :error echo ================ echo use: working.bat [filename] echo ( только имя без расширения 'asm') echo ================ quit
Инструкция (секретно, как всегда!): 1. Пишем исходник в test.asm, запускаем в командном режиме 2. work.bat test >list добавка '>list' - для разбора полетов, если понадобятся 3. любуемся на test.hex файл в любом текстовом редакторе 4. Подключаем test.hex в качестве содержимого для тестовой памяти к процессору в Quartus II 5. Запускаем компиляцию и симуляцию в Quartus-е 6. Любуемся на результат симуляции, если мало радости - шьем получившийся код в ПЛИС 7. Играем победный марш
Quartus II не воспринимает com-файл как правильный для прошивки в ПЛИС. Ему нужно либо mif-файл (альтеровский формат), либо hex-файл (интеловский hex-формат).
Не сильно раздумывая можно поступить двумя путями - 1. - Написать конвертор (или сразу целевой компилятор) на форте 2. - Использовать имеющийся конвертор форматов - bin2hex.exe
Второе - явно проще и быстрее, поэтому именно этот способ и применен, так же как TASM для генерации бинарника. K TASM-у нужен еще и Link.exe.
Таким образом, для первого эксперимента с процессором понадобятся следующие файлы:
Tasm.exe - турбо-ассемблер Link.exe - линкер Exe2bin.exe - для преобразования получающегося exe-шника в bin-арник Bin2hex.exe - для преобразования bin-арника в hex-файл
Чтобы не долго раздумывать, как это все связать, приведу здесь содержимое файла Work.bat :
[code]rem @echo off echo ====================== echo TRANSCODE from *.ASM to *.HEX echo Writed by WingLion 2010 echo ====================== if '%1-' == '-' goto error c:\_asm\tasm %1.asm,%1,%1,%1 if exist %1.obj c:\_asm\link %1.obj,%1,%1,, if not exist %1.exe goto error if '%2-' == '-' goto label1 CALL c:\_asm\exe2bin %1.exe %2 GOTO LABEL2 :label1 CALL c:\_asm\exe2bin %1.exe %1.bin CALL Bin2hex.exe %1.bin :LABEL2 DEL %1.XRF DEL %1.EXE REM DEL %1.LST DEL %1.MAP DEL %1.OBJ EXIT :error echo ================ echo use: working.bat [filename] echo ( только имя без расширения 'asm') echo ================ quit [/code]
Инструкция (секретно, как всегда!): 1. Пишем исходник в test.asm, запускаем в командном режиме 2. work.bat test >list добавка '>list' - для разбора полетов, если понадобятся 3. любуемся на test.hex файл в любом текстовом редакторе 4. Подключаем test.hex в качестве содержимого для тестовой памяти к процессору в Quartus II 5. Запускаем компиляцию и симуляцию в Quartus-е 6. Любуемся на результат симуляции, если мало радости - шьем получившийся код в ПЛИС 7. Играем победный марш
|
|
|
|
Добавлено: Вс окт 10, 2010 07:42 |
|
|
|
|
|
Заголовок сообщения: |
Re: Ну, очень смешной процессор... |
|
|
к очень смешному процессору подошел очень смешной старый-добрый TASM пишем в тестовый файл test.asm такой код Код: .386 .MODEL tiny .CODE
include ssCPU.asm ; макро-определения для форт-команд
org 100h
begin: fLIT 10h fLIT 20h PRISW fCALL program ; однако, это вызов адресного интерпретатора, а не подпрограммы NEXTA program ; повторный вызов той же программы NEXTA fcode ; закончить адресную интерпретацию и вернутся к исполнению кода fSTOP ; СТОЯТЬ! руки за голову и не дышать!
program: fLIT 100h fLIT 200h PRISW fNEXT ; программа заканчивается fcode: fRET
end begin
рядом к нему располагаем файл ssCPU.asm с таким содержимым: Код: ; макро-определения для форт-команд
f_NOP MACRO db 00h ENDM
fLIT MACRO data1 db 01h dw data1 ENDM
fCALL MACRO addr1 db 03h dw addr1-100h ENDM
fRET MACRO db 05h ENDM
fNEXT MACRO db 06h ENDM
RAZIM MACRO db 08h ENDM
PRISW MACRO db 0Bh ENDM
fBRANCH MACRO addr1 db 08h dw addr1-100h ENDM
fDUP MACRO db 11h ENDM
fDROP MACRO db 12h ENDM
fOVER MACRO db 13h ENDM
fSWAP MACRO db 14h ENDM
toR MACRO db 17h ENDM
fromR MACRO db 18h ENDM
fNAND MACRO db 19h ENDM
f_ADD MACRO db 1Ah ENDM
f2_ MACRO db 1Bh ENDM
fSTOP MACRO db 1Ch ENDM
; это команда компиляции адреса для адресной интерпретации NEXTA MACRO addr1 dw addr1-100h ENDM
В результате имеем следующий листинг генерации кода (лишние строки листинга скипнуты для ясности): Код: Turbo Assembler Version 3.1 09/10/10 23:26:56 Page 1 test.asm 91 org 100h 92 93 00000100 begin: 94 fLIT 10h 1 95 00000100 01 db 01h 1 96 00000101 0010 dw 10h 97 fLIT 20h 1 98 00000103 01 db 01h 1 99 00000104 0020 dw 20h 100 PRISW 1 101 00000106 0B db 0Bh 102 fCALL program ; однако, это вызов адресного интерпретатора, а не подпрограммы 1 103 00000107 03 db 03h 1 104 00000108 000Fr dw program-100h 105 NEXTA program ; повторный вызов той же программы 1 106 0000010A 000Fr dw program-100h 107 NEXTA fcode ; закончить адресную интерпретацию и вернутся к исполнению кода 1 108 0000010C 0017r dw fcode-100h 109 fSTOP ; СТОЯТЬ! руки за голову и не дышать! 1 110 0000010E 1C db 1Ch 111 112 0000010F program: 113 fLIT 100h 1 114 0000010F 01 db 01h 1 115 00000110 0100 dw 100h 116 fLIT 200h 1 117 00000112 01 db 01h 1 118 00000113 0200 dw 200h 119 PRISW 1 120 00000115 0B db 0Bh 121 fNEXT ; программа заканчивается 1 122 00000116 06 db 06h 123 00000117 fcode: 124 fRET 1 125 00000117 05 db 05h 126 127 end begin Получившийся после компиляции com-файл остается только прошить в ПЛИС вместе с процессором для проверки-проверки
к очень смешному процессору подошел очень смешной старый-добрый TASM ;)
пишем в тестовый файл test.asm такой код
[code]
.386 .MODEL tiny .CODE
include ssCPU.asm ; макро-определения для форт-команд
org 100h
begin: fLIT 10h fLIT 20h PRISW fCALL program ; однако, это вызов адресного интерпретатора, а не подпрограммы NEXTA program ; повторный вызов той же программы NEXTA fcode ; закончить адресную интерпретацию и вернутся к исполнению кода fSTOP ; СТОЯТЬ! руки за голову и не дышать!
program: fLIT 100h fLIT 200h PRISW fNEXT ; программа заканчивается fcode: fRET
end begin[/code]
рядом к нему располагаем файл ssCPU.asm с таким содержимым:
[code] ; макро-определения для форт-команд
f_NOP MACRO db 00h ENDM
fLIT MACRO data1 db 01h dw data1 ENDM
fCALL MACRO addr1 db 03h dw addr1-100h ENDM
fRET MACRO db 05h ENDM
fNEXT MACRO db 06h ENDM
RAZIM MACRO db 08h ENDM
PRISW MACRO db 0Bh ENDM
fBRANCH MACRO addr1 db 08h dw addr1-100h ENDM
fDUP MACRO db 11h ENDM
fDROP MACRO db 12h ENDM
fOVER MACRO db 13h ENDM
fSWAP MACRO db 14h ENDM
toR MACRO db 17h ENDM
fromR MACRO db 18h ENDM
fNAND MACRO db 19h ENDM
f_ADD MACRO db 1Ah ENDM
f2_ MACRO db 1Bh ENDM
fSTOP MACRO db 1Ch ENDM
; это команда компиляции адреса для адресной интерпретации NEXTA MACRO addr1 dw addr1-100h ENDM
[/code]
В результате имеем следующий листинг генерации кода (лишние строки листинга скипнуты для ясности):
[code] Turbo Assembler Version 3.1 09/10/10 23:26:56 Page 1 test.asm 91 org 100h 92 93 00000100 begin: 94 fLIT 10h 1 95 00000100 01 db 01h 1 96 00000101 0010 dw 10h 97 fLIT 20h 1 98 00000103 01 db 01h 1 99 00000104 0020 dw 20h 100 PRISW 1 101 00000106 0B db 0Bh 102 fCALL program ; однако, это вызов адресного интерпретатора, а не подпрограммы 1 103 00000107 03 db 03h 1 104 00000108 000Fr dw program-100h 105 NEXTA program ; повторный вызов той же программы 1 106 0000010A 000Fr dw program-100h 107 NEXTA fcode ; закончить адресную интерпретацию и вернутся к исполнению кода 1 108 0000010C 0017r dw fcode-100h 109 fSTOP ; СТОЯТЬ! руки за голову и не дышать! 1 110 0000010E 1C db 1Ch 111 112 0000010F program: 113 fLIT 100h 1 114 0000010F 01 db 01h 1 115 00000110 0100 dw 100h 116 fLIT 200h 1 117 00000112 01 db 01h 1 118 00000113 0200 dw 200h 119 PRISW 1 120 00000115 0B db 0Bh 121 fNEXT ; программа заканчивается 1 122 00000116 06 db 06h 123 00000117 fcode: 124 fRET 1 125 00000117 05 db 05h 126 127 end begin[/code]
Получившийся после компиляции com-файл остается только прошить в ПЛИС вместе с процессором для проверки-проверки
|
|
|
|
Добавлено: Сб окт 09, 2010 23:33 |
|
|
|
|
|
Заголовок сообщения: |
Ну, очень смешной процессор... |
|
|
Код процесора на AHDL (код для стека не показан). Код: TITLE "Stupid Simple CPU"; include "Stack";
-- команды для памяти CONSTANT READ = 1; CONSTANT WRITE = 2; -- команды для стеков CONSTANT NOP = 0; CONSTANT PUSH = 1; CONSTANT POP = 2; CONSTANT SWAP = 3; SUBDESIGN ssCPU ( -- входная синхронизация CLK : input; -- адресная пина A[15..0] : output; -- вход данных Di[7..0] : input; -- выход данных Do[7..0] : output; -- сигналы управления внешней памятью MEMcs,MEMrd,MEMwr : output; -- сброс разумеется! RESET : input; ) VARIABLE -- внутренний сигнал сброса RST : node; -- код операции памяти MEM[1..0] : node; -- код операции стека возвратов RSTC[1..0] : node; -- код операции стека данных DSTC[1..0] : node; -- счетчик команд PC[15..0] : DFF; -- регистр команды CMDR[7..0] : DFF; -- буферный регистр BUF[15..0] : DFF; -- стеки RStack : Stack WITH (WIDTH=16, DEPTH=3); DStack : Stack WITH (WIDTH=16, DEPTH=3); BEGIN -- формирование синхронного внутреннего сброса RST = DFF(RESET,CLK,,); -- сброс регистров PC[].clrn = RST; CMDR[].clrn = RST; -- синхронизировать ВСЕ! CMDR[].clk = CLK; PC[].clk = CLK; BUF[].clk = CLK; RStack.clk = CLK; DStack.clk = CLK; -- командировки для стеков RStack.stc[] = RSTC[]; DStack.stc[] = DSTC[];
CASE CMDR[4..0] IS -- NOP выборка следующей команды (нет операции) WHEN 0 => A[] = PC[]; PC[] = PC[] + 1; CMDR[] = Di[]; BUF[] = BUF[]; DStack.d[] = DStack.q[]; RStack.d[] = RStack.q[]; MEM[] = READ; RSTC[] = NOP; DSTC[] = NOP; -- LIT загрузка непосредственного литерала на стек ( --> data ) WHEN 1 => A[] = PC[]; PC[] = PC[] + 1; CMDR[] = 2; BUF[] = (H"00",Di[]); DStack.d[] = DStack.q[]; RStack.d[] = RStack.q[]; MEM[] = READ; RSTC[] = NOP; DSTC[] = NOP; WHEN 2 => A[] = PC[]; PC[] = PC[] + 1; CMDR[] = 0; DStack.d[] = (Di[],BUF[7..0]); BUF[] = (Di[],BUF[7..0]); RStack.d[] = RStack.q[]; MEM[] = READ; RSTC[] = NOP; DSTC[] = PUSH; -- CALL вызов попрограммы ( вызов адресного интерпретатора) WHEN 3 => A[] = PC[]; PC[] = PC[] + 1; CMDR[] = 4; BUF[] = (H"00",Di[]); DStack.d[] = DStack.q[]; RStack.d[] = RStack.q[]; MEM[] = READ; RSTC[] = NOP; DSTC[] = NOP; WHEN 4 => A[] = PC[]; CMDR[] = 0; PC[] = (Di[],BUF[7..0]); BUF[] = (Di[],BUF[7..0]); RStack.d[] = PC[] + 1; DStack.d[] = DStack.q[]; MEM[] = READ; RSTC[] = PUSH; DSTC[] = NOP; -- RET возврат из подпрограммы WHEN 5 => A[] = PC[]; PC[] = RStack.q[]; CMDR[] = 0; BUF[] = BUF[]; DStack.d[] = DStack.q[]; RStack.d[] = RStack.q[]; MEM[] = NOP; RSTC[] = POP; DSTC[] = NOP; -- NEXT переход на следующее слово (адресная интерпретация) WHEN 6 => CMDR[] = 7; A[] = RStack.q[]; RStack.d[] = RStack.q[] + 1; DStack.d[] = DStack.q[]; PC[] = PC[]; BUF[] = (H"00",Di[]); MEM[] = READ; RSTC[] = SWAP; DSTC[] = NOP; WHEN 7 => CMDR[] = 0; A[] = RStack.q[]; RStack.d[] = RStack.q[] + 1; DStack.d[] = DStack.q[]; PC[] = (Di[],BUF[7..0]); BUF[] = (Di[],BUF[7..0]); MEM[] = READ; RSTC[] = SWAP; DSTC[] = NOP; -- @ извлечь данное по адресу из стека ( addr --> data=mem[addr]) WHEN 8 => CMDR[] = 9; A[] = DStack.q[]; DStack.d[] = DStack.q[] + 1; PC[] = PC[]; BUF[] = (H"00",Di[]); RStack.d[] = RStack.q[]; MEM[] = READ; RSTC[] = NOP; DSTC[] = SWAP; WHEN 9 => CMDR[] = 10; A[] = DStack.q[]; PC[] = PC[]; BUF[] = (Di[],BUF[7..0]); RStack.d[] = RStack.q[]; MEM[] = READ; RSTC[] = NOP; DSTC[] = NOP; WHEN 10 => CMDR[] = 0; A[] = PC[]; PC[] = PC[]; BUF[] = BUF[]; DStack.d[] = BUF[]; RStack.d[] = RStack.q[]; MEM[] = NOP; RSTC[] = NOP; DSTC[] = SWAP; -- ! сохранить даное в памяти по адресу ( data, addr --> ) WHEN 11 => CMDR[] = 12; A[] = DStack.q[]; DStack.d[] = DStack.q[] + 1; PC[] = PC[]; RStack.d[] = RStack.q[]; MEM[] = WRITE; RSTC[] = NOP; DSTC[] = SWAP; Do[] = DStack.qq[7..0]; WHEN 12 => CMDR[] = 13; A[] = DStack.q[]; DStack.d[] = DStack.q[] + 1; PC[] = PC[]; RStack.d[] = RStack.q[]; MEM[] = WRITE; RSTC[] = NOP; DSTC[] = POP; Do[] = DStack.qq[15..8]; WHEN 13 => CMDR[] = 0; A[] = DStack.q[]; PC[] = PC[]; BUF[] = BUF[]; DStack.d[] = DStack.q[]; RStack.d[] = RStack.q[]; MEM[] = NOP; RSTC[] = NOP; DSTC[] = POP; -- ?BRANCH (IFNZ) переход, если на стеке не ноль WHEN 14 => A[] = PC[]; IF DFF(DStack.q[] == 0,CLK,,) THEN CMDR[] = 15; PC[] = PC[]; ELSE CMDR[] = 0; PC[] = PC[] + 2; END IF; BUF[] = BUF[]; DStack.d[] = DStack.q[]; RStack.d[] = RStack.q[]; MEM[] = NOP; RSTC[] = NOP; DSTC[] = NOP; WHEN 15 => CMDR[] = 16; A[] = PC[]; PC[] = PC[] + 1; BUF[] = (H"00",Di[]); DStack.d[] = DStack.q[]; RStack.d[] = RStack.q[]; MEM[] = READ; RSTC[] = NOP; DSTC[] = NOP; WHEN 16 => CMDR[] = 0; A[] = PC[]; BUF[] = (Di[],BUF[7..0]); PC[] = (Di[],BUF[7..0]); DStack.d[] = DStack.q[]; RStack.d[] = RStack.q[]; MEM[] = READ; RSTC[] = NOP; DSTC[] = NOP; -- DUP дублирование данного с вершины стека WHEN 17 => A[] = PC[]; PC[] = PC[] + 1; CMDR[] = Di[]; BUF[] = BUF[]; DStack.d[] = DStack.q[]; MEM[] = READ; DSTC[] = PUSH; RSTC[] = NOP; -- DROP удаление данного с вершины стека WHEN 18 => A[] = PC[]; PC[] = PC[] + 1; CMDR[] = Di[]; BUF[] = BUF[]; DStack.d[] = DStack.q[]; MEM[] = READ; DSTC[] = POP; RSTC[] = NOP; -- OVER копирование второго элемента стека WHEN 19 => A[] = PC[]; PC[] = PC[] + 1; CMDR[] = Di[]; BUF[] = BUF[]; DStack.d[] = DStack.qq[]; MEM[] = READ; DSTC[] = PUSH; RSTC[] = NOP; -- SWAP перестановка двух элементов на вершине стека WHEN 20 => CMDR[] = 21; A[] = PC[]; PC[] = PC[]; BUF[] = DStack.q[]; DStack.d[] = BUF[]; DSTC[] = POP; RStack.d[] = RStack.q[]; RSTC[] = NOP; MEM[] = NOP; WHEN 21 => CMDR[] = 22; A[] = PC[]; PC[] = PC[]; BUF[] = DStack.q[]; DStack.d[] = BUF[]; DSTC[] = SWAP; RStack.d[] = RStack.q[]; RSTC[] = NOP; MEM[] = NOP; WHEN 22 => CMDR[] = 0; A[] = PC[]; PC[] = PC[]; BUF[] = DStack.q[]; DStack.d[] = BUF[]; DSTC[] = PUSH; RStack.d[] = RStack.q[]; RSTC[] = NOP; MEM[] = NOP; -- >R переместить данное со стека данных на стек возвратов WHEN 23 => CMDR[] = 0; A[] = PC[]; PC[] = PC[]; DStack.d[] = DStack.q[]; BUF[] = BUF[]; RStack.d[] = DStack.q[]; DSTC[] = POP; RSTC[] = PUSH; MEM[] = NOP; -- R> переместить данное со стека возвратов на стек данных WHEN 24 => CMDR[] = 0; A[] = PC[]; PC[] = PC[]; DStack.d[] = RStack.q[]; BUF[] = BUF[]; RStack.d[] = RStack.q[]; DSTC[] = PUSH; RSTC[] = POP; MEM[] = NOP; -- NAND поразрядное логическое "И-НЕ" двух верхних элементов стека ( d1 d1 --> d1 nand d2) WHEN 25 => CMDR[] = 10; A[] = PC[]; PC[] = PC[]; DStack.d[] = DStack.q[]; BUF[] = !(DStack.q[] and DStack.qq[]); DSTC[] = POP; MEM[] = NOP; -- ADD сложить два верхних элемента стека (d1 d2 --> d1+d2) WHEN 26 => CMDR[] = 10; A[] = PC[]; PC[] = PC[]; DStack.d[] = DStack.q[]; BUF[] = !(DStack.q[] + DStack.qq[]); DSTC[] = POP; MEM[] = NOP; -- 2/ разделить верхний элемент стека на 2 WHEN 27 => CMDR[] = 0; A[] = PC[]; PC[] = PC[]; DStack.d[] = (DStack.q[15],DStack.q[15..1]); BUF[] = BUF[]; DSTC[] = SWAP; MEM[] = NOP; -- HALT - All other commands WHEN others => CMDR[] = CMDR[]; A[] = PC[]; BUF[] = BUF[]; DStack.d[] = DStack.q[]; RStack.d[] = RStack.q[]; PC[] = PC[]; MEM[] = NOP; RSTC[] = NOP; DSTC[] = NOP; END CASE;
-- формирование сигналов для внешней памяти CASE MEM[] IS WHEN READ => MEMcs = CLK; MEMrd = CLK; MEMwr = VCC; WHEN WRITE => MEMcs = CLK; MEMrd = VCC; MEMwr = CLK; WHEN others => MEMcs = VCC; MEMrd = VCC; MEMwr = VCC; END CASE; END;
Процессор 16-разрядный, но с 8-разрядной шиной данных и 16-разрядным адресом (ну, почти как у Z80). Каждому 8-разрядному коду соответствует некая операция (забитая в оператор CASE) В нем же определяется, какой код будет следующим. Если он равен нулю, то следующий код считывается из внешней памяти. Таким образом любая команда исполняется за несколько тактов - первый - чтение команды, остальные - исполнение. В конце исполнения каждой команды происходит вызов чтения следующей команды. Если этого не сделать - новая комнда не загрузится и процессор зациклится на каком-нибудь коде. (ветвь others именно такая). Компилируется сие "чудо" с рабочей частотой ~100Mhz, но никакая внешняя память такую частоту не потянет, поэтому частоту можно смело занижать или подключать к процессору внутреннюю память ПЛИС-а. По ячейкам процессор занимает ~600LCELL при глубине стеков в 3 элемента. Система команд обсуждалась здесь: viewtopic.php?f=3&t=2564
Код процесора на AHDL (код для стека не показан).
[code] TITLE "Stupid Simple CPU"; include "Stack";
-- команды для памяти CONSTANT READ = 1; CONSTANT WRITE = 2; -- команды для стеков CONSTANT NOP = 0; CONSTANT PUSH = 1; CONSTANT POP = 2; CONSTANT SWAP = 3; SUBDESIGN ssCPU ( -- входная синхронизация CLK : input; -- адресная пина A[15..0] : output; -- вход данных Di[7..0] : input; -- выход данных Do[7..0] : output; -- сигналы управления внешней памятью MEMcs,MEMrd,MEMwr : output; -- сброс разумеется! RESET : input; ) VARIABLE -- внутренний сигнал сброса RST : node; -- код операции памяти MEM[1..0] : node; -- код операции стека возвратов RSTC[1..0] : node; -- код операции стека данных DSTC[1..0] : node; -- счетчик команд PC[15..0] : DFF; -- регистр команды CMDR[7..0] : DFF; -- буферный регистр BUF[15..0] : DFF; -- стеки RStack : Stack WITH (WIDTH=16, DEPTH=3); DStack : Stack WITH (WIDTH=16, DEPTH=3); BEGIN -- формирование синхронного внутреннего сброса RST = DFF(RESET,CLK,,); -- сброс регистров PC[].clrn = RST; CMDR[].clrn = RST; -- синхронизировать ВСЕ! CMDR[].clk = CLK; PC[].clk = CLK; BUF[].clk = CLK; RStack.clk = CLK; DStack.clk = CLK; -- командировки для стеков RStack.stc[] = RSTC[]; DStack.stc[] = DSTC[];
CASE CMDR[4..0] IS -- NOP выборка следующей команды (нет операции) WHEN 0 => A[] = PC[]; PC[] = PC[] + 1; CMDR[] = Di[]; BUF[] = BUF[]; DStack.d[] = DStack.q[]; RStack.d[] = RStack.q[]; MEM[] = READ; RSTC[] = NOP; DSTC[] = NOP; -- LIT загрузка непосредственного литерала на стек ( --> data ) WHEN 1 => A[] = PC[]; PC[] = PC[] + 1; CMDR[] = 2; BUF[] = (H"00",Di[]); DStack.d[] = DStack.q[]; RStack.d[] = RStack.q[]; MEM[] = READ; RSTC[] = NOP; DSTC[] = NOP; WHEN 2 => A[] = PC[]; PC[] = PC[] + 1; CMDR[] = 0; DStack.d[] = (Di[],BUF[7..0]); BUF[] = (Di[],BUF[7..0]); RStack.d[] = RStack.q[]; MEM[] = READ; RSTC[] = NOP; DSTC[] = PUSH; -- CALL вызов попрограммы ( вызов адресного интерпретатора) WHEN 3 => A[] = PC[]; PC[] = PC[] + 1; CMDR[] = 4; BUF[] = (H"00",Di[]); DStack.d[] = DStack.q[]; RStack.d[] = RStack.q[]; MEM[] = READ; RSTC[] = NOP; DSTC[] = NOP; WHEN 4 => A[] = PC[]; CMDR[] = 0; PC[] = (Di[],BUF[7..0]); BUF[] = (Di[],BUF[7..0]); RStack.d[] = PC[] + 1; DStack.d[] = DStack.q[]; MEM[] = READ; RSTC[] = PUSH; DSTC[] = NOP; -- RET возврат из подпрограммы WHEN 5 => A[] = PC[]; PC[] = RStack.q[]; CMDR[] = 0; BUF[] = BUF[]; DStack.d[] = DStack.q[]; RStack.d[] = RStack.q[]; MEM[] = NOP; RSTC[] = POP; DSTC[] = NOP; -- NEXT переход на следующее слово (адресная интерпретация) WHEN 6 => CMDR[] = 7; A[] = RStack.q[]; RStack.d[] = RStack.q[] + 1; DStack.d[] = DStack.q[]; PC[] = PC[]; BUF[] = (H"00",Di[]); MEM[] = READ; RSTC[] = SWAP; DSTC[] = NOP; WHEN 7 => CMDR[] = 0; A[] = RStack.q[]; RStack.d[] = RStack.q[] + 1; DStack.d[] = DStack.q[]; PC[] = (Di[],BUF[7..0]); BUF[] = (Di[],BUF[7..0]); MEM[] = READ; RSTC[] = SWAP; DSTC[] = NOP; -- @ извлечь данное по адресу из стека ( addr --> data=mem[addr]) WHEN 8 => CMDR[] = 9; A[] = DStack.q[]; DStack.d[] = DStack.q[] + 1; PC[] = PC[]; BUF[] = (H"00",Di[]); RStack.d[] = RStack.q[]; MEM[] = READ; RSTC[] = NOP; DSTC[] = SWAP; WHEN 9 => CMDR[] = 10; A[] = DStack.q[]; PC[] = PC[]; BUF[] = (Di[],BUF[7..0]); RStack.d[] = RStack.q[]; MEM[] = READ; RSTC[] = NOP; DSTC[] = NOP; WHEN 10 => CMDR[] = 0; A[] = PC[]; PC[] = PC[]; BUF[] = BUF[]; DStack.d[] = BUF[]; RStack.d[] = RStack.q[]; MEM[] = NOP; RSTC[] = NOP; DSTC[] = SWAP; -- ! сохранить даное в памяти по адресу ( data, addr --> ) WHEN 11 => CMDR[] = 12; A[] = DStack.q[]; DStack.d[] = DStack.q[] + 1; PC[] = PC[]; RStack.d[] = RStack.q[]; MEM[] = WRITE; RSTC[] = NOP; DSTC[] = SWAP; Do[] = DStack.qq[7..0]; WHEN 12 => CMDR[] = 13; A[] = DStack.q[]; DStack.d[] = DStack.q[] + 1; PC[] = PC[]; RStack.d[] = RStack.q[]; MEM[] = WRITE; RSTC[] = NOP; DSTC[] = POP; Do[] = DStack.qq[15..8]; WHEN 13 => CMDR[] = 0; A[] = DStack.q[]; PC[] = PC[]; BUF[] = BUF[]; DStack.d[] = DStack.q[]; RStack.d[] = RStack.q[]; MEM[] = NOP; RSTC[] = NOP; DSTC[] = POP; -- ?BRANCH (IFNZ) переход, если на стеке не ноль WHEN 14 => A[] = PC[]; IF DFF(DStack.q[] == 0,CLK,,) THEN CMDR[] = 15; PC[] = PC[]; ELSE CMDR[] = 0; PC[] = PC[] + 2; END IF; BUF[] = BUF[]; DStack.d[] = DStack.q[]; RStack.d[] = RStack.q[]; MEM[] = NOP; RSTC[] = NOP; DSTC[] = NOP; WHEN 15 => CMDR[] = 16; A[] = PC[]; PC[] = PC[] + 1; BUF[] = (H"00",Di[]); DStack.d[] = DStack.q[]; RStack.d[] = RStack.q[]; MEM[] = READ; RSTC[] = NOP; DSTC[] = NOP; WHEN 16 => CMDR[] = 0; A[] = PC[]; BUF[] = (Di[],BUF[7..0]); PC[] = (Di[],BUF[7..0]); DStack.d[] = DStack.q[]; RStack.d[] = RStack.q[]; MEM[] = READ; RSTC[] = NOP; DSTC[] = NOP; -- DUP дублирование данного с вершины стека WHEN 17 => A[] = PC[]; PC[] = PC[] + 1; CMDR[] = Di[]; BUF[] = BUF[]; DStack.d[] = DStack.q[]; MEM[] = READ; DSTC[] = PUSH; RSTC[] = NOP; -- DROP удаление данного с вершины стека WHEN 18 => A[] = PC[]; PC[] = PC[] + 1; CMDR[] = Di[]; BUF[] = BUF[]; DStack.d[] = DStack.q[]; MEM[] = READ; DSTC[] = POP; RSTC[] = NOP; -- OVER копирование второго элемента стека WHEN 19 => A[] = PC[]; PC[] = PC[] + 1; CMDR[] = Di[]; BUF[] = BUF[]; DStack.d[] = DStack.qq[]; MEM[] = READ; DSTC[] = PUSH; RSTC[] = NOP; -- SWAP перестановка двух элементов на вершине стека WHEN 20 => CMDR[] = 21; A[] = PC[]; PC[] = PC[]; BUF[] = DStack.q[]; DStack.d[] = BUF[]; DSTC[] = POP; RStack.d[] = RStack.q[]; RSTC[] = NOP; MEM[] = NOP; WHEN 21 => CMDR[] = 22; A[] = PC[]; PC[] = PC[]; BUF[] = DStack.q[]; DStack.d[] = BUF[]; DSTC[] = SWAP; RStack.d[] = RStack.q[]; RSTC[] = NOP; MEM[] = NOP; WHEN 22 => CMDR[] = 0; A[] = PC[]; PC[] = PC[]; BUF[] = DStack.q[]; DStack.d[] = BUF[]; DSTC[] = PUSH; RStack.d[] = RStack.q[]; RSTC[] = NOP; MEM[] = NOP; -- >R переместить данное со стека данных на стек возвратов WHEN 23 => CMDR[] = 0; A[] = PC[]; PC[] = PC[]; DStack.d[] = DStack.q[]; BUF[] = BUF[]; RStack.d[] = DStack.q[]; DSTC[] = POP; RSTC[] = PUSH; MEM[] = NOP; -- R> переместить данное со стека возвратов на стек данных WHEN 24 => CMDR[] = 0; A[] = PC[]; PC[] = PC[]; DStack.d[] = RStack.q[]; BUF[] = BUF[]; RStack.d[] = RStack.q[]; DSTC[] = PUSH; RSTC[] = POP; MEM[] = NOP; -- NAND поразрядное логическое "И-НЕ" двух верхних элементов стека ( d1 d1 --> d1 nand d2) WHEN 25 => CMDR[] = 10; A[] = PC[]; PC[] = PC[]; DStack.d[] = DStack.q[]; BUF[] = !(DStack.q[] and DStack.qq[]); DSTC[] = POP; MEM[] = NOP; -- ADD сложить два верхних элемента стека (d1 d2 --> d1+d2) WHEN 26 => CMDR[] = 10; A[] = PC[]; PC[] = PC[]; DStack.d[] = DStack.q[]; BUF[] = !(DStack.q[] + DStack.qq[]); DSTC[] = POP; MEM[] = NOP; -- 2/ разделить верхний элемент стека на 2 WHEN 27 => CMDR[] = 0; A[] = PC[]; PC[] = PC[]; DStack.d[] = (DStack.q[15],DStack.q[15..1]); BUF[] = BUF[]; DSTC[] = SWAP; MEM[] = NOP; -- HALT - All other commands WHEN others => CMDR[] = CMDR[]; A[] = PC[]; BUF[] = BUF[]; DStack.d[] = DStack.q[]; RStack.d[] = RStack.q[]; PC[] = PC[]; MEM[] = NOP; RSTC[] = NOP; DSTC[] = NOP; END CASE;
-- формирование сигналов для внешней памяти CASE MEM[] IS WHEN READ => MEMcs = CLK; MEMrd = CLK; MEMwr = VCC; WHEN WRITE => MEMcs = CLK; MEMrd = VCC; MEMwr = CLK; WHEN others => MEMcs = VCC; MEMrd = VCC; MEMwr = VCC; END CASE; END;
[/code]
Процессор 16-разрядный, но с 8-разрядной шиной данных и 16-разрядным адресом (ну, почти как у Z80). Каждому 8-разрядному коду соответствует некая операция (забитая в оператор CASE) В нем же определяется, какой код будет следующим. Если он равен нулю, то следующий код считывается из внешней памяти. Таким образом любая команда исполняется за несколько тактов - первый - чтение команды, остальные - исполнение. В конце исполнения каждой команды происходит вызов чтения следующей команды. Если этого не сделать - новая комнда не загрузится и процессор зациклится на каком-нибудь коде. (ветвь others именно такая).
Компилируется сие "чудо" с рабочей частотой ~100Mhz, но никакая внешняя память такую частоту не потянет, поэтому частоту можно смело занижать или подключать к процессору внутреннюю память ПЛИС-а.
По ячейкам процессор занимает ~600LCELL при глубине стеков в 3 элемента.
Система команд обсуждалась здесь: http://fforum.winglion.ru/viewtopic.php?f=3&t=2564
|
|
|
|
Добавлено: Чт окт 07, 2010 22:00 |
|
|
|
|