Forth и другие саморасширяющиеся системы программирования Locations of visitors to this page
Текущее время: Чт мар 28, 2024 13:33

...
Google Search
Forth-FAQ Spy Grafic

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




Начать новую тему Ответить на тему  [ Сообщений: 13 ] 
Автор Сообщение
 Заголовок сообщения: Портирование форта. Изучение вариантов построения Форт-ядра.
СообщениеДобавлено: Пт сен 04, 2009 16:32 
Не в сети
Moderator
Moderator
Аватара пользователя

Зарегистрирован: Чт май 04, 2006 00:53
Сообщения: 5062
Откуда: был Крым, теперь Новосибирск
Благодарил (а): 23 раз.
Поблагодарили: 63 раз.
Автор: Бред Родригес
Дата публикации: 1993
оригинал статьи взят MOVING FORTH
Перевел: mOleg

Портирование Форта. часть 2.

Изучение производительности.
Теперь посмотрим, какой ответ на каждый вопрос проектирования даст кодирование.
Понятно, вы не хотите писать одно ядро различными методами только для оценки различных методик. К счастью вы можете получить очень хорошее «ощущение» на очень малом наборе слов Форт-ядра.

Гай Келли [KEL92] рассматривал следующие 19 примитивов для 19 различных Фортов на IBM-PC.

NEXT … «адресный интерпретатор» который связывает слова в определении. Он используется в конце каждого низкоуровневого определения, и является одним из наиболее важных факторов, определяющих скорость работы Форт-системы. Вы уже видели псевдокод для него в косвенном, прямом шитом кодах (в подпрограммном коде его роль исполняет пара машинных команд CALL и RETURN).

ENTER ... так же называемый DOCOL или DOCOLON; действие поля кода, позволяющее исполняться двоеточному высокоуровневому определению. Это тоже критично для скорости исполнения, так как используется в начале каждого двоеточного определения. Не нужно для подпрограммного ШК.

EXIT ... называемый ;S в fig-Forth; код, завершающий исполнение высокоуровневого определения. Это, по сути, высокоуровневый возврат из подпрограммы, и он встречается в каждом двоеточном определении. В подпрограммном ШК это лишь машинная команда RET.

NEXT, ENTER, и EXIT определяют производительность механизма адресного интерпретатора. Они должны быть закодированы для оценки эффективности работы косвенного, прямого и подпрограммного шитых кодов. Они так же отображают эффективность вашего распределения регистров IP, W, и RSP для используемого процессора.

DOVAR ...так же известный как "variable" - фрагмент машинного кода, который определяет работу поля кода для всех переменных в Форте.

DOCON ...так же исзвестный как "constant" - фрагмент машинного кода, определяющий работу поля кода для всех констант.

DOCON и DOVAR вместе с ENTER показывают эффективность работы с полем параметров исполнимого слова. Это отражает удачность вашего выбора регистра W. В системах с прямым ШК так же показывает что выгоднее использовать в поле кода JUMP или CALL.

LIT ... или «literal»; это Форт слово извлекает значение, хранимое в ячейке памяти, находящейся сразу за LIT. Различные слова используют такие данные в коде, и это слово хорошо показывает их эффективность. Это так же показывает удачность выбора регистра IP.

@ … оператор извлечения данных, показывает на сколько быстро ведется работа с памятью системы из выскоуровневых определений. Это слово обычно показывает на сколько выгодно реализована работа с TOS.

! ... оператор сохранения данных в памяти, другой индикатор эффективности работы с памятью. Он потребляет два значения со стека, и показывает эффективность работы со стеком данных. Это хороший индикатор для выбора местоположения виртуального регистра TOS (в памяти либо в регистре процессора).

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

Это прекрасный выбор фрагментов шитого кода. От себя добавлю несколько своих любимцев:

DODOES ... действие поля кода слов, построенных с помощью конструкции CREATE DOES> . Этот код не сильно влияет на скорость работы системы, но может показать эффективность расположения виртуальных регистров: W, IP, RSP. Я его добавляю потому что это самый необычный код в ядре Форт-системы. Если вы можете, набросайте код DODOES . Запутанность DODOES будет развеяна в следующей части статьи.

SWAP ... простой стековый оператор, но тем не менее учебный.

OVER ... более сложный стековый оператор. Показывает вам, на сколько легко вы можете работать со стеком данных.

ROT ... еще более сложный стековый оператор, и скорее всего вам потребуется дополнительный временный регистр для его реализации. Если же вам удастся обойтись без временного регистра, вам скорее всего вообще не нужен регистр X .

0= ... один из немногих однопараметрических арифметических операторов, и скорее всего показывает выгодность выбора регистра для TOS.

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

Перечисленные слова наиболее часто используются в Форт-ядре. Оптимизация их работы себя оправдывает. Я покажу примеры для всех перечисленных слов, включая псевдокод для процессора 6809, для остальных процессоров я буду использовать только избранные примеры для отражения специфических особенностей реализации.

Первый вариант: Motorola 6809
В мире 8-и битных процессоров 6809 – мечта Форт программистов. Он поддерживает два стека! Он так же имеет два других адресных регистра, и богатство ортогональных режимов адресации («ортогональный» означает, работающий одинаково и имеющий одинаковые опции для всех адресных регистров). Два 8-и битных аккумулятора могут рассматриваться как один 16-битный аккумулятор, так же имеется много 16-битных операций.

Программная модель 6809 следующая [MOT83]:

A – 8 битный аккумулятор
B – 8 битный аккумулятор

Большинство арифметических операций используют аккумулятор как приемник. А и В могут быть объединены и рассматриваться как один 16битный аккумулятор D (A- старший разряд, а В – младший).

X - 16 битный индексный регистр
Y - 16 битный индексный регистр
S - 16 битный указатель стека
U - 16 битный указатель стека

Все адресные режимы для X и Y так же могут использоваться с регистрами S и U.

PC - 16 битный счетчик команд
CC - 8 битный регистр условий
DP - 8 битный страничный регистр

Режим прямой адресации в 6800 ветке процессоров использует 8-битный адрес для работы с нулевой страницей памяти. 6809 позволяет прямо адресовать любую страницу памяти, регистр DP хранит старшие 8 бит адреса.

Два регистра указателя стека просятся для Форта. Они похожи, за исключением того, что S используется для подпрограммных вызовов и прерываний. Давайте будем последовательны, и будем использовать S для хранения адресов возвратов, оставив U для стека данных.

W и IP оба должны быть адресными регистрами, таким образом, логично использовать Х и Y для этих целей. Х и Y эквивалентны, поэтому давайте своевольно договоримся: X=W и Y = IP.

Теперь должна быть выбрана модель адресной интерпретации. Я набросаю прямой и косвенный ШК чтобы получить традиционный Форт. Лимитирующий быстродействие фактор – подпрограмма NEXT. Давайте посмотрим на оба его варианта в прямом и косвенном ШК:
<pre>
ITC-NEXT: LDX ,Y++ (8) (IP)->W, увеличить IP
JMP [,X] (6) (W)->temp, перейти на адрес, хранимый в temp

DTC-NEXT: JMP [,Y++] (9) (IP)->temp, увеличить IP,
Выполнить переход на адрес, хранимый в temp ("temp" внутри 6809)
</pre>
NEXT на 6809 в прямом ШК реализуется с помощью единственной машинной команды! Это означает, что вы можете кодировать его в виде двухбайтовых вставок маш.кода, что одновременно и быстрее и меньше, чем JMP NEXT. Для сравнения посмотрите на логику работы NEXT для подпрограммного ШК:
<pre>
RTS (5) ... в конце низкоуровневого слова
JSR nextword (8) ... в цепочке
... ... начало следующего низкоуровневого слова
</pre>
В подпрограммном ШК переход на следующее слово в определении занимает 13 тактов, по сравнению с 9-ю тактами в прямом ШК. Это потому что подпрограммный ШК постоянно сохраняет и восстанавливает адреса возвратов на стеке, в то время как простой прямой или косвенный ШК в пределах одного определения этого не делают.

Сделав выбор в пользу прямого ШК, вы должны решиться, должен ли вызываться высокоуровневый код с помощью машинной команды CALL или JUMP в его поле кода.
Направляющее размышление – как быстро вы можете получить адрес поля параметров, следующего за кодом. Давайте посмотрим на код для входа в двоеточное определение, используя символические имена виртуальных Форт-регистов:

С использованием JSR (Call):
<pre>
JSR ENTER (8)
...
ENTER: PULS W (7) получить адрес следующий за JSR в регистр W
PSHS IP (7) сохранить старое значение IP на стеке возвратов
TFR W,IP (6) адрес поля параметров => IP
NEXT (9) ассемблерное макро для JMP [,Y++]
37 всего циклов
</pre>
С использованием JMP:
<pre>
JMP ENTER (4)
...
ENTER: PSHS IP (7) сохранить старый IP на вершину стека возвратов
LDX -2,IP (6) повторно извлечь адрес поля кода
LEAY 3,X (5) добавить 3 и положить в регистр IP (Y)
NEXT (9)
31 циклов всего

(в скобках отражается количество циклов процессора на исполнение команды)
</pre>
NEXT на 6809 процессоре в прямом ШК не требует существования регистра W: имеются режимы косвенной адресации. Версия ENTER с использованием JMP должна повторно перечитать адрес поля кода, так как NEXT не оставляет его ни в одном из регистров, и затем добавить 3, чтобы получить адрес поля параметров. JSR версия может получать адрес поля параметров напрямую за счет извлечения адреса с вершины стека возвратов. Даже при этих условиях JMP версия быстрее. (Пример для студентов: попытайтесь написать JSR ENTER при условии S=PSP и U=RSP.)


В любом случае код слова EXIT одинаковый:
<pre>
EXIT: PULS IP вытолкнуть старое значение IP со стека возвратов
NEXT продолжить адресную интерпретацию
</pre>
Осталось зафиксировать несколько регистров. Вы можете хранить указатель на пользовательскую область (UP) в памяти, и этот Форт будет оставаться достаточно быстр.
Но тогда останется неиспользованный регистр “DP”, который больше не на что использовать. Давайте, используем описанный выше трюк, и будем хранить старший байт UP в регистре “DP”. Подразумевается, что младший байт регистра UP сброшен в нуль.

Остается один 16-битный регистр: “D” Большинство арифметических операций работают с ним. Стоит ли его использовать как временный регистр, либо кэшировать в нем TOS? 6809 команды используют память как операнд, таким образом второй рабочий регистр не обязателен. И если временный регистр необходим, легко сохранять “D” в стеке. Давайте напишем тестовые примитивы для обоих вариантов и посмотрим какой быстрее.

NEXT, ENTER, и EXIT не используют стек данных, и поэтому выглядят одинаково в любом случае.

DOVAR, DOCON, LIT, и OVER требуют одинаковое количество циклов процессора в любом случае. Следующее иллюстрирует, что хранение TOS в регистре часто только меняет место, где встретится команда PUSH или POP :
<pre>
TOS в D TOS в памяти псевдокод

DOVAR: PSHU TOS LDD -2,IP адрес поля кода => D
LDD -2,IP ADDD #3 адрес поля параметров => D
ADDD #3 PSHU D поместить D на вершину стека
NEXT NEXT

DOCON: PSHU TOS LDX -2,IP адрес поля кода => W
LDX -2,IP LDD 3,X содержимое поля параметров => D
LDD 3,X PSHU D вытолкнуть D в стек даных
NEXT NEXT

LIT: PSHU TOS LDD ,IP++ (IP) => D, увеличить IP
LDD ,IP++ PSHU D вытолкнуть D в стек даных
NEXT NEXT

OVER: PSHU D LDD 2,PSP второй элемент стека данных => D
LDD 2,PSP PSHU D вытолкнуть D в стек даных
NEXT NEXT
</pre>
SWAP, ROT, 0=, @, и особенно + всегда быстрее, если TOS находится в регистре:
<pre>
TOS в D TOS в памяти псевдокод

SWAP: LDX ,PSP (5) LDD ,PSP (5) TOS => D
STD ,PSP (5) LDX 2,PSP (6) второй элемент стека данных => X
TFR X,D (6) STD 2,PSP (6) D => во второй элемент стека
NEXT STX ,PSP (5) X => TOS
NEXT

ROT: LDX ,PSP (5) LDX ,PSP (5) TOS => X
STD ,PSP (5) LDD 2,PSP (6) второй со стека данных => D
LDD 2,PSP (6) STX 2,PSP (6) X => второй на стек
STX 2,PSP (6) LDX 4,PSP (6) третий со стека => X
NEXT STD 4,PSP (6) D => третий на стек
STX ,PSP (5) X => TOS
NEXT

0=: CMPD #0 LDD ,PSP TOS => D
BEQ TRUE CMPD #0 D равно нулю?
BEQ TRUE
FALSE: LDD #0 LDD #0 нет, = положить 0 в TOS
NEXT STD ,PSP
NEXT
TRUE: LDD #-1 LDD #-1 да, = положить -1 в TOS
NEXT STD ,PSP
NEXT

@: TFR TOS,W (6) LDD [,PSP] (8) извлечь D используя адрес в TOS
LDD ,W (5) STD ,PSP (5) D => TOS
NEXT NEXT

+: ADDD ,U++ PULU D вытолкнуть TOS в D
NEXT ADDD ,PSP добавить новый TOS к D
STD ,PSP сохранить D в TOS
NEXT
</pre>
! и +! медленнее работают в случае хранения TOS в регистре процессора:
<pre>
TOS в D TOS в памяти псевдокод

!: TFR TOS,W (6) PULU W (7) вытолкнуть адрес в W
PULU D (7) PULU D (7) вытолкнуть данные в D
STD ,W (5) STD ,W (5) сохранить данные по адресу
PULU TOS (7) NEXT
NEXT

+!: TFR TOS,W (6) PULU W (7) вытолкнуть адрес в W
PULU TOS (7) PULU D (7) вытолкнуть данные в D
ADDD ,W (6) ADDD ,W (6) добавить к D содержимое памяти
STD ,W (5) STD ,W (5) сохранить D в память
PULU TOS (7) NEXT
NEXT
</pre>
Причина медленности этих слов заключается в том, что они ожидают адрес на вершине стека данных, поэтому нужна дополнительная инструкция TFR. Поэтому удобно если TOS является адресным регистром. К сожалению, все адресные регистры 6809 процессора обсуждались, и более важно хранить W, IP, PSP, и RSP в них, чем TOS. Пенальти от размещения TOS в регистре процессора для операций ! +! будет перевешиваться выигрышем от множества арифметических и логических стековых операций.

Второй вариант: Intel 8051
Если 6809 это процессор мечты для Фортописателей, 8051 – кошмар. Он имеет только один адресный регистр общего назначения, и один режим адресации, который всегда использует 8-битный аккумулятор.

Все арифметические операции и много логических должны использовать аккумулятор. Есть только одна 16-битная операция INC DPTR. Аппаратный стек должен использовать 128-байтный накристальный файловый регистр. Такой процессор может вызвать язву [SIG92].

Некоторые 8051 Форты используют 16-битную модель [PAY90], но они на мой вкус слишком неторопливы. Давайте сделаем некоторые компромиссы и сделаем более быстрый Форт для 8051 процессора.

У нас есть только один адресный регистр. Поэтому давайте использовать в качестве счетчика команд родной регистр IP 8051 процессора, и выберем подпрограммный ШК. Если компилятор использует двухбайтные ACALL вместо трехбайтных LCALL-ов везде, где это возможно, большинство подпрограммного ШК будет занимать так же мало места, как и в случае с прямым и косвенным ШК.

Подпрограммный ШК предполагает, что в качестве указателя вершины стека возвратов используется аппаратный указатель стека. В 8051 64 ячейки пространства в накристальном регистровом файле, не достаточно места для хранения стеков в многозадачной системе. Поэтому вы можете:
a) ограничиться однозадачной Форт-системой;
b) писать таким образом все Форт-слова, что во время вызова они сохраняют адрес возврата в программный стек в ОЗУ; или
c) делать переключения задач с сохранением стека возвратов во внешнее ОЗУ.

Вариант b медленный! Перенос 128 байт при каждом переключении задач будет быстрее пересылки двух байт для каждого Форт-слова. Поэтому выберем вариант “a”, оставив открытой дверь для варианта “c” на будущее.

Один единственный действительно адресный регистр DPTR будет использоваться для многочисленных нужд. Он будет многоцелевым рабочим регистром W.

По правде, существует два других регистра, позволяющих адресовать внешнюю память: R0 и R1. Они работают только с 8битными адресами, старшие 8 бит явно выводятся в port 2. Но это допустимое ограничение для стеков, теперь они будут ограничены пространством в 256 байт. Давайте будем использовать R0 как указатель стека данных(PSP).

Это 256-байтное пространство может быть использовано под пользовательскую область.
Это делает P2 (второй порт) вторым байтом UP, и, подобно 6809, младший байт будет всегда нулем.

Так какая же программная модель на 8051 у нас получилась?
<pre>
Адрес имя назначение использования

0 R0 младший байт регистра PSP
1 R1
2 R2
3 R3
4 R4
5 R5
6 R6
7 R7
8-7Fh 120 байт стека возвратов
81h SP младший байт стека возвратов RSP (старший=00)
82-83h DPTR рабочий регистр W
A0h P2 старший байт регистров UP и PSP
E0h A
F0h B
</pre>
Замечу, что используется только нулевой регистровый банк. Дополнительные три регистровых банка с 08h по 1Fh, и побитно-адресуемый регион с 20h по 2Fh не используются в Форте. Использование нулевого банка оставляет наибольшее непрерывное пространство для стека возвратов. Позднее стек возвратов может быть уменьшен, если необходимо.

Подпрограммы NEXT, ENTER и EXIT не нужны на Форте с подпрограммным ШК.

Что насчет вершины стека данных? Регистров хватает, а операции с памятью на 8051 накладные. Давайте поместим TOS в R3:R2 (R3- старший байт на Интеловский манер).
Заметим, что B:A не будет использоваться – регистр А канал через который вся доступная память адресуется!

Гарвардские архитектуры
8051 использует Гарвардскую архитектуру: программа и данные хранятся в раздельных адресных пространствах. (Z8 и TMS320 два других примера.) 8051 – дегенеративный случай: нет физической возможности писать в память программ!
Это означает, что Фортописатель должен сделать одно из двух:

А) делать кросскомпиляцию всего, включая приложение, и распрощаться с надеждой на интерактивный Форт на 8051; или

b) отразить частично или полностью память программ в пространстве данных. Простейший путь – сделать полное перекрытие пространств с помощью внешнего «ИЛИ» над сигналами PSEN* и RD*.

Z8 и TMS320C25 более цивилизованные: они позволяют писать в память программ.

Третий вариант: Zilog Z80
Вариант Z80 очень полезный, потому что это экстремальный пример неортогонального процессора. Он имеет четыре различных вида адресных регистров! Некоторые операции используют A как приемник, другие - 8-битные регистры, третьи – HL, остальные любой 16-битный регистр… Много операций (подобных EX DE, HL ) определены только для одной комбинации регистров.

На подобных процессорах (Z80 или 8086), назначение Форт-функций должно быть осторожно сопоставлено с возможностями регистров. Необходимо рассмотреть множество альтернатив, и часто единственный путь – писать наброски кода для различных вариантов решений. Вместо рассмотрения бесконечных вариантов Форт-кода, я представлю одно распределение регистров, основанное на большом количестве экспериментов. Базовые принципы выбора я уже описал ранее.

Я хочу традиционный Форт, хотя я буду использовать прямой ШК. Все «классические» виртуальные регистры будут необходимы.

Игнорирую альтернативный набор регистров, Z80 имеет шесть адресных регистров со следующими возможностями:

BC,DE - LD A косвенно, INC, DEC
так же обмен DE/HL

HL - LD r косвенный, ALU косвенно, INC, DEC, ADD, ADC,
SBC, обмен с TOS, косвенный переход (JP)

IX,IY - LD r индексированный, ALU индексно, INC, DEC, ADD, ADC,
SBC, обмен с TOS, JP косвенно (все медленно)

SP - PUSH/POP 16-бит, ADD/ADC/SUB с HL/IX/IY

BC, DE, и HL так же могут модифицироваться 8битными кусками.

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

HL несомненно наиболее многоцелевой регистр он может использоваться как любой из Форт-виртуальных регистров. В любом случае, из-за того, что это единственный регистр позволяющий делать косвенный переход, HL должен использоваться как W (рабочий многоцелевой регистр).

IX и IY можно использовать как указатели стеков за счет их индексных режимов адресации, которые могут использоваться совместно с арифметическими операциями. Но возникает две проблемы: SP остается без работы, и IX/IY очень медленные! Большинство операций на обоих стеках производится над 16-битными числами. Это одна операция с использованием SP, но это требует четыре операции с использованием IX/IY. Один из Форт стеков будет использовать SP. И это должен быть стек данных, так как он используется более активно, нежели стек возвратов.

Что насчет Фортового IP? В основном IP извлекается из памяти и инкрементируется, поэтому нету преимуществ в использовании IX/IY вместо BC/DE. Но скорость существенна для IP, и BC/DE быстрее. Давайте поместим IP в DE : это имеет преимущество, так как DE может обмениваться с HL, что добавляет гибкости.

Вторая регистровая пара Z80 (в дополнение к W) будет нужна для 16-битной арифметики. Остается только BC, и он может использоваться для работы совместно с A в арифметических операциях. Но должен ли BC быть вторым рабочим регистром «Х» или вершиной стека? Только код может ответить, поэтому сейчас давайте оптимистично договоримся что BC = TOS.

Остаются несогласованными RSP и UP, а IX и IY не использованы. А раз IX и IY эквивалентны, пусть IX=RSP, а IY=UP.

Таким образом, соглашение по использованию регистров Z80 следующие:
<pre>
BC = TOS IX = RSP
DE = IP IY = UP
HL = W SP = PSP
</pre>
Теперь давайте посмотрим на NEXT для прямого ШК:
<pre>
DTC-NEXT: LD A,(DE) (7) (IP)->W, увеличить IP
LD L,A (4)
INC DE (6)
LD A,(DE) (7)
LD H,A (4)
INC DE (6)
JP (HL) (4) перейти на адрес, хранящийся в W
</pre>
Альтернативная версия (такое же число тактовых циклов)
<pre>
DTC-NEXT: EX DE,HL (4) (IP)->W, увеличить IP
NEXT-HL: LD E,(HL) (7)
INC HL (6)
LD D,(HL) (7)
INC HL (6)
EX DE,HL (4)
JP (HL) (4) перейти на адрес, хранимый в W
</pre>
Заметка: ячейки хранятся в обратном порядке, когда младший байт находится ближе к началу памяти. Так же, хотя может казаться выгодным хранить IP в HL, это не так потому что Z80 не может выполнять JP (DE). Использовать NEXT-HL будет короче.

Только для сравнения, давайте посмотрим на реализацию NEXT с использованием косвенного ШК. Приведенный ранее псевдокод требует наличия еще одного временного регистра «Х», содержимое которого может использоваться в косвенном переходе. Возьмем DE=X, а BC=IP, TOS будет храниться в ОЗУ.
<pre>
ITC-NEXT: LD A,(BC) (7) (IP)->W, увеличить IP
LD L,A (4)
INC BC (6)
LD A,(BC) (7)
LD H,A (4)
INC BC (6)

LD E,(HL) (7) (W)->X
INC HL (6)
LD D,(HL) (7)
EX DE,HL (4) перейти на адрес в X
JP (HL) (4)
</pre>
NEXT в прямом ШК имеет длину в 7 инструкций по сравнению с косвенным ШК, длиной в 11 инструкций. И косвенный ШК на Z80 теряет возможность хранить TOS в регистре. Мой выбор прямой ШК.

В случае использования прямого ШК в виде инлайн вставок код будет занимать по семь байт на слово. Переход на общий NEXT будет занимать только три байта, но это будет занимать дополнительные 10 тактовых циклов времени. Это другое компромиссное решение при создании ядра Форт-системы. Давайте выберем более быстрый инлайн вариант адресного интерпретатора NEXT. Иногда NEXT имеет еще больший размер, или памяти уж больно мало, тогда будет оправдан переход на NEXT.

Теперь давайте посмотрим на код слова ENTER. Используется CALL для получения адреса поля параметров с вершины стека возвратов:
<pre>
CALL ENTER (17)
...
ENTER: DEC IX (10) затолкнуть старое значение IP на стек возвратов
LD (IX+0),D (19)
DEC IX (10)
LD (IX+0),E (19)
POP DE (10) адрес поля параметров => IP
NEXT (38) ассемблерное макро на 7 инструкций
</pre>
Быстрее выполнять POP HL, и затем использовать последующие шесть инструкций NEXT
(минуя EX DE,HL):
<pre>
CALL ENTER (17)
...
ENTER: DEC IX (10) затолкнуть старое значение IP на стек возвратов
LD (IX+0),D (19)
DEC IX (10)
LD (IX+0),E (19)
POP HL (10) адрес поля параметров => HL
NEXT-HL (34) смотрите выше код NEXT для прямого ШК
119 всего циклов
</pre>
Когда используется JP, регистр W (HL) продолжает указывать на поле кода, а поле параметров находится на три байта дальше:
<pre>
JP ENTER (10)
...
ENTER: DEC IX (10) затолкнуть старое значение IP на стек возвратов
LD (IX+0),D (19)
DEC IX (10)
LD (IX+0),E (19)
INC HL ( 6) адрес поля параметров => IP
INC HL ( 6)
INC HL ( 6)
NEXT-HL (34)
120 циклов всего
</pre>
Итак, за счет альтернативной точки входа в NEXT , новое значение для IP не должно засылаться в регистровую пару DE.

Версия с CALL быстрее на один цикл. На встраиваемых Z80 однобайтная машинная команда RST может дать выигрыш в размере кода и скорости исполнения. Эта возможность не доступна на многих персональных компьютерах на Z80.

Четвертый вариант: Intel 8086
I8086 – другой поучительный процессор. Вместо проектирования собственного варианта давайте взглянем на один из новых шараварных Фортов для IBM PC: Pygmy Forth [SER90].

Pygmy это Форт основанный на прямом шитом коде с хранением верхнего элемента стека данных в регистре. Использование регистров 8086 процессора следующее:
<pre>
AX = W DI = свободный
BX = TOS SI = IP
CX = свободный BP = RSP
DX = свободный SP = PSP
</pre>
Большинство i8086 Фортов использует регистр SI как указатель интерпретации IP, таким образом NEXT может быть написан с использованием машинной инструкции LODSW. В Pygmy NEXT (прямой ШК) выглядит так:
<pre>
NEXT: LODSW
JMP AX
</pre>
Это достаточно коротко для использования этого кода в виде инлайн вставок.

Высокоуровневые Форт –слова используют JMP (относительный) на их машинный код. Подпрограмма ENTER (называемая 'docol' в Pygmy) должна брать адрес поля параметров из W:
<pre>
ENTER: XCHG SP,BP
PUSH SI
XCHG SP,BP
ADD AX,3 aдрес поля параметров => IP
MOV SI,AX
NEXT
</pre>
Заметка: используйте XCHG для обмена двух указателей стека. Это позволяет использовать команды PUSH и POP для обоих стеков, что быстрее косвенного доступа.
<pre>
EXIT: XCHG SP,BP
POP SI
XCHG SP,BP
NEXT
</pre>
Сегментная модель
Pygmy – односегментный Форт. Весь код и данные содержатся в пределах единого 64Кбайтного сегмента. (это “tiny” модель в Турбо Си). Все стандарты Форта описывают модель в которой все хранится в едином адресном пространстве, доступном одними и теми же операциями чтения и записи.

Однако появляются IBM PC Форты, использующие множество сегментов – вплоть до пяти различных видов данных [KEL92,SEY89]. Пример:

CODE ... машинный код
LIST ... выскоуровневый код (определения слов)
HEAD ... заголовки для всех Форт-слов
STACK ...стек данных и стек возвратов
DATA ... переменные и пользовательские данные

Это позволяет PC Фортам отодвинуть 64Кбайтный предел памяти без накладок на реализацию 32-битного Форта на 16-битном процессоре. Реализация многосегментной модели находится за пределами этой статьи.

Оппа!
В моих дизайнерских решениях для 6809 в предыдущей части колоссальная ошибка. Это стало очевидно, когда я взялся кодировать слово EXECUTE. Execute вызывает исполнение Форт-слова, чей адрес находится на вершине стека данных (точнее: адрес компиляции, называемый адресом поля кода, находится на вершине стека данных). Это может быть любое Форт-слово, в том числе константа или переменная. Это отличается от обычного процесса адресной интерпретации, в котором адрес слова, которое надо исполнять хранится в IP.

В нашем прямом ШК для 6809 это легко может быть закодировано так:
<pre>
EXECUTE: TFR TOS,W положить исполнимый адрес слова в регистр W
PULU TOS извлечь новое значение TOS со стека данных
JMP ,W перейти на адрес, хранимый в W
</pre>
Заметка: это JMP ,W а не JMP [,W], так как мы уже имеем адрес поля кода слова. Мы не извлекаем этот адрес из шитого кода. Если TOS не в регистре, EXECUTE может быть выполнено с помощью простого JMP [,PSP++].

Теперь, допустим, что это исполняемое слово определено через двоеточие, а W будет указывать на его поле кода, которое содержит JMP ENTER. Это приведет к следующему (описано выше):
<pre>
JMP ENTER
...
ENTER: PSHS IP
LDX -2,IP перечитать адрес поля кода
LEAY 3,X
NEXT
</pre>
Это ошибка! Мы не исполняем это слово изнутри ШК, и поэтому IP не указывает на копию адреса поля кода(помните, адрес исполняемого слова пришел со стека данных)! Этот вариант ENTER не будет работать совместно с EXECUTE, потому что нет возможности найти адрес исполнимого слова!

Это выдвигает новое важное правило для Фортов с прямым ШК: если NEXT не оставляет адрес исполнимого слова в регистре, вы должны использовать CALL в поле кода вызываемого слова.

Таким образом, в 6809 возвращаем использование JSR в поле кода. Но для избегания потери скорости для ENTER, который является одним из наиболее используемых фрагментов кода в Форте, я завершу «пример для студента» из начала этой статьи. Отметьте, что случается если вы обмениваете регистры назначенные для RSP и PSP.
<pre>
c RSP=S, c RSP=U,
и PSP=U и PSP=S
(старый) (новый)

JSR ENTER JSR ENTER
... ...
ENTER: PULS W PSHU IP затолкнуть старый IP на стек возвратов
PSHS IP PULS IP извлечь новый IP из стека данных
TFR W,IP NEXT
NEXT
</pre>
Новая версия исполняется за 31 цикл, столько же, сколько JMP версия, которую я хотел использовать. Улучшение, потому что JSR версия ENTER должна использовать и стек возвратов и 6809 подпрограммный стек возвратов. Использование двух различных стековых указателей означает, что мы не должны обменивать TOS с IP, убирается необходимость во временном регистре.

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

Это важный урок: набрасывайте EXECUTE в тестовый набор слов!

Оппа, опять
Карли Блудворт указал на незначительную, но досадную ошибку в моем 6809 коде. В версии с хранением вершины стека в памяти версия слова 0= , я приведу фрагмент кода
<pre>
LDD ,PSP
CMPD #0
</pre>
на тестирование вершины стека на равенство нулю. В этом случае CMPD инструкция лишняя, так как LDD инструкция установит zero флаг если D равен нулю (в случае варианта TOS в регистре D продолжает требовать CMPD инструкцию, но остается быстрее, чем TOS в памяти).

Литература:


[KEL92] Kelly, Guy M., "Forth Systems Comparisons," Forth Dimensions XIII:6 (Mar/Apr 1992). Also published in the 1991 FORML Conference Proceedings. Both available from the Forth Interest Group, P.O. Box 2154, Oakland, CA 94621. Illustrates design tradeoffs of many 8086 Forths with code fragments and benchmarks -- highly recommended!

[MOT83] Motorola Inc., 8-Bit Microprocessor and Peripheral Data, Motorola data book (1983).

[SIG92] Signetics Inc., 80C51-Based 8-Bit Microcontrollers, Signetics data book (1992).



Форт-системы

[PAY90] Payne, William H., Embedded Controller FORTH for the 8051 Family, Academic Press (1990), ISBN 0-12-547570-5. This is a complete "kit" for a 8051 Forth, including a metacompiler for the IBM PC. Hardcopy only; files can be downloaded from GEnie. Not for the novice!

[SER90] Sergeant, Frank, Pygmy Forth for the IBM PC, version 1.3 (1990). Distributed by the author, available from the Forth Interest Group. Version 1.4 is now available on GEnie, and worth the extra effort to obtain.

[SEY89] Seywerd, H., Elehew, W. R., and Caven, P., LOVE-83Forth for the IBM PC, version 1.20 (1989). A shareware Forth using a five-segment model. Contact Seywerd Associates, 265 Scarboro Cres., Scarborough, Ontario M1M 2J7 Canada.


Последний раз редактировалось mOleg Пт сен 04, 2009 17:47, всего редактировалось 3 раз(а).

Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Сб сен 05, 2009 21:38 
Не в сети
Аватара пользователя

Зарегистрирован: Чт июн 25, 2009 11:12
Сообщения: 412
Благодарил (а): 41 раз.
Поблагодарили: 8 раз.
Хорошие статьи, читал их еще по-английски. Оттуда узнал про Pygmy и очень этим фортом доволен.


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Сб окт 03, 2009 17:51 
Не в сети
Moderator
Moderator
Аватара пользователя

Зарегистрирован: Чт май 04, 2006 00:53
Сообщения: 5062
Откуда: был Крым, теперь Новосибирск
Благодарил (а): 23 раз.
Поблагодарили: 63 раз.
почти доперевел третью часть, так что в скорости выложу (правда с инетом пока затык, поэтому, скорее всего статья будет не отформатирована нормально)

_________________
Мне бы только мой крошечный вклад внести,
За короткую жизнь сплести
Хотя бы ниточку шёлка.
fleur


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Ср дек 02, 2009 19:59 
Не в сети

Зарегистрирован: Вт май 09, 2006 12:31
Сообщения: 3438
Благодарил (а): 5 раз.
Поблагодарили: 16 раз.
Примечательно в этой статье количество ошибок в таком простом коде. Я называю это "иллюзия простоты", которая свойственна ряду технологий программирования, и , видимо, форту в том числе. Автор не увидел ошибок сразу, т.к. считал рассмтриваемые алгоритмы простыми, о чём, кстати, прямо и говорит


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Ср дек 02, 2009 20:32 
Не в сети
Moderator
Moderator
Аватара пользователя

Зарегистрирован: Чт май 04, 2006 00:53
Сообщения: 5062
Откуда: был Крым, теперь Новосибирск
Благодарил (а): 23 раз.
Поблагодарили: 63 раз.
вопрос писал(а):
Примечательно в этой статье количество ошибок в таком простом коде.

Ну, как бы код и не такой простой, и факторов, которые нужно учесть при разработке ФВМ достаточно много, вполне достаточно для зевания ;)
Иллюзии тут никакой нет: чем больше параметров одновременно приходится рассматривать, тем сложнее все удержать в голове. Кстати эта особенность очень хорошо чувствуется в Форте, когда пытаешься писать слишком длинные определения.
Вобщем, простота простоте рознь!

_________________
Мне бы только мой крошечный вклад внести,
За короткую жизнь сплести
Хотя бы ниточку шёлка.
fleur


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Ср дек 02, 2009 20:56 
Не в сети

Зарегистрирован: Вт май 09, 2006 12:31
Сообщения: 3438
Благодарил (а): 5 раз.
Поблагодарили: 16 раз.
Цитата:
Иллюзии тут никакой нет: чем больше параметров одновременно приходится рассматривать, тем сложнее все удержать в голове.
Возражу - иллюзия простоты присутствует, но, может, не у всех в одном и том же случае. ОБнаружить её не так легко, впрочем, её проявления достаточно заметны: скажем, именно она вызывает заявления, что на форте можно в короткий срок реализовать другой язык программирования. Это иллюзия - реализация языка программирования - это реализация алгоритма компилятора, который, обладая определённой сложностью, не может быть реализован быстрее, чем ... может быть реализован код именно с этой самой сложноcтью


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Ср дек 02, 2009 21:10 
Не в сети
Moderator
Moderator
Аватара пользователя

Зарегистрирован: Чт май 04, 2006 00:53
Сообщения: 5062
Откуда: был Крым, теперь Новосибирск
Благодарил (а): 23 раз.
Поблагодарили: 63 раз.
вопрос писал(а):
Цитата:Иллюзии тут никакой нет: чем больше параметров одновременно приходится рассматривать, тем сложнее все удержать в голове. Возражу - иллюзия простоты присутствует, но, может, не у всех в одном и том же случае.

нуу, тут совсем не случай играет роль. Проблема лежит именно в плоскости правила Миллера (того самого, которое 7+-2). Собственно, это даже как бы не совсем проблема, потому что ошибки совершаются в первой стадии проекта - написание ФВМ и небольшого количества кода поверх нее, потом, во время отладки ошибки легко вылавливаются, потому что задача уже решается не для общего случая, а в конкретных частных моментах.

вопрос писал(а):
скажем, именно она вызывает заявления, что на форте можно в короткий срок реализовать другой язык программирования.

Ну, такие заявления много не стоят для любого языка, обращать на них смысла нет (как и на рыбака, разводящего руки в стороны). В реальности не так сложно написать другой ЯП, как обеспечить его работу в рамках спецификаций. То есть скилет действительно можно достаточно быстро накидать, но не более того.

вопрос писал(а):
Это иллюзия - реализация языка программирования - это реализация алгоритма компилятора, который, обладая определённой сложностью, не может быть реализован быстрее, чем ... может быть реализован код именно с этой самой сложноcтью

да, собственно сложность реализации задачи от языка слабо зависит (если только нет готового компонента). Но опять же, не стоит путать, к примеру, написание сишного компилятора (то есть системы распознающей Сишный синтаксис и структуру, и позволяющий получать готовый код) и написание оптимизатора (который будет генерить код, качество которого будет сопоставимо с другими Сишными оптимизаторами). Это разные задачи.

_________________
Мне бы только мой крошечный вклад внести,
За короткую жизнь сплести
Хотя бы ниточку шёлка.
fleur


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Ср дек 02, 2009 21:40 
Не в сети

Зарегистрирован: Вт май 09, 2006 12:31
Сообщения: 3438
Благодарил (а): 5 раз.
Поблагодарили: 16 раз.
Цитата:
да, собственно сложность реализации задачи от языка слабо зависит (если только нет готового компонента).
именно, и, следует признать, фортеров часто посещают мысли, что Форт - очень универсальный "готовый компонент", многого ли стоят заявления - другой вопрос, но они существуют.
Кстати, напомню, как долго мы решали простенькую и входящую в состав любого компилятора задачу перевода ин-пре-постфиксного порядка в строго постфиксный - это пример сложности.


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Ср дек 02, 2009 22:26 
Не в сети
Moderator
Moderator
Аватара пользователя

Зарегистрирован: Чт май 04, 2006 00:53
Сообщения: 5062
Откуда: был Крым, теперь Новосибирск
Благодарил (а): 23 раз.
Поблагодарили: 63 раз.
вопрос писал(а):
Цитата:да, собственно сложность реализации задачи от языка слабо зависит (если только нет готового компонента). именно, и, следует признать, фортеров часто посещают мысли, что Форт - очень универсальный "готовый компонент", многого ли стоят заявления - другой вопрос, но они существуют.

упс, тут как бы другой вопрос, имхо.
вот, есть несколько вариантов:
1) ты знаешь как решать задачу и одинаково хорошо знаешь два языка программирования
2) ты знаешь задачу, и хорошо знаешь только один ЯП
3) ты не знаешь как решать задачу но знаешь два ЯП
4) ты не знаешь как решать задачу, и хорошо знаешь только один ЯП
5) ты не знаешь как решать задачу, но у тебя под рукой много либ
и т.д. то есть сравнить не так просто (на нетривиальных задачах), к тому же у каждого программиста есть собственный "потолок" и два человека одинаково хорошо знающих один и тот же ЯП будут решать одну и ту же задачу разное время :)

Форт за счет интерактивности позволяет при правильном подходе быстро делать наброски при решении задачи - это его плюс.

_________________
Мне бы только мой крошечный вклад внести,
За короткую жизнь сплести
Хотя бы ниточку шёлка.
fleur


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Ср дек 02, 2009 22:31 
Не в сети
Moderator
Moderator
Аватара пользователя

Зарегистрирован: Чт май 04, 2006 00:53
Сообщения: 5062
Откуда: был Крым, теперь Новосибирск
Благодарил (а): 23 раз.
Поблагодарили: 63 раз.
вопрос писал(а):
Кстати, напомню, как долго мы решали простенькую и входящую в состав любого компилятора задачу перевода ин-пре-постфиксного порядка в строго постфиксный - это пример сложности.

имхо, это вопрос о том, кто решал ;)

_________________
Мне бы только мой крошечный вклад внести,
За короткую жизнь сплести
Хотя бы ниточку шёлка.
fleur


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Ср дек 02, 2009 22:46 
Не в сети

Зарегистрирован: Вт май 09, 2006 12:31
Сообщения: 3438
Благодарил (а): 5 раз.
Поблагодарили: 16 раз.
имхо, это вопрос о том, кто решал
не понял, о чём это


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Ср дек 02, 2009 23:17 
Не в сети
Moderator
Moderator
Аватара пользователя

Зарегистрирован: Чт май 04, 2006 00:53
Сообщения: 5062
Откуда: был Крым, теперь Новосибирск
Благодарил (а): 23 раз.
Поблагодарили: 63 раз.
вопрос писал(а):
не понял, о чём это

это о том, что проблема возникла у того, кто попытался напрямую перенести Сишное решение в Форт, и закономерно получил кучу проблем ;)

_________________
Мне бы только мой крошечный вклад внести,
За короткую жизнь сплести
Хотя бы ниточку шёлка.
fleur


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Чт дек 03, 2009 01:27 
Не в сети

Зарегистрирован: Вт май 09, 2006 12:31
Сообщения: 3438
Благодарил (а): 5 раз.
Поблагодарили: 16 раз.
Цитата:
это о том, что проблема возникла у того, кто попытался напрямую перенести Сишное решение в Форт, и закономерно получил кучу проблем
Как раз тот, кто пытался сишное в Форт, у того было меньше всех проблем: и ошибки с самого начала ловились и предупреждения выдавались и всё было относительно компактно, и настраиваемость была сквозная - что хочешь , то и транслируй. Просто код был с непривычки нечитаем. проблема была в том, что "общее" решение не обозначилось - такое, которое можно было бы сделать библиотекой


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

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


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

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


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

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