Автор |
Сообщение |
|
|
Заголовок сообщения: |
|
|
|
|
|
|
Добавлено: Пт сен 21, 2007 11:32 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
Цитата: нет таких ситуаций, что часть операции исполнилась, часть нет, и при исполнении следующей части цикла в качестве данных появились новые данные от исполненной первой части. В программе на такое сплошь и рядом натыкаешься, и начинается такая путаница и свалка, что перестаешь понимать, что и когда делать. Поэтому буду переделывать
Как это получалос?
[quote]нет таких ситуаций, что часть операции исполнилась, часть нет, и при исполнении следующей части цикла в качестве данных появились новые данные от исполненной первой части. В программе на такое сплошь и рядом натыкаешься, и начинается такая путаница и свалка, что перестаешь понимать, что и когда делать. Поэтому буду переделывать [/quote]
Как это получалос?
|
|
|
|
Добавлено: Вс июл 29, 2007 16:05 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
Аха, а потом, можно и две и три структуры сделать, эмулируя тем самым конвейерную структуру
Вот только сейчас уже ясно, что вскоре слово TAKT будет исполняться намного быстрее чем LOGIC, Т.е. существенного ускорения с переключением структур не будет.
Аха, а потом, можно и две и три структуры сделать, эмулируя тем самым конвейерную структуру :)
Вот только сейчас уже ясно, что вскоре слово TAKT будет исполняться намного быстрее чем LOGIC, Т.е. существенного ускорения с переключением структур не будет.
|
|
|
|
Добавлено: Вс июл 29, 2007 15:58 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
Интересная идея!!
А для ускорения можно так. Заводим struct (aka record), распихиваем по полям все переменные состояния. Объявляем два экземпляра (1 и 2) и два указателя (current, new). В процессе работы просто меняем местами указатели - новое автоматически становится текущим.
Интересная идея!!
А для ускорения можно так. Заводим struct (aka record), распихиваем по полям все переменные состояния. Объявляем два экземпляра (1 и 2) и два указателя (current, new). В процессе работы просто меняем местами указатели - новое автоматически становится текущим.
|
|
|
|
Добавлено: Вс июл 29, 2007 15:39 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
Ковырял я тут свой коде и понял, что доковырялся до того, что сам перестал понимать, что и где делается.
Короче, проблемы следующие.
1. В железе все делается параллельно, т.е. нет таких ситуаций, что часть операции исполнилась, часть нет, и при исполнении следующей части цикла в качестве данных появились новые данные от исполненной первой части. В программе на такое сплошь и рядом натыкаешься, и начинается такая путаница и свалка, что перестаешь понимать, что и когда делать.
Поэтому буду переделывать ВМ с иным принципом тактирования.
Суть примерно такая же, как в железе в тригерах типа "мастер-помощник".
Для каждого регистра завидутся не одна, а две переменные. Одна из них - истиное значение, вторая - значение, которое будет присвоено на следующем такте работы ВМ. Вычисляются вторые значения из первых, а, когда они вычислены, тогда и производится ТАКТ - все вычисленные значения значения вписываются в регистры.
Такая программа будет ужасно тормозить, просто потому, что все действия будут исполняться последовательно, плюс дополнительная операция по копированию вычисленных значений.
Однако, она будет более точно отражать железо и, соответственно, в железе все 'должно' будет работать сразу же, как только будут реализованы регистры и логика.
Код: \ Emulator Forth-CPU version-2 \ Пока только заглушка
: H. BASE @ SWAP HEX S>D <# # # # # # # # # #> TYPE SPACE BASE ! ;
HEX 20 CONSTANT NRs CREATE R-OUTS NRs CELLS ALLOT ( выходы всех регистров ) CREATE R-INS NRs CELLS ALLOT ( входы всех регистров )
: Visuale ( отображение состояния R-OUTS ) H. CR ; : TAKT R-INS R-OUTS NRs CELLS MOVE ; ( копирование данных со входов на выходы )
: LOGIC ; ( заглушка. тут вычисляются R-INS из R-OUTS )
: RESET ( начальная установка R-INS ) ;
: Работай-падла! RESET TAKT 10 0 DO LOGIC TAKT I Visuale LOOP KEY BYE ; ( исполнить 10 тактов)
Работай-падла!
Ковырял я тут свой коде и понял, что доковырялся до того, что сам перестал понимать, что и где делается.
Короче, проблемы следующие.
1. В железе все делается параллельно, т.е. нет таких ситуаций, что часть операции исполнилась, часть нет, и при исполнении следующей части цикла в качестве данных появились новые данные от исполненной первой части. В программе на такое сплошь и рядом натыкаешься, и начинается такая путаница и свалка, что перестаешь понимать, что и когда делать.
Поэтому буду переделывать ВМ с иным принципом [b]тактирования[/b].
Суть примерно такая же, как в железе в тригерах типа "мастер-помощник".
Для каждого регистра завидутся не одна, а две переменные. Одна из них - истиное значение, вторая - значение, которое будет присвоено на следующем такте работы ВМ. Вычисляются вторые значения из первых, а, когда они вычислены, тогда и производится ТАКТ - все вычисленные значения значения вписываются в регистры.
Такая программа будет ужасно тормозить, просто потому, что все действия будут исполняться последовательно, плюс дополнительная операция по копированию вычисленных значений.
Однако, она будет более точно отражать [b]железо[/b] и, соответственно, в железе все 'должно' будет работать сразу же, как только будут реализованы регистры и логика.
[code] \ Emulator Forth-CPU version-2 \ Пока только заглушка
: H. BASE @ SWAP HEX S>D <# # # # # # # # # #> TYPE SPACE BASE ! ;
HEX 20 CONSTANT NRs CREATE R-OUTS NRs CELLS ALLOT ( выходы всех регистров ) CREATE R-INS NRs CELLS ALLOT ( входы всех регистров )
: Visuale ( отображение состояния R-OUTS ) H. CR ; : TAKT R-INS R-OUTS NRs CELLS MOVE ; ( копирование данных со входов на выходы )
: LOGIC ; ( заглушка. тут вычисляются R-INS из R-OUTS )
: RESET ( начальная установка R-INS ) ;
: Работай-падла! RESET TAKT 10 0 DO LOGIC TAKT I Visuale LOOP KEY BYE ; ( исполнить 10 тактов)
Работай-падла!
[/code]
|
|
|
|
Добавлено: Вс июл 29, 2007 15:36 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
Выдался свободный часок, от совсем нечего делать поковырял тут код. Просто хочу помочь.
Шаг номер раз (список по мере важности):
http://files.myopera.com/profiT/forth/fcpu-table.f
1. Правильное включение библиотек (~day\common\console.f и ~profit\lib\chartable.f)
2. Использование таблиц, тех что из библиотеки (без выдираловки с мясом и мышцами отдельных функций)
3. Сохранение и восстановление системы счисления
Шаг номер два (рефакторизация nop в advance):
http://files.myopera.com/profiT/forth/fcpu-advance.f
1. nop , как оно и по логике вроде должно быть, сделано пустым
2. Действия по переходу к следующей команде (бывшие раньше в nop) обозначены как слово advance и это слово вызывается не в каждой команде отдельно, а централизировано вызывается в STEP.
Шаг номер три (переход с таблиц на состояния конечного автомата и демонстрация возможностей их, придуманы от фонаря полностью, чиста для демонстрации действия для пока незадействованных префиксов):
http://files.myopera.com/profiT/forth/fcpu-automata.f
1. "Префикс" sys допустим переключает способ работы lit (именно переключает, чтобы вернуть назад, нужно указать "префикс" sys ещё раз). В "обычном" режиме lit кладёт число на новый элемент стека, а в "режиме перекрывающего lit" эта команда не будет изменять глубину стека а будет пихать число сразу в аккумулятор, затирая старое значение.
2. Префикс user например говорит что допустим следующие три команды (число команда, взято оттуда, с потолка) выводить с отладочной печатью.
3. pre представляет собой условный префикс. Если на стеке стоит TRUE следом идущая команда обрабатывается, если FALSE -- игнорируется ("режим-пропускаемой-команды").
PS. Я там код правил вообще не смотря, не читая, и не понимая. Будут глюки -- звиняюсь.
Выдался свободный часок, от совсем нечего делать поковырял тут код. Просто хочу помочь.
Шаг номер раз (список по мере важности):
http://files.myopera.com/profiT/forth/fcpu-table.f
1. Правильное включение библиотек (~day\common\console.f и ~profit\lib\chartable.f)
2. Использование таблиц, тех что из библиотеки (без выдираловки с мясом и мышцами отдельных функций)
3. Сохранение и восстановление системы счисления
Шаг номер два (рефакторизация nop в advance):
http://files.myopera.com/profiT/forth/fcpu-advance.f
1. nop , как оно и по логике вроде должно быть, сделано пустым
2. Действия по переходу к следующей команде (бывшие раньше в nop) обозначены как слово advance и это слово вызывается не в каждой команде отдельно, а централизировано вызывается в STEP.
Шаг номер три (переход с таблиц на состояния конечного автомата и демонстрация возможностей их, придуманы от фонаря полностью, чиста для демонстрации действия для пока незадействованных префиксов):
http://files.myopera.com/profiT/forth/fcpu-automata.f
1. "Префикс" sys допустим переключает способ работы lit (именно переключает, чтобы вернуть назад, нужно указать "префикс" sys ещё раз). В "обычном" режиме lit кладёт число на новый элемент стека, а в "режиме перекрывающего lit" эта команда не будет изменять глубину стека а будет пихать число сразу в аккумулятор, затирая старое значение.
2. Префикс user например говорит что допустим следующие три команды (число команда, взято оттуда, с потолка) выводить с отладочной печатью.
3. pre представляет собой условный префикс. Если на стеке стоит TRUE следом идущая команда обрабатывается, если FALSE -- игнорируется ("режим-пропускаемой-команды").
PS. Я там код правил вообще не смотря, не читая, и не понимая. Будут глюки -- звиняюсь.
|
|
|
|
Добавлено: Ср май 23, 2007 17:38 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
рано или не рано, но сделал через таблицу
Последний вариант кода в первом посте этого топика
Мысли вслух, чтобы не посеять:
1. арифметика и логика через префиксы не так уж часто они встречаются, чтобы жалеть байтики (даже половинки байтов)
2. lit сделать префиксом, чтобы определять литералы разной длины,
одно, двух, трех, и т.д. до восьмибайтовых(?) плюс
8 предопределенных литералов 0, -1, 1, 2, 4...
(разберемся каких надо больше)
рано или не рано, но сделал через таблицу :)
[color=red] [b]Последний вариант кода в первом посте этого топика[/b][/color]
Мысли вслух, чтобы не посеять:
1. арифметика и логика через префиксы не так уж часто они встречаются, чтобы жалеть байтики (даже половинки байтов)
2. [b]lit[/b] сделать префиксом, чтобы определять литералы разной длины,
одно, двух, трех, и т.д. до восьмибайтовых(?) плюс
8 предопределенных литералов 0, -1, 1, 2, 4...
(разберемся каких надо больше)
|
|
|
|
Добавлено: Пн май 21, 2007 12:33 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
таблицу рановато делать... я еще с префиксами думаю, как лучше сделать, чтобы их можно было подключать/отключать
таблицу рановато делать... я еще с префиксами думаю, как лучше сделать, чтобы их можно было подключать/отключать
|
|
|
|
Добавлено: Пн май 21, 2007 03:02 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
WingLion писал(а): : H. BASE @ >R HEX S>D <# # # # # # # # # #> TYPE SPACE R> BASE ! ;
Код: : H. BASE @ SWAP HEX S>D <# # # # # # # # # #> TYPE SPACE BASE ! ;
А про таблицу мне подумать надо... поискать в готовых утилитах...
[quote="WingLion"]: H. BASE @ >R HEX S>D <# # # # # # # # # #> TYPE SPACE R> BASE ! ; [/quote]
[code]: H. BASE @ SWAP HEX S>D <# # # # # # # # # #> TYPE SPACE BASE ! ;[/code]
А про таблицу мне подумать надо... поискать в готовых утилитах... ;)
|
|
|
|
Добавлено: Пн май 21, 2007 02:47 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
Так, показываю, что получилось теперь :
Последний вариант кода в первом посте этого топика
Добавился вариант 4-хбитных команд
(пока не всех, но тех, что получились)
проверял еще далеко не все, поэтому могут быть глюки
Так, показываю, что получилось теперь :
[color=red] [b]Последний вариант кода в первом посте этого топика[/b][/color]
Добавился вариант 4-хбитных команд
(пока не всех, но тех, что получились)
проверял еще далеко не все, поэтому могут быть глюки
|
|
|
|
Добавлено: Пн май 21, 2007 02:16 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
В данный момент почти ничего не может. Т.к. кода для команд нет - НОПы на все коды команд стоят, кроме одной. На этой одной, где нет НОПа программа и зацикливается, потому что PC меняется НОПом
В рабочем цикле (слово pp) выводится состояние регистров (OUTST) , стеков и памяти ВМ, исполняется одна команда (слово STEP) и цикл повторяется, пока не нажата клавиша ESC.
100 PAUSE - чтобы успеть увидеть, что делается
меняется PC и CMD. на CMD = 0F ВМ зацикливается на одном месте.
Чтобы увидеть это, надо код скопировать и ввести в SPF (у меня 4.18)
В данный момент почти ничего не может. Т.к. кода для команд нет - НОПы на все коды команд стоят, кроме одной. На этой одной, где нет НОПа программа и зацикливается, потому что PC меняется НОПом
В рабочем цикле (слово pp) выводится состояние регистров (OUTST) , стеков и памяти ВМ, исполняется одна команда (слово STEP) и цикл повторяется, пока не нажата клавиша ESC.
100 PAUSE - чтобы успеть увидеть, что делается
меняется PC и CMD. на CMD = 0F ВМ зацикливается на одном месте.
Чтобы увидеть это, надо код скопировать и ввести в SPF (у меня 4.18)
|
|
|
|
Добавлено: Вс май 20, 2007 22:38 |
|
|
|
|
|
Заголовок сообщения: |
|
|
|
И что сейчас она может? ( Я не могу пока понять). На СИ будет значительно больший исходник.
И что сейчас она может? ( Я не могу пока понять). На СИ будет значительно больший исходник.
|
|
|
|
Добавлено: Вс май 20, 2007 22:11 |
|
|
|
|
|
Заголовок сообщения: |
ВМ на SPF для отработки системы команд и коротких программ |
|
|
Код: \ ForthCPU/VM emulator by WingLion
\ сначала доопределение Форта ~day\common\console.f
HEX CLS 0 0 AT-XY
\ закройте глаза и не читайте следующие 3-4 строчки! \ почему в SPF нет слова H. - не знаю
: H. BASE @ SWAP HEX S>D <# # # # # # # # # #> TYPE SPACE BASE ! ;
: FALSE! FALSE SWAP ! ; : TRUE! TRUE SWAP ! ; \ : 1+! 1 +! ; \ эта команда и так есть : 1-! -1 +! ; \ а этой в SPF не оказалось
\ по подсказке ygrek-a (нужно для многострочного определения таблицы ) : NEXT-NAME BEGIN PARSE-NAME DUP 0= WHILE 2DROP REFILL 0= THROW REPEAT ;
\ ******************** \ тиснутое у ~profit-a и перековырянное определениe для таблиц : нифига \ вспоможитель ." Команда выполнила невыполнимую операцию и будет отшлепана по заднице! " CR ; : таблица ( число-случаев "имя" -- ) CREATE DUP 1+ , \ кол-во случаев плюс один \ HERE TO текущее-состояние 0 DO NEXT-NAME ['] ' EVALUATE-WITH , LOOP \ 0 DO ' , LOOP \ сразу скомпилировать все слова в таблицу \ если слов при определении таблицы окажется меньше - полезут глюки ['] нифига DUP , , \ действие по-умолчанию, \ для случаев номера которых превышают кол-во состояний \ два раза потому что с одним вылазит accec violation :-\ DOES> DUP @ ROT MIN 1+ CELLS + @ EXECUTE ;
\ тупая проверка : действие0 ." действие0" CR ; : действие1 ." действие1" CR ; : действие2 ." действие2" CR ; 5 таблица тупая-проверка действие0 действие1 действие2 действие2 нифига
0 DUP . тупая-проверка 1 DUP . тупая-проверка 2 DUP . тупая-проверка 3 DUP . тупая-проверка 4 DUP . тупая-проверка F DUP . тупая-проверка
\ остановиться и поглядеть KEY \ BYE
\ 5 таблица TEST TRUE FALSE TRUE FALSE TRUE FALSE \ 1 TEST . CR \ должно напечатать 2 \ 5 TEST . CR \ должно напечатать 11 \ KEY \ ждать клавишу \ BYE
\ *********************** ну, привык я юзать звездюлины как разделители \ теперь определения для ВМ
\ глобальные параметры 1000 CONSTANT MemSize \ размер памяти ВМ (в байтах) 10 CONSTANT DStS \ глубина стека данных (в словах) 10 CONSTANT RStS \ глубина стека возвратов (в словах)
\ блоки ВМ VARIABLE PC \ счетчик команд VARIABLE RAD \ регистр адреса/данных VARIABLE CMD \ регистр команды VARIABLE RADF \ флаг входного мультиплексора для RAD \ TRUE - RStack -> RAD \ FALSE - DStack ->RAD VARIABLE RStF \ флаг входного мультиплексора для RStack \ TRUE - PC+1 ->RStack \ FALSE - RAD ->RStack
VARIABLE DStP \ поинтер D-стека CREATE DStack DStS CELLS ALLOT \ стек данных VARIABLE DStDO \ текущая вершина стека данных (вых. регистр стека)
VARIABLE RStP \ поинтер R-стека CREATE RStack RStS CELLS ALLOT \ стек возвратов VARIABLE RStDO \ текущая вершина стека возвратов (вых. регистр стека)
CREATE MEM MemSize ALLOT \ память ВМ MemSize 1- CONSTANT MASK \ ограничитель памяти ВМ
\ ****************************
: -1OO! 1- OVER OVER C! NIP ; : init_MEM MEM MemSize ERASE
\ микро-DUMP памяти ВМ
00 00 00 00 \ nop nop 01 10 00 00 00 \ call 0010 03 55 AA 00 00 \ lit AA55 00 00 \ nop nop 01 08 00 00 00 \ call 0008
MEM 15 + 15 0 DO -1OO! LOOP
\ 10 0 DO I DUP MEM + C! LOOP ;
: reset PC 0! DStP 0! RStP 0! RADF FALSE! RStF TRUE! ;
reset init_MEM
\ ****************************
: OUTMST \ вывод состояния стеков и памяти CR ." DataStack:" DStP @ H. DStack 8 DUMP CR ." RetStack:" RStP @ H. RStack 8 DUMP CR \ память CR ." Memory:" CR MEM 40 DUMP ;
: OUTSTR \ вывод состояния регистров \ регистры \ 0 0 AT-XY CR ." PC: " PC @ H. \ счетчик команд ." RAD " RAD @ H. \ регистр адреса/данных ." CMD " CMD @ H. \ регистр команды ." DSt " DStDO @ H. \ Вершина стека данных ." RSt " RStDO @ H. \ Вершина стека возвратов ;
: OUTST \ вывод состояния ВМ \ 0 0 AT-XY OUTSTR \ OUTMST ;
\ **************************** \ Работа ВМ \ **************************** \ вспоможители : PC++ PC 1+! ; : MPC@ MEM PC @ MASK AND + @ ; \ читать данные из памяти ВМ по адресу PC -- МЕМ(PC) : MPC! MEM PC @ MASK AND + RAD @ SWAP ! ; \ записать данные из RAD по адресу в PC \ тут еще разбираться с шириной данных ВМ
: GetLit MPC@ PC @ 4 + PC ! ; \ получить литерал : RdCMD MPC@ CMD C! PC++ ; \ читать команду \ тут может быть и какая-нибудь распаковка и доп. чтение-вперед
\ **************************** \ работа со стеком возвратов \ ****************************
: RStA RStP @ RStS 1- AND CELLS RStack + ; \ реальный адрес вершины
: RNOP RStA @ RStDO ! RStF TRUE! ; \ прочитать вершину стека возвратов
: RSWAP RNOP RStF @ IF PC @ 1+ ELSE RAD @ THEN RStA ! ; \ записать значение PC+1 или RAD в стек возвратов и счит. стар.вершину
: RPUSH RStP 1+! RSWAP RNOP ; \ записать новое значение в стек возвратов и считать новую вершину
: RPOP RStP 1-! RNOP ; \ снять со стека возвратов одно значение
\ **************************** \ работа со стеком данных \ ****************************
: DStA RStP @ DStS 1- AND CELLS DStack + ; \ реальный адрес вершины
: DNOP DStA @ DUP DStDO ! ; \ прочитать вершину стека возвратов
: DSWAP DNOP RAD @ DStA ! ; \ записать значение RAD в стек возвратов и считать старую вершину
: DPUSH DStP 1+! DSWAP DNOP ; \ записать значение RAD в стек возвратов и считать новую вершину
: DPOP DStP 1-! DNOP ; \ снять со стека возвратов одно значение
\ **************************** \ работа с RAD
: >RAD RADF @ IF RStDO ELSE DStDO THEN @ RAD ! RADF FALSE! ; : ALU>RAD ; \ ALU-операция : nRAD ; \ ничего не делать с RAD
\ **************************** \ команды-команды-команды \ ****************************
\ 0 - nop : nop RdCMD RNOP DNOP nRAD ; \ 1 - call : call MPC@ PC++ RPUSH PC ! nop ; \ 2 - if : if GetLit RAD @ IF PC ! ELSE PC++ THEN nop ; \ 3 - lit : lit DPUSH GetLit RAD ! nop ; \ 4 - >R : >r RStF FALSE! RPUSH DPOP RADF FALSE! >RAD nop ; \ 5 - R> : r> RPOP DPUSH RADF TRUE! >RAD nop ; \ 6 - ret : ret RPOP RStDO @ PC ! nop ; \ 7 - dup : dup DPUSH >RAD nop ; \ 8 - drop : drop DPOP >RAD nop ; \ 9 - over : over DPOP DSWAP >RAD DPUSH DSWAP >RAD nop ; \ A - swap : swap DSWAP >RAD nop ; \ B - pre: : pre: nop ; \ C - user: : user: nop ; \ D - sys: : sys: nop ; \ E - fetch ( @ ) : fetch RPUSH RAD @ PC ! MPC@ RAD ! ret ; \ F - store ( ! ) : store RPUSH RAD @ PC ! DPOP >RAD MPC! ret ;
\ ******************************
: CMD@ CMD @ 0F AND ; \ читать регистр команды
\ переопределение дешифрации команд через таблицу 10 таблица CMD-TAB nop call if lit >r r> ret dup drop over swap pre: user: sys: fetch store
: STEP CMD@ CMD-TAB ;
\ рабочий цикл : pp CLS 0 0 AT-XY S" [ESC] - выход" TYPE OUTMST CR BEGIN 100 PAUSE OUTST STEP KEY? IF KEY 1B = IF EXIT THEN THEN AGAIN ;
pp
\ 1000 PAUSE
\ BYE
Сюда буду сливать последний вариант кода,
пока он помещается в форумный формат
[code] \ ForthCPU/VM emulator by WingLion
\ сначала доопределение Форта ~day\common\console.f
HEX CLS 0 0 AT-XY
\ закройте глаза и не читайте следующие 3-4 строчки! \ почему в SPF нет слова H. - не знаю
: H. BASE @ SWAP HEX S>D <# # # # # # # # # #> TYPE SPACE BASE ! ;
: FALSE! FALSE SWAP ! ; : TRUE! TRUE SWAP ! ; \ : 1+! 1 +! ; \ эта команда и так есть : 1-! -1 +! ; \ а этой в SPF не оказалось
\ по подсказке ygrek-a (нужно для многострочного определения таблицы ) : NEXT-NAME BEGIN PARSE-NAME DUP 0= WHILE 2DROP REFILL 0= THROW REPEAT ;
\ ******************** \ тиснутое у ~profit-a и перековырянное определениe для таблиц : нифига \ вспоможитель ." Команда выполнила невыполнимую операцию и будет отшлепана по заднице! " CR ; : таблица ( число-случаев "имя" -- ) CREATE DUP 1+ , \ кол-во случаев плюс один \ HERE TO текущее-состояние 0 DO NEXT-NAME ['] ' EVALUATE-WITH , LOOP \ 0 DO ' , LOOP \ сразу скомпилировать все слова в таблицу \ если слов при определении таблицы окажется меньше - полезут глюки ['] нифига DUP , , \ действие по-умолчанию, \ для случаев номера которых превышают кол-во состояний \ два раза потому что с одним вылазит accec violation :-\ DOES> DUP @ ROT MIN 1+ CELLS + @ EXECUTE ;
\ тупая проверка : действие0 ." действие0" CR ; : действие1 ." действие1" CR ; : действие2 ." действие2" CR ; 5 таблица тупая-проверка действие0 действие1 действие2 действие2 нифига
0 DUP . тупая-проверка 1 DUP . тупая-проверка 2 DUP . тупая-проверка 3 DUP . тупая-проверка 4 DUP . тупая-проверка F DUP . тупая-проверка
\ остановиться и поглядеть KEY \ BYE
\ 5 таблица TEST TRUE FALSE TRUE FALSE TRUE FALSE \ 1 TEST . CR \ должно напечатать 2 \ 5 TEST . CR \ должно напечатать 11 \ KEY \ ждать клавишу \ BYE
\ *********************** ну, привык я юзать звездюлины как разделители \ теперь определения для ВМ
\ глобальные параметры 1000 CONSTANT MemSize \ размер памяти ВМ (в байтах) 10 CONSTANT DStS \ глубина стека данных (в словах) 10 CONSTANT RStS \ глубина стека возвратов (в словах)
\ блоки ВМ VARIABLE PC \ счетчик команд VARIABLE RAD \ регистр адреса/данных VARIABLE CMD \ регистр команды VARIABLE RADF \ флаг входного мультиплексора для RAD \ TRUE - RStack -> RAD \ FALSE - DStack ->RAD VARIABLE RStF \ флаг входного мультиплексора для RStack \ TRUE - PC+1 ->RStack \ FALSE - RAD ->RStack
VARIABLE DStP \ поинтер D-стека CREATE DStack DStS CELLS ALLOT \ стек данных VARIABLE DStDO \ текущая вершина стека данных (вых. регистр стека)
VARIABLE RStP \ поинтер R-стека CREATE RStack RStS CELLS ALLOT \ стек возвратов VARIABLE RStDO \ текущая вершина стека возвратов (вых. регистр стека)
CREATE MEM MemSize ALLOT \ память ВМ MemSize 1- CONSTANT MASK \ ограничитель памяти ВМ
\ ****************************
: -1OO! 1- OVER OVER C! NIP ; : init_MEM MEM MemSize ERASE
\ микро-DUMP памяти ВМ
00 00 00 00 \ nop nop 01 10 00 00 00 \ call 0010 03 55 AA 00 00 \ lit AA55 00 00 \ nop nop 01 08 00 00 00 \ call 0008
MEM 15 + 15 0 DO -1OO! LOOP
\ 10 0 DO I DUP MEM + C! LOOP ;
: reset PC 0! DStP 0! RStP 0! RADF FALSE! RStF TRUE! ;
reset init_MEM
\ ****************************
: OUTMST \ вывод состояния стеков и памяти CR ." DataStack:" DStP @ H. DStack 8 DUMP CR ." RetStack:" RStP @ H. RStack 8 DUMP CR \ память CR ." Memory:" CR MEM 40 DUMP ;
: OUTSTR \ вывод состояния регистров \ регистры \ 0 0 AT-XY CR ." PC: " PC @ H. \ счетчик команд ." RAD " RAD @ H. \ регистр адреса/данных ." CMD " CMD @ H. \ регистр команды ." DSt " DStDO @ H. \ Вершина стека данных ." RSt " RStDO @ H. \ Вершина стека возвратов ;
: OUTST \ вывод состояния ВМ \ 0 0 AT-XY OUTSTR \ OUTMST ;
\ **************************** \ Работа ВМ \ **************************** \ вспоможители : PC++ PC 1+! ; : MPC@ MEM PC @ MASK AND + @ ; \ читать данные из памяти ВМ по адресу PC -- МЕМ(PC) : MPC! MEM PC @ MASK AND + RAD @ SWAP ! ; \ записать данные из RAD по адресу в PC \ тут еще разбираться с шириной данных ВМ
: GetLit MPC@ PC @ 4 + PC ! ; \ получить литерал : RdCMD MPC@ CMD C! PC++ ; \ читать команду \ тут может быть и какая-нибудь распаковка и доп. чтение-вперед
\ **************************** \ работа со стеком возвратов \ ****************************
: RStA RStP @ RStS 1- AND CELLS RStack + ; \ реальный адрес вершины
: RNOP RStA @ RStDO ! RStF TRUE! ; \ прочитать вершину стека возвратов
: RSWAP RNOP RStF @ IF PC @ 1+ ELSE RAD @ THEN RStA ! ; \ записать значение PC+1 или RAD в стек возвратов и счит. стар.вершину
: RPUSH RStP 1+! RSWAP RNOP ; \ записать новое значение в стек возвратов и считать новую вершину
: RPOP RStP 1-! RNOP ; \ снять со стека возвратов одно значение
\ **************************** \ работа со стеком данных \ ****************************
: DStA RStP @ DStS 1- AND CELLS DStack + ; \ реальный адрес вершины
: DNOP DStA @ DUP DStDO ! ; \ прочитать вершину стека возвратов
: DSWAP DNOP RAD @ DStA ! ; \ записать значение RAD в стек возвратов и считать старую вершину
: DPUSH DStP 1+! DSWAP DNOP ; \ записать значение RAD в стек возвратов и считать новую вершину
: DPOP DStP 1-! DNOP ; \ снять со стека возвратов одно значение
\ **************************** \ работа с RAD
: >RAD RADF @ IF RStDO ELSE DStDO THEN @ RAD ! RADF FALSE! ; : ALU>RAD ; \ ALU-операция : nRAD ; \ ничего не делать с RAD
\ **************************** \ команды-команды-команды \ ****************************
\ 0 - nop : nop RdCMD RNOP DNOP nRAD ; \ 1 - call : call MPC@ PC++ RPUSH PC ! nop ; \ 2 - if : if GetLit RAD @ IF PC ! ELSE PC++ THEN nop ; \ 3 - lit : lit DPUSH GetLit RAD ! nop ; \ 4 - >R : >r RStF FALSE! RPUSH DPOP RADF FALSE! >RAD nop ; \ 5 - R> : r> RPOP DPUSH RADF TRUE! >RAD nop ; \ 6 - ret : ret RPOP RStDO @ PC ! nop ; \ 7 - dup : dup DPUSH >RAD nop ; \ 8 - drop : drop DPOP >RAD nop ; \ 9 - over : over DPOP DSWAP >RAD DPUSH DSWAP >RAD nop ; \ A - swap : swap DSWAP >RAD nop ; \ B - pre: : pre: nop ; \ C - user: : user: nop ; \ D - sys: : sys: nop ; \ E - fetch ( @ ) : fetch RPUSH RAD @ PC ! MPC@ RAD ! ret ; \ F - store ( ! ) : store RPUSH RAD @ PC ! DPOP >RAD MPC! ret ;
\ ******************************
: CMD@ CMD @ 0F AND ; \ читать регистр команды
\ переопределение дешифрации команд через таблицу 10 таблица CMD-TAB nop call if lit >r r> ret dup drop over swap pre: user: sys: fetch store
: STEP CMD@ CMD-TAB ;
\ рабочий цикл : pp CLS 0 0 AT-XY S" [ESC] - выход" TYPE OUTMST CR BEGIN 100 PAUSE OUTST STEP KEY? IF KEY 1B = IF EXIT THEN THEN AGAIN ;
pp
\ 1000 PAUSE
\ BYE [/code]
Сюда буду сливать последний вариант кода,
пока он помещается в форумный формат
|
|
|
|
Добавлено: Сб май 19, 2007 21:29 |
|
|
|
|