Forth и другие саморасширяющиеся системы программирования Locations of visitors to this page
Текущее время: Вс сен 23, 2018 17:59

...
Google Search
Forth-FAQ Spy Grafic

Часовой пояс: UTC + 3 часа [ Летнее время ]




Начать новую тему Ответить на тему  [ Сообщений: 4 ] 
Автор Сообщение
 Заголовок сообщения: Ну, очень смешной процессор...
СообщениеДобавлено: Чт окт 07, 2010 22:00 
Не в сети
Administrator
Administrator
Аватара пользователя

Зарегистрирован: Вт май 02, 2006 13:19
Сообщения: 3565
Откуда: St.Petersburg
Благодарил (а): 4 раз.
Поблагодарили: 72 раз.
Код процесора на 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

_________________
С уважением, WingLion
Forth-CPU . RuF09WE
Мой Форт
Отсутствие бана это не заслуга юзера, а недоработка модератора (с)


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения: Re: Ну, очень смешной процессор...
СообщениеДобавлено: Сб окт 09, 2010 23:33 
Не в сети
Administrator
Administrator
Аватара пользователя

Зарегистрирован: Вт май 02, 2006 13:19
Сообщения: 3565
Откуда: St.Petersburg
Благодарил (а): 4 раз.
Поблагодарили: 72 раз.
к очень смешному процессору подошел очень смешной старый-добрый 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-файл остается только прошить в ПЛИС вместе с процессором для проверки-проверки

_________________
С уважением, WingLion
Forth-CPU . RuF09WE
Мой Форт
Отсутствие бана это не заслуга юзера, а недоработка модератора (с)


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения: Re: Ну, очень смешной процессор...
СообщениеДобавлено: Вс окт 10, 2010 07:42 
Не в сети
Administrator
Administrator
Аватара пользователя

Зарегистрирован: Вт май 02, 2006 13:19
Сообщения: 3565
Откуда: St.Petersburg
Благодарил (а): 4 раз.
Поблагодарили: 72 раз.
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. Играем победный марш

_________________
С уважением, WingLion
Forth-CPU . RuF09WE
Мой Форт
Отсутствие бана это не заслуга юзера, а недоработка модератора (с)


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения: Re: Ну, очень смешной процессор...
СообщениеДобавлено: Вс окт 10, 2010 16:15 
Не в сети
Administrator
Administrator
Аватара пользователя

Зарегистрирован: Вт май 02, 2006 13:19
Сообщения: 3565
Откуда: St.Petersburg
Благодарил (а): 4 раз.
Поблагодарили: 72 раз.
Ради интереса откомпилировал (последнюю версию) процессора в MAX-Plus II для EP1K30QC208-3

Результат: объем - 690LCELLs (40%), максимальная частота - 30MHz

_________________
С уважением, WingLion
Forth-CPU . RuF09WE
Мой Форт
Отсутствие бана это не заслуга юзера, а недоработка модератора (с)


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 4 ] 

Часовой пояс: UTC + 3 часа [ Летнее время ]


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2


Вы не можете начинать темы
Вы можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
phpBB сборка от FladeX // Русская поддержка phpBB